Process recieves incomplete vdso

55 views
Skip to first unread message

fctorial

unread,
Mar 3, 2021, 11:16:23 PM3/3/21
to zircon-dev
I've written a program that runs on zircon. It triggers a page fault when it tries to read the passed in vdso beyond 9 4k pages of memory (36864 bytes):


This is the output of this program:


The offset of section headers (166896) plus the size of section headers adds up to the size of libzircon.so.debug.

What could be causing this issue?

fctorial

unread,
Mar 3, 2021, 11:19:06 PM3/3/21
to zircon-dev, fctorial
This process is being created by userboot.

Marco Vanotti

unread,
Mar 4, 2021, 1:57:37 PM3/4/21
to fctorial, zircon-dev
Hi fctorial,

If I recall correctly, the section headers is removed from the elf that gets loaded into userspace. What's the value of e_shnum? It should be zero.

When your program crashes, you can see where the vdso gets loaded. In my computer, the size is 0x9000 bytes, which matches your experience.

--
All posts must follow the Fuchsia Code of Conduct https://fuchsia.dev/fuchsia-src/CODE_OF_CONDUCT or may be removed.
---
You received this message because you are subscribed to the Google Groups "zircon-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to zircon-dev+...@fuchsia.dev.
To view this discussion on the web visit https://groups.google.com/a/fuchsia.dev/d/msgid/zircon-dev/c9f7a28f-18b4-4ae6-9f20-9e38b5a9126an%40fuchsia.dev.

Roland McGrath

unread,
Mar 4, 2021, 4:05:31 PM3/4/21
to fctorial, zircon-dev
ELF sections are a development-time concept that does not exist at runtime when loading an ELF file such as an executable or shared library.
What you're doing with the vDSO is equivalent to what this C++ program does on its main executable:

#include <elf.h>                                                                
#include <link.h>                                                              
#include <inttypes.h>                                                          
#include <stdio.h>                                                              
                                                                               
extern "C" ElfW(Ehdr) __ehdr_start;                                            
                                                                               
int main(void) {                                                                
  printf("shoff %#" PRIx64 ", shnum %#" PRIu16 "\n",                            
         __ehdr_start.e_shoff, __ehdr_start.e_shnum);                          
  const ElfW(Shdr)* shdrs = reinterpret_cast<const ElfW(Shdr)*>(                
      reinterpret_cast<const char*>(&__ehdr_start) + __ehdr_start.e_shoff);    
  for (unsigned int i = 0; i < __ehdr_start.e_shnum; ++i) {                    
    printf("[%u] sh_type = %#x\n", i, shdrs[i].sh_type);                        
  }                                                                            


If you build that e.g. on Linux with `g++ -g -o foo foo.cc` and run `./foo` you'll see that e_shoff and e_shnum are set (consistent with that `readelf -WS foo` shows you).
However, the `sh_type` values it prints out don't match up with the actual sections in the file `foo`.
That's because the section table is not part of the runtime image, even though the ELF file header that points to it is.  

If you look at `readelf -Wl foo` you'll see the program headers, and specifically the LOAD segments.  That shows the regions of the file on disk that actually map to the runtime image.  The rest of the file, such as the section table and the debugging information, are part of the file but not part of the runtime image.  If you want to look at the section table or the debugging information, you need to look at the file `foo`, not the runtime memory of a process running `foo`.

In the case of the vDSO, there is no original file that you see anywhere on disk in the running system.  You can see the runtime memory image in your memory, but that's all you get.  If you want to look at the vDSO's development-time details like its debugging information, you can find the original file in the Fuchsia build (easiest way is by build ID lookup) but it will never exist anywhere as a file on a Fuchsia device.

fctorial

unread,
Mar 4, 2021, 5:50:30 PM3/4/21
to zircon-dev, Roland McGrath, zircon-dev, Marco Vanotti
This makes sense. I was trying to parse the vdso by reading the symbol table (locating it via section table). It worked for libzircon.so but failed for vdso. What is the intended way of locating the functions in the vdso?

fctorial

unread,
Mar 4, 2021, 6:03:31 PM3/4/21
to zircon-dev, fctorial, Roland McGrath, zircon-dev, marcova...@gmail.com
Never mind. It can be done with program headers. Thanks.

Roland McGrath

unread,
Mar 5, 2021, 4:53:34 PM3/5/21
to fctorial, zircon-dev, marcova...@gmail.com
Usually programs just rely on the dynamic linker to do this, e.g. with `dlsym(RTLD_NEXT, "_zx_foobar")` or `void* ptr = dlopen("libzircon.so", RTLD_NOW)` followed by `dlsym(ptr, "_zx_foobar")`.  But indeed if you are doing it from scratch (and what the dynamic linker is doing under the covers) is using the ELF file header (e_phoff/e_phnum) to find the program headers and using PT_DYNAMIC to find the dynamic symbol table and other such things in memory.
Reply all
Reply to author
Forward
0 new messages