diff options
author | Pawit Pornkitprasan <p.pawit@gmail.com> | 2012-11-23 12:27:25 +0700 |
---|---|---|
committer | Pawit Pornkitprasan <p.pawit@gmail.com> | 2012-11-23 19:12:00 +0700 |
commit | 6abffe3959f93a129c2ccda185379b02cc688ee3 (patch) | |
tree | 9ad1d983f0cb5a9ad91efba93daf3ca37171d405 /linker | |
parent | 5015fe9bf8869e794cfd972189876e5ff67a3a77 (diff) | |
download | bionic-6abffe3959f93a129c2ccda185379b02cc688ee3.zip bionic-6abffe3959f93a129c2ccda185379b02cc688ee3.tar.gz bionic-6abffe3959f93a129c2ccda185379b02cc688ee3.tar.bz2 |
linker: restore prelink support
Prelink support is required to load old vendor binary blobs
on many devices properly
This commit partially reverts 4688279db5dcc4004941e7f133c4a1c3617d842c
Change-Id: Ibc835095579c0bbd18aff61f37bd420de353e94d
Diffstat (limited to 'linker')
-rw-r--r-- | linker/linker.cpp | 50 | ||||
-rw-r--r-- | linker/linker_phdr.c | 8 | ||||
-rw-r--r-- | linker/linker_phdr.h | 1 |
3 files changed, 40 insertions, 19 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp index 46d1335..2362099 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -641,33 +641,35 @@ static int open_library(const char *name) return -1; } -// Returns 'true' if the library is prelinked or on failure so we error out -// either way. We no longer support prelinking. -static bool is_prelinked(int fd, const char* name) +typedef struct { + long mmap_addr; + char tag[4]; /* 'P', 'R', 'E', ' ' */ +} prelink_info_t; + +/* Returns the requested base address if the library is prelinked, + * and 0 otherwise. */ +static unsigned long +is_prelinked(int fd, const char *name) { - struct prelink_info_t { - long mmap_addr; - char tag[4]; // "PRE ". - }; - off_t sz = lseek(fd, -sizeof(prelink_info_t), SEEK_END); if (sz < 0) { - DL_ERR("lseek failed: %s", strerror(errno)); - return true; + DL_ERR("lseek() failed!"); + return 0; } prelink_info_t info; int rc = TEMP_FAILURE_RETRY(read(fd, &info, sizeof(info))); if (rc != sizeof(info)) { - DL_ERR("could not read prelink_info_t structure for \"%s\":", name, strerror(errno)); - return true; + WARN("Could not read prelink_info_t structure for `%s`\n", name); + return 0; } - if (memcmp(info.tag, "PRE ", 4) == 0) { - DL_ERR("prelinked libraries no longer supported: %s", name); - return true; + if (memcmp(info.tag, "PRE ", 4)) { + WARN("`%s` is not a prelinked library\n", name); + return 0; } - return false; + + return (unsigned long)info.mmap_addr; } /* verify_elf_header @@ -781,10 +783,21 @@ static soinfo* load_library(const char* name) return NULL; } - // We no longer support pre-linked libraries. - if (is_prelinked(fd.fd, name)) { + unsigned req_base = (unsigned) is_prelinked(fd.fd, name); + if (req_base == (unsigned)-1) { + DL_ERR("%5d can't read end of library: %s: %s", pid, name, + strerror(errno)); return NULL; } + if (req_base != 0) { + TRACE("[ %5d - Prelinked library '%s' requesting base @ 0x%08x ]\n", + pid, name, req_base); + } else { + TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name); + } + + TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name, + (req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz); // Reserve address space for all loadable segments. void* load_start = NULL; @@ -792,6 +805,7 @@ static soinfo* load_library(const char* name) Elf32_Addr load_bias = 0; ret = phdr_table_reserve_memory(phdr_table, phdr_count, + req_base, &load_start, &load_size, &load_bias); diff --git a/linker/linker_phdr.c b/linker/linker_phdr.c index 250ca20..36f848b 100644 --- a/linker/linker_phdr.c +++ b/linker/linker_phdr.c @@ -218,6 +218,8 @@ Elf32_Addr phdr_table_get_load_size(const Elf32_Phdr* phdr_table, * Input: * phdr_table -> program header table * phdr_count -> number of entries in the tables + * required_base -> for prelinked libraries, mandatory load address + * of the first loadable segment. 0 otherwise. * Output: * load_start -> first page of reserved address space range * load_size -> size in bytes of reserved address space range @@ -229,18 +231,22 @@ Elf32_Addr phdr_table_get_load_size(const Elf32_Phdr* phdr_table, int phdr_table_reserve_memory(const Elf32_Phdr* phdr_table, size_t phdr_count, + Elf32_Addr required_base, void** load_start, Elf32_Addr* load_size, Elf32_Addr* load_bias) { Elf32_Addr size = phdr_table_get_load_size(phdr_table, phdr_count); + if (size == 0) { errno = EINVAL; return -1; } int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; - void* start = mmap(NULL, size, PROT_NONE, mmap_flags, -1, 0); + if (required_base != 0) + mmap_flags |= MAP_FIXED; + void* start = mmap((void*)required_base, size, PROT_NONE, mmap_flags, -1, 0); if (start == MAP_FAILED) { return -1; } diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index a759262..19e281b 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -61,6 +61,7 @@ phdr_table_get_load_size(const Elf32_Phdr* phdr_table, int phdr_table_reserve_memory(const Elf32_Phdr* phdr_table, size_t phdr_count, + Elf32_Addr required_base, void** load_start, Elf32_Addr* load_size, Elf32_Addr* load_bias); |