From d9ad62343c2db6b66a5fa597c9b20a6faabd7a9a Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Thu, 20 Oct 2011 14:57:56 -0700 Subject: [PATCH] Add linker support for PIE Modify the dynamic linker so that executables can be loaded at locations other than 0x00000000. Modify crtbegin* so that non-PIC compilant "thumb interwork veneers" are not created by the linker. Bug: 5323301 Change-Id: Iece0272e2b708c79034f302c20160e1fe9029588 --- libc/arch-arm/bionic/crtbegin_dynamic.S | 14 ++++------ libc/arch-arm/bionic/crtbegin_static.S | 14 ++++------ linker/linker.c | 37 +++++++++++++++---------- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/libc/arch-arm/bionic/crtbegin_dynamic.S b/libc/arch-arm/bionic/crtbegin_dynamic.S index 099908444..6ca08458e 100644 --- a/libc/arch-arm/bionic/crtbegin_dynamic.S +++ b/libc/arch-arm/bionic/crtbegin_dynamic.S @@ -43,21 +43,17 @@ # - address of an "onexit" function, not used on any # platform supported by Bionic # -# - address of the "main" function of the program. We -# can't hard-code it in the adr pseudo instruction -# so we use a tiny trampoline that will get relocated -# by the dynamic linker before this code runs +# - address of the "main" function of the program. # # - address of the constructor list # _start: mov r0, sp mov r1, #0 - adr r2, 0f - adr r3, 1f - b __libc_init - -0: b main + ldr r2, =main + adr r3, 1f + ldr r4, =__libc_init + bx r4 1: .long __PREINIT_ARRAY__ .long __INIT_ARRAY__ diff --git a/libc/arch-arm/bionic/crtbegin_static.S b/libc/arch-arm/bionic/crtbegin_static.S index 13b05b272..e62ac1d6b 100644 --- a/libc/arch-arm/bionic/crtbegin_static.S +++ b/libc/arch-arm/bionic/crtbegin_static.S @@ -43,21 +43,17 @@ # - address of an "onexit" function, not used on any # platform supported by Bionic # -# - address of the "main" function of the program. We -# can't hard-code it in the adr pseudo instruction -# so we use a tiny trampoline that will get relocated -# by the dynamic linker before this code runs +# - address of the "main" function of the program. # # - address of the constructor list # _start: mov r0, sp mov r1, #0 - adr r2, 0f - adr r3, 1f - b __libc_init - -0: b main + ldr r2, =main + adr r3, 1f + ldr r4, =__libc_init + bx r4 1: .long __PREINIT_ARRAY__ .long __INIT_ARRAY__ diff --git a/linker/linker.c b/linker/linker.c index e0a8a1827..504fb9359 100644 --- a/linker/linker.c +++ b/linker/linker.c @@ -1741,16 +1741,17 @@ static int link_image(soinfo *si, unsigned wr_offset) if (phdr->p_type == PT_LOAD) { /* For the executable, we use the si->size field only in dl_unwind_find_exidx(), so the meaning of si->size - is not the size of the executable; it is the last - virtual address of the loadable part of the executable; - since si->base == 0 for an executable, we use the - range [0, si->size) to determine whether a PC value - falls within the executable section. Of course, if - a value is below phdr->p_vaddr, it's not in the - executable section, but a) we shouldn't be asking for - such a value anyway, and b) if we have to provide - an EXIDX for such a value, then the executable's - EXIDX is probably the better choice. + is not the size of the executable; it is the distance + between the load location of the executable and the last + address of the loadable part of the executable. + We use the range [si->base, si->base + si->size) to + determine whether a PC value falls within the executable + section. Of course, if a value is between si->base and + (si->base + phdr->p_vaddr), it's not in the executable + section, but a) we shouldn't be asking for such a value + anyway, and b) if we have to provide an EXIDX for such a + value, then the executable's EXIDX is probably the better + choice. */ DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid); if (phdr->p_vaddr + phdr->p_memsz > si->size) @@ -1760,12 +1761,20 @@ static int link_image(soinfo *si, unsigned wr_offset) if (!(phdr->p_flags & PF_W)) { unsigned _end; - if (phdr->p_vaddr < si->wrprotect_start) - si->wrprotect_start = phdr->p_vaddr; - _end = (((phdr->p_vaddr + phdr->p_memsz + PAGE_SIZE - 1) & + if (si->base + phdr->p_vaddr < si->wrprotect_start) + si->wrprotect_start = si->base + phdr->p_vaddr; + _end = (((si->base + phdr->p_vaddr + phdr->p_memsz + PAGE_SIZE - 1) & (~PAGE_MASK))); if (_end > si->wrprotect_end) si->wrprotect_end = _end; + /* Make the section writable just in case we'll have to + * write to it during relocation (i.e. text segment). + * However, we will remember what range of addresses + * should be write protected. + */ + mprotect((void *) (si->base + phdr->p_vaddr), + phdr->p_memsz, + PFLAGS_TO_PROT(phdr->p_flags) | PROT_WRITE); } } else if (phdr->p_type == PT_DYNAMIC) { if (si->dynamic != (unsigned *)-1) { @@ -2183,7 +2192,7 @@ unsigned __linker_init(unsigned **elfdata) vecs += 2; } - si->base = 0; + si->base = (Elf32_Addr) si->phdr - si->phdr->p_vaddr; si->dynamic = (unsigned *)-1; si->wrprotect_start = 0xffffffff; si->wrprotect_end = 0;