mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-22 04:50:07 +00:00
elf: Introduce rtld_setup_main_map
This function collects most of the processing needed to initialize the link map for the main executable. Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
This commit is contained in:
parent
0eb230ccce
commit
b4d4ff8963
303
elf/rtld.c
303
elf/rtld.c
@ -1129,17 +1129,172 @@ rtld_chain_load (struct link_map *main_map, char *argv0)
|
|||||||
rtld_soname, pathname, errcode);
|
rtld_soname, pathname, errcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called to complete the initialization of the link map for the main
|
||||||
|
executable. Returns true if there is a PT_INTERP segment. */
|
||||||
|
static bool
|
||||||
|
rtld_setup_main_map (struct link_map *main_map)
|
||||||
|
{
|
||||||
|
/* This have already been filled in right after _dl_new_object, or
|
||||||
|
as part of _dl_map_object. */
|
||||||
|
const ElfW(Phdr) *phdr = main_map->l_phdr;
|
||||||
|
ElfW(Word) phnum = main_map->l_phnum;
|
||||||
|
|
||||||
|
bool has_interp = false;
|
||||||
|
|
||||||
|
main_map->l_map_end = 0;
|
||||||
|
main_map->l_text_end = 0;
|
||||||
|
/* Perhaps the executable has no PT_LOAD header entries at all. */
|
||||||
|
main_map->l_map_start = ~0;
|
||||||
|
/* And it was opened directly. */
|
||||||
|
++main_map->l_direct_opencount;
|
||||||
|
|
||||||
|
/* Scan the program header table for the dynamic section. */
|
||||||
|
for (const ElfW(Phdr) *ph = phdr; ph < &phdr[phnum]; ++ph)
|
||||||
|
switch (ph->p_type)
|
||||||
|
{
|
||||||
|
case PT_PHDR:
|
||||||
|
/* Find out the load address. */
|
||||||
|
main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
|
||||||
|
break;
|
||||||
|
case PT_DYNAMIC:
|
||||||
|
/* This tells us where to find the dynamic section,
|
||||||
|
which tells us everything we need to do. */
|
||||||
|
main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
|
||||||
|
main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
|
||||||
|
break;
|
||||||
|
case PT_INTERP:
|
||||||
|
/* This "interpreter segment" was used by the program loader to
|
||||||
|
find the program interpreter, which is this program itself, the
|
||||||
|
dynamic linker. We note what name finds us, so that a future
|
||||||
|
dlopen call or DT_NEEDED entry, for something that wants to link
|
||||||
|
against the dynamic linker as a shared library, will know that
|
||||||
|
the shared object is already loaded. */
|
||||||
|
_dl_rtld_libname.name = ((const char *) main_map->l_addr
|
||||||
|
+ ph->p_vaddr);
|
||||||
|
/* _dl_rtld_libname.next = NULL; Already zero. */
|
||||||
|
GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
|
||||||
|
|
||||||
|
/* Ordinarilly, we would get additional names for the loader from
|
||||||
|
our DT_SONAME. This can't happen if we were actually linked as
|
||||||
|
a static executable (detect this case when we have no DYNAMIC).
|
||||||
|
If so, assume the filename component of the interpreter path to
|
||||||
|
be our SONAME, and add it to our name list. */
|
||||||
|
if (GL(dl_rtld_map).l_ld == NULL)
|
||||||
|
{
|
||||||
|
const char *p = NULL;
|
||||||
|
const char *cp = _dl_rtld_libname.name;
|
||||||
|
|
||||||
|
/* Find the filename part of the path. */
|
||||||
|
while (*cp != '\0')
|
||||||
|
if (*cp++ == '/')
|
||||||
|
p = cp;
|
||||||
|
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
_dl_rtld_libname2.name = p;
|
||||||
|
/* _dl_rtld_libname2.next = NULL; Already zero. */
|
||||||
|
_dl_rtld_libname.next = &_dl_rtld_libname2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
has_interp = true;
|
||||||
|
break;
|
||||||
|
case PT_LOAD:
|
||||||
|
{
|
||||||
|
ElfW(Addr) mapstart;
|
||||||
|
ElfW(Addr) allocend;
|
||||||
|
|
||||||
|
/* Remember where the main program starts in memory. */
|
||||||
|
mapstart = (main_map->l_addr
|
||||||
|
+ (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
|
||||||
|
if (main_map->l_map_start > mapstart)
|
||||||
|
main_map->l_map_start = mapstart;
|
||||||
|
|
||||||
|
/* Also where it ends. */
|
||||||
|
allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz;
|
||||||
|
if (main_map->l_map_end < allocend)
|
||||||
|
main_map->l_map_end = allocend;
|
||||||
|
if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end)
|
||||||
|
main_map->l_text_end = allocend;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PT_TLS:
|
||||||
|
if (ph->p_memsz > 0)
|
||||||
|
{
|
||||||
|
/* Note that in the case the dynamic linker we duplicate work
|
||||||
|
here since we read the PT_TLS entry already in
|
||||||
|
_dl_start_final. But the result is repeatable so do not
|
||||||
|
check for this special but unimportant case. */
|
||||||
|
main_map->l_tls_blocksize = ph->p_memsz;
|
||||||
|
main_map->l_tls_align = ph->p_align;
|
||||||
|
if (ph->p_align == 0)
|
||||||
|
main_map->l_tls_firstbyte_offset = 0;
|
||||||
|
else
|
||||||
|
main_map->l_tls_firstbyte_offset = (ph->p_vaddr
|
||||||
|
& (ph->p_align - 1));
|
||||||
|
main_map->l_tls_initimage_size = ph->p_filesz;
|
||||||
|
main_map->l_tls_initimage = (void *) ph->p_vaddr;
|
||||||
|
|
||||||
|
/* This image gets the ID one. */
|
||||||
|
GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PT_GNU_STACK:
|
||||||
|
GL(dl_stack_flags) = ph->p_flags;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PT_GNU_RELRO:
|
||||||
|
main_map->l_relro_addr = ph->p_vaddr;
|
||||||
|
main_map->l_relro_size = ph->p_memsz;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Process program headers again, but scan them backwards so
|
||||||
|
that PT_NOTE can be skipped if PT_GNU_PROPERTY exits. */
|
||||||
|
for (const ElfW(Phdr) *ph = &phdr[phnum]; ph != phdr; --ph)
|
||||||
|
switch (ph[-1].p_type)
|
||||||
|
{
|
||||||
|
case PT_NOTE:
|
||||||
|
_dl_process_pt_note (main_map, -1, &ph[-1]);
|
||||||
|
break;
|
||||||
|
case PT_GNU_PROPERTY:
|
||||||
|
_dl_process_pt_gnu_property (main_map, -1, &ph[-1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust the address of the TLS initialization image in case
|
||||||
|
the executable is actually an ET_DYN object. */
|
||||||
|
if (main_map->l_tls_initimage != NULL)
|
||||||
|
main_map->l_tls_initimage
|
||||||
|
= (char *) main_map->l_tls_initimage + main_map->l_addr;
|
||||||
|
if (! main_map->l_map_end)
|
||||||
|
main_map->l_map_end = ~0;
|
||||||
|
if (! main_map->l_text_end)
|
||||||
|
main_map->l_text_end = ~0;
|
||||||
|
if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name)
|
||||||
|
{
|
||||||
|
/* We were invoked directly, so the program might not have a
|
||||||
|
PT_INTERP. */
|
||||||
|
_dl_rtld_libname.name = GL(dl_rtld_map).l_name;
|
||||||
|
/* _dl_rtld_libname.next = NULL; Already zero. */
|
||||||
|
GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
assert (GL(dl_rtld_map).l_libname); /* How else did we get here? */
|
||||||
|
|
||||||
|
return has_interp;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dl_main (const ElfW(Phdr) *phdr,
|
dl_main (const ElfW(Phdr) *phdr,
|
||||||
ElfW(Word) phnum,
|
ElfW(Word) phnum,
|
||||||
ElfW(Addr) *user_entry,
|
ElfW(Addr) *user_entry,
|
||||||
ElfW(auxv_t) *auxv)
|
ElfW(auxv_t) *auxv)
|
||||||
{
|
{
|
||||||
const ElfW(Phdr) *ph;
|
|
||||||
struct link_map *main_map;
|
struct link_map *main_map;
|
||||||
size_t file_size;
|
size_t file_size;
|
||||||
char *file;
|
char *file;
|
||||||
bool has_interp = false;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
bool prelinked = false;
|
bool prelinked = false;
|
||||||
bool rtld_is_main = false;
|
bool rtld_is_main = false;
|
||||||
@ -1353,7 +1508,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
|||||||
load the program below unless it has a PT_GNU_STACK indicating
|
load the program below unless it has a PT_GNU_STACK indicating
|
||||||
nonexecutable stack is ok. */
|
nonexecutable stack is ok. */
|
||||||
|
|
||||||
for (ph = phdr; ph < &phdr[phnum]; ++ph)
|
for (const ElfW(Phdr) *ph = phdr; ph < &phdr[phnum]; ++ph)
|
||||||
if (ph->p_type == PT_GNU_STACK)
|
if (ph->p_type == PT_GNU_STACK)
|
||||||
{
|
{
|
||||||
GL(dl_stack_flags) = ph->p_flags;
|
GL(dl_stack_flags) = ph->p_flags;
|
||||||
@ -1472,147 +1627,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
|||||||
information for the program. */
|
information for the program. */
|
||||||
}
|
}
|
||||||
|
|
||||||
main_map->l_map_end = 0;
|
bool has_interp = rtld_setup_main_map (main_map);
|
||||||
main_map->l_text_end = 0;
|
|
||||||
/* Perhaps the executable has no PT_LOAD header entries at all. */
|
|
||||||
main_map->l_map_start = ~0;
|
|
||||||
/* And it was opened directly. */
|
|
||||||
++main_map->l_direct_opencount;
|
|
||||||
|
|
||||||
/* Scan the program header table for the dynamic section. */
|
|
||||||
for (ph = phdr; ph < &phdr[phnum]; ++ph)
|
|
||||||
switch (ph->p_type)
|
|
||||||
{
|
|
||||||
case PT_PHDR:
|
|
||||||
/* Find out the load address. */
|
|
||||||
main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
|
|
||||||
break;
|
|
||||||
case PT_DYNAMIC:
|
|
||||||
/* This tells us where to find the dynamic section,
|
|
||||||
which tells us everything we need to do. */
|
|
||||||
main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
|
|
||||||
main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
|
|
||||||
break;
|
|
||||||
case PT_INTERP:
|
|
||||||
/* This "interpreter segment" was used by the program loader to
|
|
||||||
find the program interpreter, which is this program itself, the
|
|
||||||
dynamic linker. We note what name finds us, so that a future
|
|
||||||
dlopen call or DT_NEEDED entry, for something that wants to link
|
|
||||||
against the dynamic linker as a shared library, will know that
|
|
||||||
the shared object is already loaded. */
|
|
||||||
_dl_rtld_libname.name = ((const char *) main_map->l_addr
|
|
||||||
+ ph->p_vaddr);
|
|
||||||
/* _dl_rtld_libname.next = NULL; Already zero. */
|
|
||||||
GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
|
|
||||||
|
|
||||||
/* Ordinarilly, we would get additional names for the loader from
|
|
||||||
our DT_SONAME. This can't happen if we were actually linked as
|
|
||||||
a static executable (detect this case when we have no DYNAMIC).
|
|
||||||
If so, assume the filename component of the interpreter path to
|
|
||||||
be our SONAME, and add it to our name list. */
|
|
||||||
if (GL(dl_rtld_map).l_ld == NULL)
|
|
||||||
{
|
|
||||||
const char *p = NULL;
|
|
||||||
const char *cp = _dl_rtld_libname.name;
|
|
||||||
|
|
||||||
/* Find the filename part of the path. */
|
|
||||||
while (*cp != '\0')
|
|
||||||
if (*cp++ == '/')
|
|
||||||
p = cp;
|
|
||||||
|
|
||||||
if (p != NULL)
|
|
||||||
{
|
|
||||||
_dl_rtld_libname2.name = p;
|
|
||||||
/* _dl_rtld_libname2.next = NULL; Already zero. */
|
|
||||||
_dl_rtld_libname.next = &_dl_rtld_libname2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
has_interp = true;
|
|
||||||
break;
|
|
||||||
case PT_LOAD:
|
|
||||||
{
|
|
||||||
ElfW(Addr) mapstart;
|
|
||||||
ElfW(Addr) allocend;
|
|
||||||
|
|
||||||
/* Remember where the main program starts in memory. */
|
|
||||||
mapstart = (main_map->l_addr
|
|
||||||
+ (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
|
|
||||||
if (main_map->l_map_start > mapstart)
|
|
||||||
main_map->l_map_start = mapstart;
|
|
||||||
|
|
||||||
/* Also where it ends. */
|
|
||||||
allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz;
|
|
||||||
if (main_map->l_map_end < allocend)
|
|
||||||
main_map->l_map_end = allocend;
|
|
||||||
if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end)
|
|
||||||
main_map->l_text_end = allocend;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PT_TLS:
|
|
||||||
if (ph->p_memsz > 0)
|
|
||||||
{
|
|
||||||
/* Note that in the case the dynamic linker we duplicate work
|
|
||||||
here since we read the PT_TLS entry already in
|
|
||||||
_dl_start_final. But the result is repeatable so do not
|
|
||||||
check for this special but unimportant case. */
|
|
||||||
main_map->l_tls_blocksize = ph->p_memsz;
|
|
||||||
main_map->l_tls_align = ph->p_align;
|
|
||||||
if (ph->p_align == 0)
|
|
||||||
main_map->l_tls_firstbyte_offset = 0;
|
|
||||||
else
|
|
||||||
main_map->l_tls_firstbyte_offset = (ph->p_vaddr
|
|
||||||
& (ph->p_align - 1));
|
|
||||||
main_map->l_tls_initimage_size = ph->p_filesz;
|
|
||||||
main_map->l_tls_initimage = (void *) ph->p_vaddr;
|
|
||||||
|
|
||||||
/* This image gets the ID one. */
|
|
||||||
GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PT_GNU_STACK:
|
|
||||||
GL(dl_stack_flags) = ph->p_flags;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PT_GNU_RELRO:
|
|
||||||
main_map->l_relro_addr = ph->p_vaddr;
|
|
||||||
main_map->l_relro_size = ph->p_memsz;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Process program headers again, but scan them backwards so
|
|
||||||
that PT_NOTE can be skipped if PT_GNU_PROPERTY exits. */
|
|
||||||
for (ph = &phdr[phnum]; ph != phdr; --ph)
|
|
||||||
switch (ph[-1].p_type)
|
|
||||||
{
|
|
||||||
case PT_NOTE:
|
|
||||||
_dl_process_pt_note (main_map, -1, &ph[-1]);
|
|
||||||
break;
|
|
||||||
case PT_GNU_PROPERTY:
|
|
||||||
_dl_process_pt_gnu_property (main_map, -1, &ph[-1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adjust the address of the TLS initialization image in case
|
|
||||||
the executable is actually an ET_DYN object. */
|
|
||||||
if (main_map->l_tls_initimage != NULL)
|
|
||||||
main_map->l_tls_initimage
|
|
||||||
= (char *) main_map->l_tls_initimage + main_map->l_addr;
|
|
||||||
if (! main_map->l_map_end)
|
|
||||||
main_map->l_map_end = ~0;
|
|
||||||
if (! main_map->l_text_end)
|
|
||||||
main_map->l_text_end = ~0;
|
|
||||||
if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name)
|
|
||||||
{
|
|
||||||
/* We were invoked directly, so the program might not have a
|
|
||||||
PT_INTERP. */
|
|
||||||
_dl_rtld_libname.name = GL(dl_rtld_map).l_name;
|
|
||||||
/* _dl_rtld_libname.next = NULL; Already zero. */
|
|
||||||
GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
assert (GL(dl_rtld_map).l_libname); /* How else did we get here? */
|
|
||||||
|
|
||||||
/* If the current libname is different from the SONAME, add the
|
/* If the current libname is different from the SONAME, add the
|
||||||
latter as well. */
|
latter as well. */
|
||||||
|
Loading…
Reference in New Issue
Block a user