Bug 651889 - Add support for dynamic symbol lookup in the Android dynamic linker. r=mwu

This commit is contained in:
Mike Hommey 2011-08-09 13:35:52 +02:00
Родитель dde3628746
Коммит 05fea6caff
1 изменённых файлов: 78 добавлений и 8 удалений

Просмотреть файл

@ -1428,9 +1428,7 @@ static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count)
}
void * remapped_page = NULL;
void * copy_page = mmap(NULL, PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
void * copy_page = NULL;
for (idx = 0; idx < count; ++idx) {
unsigned type = ELF32_R_TYPE(rel->r_info);
@ -1521,6 +1519,10 @@ static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count)
void * reloc_page = reloc & ~PAGE_MASK;
if ((si->flags & FLAG_MMAPPED) &&
(reloc < ro_region_end && reloc_page != remapped_page)) {
if (copy_page == NULL)
copy_page = mmap(NULL, PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (remapped_page != NULL)
mprotect(remapped_page, PAGE_SIZE, PROT_READ | PROT_EXEC);
memcpy(copy_page, reloc_page, PAGE_SIZE);
@ -1640,7 +1642,8 @@ static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count)
}
rel++;
}
munmap(copy_page, PAGE_SIZE);
if (copy_page)
munmap(copy_page, PAGE_SIZE);
return 0;
}
@ -1895,6 +1898,66 @@ static int nullify_closed_stdio (void)
return return_value;
}
/* Performs a single (plt) relocation for the relocation at index num, and
* returns the resulting relocated address */
static unsigned int plt_reloc(soinfo *si, unsigned int num)
{
if (si->plt_rel) {
reloc_library(si, &si->plt_rel[num], 1);
return *(unsigned int *)(si->base + si->plt_rel[num].r_offset);
}
#ifdef ANDROID_SH_LINKER
if (si->plt_rela) {
reloc_library_a(si, &si->plt_rela[num], 1);
return *(unsigned int *)(si->base + si->plt_rela[num].r_offset);
}
#endif
}
/* As this function is only referenced from assembly, we need to tell the
* compiler not to throw it away */
static unsigned int plt_reloc(soinfo *si, unsigned int num) __attribute__((used));
#ifdef ANDROID_ARM_LINKER
/* On ARM, the runtime symbol resolution function is called with
* - ip pointing to the function pointer to update in PLT_GOT
* - lr pointing to &PLT_GOT[2]
* - a pointer to the return address on top of the stack.
* Note that the stack, when this function is called, in unaligned
*/
__asm__ (
".text\n"
".align 2\n"
".type runtime_reloc, %function\n"
"runtime_reloc:\n"
/* We need to save r0-r3 because they are arguments we will be passing
* to the resolved function, and r4 to realign the stack */
"stmfd sp!, {r0-r4}\n"
/* Prepare the call to plt_reloc.
* The first argument is the soinfo pointer, which we stored at
* PLT_GOT[1], which is at lr - 4. */
"ldr r0, [lr, #-4]\n"
/* The second argument is the index of the plt entry, starting from
PLT_GOT[3]. This is (ip - (lr + 4)) / 4. */
"sub r1, ip, lr\n"
"sub r1, #4\n"
"lsr r1, r1, #2\n"
/* Call plt_reloc */
"bl plt_reloc\n"
/* Store the resolved function address to ip to use after overwriting
r0. */
"mov ip, r0\n"
/* Restore r0-r3 to be used as arguments when calling the resolved
* function, r4 which we saved to realign the stack and lr which
* was saved by the plt trampoline. */
"ldmia sp!, {r0-r4,lr}\n"
/* Jump to the resolved function. */
"bx ip\n"
);
#endif
static void runtime_reloc() __attribute__((used));
static int link_image(soinfo *si, unsigned wr_offset)
{
unsigned *d;
@ -2138,10 +2201,16 @@ static int link_image(soinfo *si, unsigned wr_offset)
}
}
/* Initialize GOT[1] and GOT[2], which are used by the PLT trampoline */
Elf32_Addr *got = (Elf32_Addr *)si->plt_got;
got[1] = (Elf32_Addr) si;
got[2] = (Elf32_Addr) runtime_reloc;
if(si->plt_rel) {
DEBUG("[ %5d relocating %s plt ]\n", pid, si->name );
if(reloc_library(si, si->plt_rel, si->plt_rel_count))
goto fail;
/* Relocate PLT GOT */
for (d = got + 3; d < got + 3 + si->plt_rel_count; d++)
*d += si->base;
}
if(si->rel) {
DEBUG("[ %5d relocating %s ]\n", pid, si->name );
@ -2152,8 +2221,9 @@ static int link_image(soinfo *si, unsigned wr_offset)
#ifdef ANDROID_SH_LINKER
if(si->plt_rela) {
DEBUG("[ %5d relocating %s plt ]\n", pid, si->name );
if(reloc_library_a(si, si->plt_rela, si->plt_rela_count))
goto fail;
/* Relocate PLT GOT */
for (d = got + 3; d < got + 3 + si->plt_rela_count; d++)
*d += si->base;
}
if(si->rela) {
DEBUG("[ %5d relocating %s ]\n", pid, si->name );