I have a C++ program that reads link_map
obtained from dlinfo(handle, RTLD_DI_LINKMAP, &link_map);
where handle was obtained by dlopen(NULL, RTLD_LAZY);
The program displays information about dynamic section for every library in link_map
. I'm trying to use d_ptr value from DT_SYMTAB tag (dyn->d_un.d_ptr
) to read symbols from the library.
One thing that I don't understand is why this address is small for linux-vdso.so.1
. I found that this is an offset from loaded_link_map->l_addr
.
I was looking information in many places. (eg. Use dlinfo to print all symbols in a library, http://www.sco.com/developers/gabi/latest/ch5.dynamic.html, https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/, http://www.sco.com/developers/gabi/1998-04-29/ch4.sheader.html, http://s.eresi-project.org/inc/articles/elf-rtld.txt)
I cannot find answers to this questions :
How to determinate if d_ptr is a "program virtual addresses" or "offset from loaded_link_map->l_addr"?
If small value (offsett) in
linux-vdso.so.1
is an exception or bug or this is ok and I don't understand why?
This is my simple program code:
#include <link.h>
#include <cstdio>
static const char *tag = "dl_util";
const char *dyn_tag_to_name(ElfW(Sxword) d_tag) {
switch (d_tag) {
case DT_STRTAB: return("DT_STRTAB");
case DT_SYMTAB: return("DT_SYMTAB");
default: return("UNKNOWN");
}
}
void print_dynamic_sections(const link_map *l) {
const ElfW(Dyn) *const dyn_start = l->l_ld;
const ElfW(Addr) load_addr = l->l_addr;
printf("Dynamic Sections:\n");
printf("|%-18s|%16s|\n", "Tag", "Ptr");
for (const ElfW(Dyn) *dyn = dyn_start; dyn->d_tag != DT_NULL; ++dyn) {
if(dyn->d_tag == DT_STRTAB || dyn->d_tag == DT_SYMTAB)
printf("|%-18s|%16lx|\n",
dyn_tag_to_name(dyn->d_tag),
dyn->d_un.d_val,
(const void *) (dyn->d_un.d_ptr));
}
}
int main() {
void *handle;
handle = dlopen(NULL, RTLD_LAZY);
if (!handle) {
printf("Error[%s]: %s\n", tag, dlerror());
return 1;
}
struct link_map *l;
int ld_ret = dlinfo(handle, RTLD_DI_LINKMAP, &l);
if (ld_ret) {
printf("Error[%s]: %s\n", tag, dlerror());
return 1;
}
printf("Loaded libraries: handle:0x%lx, prev:0x%lx\n", handle, (void*)l->l_prev);
do {
printf(" 0x%lx, %s\n", l->l_addr, l->l_name);
print_dynamic_sections(l);
l = l->l_next;
} while (l != NULL);
return 0;
}
And the code output is:
Loaded libraries: handle:0x7fb3f5bf7120, prev:0x0
0x562410906000,
Dynamic Sections:
|Tag | Ptr|
|DT_STRTAB | 562410906448|
|DT_SYMTAB | 562410906328|
0x7fff5978b000, linux-vdso.so.1
Dynamic Sections:
|Tag | Ptr|
|DT_STRTAB | 298|
|DT_SYMTAB | 1a8|
0x7fb3f5b55000, /usr/lib/libdl.so.2
Dynamic Sections:
|Tag | Ptr|
|DT_STRTAB | 7fb3f5b557a8|
|DT_SYMTAB | 7fb3f5b553a0|
0x7fb3f59c6000, /usr/lib/libstdc++.so.6
Dynamic Sections:
|Tag | Ptr|
|DT_STRTAB | 7fb3f59eef90|
|DT_SYMTAB | 7fb3f59ce758|
... more libraries