summaryrefslogtreecommitdiffstats
path: root/linker/linker.cpp
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2013-02-07 10:14:39 -0800
committerElliott Hughes <enh@google.com>2013-02-07 11:44:21 -0800
commit42b2c6a5eed5e4ef35315b8cd32d1355f12a69b6 (patch)
tree0fb55a369b620ef79cfa103f67a5184f067dadeb /linker/linker.cpp
parentd32fdbaf03f688497adbec885e85c0a69f7a4542 (diff)
downloadbionic-42b2c6a5eed5e4ef35315b8cd32d1355f12a69b6.zip
bionic-42b2c6a5eed5e4ef35315b8cd32d1355f12a69b6.tar.gz
bionic-42b2c6a5eed5e4ef35315b8cd32d1355f12a69b6.tar.bz2
Clean up the argc/argv/envp/auxv handling.
There's now only one place where we deal with this stuff, it only needs to be parsed once by the dynamic linker (rather than by each recipient), and it's now easier for us to get hold of auxv data early on. Change-Id: I6314224257c736547aac2e2a650e66f2ea53bef5
Diffstat (limited to 'linker/linker.cpp')
-rwxr-xr-xlinker/linker.cpp157
1 files changed, 58 insertions, 99 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 502035b..77c29a1 100755
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -42,6 +42,7 @@
// Private C library headers.
#include <private/bionic_tls.h>
#include <private/debug_format.h>
+#include <private/KernelArgumentBlock.h>
#include <private/logd.h>
#include <private/ScopedPthreadMutexLocker.h>
@@ -1771,15 +1772,8 @@ static bool soinfo_link_image(soinfo* si) {
* fixed it's own GOT. It is safe to make references to externs
* and other non-local data at this point.
*/
-static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linker_base)
-{
- static soinfo linker_soinfo;
-
- int argc = (int) *elfdata;
- char **argv = (char**) (elfdata + 1);
- unsigned *vecs = (unsigned*) (argv + argc + 1);
-
- /* NOTE: we store the elfdata pointer on a special location
+static unsigned __linker_init_post_relocation(KernelArgumentBlock& args, unsigned linker_base) {
+ /* NOTE: we store the args pointer on a special location
* of the temporary TLS area in order to pass it to
* the C Library's runtime initializer.
*
@@ -1787,7 +1781,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
* to point to a different location to ensure that no other
* shared library constructor can access it.
*/
- __libc_init_tls(elfdata);
+ __libc_init_tls(&args);
#if TIMING
struct timeval t0, t1;
@@ -1795,7 +1789,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
#endif
// Initialize environment functions, and get to the ELF aux vectors table.
- vecs = linker_env_init(vecs);
+ linker_env_init(args);
debugger_init();
@@ -1815,9 +1809,8 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
}
INFO("[ android linker & debugger ]\n");
- DEBUG("elfdata @ 0x%08x\n", (unsigned)elfdata);
- soinfo* si = soinfo_alloc(argv[0]);
+ soinfo* si = soinfo_alloc(args.argv[0]);
if (si == NULL) {
exit(EXIT_FAILURE);
}
@@ -1827,7 +1820,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
link_map* map = &(si->linkmap);
map->l_addr = 0;
- map->l_name = argv[0];
+ map->l_name = args.argv[0];
map->l_prev = NULL;
map->l_next = NULL;
@@ -1841,9 +1834,11 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
* Don't use soinfo_alloc(), because the linker shouldn't
* be on the soinfo list.
*/
- strlcpy((char*) linker_soinfo.name, "/system/bin/linker", sizeof linker_soinfo.name);
+ static soinfo linker_soinfo;
+ strlcpy(linker_soinfo.name, "/system/bin/linker", sizeof(linker_soinfo.name));
linker_soinfo.flags = 0;
linker_soinfo.base = linker_base;
+
/*
* Set the dynamic field in the link map otherwise gdb will complain with
* the following:
@@ -1851,42 +1846,29 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
* expected address (wrong library or version mismatch?)
*/
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_base;
- Elf32_Phdr *phdr =
- (Elf32_Phdr *)((unsigned char *) linker_base + elf_hdr->e_phoff);
+ Elf32_Phdr *phdr = (Elf32_Phdr*)((unsigned char*) linker_base + elf_hdr->e_phoff);
phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
&linker_soinfo.dynamic, NULL, NULL);
insert_soinfo_into_debug_map(&linker_soinfo);
- /* extract information passed from the kernel */
- while (vecs[0] != 0){
- switch(vecs[0]){
- case AT_PHDR:
- si->phdr = (Elf32_Phdr*) vecs[1];
- break;
- case AT_PHNUM:
- si->phnum = (int) vecs[1];
- break;
- case AT_ENTRY:
- si->entry = vecs[1];
- break;
- }
- vecs += 2;
- }
+ // Extract information passed from the kernel.
+ si->phdr = reinterpret_cast<Elf32_Phdr*>(args.getauxval(AT_PHDR));
+ si->phnum = args.getauxval(AT_PHNUM);
+ si->entry = args.getauxval(AT_ENTRY);
/* Compute the value of si->base. We can't rely on the fact that
* the first entry is the PHDR because this will not be true
* for certain executables (e.g. some in the NDK unit test suite)
*/
- int nn;
si->base = 0;
si->size = phdr_table_get_load_size(si->phdr, si->phnum);
si->load_bias = 0;
- for ( nn = 0; nn < si->phnum; nn++ ) {
- if (si->phdr[nn].p_type == PT_PHDR) {
- si->load_bias = (Elf32_Addr)si->phdr - si->phdr[nn].p_vaddr;
- si->base = (Elf32_Addr) si->phdr - si->phdr[nn].p_offset;
- break;
- }
+ for (int i = 0; i < si->phnum; ++i) {
+ if (si->phdr[i].p_type == PT_PHDR) {
+ si->load_bias = reinterpret_cast<Elf32_Addr>(si->phdr) - si->phdr[i].p_vaddr;
+ si->base = reinterpret_cast<Elf32_Addr>(si->phdr) - si->phdr[i].p_offset;
+ break;
+ }
}
si->dynamic = (unsigned *)-1;
si->refcount = 1;
@@ -1920,13 +1902,13 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
#if TIMING
gettimeofday(&t1,NULL);
- PRINT("LINKER TIME: %s: %d microseconds\n", argv[0], (int) (
+ PRINT("LINKER TIME: %s: %d microseconds\n", e.argv[0], (int) (
(((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
(((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)
));
#endif
#if STATS
- PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol\n", argv[0],
+ PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol\n", e.argv[0],
linker_stats.count[kRelocAbsolute],
linker_stats.count[kRelocRelative],
linker_stats.count[kRelocCopy],
@@ -1946,7 +1928,7 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
}
}
}
- PRINT("PAGES MODIFIED: %s: %d (%dKB)\n", argv[0], count, count * 4);
+ PRINT("PAGES MODIFIED: %s: %d (%dKB)\n", e.argv[0], count, count * 4);
}
#endif
@@ -1958,31 +1940,6 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata, unsigned linke
return si->entry;
}
-/*
- * Find the value of AT_BASE passed to us by the kernel. This is the load
- * location of the linker.
- */
-static unsigned find_linker_base(unsigned **elfdata) {
- int argc = (int) *elfdata;
- char **argv = (char**) (elfdata + 1);
- unsigned *vecs = (unsigned*) (argv + argc + 1);
- while (vecs[0] != 0) {
- vecs++;
- }
-
- /* The end of the environment block is marked by two NULL pointers */
- vecs++;
-
- while(vecs[0]) {
- if (vecs[0] == AT_BASE) {
- return vecs[1];
- }
- vecs += 2;
- }
-
- return 0; // should never happen
-}
-
/* Compute the load-bias of an existing executable. This shall only
* be used to compute the load bias of an executable or shared library
* that was loaded by the kernel itself.
@@ -2018,39 +1975,41 @@ get_elf_exec_load_bias(const Elf32_Ehdr* elf)
* relocations, any attempt to reference an extern variable, extern
* function, or other GOT reference will generate a segfault.
*/
-extern "C" unsigned __linker_init(unsigned **elfdata) {
- unsigned linker_addr = find_linker_base(elfdata);
- Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_addr;
- Elf32_Phdr *phdr =
- (Elf32_Phdr *)((unsigned char *) linker_addr + elf_hdr->e_phoff);
-
- soinfo linker_so;
- memset(&linker_so, 0, sizeof(soinfo));
-
- linker_so.base = linker_addr;
- linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
- linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
- linker_so.dynamic = (unsigned *) -1;
- linker_so.phdr = phdr;
- linker_so.phnum = elf_hdr->e_phnum;
- linker_so.flags |= FLAG_LINKER;
-
- if (!soinfo_link_image(&linker_so)) {
- // It would be nice to print an error message, but if the linker
- // can't link itself, there's no guarantee that we'll be able to
- // call write() (because it involves a GOT reference).
- //
- // This situation should never occur unless the linker itself
- // is corrupt.
- exit(EXIT_FAILURE);
- }
+extern "C" unsigned __linker_init(void* raw_args) {
+ KernelArgumentBlock args(raw_args);
+
+ unsigned linker_addr = args.getauxval(AT_BASE);
+
+ Elf32_Ehdr *elf_hdr = (Elf32_Ehdr*) linker_addr;
+ Elf32_Phdr *phdr = (Elf32_Phdr*)((unsigned char*) linker_addr + elf_hdr->e_phoff);
+
+ soinfo linker_so;
+ memset(&linker_so, 0, sizeof(soinfo));
+
+ linker_so.base = linker_addr;
+ linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
+ linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
+ linker_so.dynamic = (unsigned*) -1;
+ linker_so.phdr = phdr;
+ linker_so.phnum = elf_hdr->e_phnum;
+ linker_so.flags |= FLAG_LINKER;
+
+ if (!soinfo_link_image(&linker_so)) {
+ // It would be nice to print an error message, but if the linker
+ // can't link itself, there's no guarantee that we'll be able to
+ // call write() (because it involves a GOT reference).
+ //
+ // This situation should never occur unless the linker itself
+ // is corrupt.
+ exit(EXIT_FAILURE);
+ }
- // We have successfully fixed our own relocations. It's safe to run
- // the main part of the linker now.
- unsigned start_address = __linker_init_post_relocation(elfdata, linker_addr);
+ // We have successfully fixed our own relocations. It's safe to run
+ // the main part of the linker now.
+ unsigned start_address = __linker_init_post_relocation(args, linker_addr);
- set_soinfo_pool_protection(PROT_READ);
+ set_soinfo_pool_protection(PROT_READ);
- // Return the address that the calling assembly stub should jump to.
- return start_address;
+ // Return the address that the calling assembly stub should jump to.
+ return start_address;
}