From e365f9d6543bc6607864ef61257505239dde15d1 Mon Sep 17 00:00:00 2001 From: Marcus Oakland Date: Thu, 10 Oct 2013 15:19:31 +0100 Subject: [PATCH] AArch64: Linker64 support for AArch64 Addition of support for AArch64 in the linker64 target. Change-Id: I8dfd9711278f6706063e91f626b6007ea7a3dd6e Signed-off-by: Marcus Oakland --- libc/arch-x86_64/include/machine/exec.h | 2 +- linker/Android.mk | 2 +- linker/arch/aarch64/begin.S | 38 ++++ linker/debugger.cpp | 2 +- linker/dlfcn.cpp | 4 +- linker/linker.cpp | 223 +++++++++++++++++++++++- linker/linker_phdr.cpp | 13 +- tests/Android.mk | 3 - 8 files changed, 264 insertions(+), 23 deletions(-) create mode 100644 linker/arch/aarch64/begin.S diff --git a/libc/arch-x86_64/include/machine/exec.h b/libc/arch-x86_64/include/machine/exec.h index 6d16439cb..829351cfb 100644 --- a/libc/arch-x86_64/include/machine/exec.h +++ b/libc/arch-x86_64/include/machine/exec.h @@ -12,7 +12,7 @@ #define ELF_TARG_CLASS ELFCLASS64 #define ELF_TARG_DATA ELFDATA2LSB -#define ELF_TARG_MACH EM_AMD64 +#define ELF_TARG_MACH EM_X86_64 #define _NLIST_DO_ELF #define _KERN_DO_ELF64 diff --git a/linker/Android.mk b/linker/Android.mk index f73d8d682..1bf3e9def 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -33,7 +33,7 @@ LOCAL_CPPFLAGS += \ # We need to access Bionic private headers in the linker. LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/ -ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86_64)) +ifeq ($(TARGET_IS_64_BIT),true) LOCAL_MODULE := linker64 else LOCAL_MODULE := linker diff --git a/linker/arch/aarch64/begin.S b/linker/arch/aarch64/begin.S new file mode 100644 index 000000000..55618b7f3 --- /dev/null +++ b/linker/arch/aarch64/begin.S @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +ENTRY(_start) + mov x0, sp + mov x1, xzr + bl __linker_init + + /* linker init returns the _entry address in the main image */ + br x0 +END(_start) diff --git a/linker/debugger.cpp b/linker/debugger.cpp index 29afab1f5..92e9dacdf 100644 --- a/linker/debugger.cpp +++ b/linker/debugger.cpp @@ -92,7 +92,7 @@ static int socket_abstract_client(const char* name, int type) { return -1; } - int err = TEMP_FAILURE_RETRY(connect(s, (sockaddr*) &addr, alen)); + int err = TEMP_FAILURE_RETRY(connect(s, reinterpret_cast(&addr), alen)); if (err == -1) { close(s); s = -1; diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 09f3ddffd..207e03c3d 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -148,13 +148,13 @@ int dlclose(void* handle) { // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012 3456789 #define ANDROID_LIBDL_STRTAB \ "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_iterate_phdr\0dl_unwind_find_exidx\0" -#elif defined(__i386__) || defined(__mips__) || defined(__x86_64__) +#elif defined(__aarch64__) || defined(__i386__) || defined(__mips__) || defined(__x86_64__) // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667 // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890 #define ANDROID_LIBDL_STRTAB \ "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_iterate_phdr\0" #else -#error Unsupported architecture. Only ARM, MIPS, x86, and x86_64 are presently supported. +#error Unsupported architecture. Only aarch64, arm, mips, x86, and x86_64 are presently supported. #endif // name_offset: starting index of the name in libdl_info.strtab diff --git a/linker/linker.cpp b/linker/linker.cpp index 6ebba8e2f..81ca2f50f 100755 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -138,10 +139,18 @@ static void count_relocation(RelocationKind) { #if COUNT_PAGES static unsigned bitmask[4096]; +#if defined(__LP64__) +#define MARK(offset) \ + do { \ + if ((((offset) >> 12) >> 5) < 4096) \ + bitmask[((offset) >> 12) >> 5] |= (1 << (((offset) >> 12) & 31)); \ + } while(0) +#else #define MARK(offset) \ do { \ bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \ } while(0) +#endif #else #define MARK(x) do {} while (0) #endif @@ -889,7 +898,20 @@ static int soinfo_relocate_a(soinfo* si, Elf_Rela* rela, unsigned count, soinfo* */ switch (type) { -#if defined(__x86_64__) +#if defined(__aarch64__) + case R_AARCH64_JUMP_SLOT: + case R_AARCH64_GLOB_DAT: + case R_AARCH64_ABS64: + case R_AARCH64_ABS32: + case R_AARCH64_ABS16: + case R_AARCH64_RELATIVE: + /* + * The sym_addr was initialized to be zero above, or the relocation + * code below does not care about value of sym_addr. + * No need to do anything. + */ + break; +#elif defined(__x86_64__) case R_X86_64_JUMP_SLOT: case R_X86_64_GLOB_DAT: case R_X86_64_32: @@ -900,7 +922,6 @@ static int soinfo_relocate_a(soinfo* si, Elf_Rela* rela, unsigned count, soinfo* sym_addr = reloc; break; #endif - default: DL_ERR("unknown weak reloc type %d @ %p (%d)", type, rela, (int) (rela - start)); return -1; @@ -915,7 +936,197 @@ static int soinfo_relocate_a(soinfo* si, Elf_Rela* rela, unsigned count, soinfo* } switch (type) { -#if defined(__x86_64__) +#if defined(__aarch64__) + case R_AARCH64_JUMP_SLOT: + count_relocation(kRelocAbsolute); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO JMP_SLOT %16lx <- %16lx %s\n", + reloc, + (sym_addr + rela->r_addend), + sym_name); + *reinterpret_cast(reloc) = (sym_addr + rela->r_addend); + break; + case R_AARCH64_GLOB_DAT: + count_relocation(kRelocAbsolute); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO GLOB_DAT %16lx <- %16lx %s\n", + reloc, + (sym_addr + rela->r_addend), + sym_name); + *reinterpret_cast(reloc) = (sym_addr + rela->r_addend); + break; + case R_AARCH64_ABS64: + count_relocation(kRelocAbsolute); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO ABS64 %16lx <- %16lx %s\n", + reloc, + (sym_addr + rela->r_addend), + sym_name); + *reinterpret_cast(reloc) += (sym_addr + rela->r_addend); + break; + case R_AARCH64_ABS32: + count_relocation(kRelocAbsolute); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO ABS32 %16lx <- %16lx %s\n", + reloc, + (sym_addr + rela->r_addend), + sym_name); + if ((static_cast(INT32_MIN) <= + (*reinterpret_cast(reloc) + (sym_addr + rela->r_addend))) && + ((*reinterpret_cast(reloc) + (sym_addr + rela->r_addend)) <= + static_cast(UINT32_MAX))) { + *reinterpret_cast(reloc) += (sym_addr + rela->r_addend); + } else { + DL_ERR("0x%016lx out of range 0x%016lx to 0x%016lx", + (*reinterpret_cast(reloc) + (sym_addr + rela->r_addend)), + static_cast(INT32_MIN), + static_cast(UINT32_MAX)); + return -1; + } + break; + case R_AARCH64_ABS16: + count_relocation(kRelocAbsolute); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO ABS16 %16lx <- %16lx %s\n", + reloc, + (sym_addr + rela->r_addend), + sym_name); + if ((static_cast(INT16_MIN) <= + (*reinterpret_cast(reloc) + (sym_addr + rela->r_addend))) && + ((*reinterpret_cast(reloc) + (sym_addr + rela->r_addend)) <= + static_cast(UINT16_MAX))) { + *reinterpret_cast(reloc) += (sym_addr + rela->r_addend); + } else { + DL_ERR("0x%016lx out of range 0x%016lx to 0x%016lx", + (*reinterpret_cast(reloc) + (sym_addr + rela->r_addend)), + static_cast(INT16_MIN), + static_cast(UINT16_MAX)); + return -1; + } + break; + case R_AARCH64_PREL64: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO REL64 %16lx <- %16lx - %16lx %s\n", + reloc, + (sym_addr + rela->r_addend), + rela->r_offset, + sym_name); + *reinterpret_cast(reloc) += (sym_addr + rela->r_addend) - rela->r_offset; + break; + case R_AARCH64_PREL32: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO REL32 %16lx <- %16lx - %16lx %s\n", + reloc, + (sym_addr + rela->r_addend), + rela->r_offset, sym_name); + if ((static_cast(INT32_MIN) <= + (*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) && + ((*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= + static_cast(UINT32_MAX))) { + *reinterpret_cast(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset); + } else { + DL_ERR("0x%016lx out of range 0x%016lx to 0x%016lx", + (*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)), + static_cast(INT32_MIN), + static_cast(UINT32_MAX)); + return -1; + } + break; + case R_AARCH64_PREL16: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO REL16 %16lx <- %16lx - %16lx %s\n", + reloc, + (sym_addr + rela->r_addend), + rela->r_offset, sym_name); + if ((static_cast(INT16_MIN) <= + (*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset))) && + ((*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)) <= + static_cast(UINT16_MAX))) { + *reinterpret_cast(reloc) += ((sym_addr + rela->r_addend) - rela->r_offset); + } else { + DL_ERR("0x%016lx out of range 0x%016lx to 0x%016lx", + (*reinterpret_cast(reloc) + ((sym_addr + rela->r_addend) - rela->r_offset)), + static_cast(INT16_MIN), + static_cast(UINT16_MAX)); + return -1; + } + break; + + case R_AARCH64_RELATIVE: + count_relocation(kRelocRelative); + MARK(rela->r_offset); + if (sym) { + DL_ERR("odd RELATIVE form..."); + return -1; + } + TRACE_TYPE(RELO, "RELO RELATIVE %16lx <- %16lx\n", + reloc, + (si->base + rela->r_addend)); + *reinterpret_cast(reloc) = (si->base + rela->r_addend); + break; + + case R_AARCH64_COPY: + if ((si->flags & FLAG_EXE) == 0) { + /* + * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf + * + * Section 4.7.1.10 "Dynamic relocations" + * R_AARCH64_COPY may only appear in executable objects where e_type is + * set to ET_EXEC. + * + * FLAG_EXE is set for both ET_DYN and ET_EXEC executables. + * We should explicitly disallow ET_DYN executables from having + * R_AARCH64_COPY relocations. + */ + DL_ERR("%s R_AARCH64_COPY relocations only supported for ET_EXEC", si->name); + return -1; + } + count_relocation(kRelocCopy); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "RELO COPY %16lx <- %ld @ %16lx %s\n", + reloc, + s->st_size, + (sym_addr + rela->r_addend), + sym_name); + if (reloc == (sym_addr + rela->r_addend)) { + Elf_Sym *src = soinfo_do_lookup(NULL, sym_name, &lsi, needed); + + if (src == NULL) { + DL_ERR("%s R_AARCH64_COPY relocation source cannot be resolved", si->name); + return -1; + } + if (lsi->has_DT_SYMBOLIC) { + DL_ERR("%s invalid R_AARCH64_COPY relocation against DT_SYMBOLIC shared " + "library %s (built with -Bsymbolic?)", si->name, lsi->name); + return -1; + } + if (s->st_size < src->st_size) { + DL_ERR("%s R_AARCH64_COPY relocation size mismatch (%ld < %ld)", + si->name, s->st_size, src->st_size); + return -1; + } + memcpy((void*)reloc, (void*)(src->st_value + lsi->load_bias), src->st_size); + } else { + DL_ERR("%s R_AARCH64_COPY relocation target cannot be resolved", si->name); + return -1; + } + break; + case R_AARCH64_TLS_TPREL64: + TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16lx <- %16lx - %16lx\n", + reloc, + (sym_addr + rela->r_addend), + rela->r_offset); + break; + case R_AARCH64_TLS_DTPREL32: + TRACE_TYPE(RELO, "RELO TLS_DTPREL32 *** %16lx <- %16lx - %16lx\n", + reloc, + (sym_addr + rela->r_addend), + rela->r_offset); + break; +#elif defined(__x86_64__) case R_X86_64_JUMP_SLOT: count_relocation(kRelocAbsolute); MARK(rela->r_offset); @@ -964,6 +1175,7 @@ static int soinfo_relocate_a(soinfo* si, Elf_Rela* rela, unsigned count, soinfo* *reinterpret_cast(reloc) = sym_addr + rela->r_addend - reloc; break; #endif + default: DL_ERR("unknown reloc type %d @ %p (%d)", type, rela, (int) (rela - start)); return -1; @@ -1934,7 +2146,11 @@ static Elf_Addr __linker_init_post_relocation(KernelArgumentBlock& args, Elf_Add for (n = 0; n < 4096; n++) { if (bitmask[n]) { unsigned x = bitmask[n]; +#if defined(__LP64__) + for (i = 0; i < 32; i++) { +#else for (i = 0; i < 8; i++) { +#endif if (x & 1) { count++; } @@ -1990,7 +2206,6 @@ extern "C" Elf_Addr __linker_init(void* raw_args) { KernelArgumentBlock args(raw_args); Elf_Addr linker_addr = args.getauxval(AT_BASE); - Elf_Ehdr* elf_hdr = reinterpret_cast(linker_addr); Elf_Phdr* phdr = (Elf_Phdr*)((unsigned char*) linker_addr + elf_hdr->e_phoff); diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 4884364a5..b4d72b27d 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -29,6 +29,7 @@ #include "linker_phdr.h" #include +#include #include #include "linker.h" @@ -201,17 +202,7 @@ bool ElfReader::VerifyElfHeader() { return false; } - if (header_.e_machine != -#if defined(__arm__) - EM_ARM -#elif defined(__i386__) - EM_386 -#elif defined(__mips__) - EM_MIPS -#elif defined(__x86_64__) - EM_X86_64 -#endif - ) { + if (header_.e_machine != ELF_TARG_MACH) { DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine); return false; } diff --git a/tests/Android.mk b/tests/Android.mk index d4d82ee8f..a342be777 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -32,9 +32,6 @@ test_c_flags = \ ifeq ($(TARGET_ARCH),aarch64) $(info TODO: $(LOCAL_PATH)/Android.mk -fstack-protector not yet available for the AArch64 toolchain) test_c_flags += -fno-stack-protector - - $(info TODO: $(LOCAL_PATH)/Android.mk aarch64 GCC sees things other GCCs do not; punt for now) - test_c_flags += -Wno-error=strict-aliasing endif # aarch64 test_src_files = \