This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] ld.so: Adjust the auxv if ld.so is directly invoked
- From: "Andreas Krebbel" <krebbel at linux dot vnet dot ibm dot com>
- To: libc-alpha at gnu dot org
- Cc: roland at redhat dot com
- Date: Wed, 13 Jan 2010 11:21:39 +0100
- Subject: [PATCH] ld.so: Adjust the auxv if ld.so is directly invoked
Hi,
if a binary gets invoked by passing it as argument to ld.so the stack
still holds the auxiliary vector of ld.so when entering the _start
routine of the executable. So the invocation via ld.so is not fully
transparent to the executable. This causes problems if the executable
wants to scan the auxv itself.
The executable might want to do this in order to locate the elf header
in memory for e.g. hwcap checks. In a discussion on libc-help:
http://sources.redhat.com/ml/libc-help/2010-01/msg00019.html the
AT_PHDR field has been identified to be the best way to do this
safely.
The attached patch adds a new parameter to dl_main which holds a
pointer to the auxv on the stack. That way it is possible to rescan
the vector and adjust several values in dl_main.
I already have a S/390 patch for start.s which will make use of this
and has successfully been tested in combination with that patch.
Tested on x86_64, s390 and s390x. No regressions.
Ok?
Bye,
-Andreas-
2010-01-13 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
* elf/dl-sysdep.c (_dl_sysdep_start): Added the auxv parameter to
dl_main.
* elf/dl-open.c (_dl_sysdep_start): Likewise..
* sysdeps/generic/ldsodefs.h (_dl_sysdep_start): Likewise.
* elf/rtld.c (dl_main): Added new parameter auxv. Adjust the
AT_PHDR, AT_PHNUM and AT_ENTRY fields if the ld.so is directly
started.
Index: glibc/elf/dl-sysdep.c
===================================================================
--- glibc.orig/elf/dl-sysdep.c 2010-01-13 09:56:54.000000000 +0100
+++ glibc/elf/dl-sysdep.c 2010-01-13 10:21:34.000000000 +0100
@@ -85,7 +85,7 @@ void *_dl_random attribute_relro = NULL;
ElfW(Addr)
_dl_sysdep_start (void **start_argptr,
void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
- ElfW(Addr) *user_entry))
+ ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv))
{
const ElfW(Phdr) *phdr = NULL;
ElfW(Word) phnum = 0;
@@ -241,7 +241,7 @@ _dl_sysdep_start (void **start_argptr,
if (__builtin_expect (INTUSE(__libc_enable_secure), 0))
__libc_check_standard_fds ();
- (*dl_main) (phdr, phnum, &user_entry);
+ (*dl_main) (phdr, phnum, &user_entry, _dl_auxv);
return user_entry;
}
Index: glibc/elf/rtld.c
===================================================================
--- glibc.orig/elf/rtld.c 2010-01-13 09:56:54.000000000 +0100
+++ glibc/elf/rtld.c 2010-01-13 10:21:34.000000000 +0100
@@ -182,7 +182,7 @@ extern struct rtld_global_ro _rtld_local
static void dl_main (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
- ElfW(Addr) *user_entry);
+ ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv);
/* These two variables cannot be moved into .data.rel.ro. */
static struct libname_list _dl_rtld_libname;
@@ -882,7 +882,8 @@ static int version_info attribute_relro;
static void
dl_main (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
- ElfW(Addr) *user_entry)
+ ElfW(Addr) *user_entry,
+ ElfW(auxv_t) *auxv)
{
const ElfW(Phdr) *ph;
enum mode mode;
@@ -927,6 +928,8 @@ dl_main (const ElfW(Phdr) *phdr,
if (*user_entry == (ElfW(Addr)) ENTRY_POINT)
{
+ ElfW(auxv_t) *av;
+
/* Ho ho. We are not the program interpreter! We are the program
itself! This means someone ran ld.so as a command. Well, that
might be convenient to do sometimes. We support it by
@@ -1082,6 +1085,20 @@ of this helper program; chances are you
makes sense to free the old string first. */
main_map->l_name = (char *) "";
*user_entry = main_map->l_entry;
+
+ for (av = auxv; av->a_type != AT_NULL; av++)
+ switch (av->a_type)
+ {
+ case AT_PHDR:
+ av->a_un.a_val = phdr;
+ break;
+ case AT_PHNUM:
+ av->a_un.a_val = phnum;
+ break;
+ case AT_ENTRY:
+ av->a_un.a_val = *user_entry;
+ break;
+ }
}
else
{
Index: glibc/elf/dl-open.c
===================================================================
--- glibc.orig/elf/dl-open.c 2010-01-13 09:56:54.000000000 +0100
+++ glibc/elf/dl-open.c 2010-01-13 10:21:34.000000000 +0100
@@ -40,7 +40,8 @@
extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
void (*dl_main) (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
- ElfW(Addr) *user_entry));
+ ElfW(Addr) *user_entry,
+ ElfW(auxv_t) *auxv));
weak_extern (BP_SYM (_dl_sysdep_start))
extern int __libc_multiple_libcs; /* Defined in init-first.c. */
Index: glibc/sysdeps/generic/ldsodefs.h
===================================================================
--- glibc.orig/sysdeps/generic/ldsodefs.h 2010-01-13 09:56:54.000000000 +0100
+++ glibc/sysdeps/generic/ldsodefs.h 2010-01-13 10:21:34.000000000 +0100
@@ -1015,7 +1015,8 @@ extern void *_dl_sysdep_read_whole_file
extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
void (*dl_main) (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
- ElfW(Addr) *user_entry))
+ ElfW(Addr) *user_entry,
+ ElfW(auxv_t) *auxv))
attribute_hidden;
extern void _dl_sysdep_start_cleanup (void)