Index: bfd/elf32-arm.c |
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c |
index 31ea8610dd21f5d0367912548a523347559ec827..bc1f19532cde4d5a48f7c88430ccdf8a7931cd3a 100644 |
--- a/bfd/elf32-arm.c |
+++ b/bfd/elf32-arm.c |
@@ -1,6 +1,6 @@ |
/* 32-bit ELF support for ARM |
Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, |
- 2008, 2009, 2010, 2011 Free Software Foundation, Inc. |
+ 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
@@ -23,9 +23,11 @@ |
#include <limits.h> |
#include "bfd.h" |
+#include "bfd_stdint.h" |
#include "libiberty.h" |
#include "libbfd.h" |
#include "elf-bfd.h" |
+#include "elf-nacl.h" |
#include "elf-vxworks.h" |
#include "elf/arm.h" |
@@ -1988,6 +1990,54 @@ elf32_arm_nabi_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) |
return TRUE; |
} |
+static char * |
+elf32_arm_nabi_write_core_note (bfd *abfd, char *buf, int *bufsiz, |
+ int note_type, ...) |
+{ |
+ switch (note_type) |
+ { |
+ default: |
+ return NULL; |
+ |
+ case NT_PRPSINFO: |
+ { |
+ char data[124]; |
+ va_list ap; |
+ |
+ va_start (ap, note_type); |
+ memset (data, 0, sizeof (data)); |
+ strncpy (data + 28, va_arg (ap, const char *), 16); |
+ strncpy (data + 44, va_arg (ap, const char *), 80); |
+ va_end (ap); |
+ |
+ return elfcore_write_note (abfd, buf, bufsiz, |
+ "CORE", note_type, data, sizeof (data)); |
+ } |
+ |
+ case NT_PRSTATUS: |
+ { |
+ char data[148]; |
+ va_list ap; |
+ long pid; |
+ int cursig; |
+ const void *greg; |
+ |
+ va_start (ap, note_type); |
+ memset (data, 0, sizeof (data)); |
+ pid = va_arg (ap, long); |
+ bfd_put_32 (abfd, pid, data + 24); |
+ cursig = va_arg (ap, int); |
+ bfd_put_16 (abfd, cursig, data + 12); |
+ greg = va_arg (ap, const void *); |
+ memcpy (data + 72, greg, 72); |
+ va_end (ap); |
+ |
+ return elfcore_write_note (abfd, buf, bufsiz, |
+ "CORE", note_type, data, sizeof (data)); |
+ } |
+ } |
+} |
+ |
#define TARGET_LITTLE_SYM bfd_elf32_littlearm_vec |
#define TARGET_LITTLE_NAME "elf32-littlearm" |
#define TARGET_BIG_SYM bfd_elf32_bigarm_vec |
@@ -1995,6 +2045,7 @@ elf32_arm_nabi_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) |
#define elf_backend_grok_prstatus elf32_arm_nabi_grok_prstatus |
#define elf_backend_grok_psinfo elf32_arm_nabi_grok_psinfo |
+#define elf_backend_write_core_note elf32_arm_nabi_write_core_note |
typedef unsigned long int insn32; |
typedef unsigned short int insn16; |
@@ -2029,24 +2080,24 @@ typedef unsigned short int insn16; |
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" |
static const unsigned long tls_trampoline [] = |
- { |
- 0xe08e0000, /* add r0, lr, r0 */ |
- 0xe5901004, /* ldr r1, [r0,#4] */ |
- 0xe12fff11, /* bx r1 */ |
- }; |
+{ |
+ 0xe08e0000, /* add r0, lr, r0 */ |
+ 0xe5901004, /* ldr r1, [r0,#4] */ |
+ 0xe12fff11, /* bx r1 */ |
+}; |
static const unsigned long dl_tlsdesc_lazy_trampoline [] = |
- { |
- 0xe52d2004, /* push {r2} */ |
- 0xe59f200c, /* ldr r2, [pc, #3f - . - 8] */ |
- 0xe59f100c, /* ldr r1, [pc, #4f - . - 8] */ |
- 0xe79f2002, /* 1: ldr r2, [pc, r2] */ |
- 0xe081100f, /* 2: add r1, pc */ |
- 0xe12fff12, /* bx r2 */ |
- 0x00000014, /* 3: .word _GLOBAL_OFFSET_TABLE_ - 1b - 8 |
+{ |
+ 0xe52d2004, /* push {r2} */ |
+ 0xe59f200c, /* ldr r2, [pc, #3f - . - 8] */ |
+ 0xe59f100c, /* ldr r1, [pc, #4f - . - 8] */ |
+ 0xe79f2002, /* 1: ldr r2, [pc, r2] */ |
+ 0xe081100f, /* 2: add r1, pc */ |
+ 0xe12fff12, /* bx r2 */ |
+ 0x00000014, /* 3: .word _GLOBAL_OFFSET_TABLE_ - 1b - 8 |
+ dl_tlsdesc_lazy_resolver(GOT) */ |
- 0x00000018, /* 4: .word _GLOBAL_OFFSET_TABLE_ - 2b - 8 */ |
- }; |
+ 0x00000018, /* 4: .word _GLOBAL_OFFSET_TABLE_ - 2b - 8 */ |
+}; |
#ifdef FOUR_WORD_PLT |
@@ -2055,22 +2106,22 @@ static const unsigned long dl_tlsdesc_lazy_trampoline [] = |
called before the relocation has been set up calls the dynamic |
linker first. */ |
static const bfd_vma elf32_arm_plt0_entry [] = |
- { |
- 0xe52de004, /* str lr, [sp, #-4]! */ |
- 0xe59fe010, /* ldr lr, [pc, #16] */ |
- 0xe08fe00e, /* add lr, pc, lr */ |
- 0xe5bef008, /* ldr pc, [lr, #8]! */ |
- }; |
+{ |
+ 0xe52de004, /* str lr, [sp, #-4]! */ |
+ 0xe59fe010, /* ldr lr, [pc, #16] */ |
+ 0xe08fe00e, /* add lr, pc, lr */ |
+ 0xe5bef008, /* ldr pc, [lr, #8]! */ |
+}; |
/* Subsequent entries in a procedure linkage table look like |
this. */ |
static const bfd_vma elf32_arm_plt_entry [] = |
- { |
- 0xe28fc600, /* add ip, pc, #NN */ |
- 0xe28cca00, /* add ip, ip, #NN */ |
- 0xe5bcf000, /* ldr pc, [ip, #NN]! */ |
- 0x00000000, /* unused */ |
- }; |
+{ |
+ 0xe28fc600, /* add ip, pc, #NN */ |
+ 0xe28cca00, /* add ip, ip, #NN */ |
+ 0xe5bcf000, /* ldr pc, [ip, #NN]! */ |
+ 0x00000000, /* unused */ |
+}; |
#else |
@@ -2079,72 +2130,111 @@ static const bfd_vma elf32_arm_plt_entry [] = |
called before the relocation has been set up calls the dynamic |
linker first. */ |
static const bfd_vma elf32_arm_plt0_entry [] = |
- { |
- 0xe52de004, /* str lr, [sp, #-4]! */ |
- 0xe59fe004, /* ldr lr, [pc, #4] */ |
- 0xe08fe00e, /* add lr, pc, lr */ |
- 0xe5bef008, /* ldr pc, [lr, #8]! */ |
- 0x00000000, /* &GOT[0] - . */ |
- }; |
+{ |
+ 0xe52de004, /* str lr, [sp, #-4]! */ |
+ 0xe59fe004, /* ldr lr, [pc, #4] */ |
+ 0xe08fe00e, /* add lr, pc, lr */ |
+ 0xe5bef008, /* ldr pc, [lr, #8]! */ |
+ 0x00000000, /* &GOT[0] - . */ |
+}; |
/* Subsequent entries in a procedure linkage table look like |
this. */ |
static const bfd_vma elf32_arm_plt_entry [] = |
- { |
- 0xe28fc600, /* add ip, pc, #0xNN00000 */ |
- 0xe28cca00, /* add ip, ip, #0xNN000 */ |
- 0xe5bcf000, /* ldr pc, [ip, #0xNNN]! */ |
- }; |
+{ |
+ 0xe28fc600, /* add ip, pc, #0xNN00000 */ |
+ 0xe28cca00, /* add ip, ip, #0xNN000 */ |
+ 0xe5bcf000, /* ldr pc, [ip, #0xNNN]! */ |
+}; |
#endif |
/* The format of the first entry in the procedure linkage table |
for a VxWorks executable. */ |
static const bfd_vma elf32_arm_vxworks_exec_plt0_entry[] = |
- { |
- 0xe52dc008, /* str ip,[sp,#-8]! */ |
- 0xe59fc000, /* ldr ip,[pc] */ |
- 0xe59cf008, /* ldr pc,[ip,#8] */ |
- 0x00000000, /* .long _GLOBAL_OFFSET_TABLE_ */ |
- }; |
+{ |
+ 0xe52dc008, /* str ip,[sp,#-8]! */ |
+ 0xe59fc000, /* ldr ip,[pc] */ |
+ 0xe59cf008, /* ldr pc,[ip,#8] */ |
+ 0x00000000, /* .long _GLOBAL_OFFSET_TABLE_ */ |
+}; |
/* The format of subsequent entries in a VxWorks executable. */ |
static const bfd_vma elf32_arm_vxworks_exec_plt_entry[] = |
- { |
- 0xe59fc000, /* ldr ip,[pc] */ |
- 0xe59cf000, /* ldr pc,[ip] */ |
- 0x00000000, /* .long @got */ |
- 0xe59fc000, /* ldr ip,[pc] */ |
- 0xea000000, /* b _PLT */ |
- 0x00000000, /* .long @pltindex*sizeof(Elf32_Rela) */ |
- }; |
+{ |
+ 0xe59fc000, /* ldr ip,[pc] */ |
+ 0xe59cf000, /* ldr pc,[ip] */ |
+ 0x00000000, /* .long @got */ |
+ 0xe59fc000, /* ldr ip,[pc] */ |
+ 0xea000000, /* b _PLT */ |
+ 0x00000000, /* .long @pltindex*sizeof(Elf32_Rela) */ |
+}; |
/* The format of entries in a VxWorks shared library. */ |
static const bfd_vma elf32_arm_vxworks_shared_plt_entry[] = |
- { |
- 0xe59fc000, /* ldr ip,[pc] */ |
- 0xe79cf009, /* ldr pc,[ip,r9] */ |
- 0x00000000, /* .long @got */ |
- 0xe59fc000, /* ldr ip,[pc] */ |
- 0xe599f008, /* ldr pc,[r9,#8] */ |
- 0x00000000, /* .long @pltindex*sizeof(Elf32_Rela) */ |
- }; |
+{ |
+ 0xe59fc000, /* ldr ip,[pc] */ |
+ 0xe79cf009, /* ldr pc,[ip,r9] */ |
+ 0x00000000, /* .long @got */ |
+ 0xe59fc000, /* ldr ip,[pc] */ |
+ 0xe599f008, /* ldr pc,[r9,#8] */ |
+ 0x00000000, /* .long @pltindex*sizeof(Elf32_Rela) */ |
+}; |
/* An initial stub used if the PLT entry is referenced from Thumb code. */ |
#define PLT_THUMB_STUB_SIZE 4 |
static const bfd_vma elf32_arm_plt_thumb_stub [] = |
- { |
- 0x4778, /* bx pc */ |
- 0x46c0 /* nop */ |
- }; |
+{ |
+ 0x4778, /* bx pc */ |
+ 0x46c0 /* nop */ |
+}; |
/* The entries in a PLT when using a DLL-based target with multiple |
address spaces. */ |
static const bfd_vma elf32_arm_symbian_plt_entry [] = |
- { |
- 0xe51ff004, /* ldr pc, [pc, #-4] */ |
- 0x00000000, /* dcd R_ARM_GLOB_DAT(X) */ |
- }; |
+{ |
+ 0xe51ff004, /* ldr pc, [pc, #-4] */ |
+ 0x00000000, /* dcd R_ARM_GLOB_DAT(X) */ |
+}; |
+ |
+/* The first entry in a procedure linkage table looks like |
+ this. It is set up so that any shared library function that is |
+ called before the relocation has been set up calls the dynamic |
+ linker first. */ |
+static const bfd_vma elf32_arm_nacl_plt0_entry [] = |
+{ |
+ /* First bundle: */ |
+ 0xe300c000, /* movw ip, #:lower16:&GOT[2]-.+8 */ |
+ 0xe340c000, /* movt ip, #:upper16:&GOT[2]-.+8 */ |
+ 0xe08cc00f, /* add ip, ip, pc */ |
+ 0xe52dc008, /* str ip, [sp, #-8]! */ |
+ /* Second bundle: */ |
+ 0xe7dfcf1f, /* bfc ip, #30, #2 */ |
+ 0xe59cc000, /* ldr ip, [ip] */ |
+ 0xe3ccc13f, /* bic ip, ip, #0xc000000f */ |
+ 0xe12fff1c, /* bx ip */ |
+ /* Third bundle: */ |
+ 0xe320f000, /* nop */ |
+ 0xe320f000, /* nop */ |
+ 0xe320f000, /* nop */ |
+ /* .Lplt_tail: */ |
+ 0xe50dc004, /* str ip, [sp, #-4] */ |
+ /* Fourth bundle: */ |
+ 0xe7dfcf1f, /* bfc ip, #30, #2 */ |
+ 0xe59cc000, /* ldr ip, [ip] */ |
+ 0xe3ccc13f, /* bic ip, ip, #0xc000000f */ |
+ 0xe12fff1c, /* bx ip */ |
+}; |
+#define ARM_NACL_PLT_TAIL_OFFSET (11 * 4) |
+ |
+/* Subsequent entries in a procedure linkage table look like this. */ |
+static const bfd_vma elf32_arm_nacl_plt_entry [] = |
+{ |
+ 0xe300c000, /* movw ip, #:lower16:&GOT[n]-.+8 */ |
+ 0xe340c000, /* movt ip, #:upper16:&GOT[n]-.+8 */ |
+ 0xe08cc00f, /* add ip, ip, pc */ |
+ 0xea000000, /* b .Lplt_tail */ |
+}; |
#define ARM_MAX_FWD_BRANCH_OFFSET ((((1 << 23) - 1) << 2) + 8) |
#define ARM_MAX_BWD_BRANCH_OFFSET ((-((1 << 23) << 2)) + 8) |
@@ -2154,12 +2244,12 @@ static const bfd_vma elf32_arm_symbian_plt_entry [] = |
#define THM2_MAX_BWD_BRANCH_OFFSET (-(1 << 24) + 4) |
enum stub_insn_type |
- { |
- THUMB16_TYPE = 1, |
- THUMB32_TYPE, |
- ARM_TYPE, |
- DATA_TYPE |
- }; |
+{ |
+ THUMB16_TYPE = 1, |
+ THUMB32_TYPE, |
+ ARM_TYPE, |
+ DATA_TYPE |
+}; |
#define THUMB16_INSN(X) {(X), THUMB16_TYPE, R_ARM_NONE, 0} |
/* A bit of a hack. A Thumb conditional branch, in which the proper condition |
@@ -2173,154 +2263,154 @@ enum stub_insn_type |
typedef struct |
{ |
- bfd_vma data; |
- enum stub_insn_type type; |
- unsigned int r_type; |
- int reloc_addend; |
+ bfd_vma data; |
+ enum stub_insn_type type; |
+ unsigned int r_type; |
+ int reloc_addend; |
} insn_sequence; |
/* Arm/Thumb -> Arm/Thumb long branch stub. On V5T and above, use blx |
to reach the stub if necessary. */ |
static const insn_sequence elf32_arm_stub_long_branch_any_any[] = |
- { |
- ARM_INSN(0xe51ff004), /* ldr pc, [pc, #-4] */ |
- DATA_WORD(0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
- }; |
+{ |
+ ARM_INSN (0xe51ff004), /* ldr pc, [pc, #-4] */ |
+ DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
+}; |
/* V4T Arm -> Thumb long branch stub. Used on V4T where blx is not |
available. */ |
static const insn_sequence elf32_arm_stub_long_branch_v4t_arm_thumb[] = |
- { |
- ARM_INSN(0xe59fc000), /* ldr ip, [pc, #0] */ |
- ARM_INSN(0xe12fff1c), /* bx ip */ |
- DATA_WORD(0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
- }; |
+{ |
+ ARM_INSN (0xe59fc000), /* ldr ip, [pc, #0] */ |
+ ARM_INSN (0xe12fff1c), /* bx ip */ |
+ DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
+}; |
/* Thumb -> Thumb long branch stub. Used on M-profile architectures. */ |
static const insn_sequence elf32_arm_stub_long_branch_thumb_only[] = |
- { |
- THUMB16_INSN(0xb401), /* push {r0} */ |
- THUMB16_INSN(0x4802), /* ldr r0, [pc, #8] */ |
- THUMB16_INSN(0x4684), /* mov ip, r0 */ |
- THUMB16_INSN(0xbc01), /* pop {r0} */ |
- THUMB16_INSN(0x4760), /* bx ip */ |
- THUMB16_INSN(0xbf00), /* nop */ |
- DATA_WORD(0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
- }; |
+{ |
+ THUMB16_INSN (0xb401), /* push {r0} */ |
+ THUMB16_INSN (0x4802), /* ldr r0, [pc, #8] */ |
+ THUMB16_INSN (0x4684), /* mov ip, r0 */ |
+ THUMB16_INSN (0xbc01), /* pop {r0} */ |
+ THUMB16_INSN (0x4760), /* bx ip */ |
+ THUMB16_INSN (0xbf00), /* nop */ |
+ DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
+}; |
/* V4T Thumb -> Thumb long branch stub. Using the stack is not |
allowed. */ |
static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb[] = |
- { |
- THUMB16_INSN(0x4778), /* bx pc */ |
- THUMB16_INSN(0x46c0), /* nop */ |
- ARM_INSN(0xe59fc000), /* ldr ip, [pc, #0] */ |
- ARM_INSN(0xe12fff1c), /* bx ip */ |
- DATA_WORD(0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
- }; |
+{ |
+ THUMB16_INSN (0x4778), /* bx pc */ |
+ THUMB16_INSN (0x46c0), /* nop */ |
+ ARM_INSN (0xe59fc000), /* ldr ip, [pc, #0] */ |
+ ARM_INSN (0xe12fff1c), /* bx ip */ |
+ DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
+}; |
/* V4T Thumb -> ARM long branch stub. Used on V4T where blx is not |
available. */ |
static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_arm[] = |
- { |
- THUMB16_INSN(0x4778), /* bx pc */ |
- THUMB16_INSN(0x46c0), /* nop */ |
- ARM_INSN(0xe51ff004), /* ldr pc, [pc, #-4] */ |
- DATA_WORD(0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
- }; |
+{ |
+ THUMB16_INSN (0x4778), /* bx pc */ |
+ THUMB16_INSN (0x46c0), /* nop */ |
+ ARM_INSN (0xe51ff004), /* ldr pc, [pc, #-4] */ |
+ DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ |
+}; |
/* V4T Thumb -> ARM short branch stub. Shorter variant of the above |
one, when the destination is close enough. */ |
static const insn_sequence elf32_arm_stub_short_branch_v4t_thumb_arm[] = |
- { |
- THUMB16_INSN(0x4778), /* bx pc */ |
- THUMB16_INSN(0x46c0), /* nop */ |
- ARM_REL_INSN(0xea000000, -8), /* b (X-8) */ |
- }; |
+{ |
+ THUMB16_INSN (0x4778), /* bx pc */ |
+ THUMB16_INSN (0x46c0), /* nop */ |
+ ARM_REL_INSN (0xea000000, -8), /* b (X-8) */ |
+}; |
/* ARM/Thumb -> ARM long branch stub, PIC. On V5T and above, use |
blx to reach the stub if necessary. */ |
static const insn_sequence elf32_arm_stub_long_branch_any_arm_pic[] = |
- { |
- ARM_INSN(0xe59fc000), /* ldr ip, [pc] */ |
- ARM_INSN(0xe08ff00c), /* add pc, pc, ip */ |
- DATA_WORD(0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X-4) */ |
- }; |
+{ |
+ ARM_INSN (0xe59fc000), /* ldr ip, [pc] */ |
+ ARM_INSN (0xe08ff00c), /* add pc, pc, ip */ |
+ DATA_WORD (0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X-4) */ |
+}; |
/* ARM/Thumb -> Thumb long branch stub, PIC. On V5T and above, use |
blx to reach the stub if necessary. We can not add into pc; |
it is not guaranteed to mode switch (different in ARMv6 and |
ARMv7). */ |
static const insn_sequence elf32_arm_stub_long_branch_any_thumb_pic[] = |
- { |
- ARM_INSN(0xe59fc004), /* ldr ip, [pc, #4] */ |
- ARM_INSN(0xe08fc00c), /* add ip, pc, ip */ |
- ARM_INSN(0xe12fff1c), /* bx ip */ |
- DATA_WORD(0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ |
- }; |
+{ |
+ ARM_INSN (0xe59fc004), /* ldr ip, [pc, #4] */ |
+ ARM_INSN (0xe08fc00c), /* add ip, pc, ip */ |
+ ARM_INSN (0xe12fff1c), /* bx ip */ |
+ DATA_WORD (0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ |
+}; |
/* V4T ARM -> ARM long branch stub, PIC. */ |
static const insn_sequence elf32_arm_stub_long_branch_v4t_arm_thumb_pic[] = |
- { |
- ARM_INSN(0xe59fc004), /* ldr ip, [pc, #4] */ |
- ARM_INSN(0xe08fc00c), /* add ip, pc, ip */ |
- ARM_INSN(0xe12fff1c), /* bx ip */ |
- DATA_WORD(0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ |
- }; |
+{ |
+ ARM_INSN (0xe59fc004), /* ldr ip, [pc, #4] */ |
+ ARM_INSN (0xe08fc00c), /* add ip, pc, ip */ |
+ ARM_INSN (0xe12fff1c), /* bx ip */ |
+ DATA_WORD (0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ |
+}; |
/* V4T Thumb -> ARM long branch stub, PIC. */ |
static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_arm_pic[] = |
- { |
- THUMB16_INSN(0x4778), /* bx pc */ |
- THUMB16_INSN(0x46c0), /* nop */ |
- ARM_INSN(0xe59fc000), /* ldr ip, [pc, #0] */ |
- ARM_INSN(0xe08cf00f), /* add pc, ip, pc */ |
- DATA_WORD(0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X) */ |
- }; |
+{ |
+ THUMB16_INSN (0x4778), /* bx pc */ |
+ THUMB16_INSN (0x46c0), /* nop */ |
+ ARM_INSN (0xe59fc000), /* ldr ip, [pc, #0] */ |
+ ARM_INSN (0xe08cf00f), /* add pc, ip, pc */ |
+ DATA_WORD (0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X) */ |
+}; |
/* Thumb -> Thumb long branch stub, PIC. Used on M-profile |
architectures. */ |
static const insn_sequence elf32_arm_stub_long_branch_thumb_only_pic[] = |
- { |
- THUMB16_INSN(0xb401), /* push {r0} */ |
- THUMB16_INSN(0x4802), /* ldr r0, [pc, #8] */ |
- THUMB16_INSN(0x46fc), /* mov ip, pc */ |
- THUMB16_INSN(0x4484), /* add ip, r0 */ |
- THUMB16_INSN(0xbc01), /* pop {r0} */ |
- THUMB16_INSN(0x4760), /* bx ip */ |
- DATA_WORD(0, R_ARM_REL32, 4), /* dcd R_ARM_REL32(X) */ |
- }; |
+{ |
+ THUMB16_INSN (0xb401), /* push {r0} */ |
+ THUMB16_INSN (0x4802), /* ldr r0, [pc, #8] */ |
+ THUMB16_INSN (0x46fc), /* mov ip, pc */ |
+ THUMB16_INSN (0x4484), /* add ip, r0 */ |
+ THUMB16_INSN (0xbc01), /* pop {r0} */ |
+ THUMB16_INSN (0x4760), /* bx ip */ |
+ DATA_WORD (0, R_ARM_REL32, 4), /* dcd R_ARM_REL32(X) */ |
+}; |
/* V4T Thumb -> Thumb long branch stub, PIC. Using the stack is not |
allowed. */ |
static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb_pic[] = |
- { |
- THUMB16_INSN(0x4778), /* bx pc */ |
- THUMB16_INSN(0x46c0), /* nop */ |
- ARM_INSN(0xe59fc004), /* ldr ip, [pc, #4] */ |
- ARM_INSN(0xe08fc00c), /* add ip, pc, ip */ |
- ARM_INSN(0xe12fff1c), /* bx ip */ |
- DATA_WORD(0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ |
- }; |
+{ |
+ THUMB16_INSN (0x4778), /* bx pc */ |
+ THUMB16_INSN (0x46c0), /* nop */ |
+ ARM_INSN (0xe59fc004), /* ldr ip, [pc, #4] */ |
+ ARM_INSN (0xe08fc00c), /* add ip, pc, ip */ |
+ ARM_INSN (0xe12fff1c), /* bx ip */ |
+ DATA_WORD (0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ |
+}; |
/* Thumb2/ARM -> TLS trampoline. Lowest common denominator, which is a |
long PIC stub. We can use r1 as a scratch -- and cannot use ip. */ |
static const insn_sequence elf32_arm_stub_long_branch_any_tls_pic[] = |
{ |
- ARM_INSN(0xe59f1000), /* ldr r1, [pc] */ |
- ARM_INSN(0xe08ff001), /* add pc, pc, r1 */ |
- DATA_WORD(0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X-4) */ |
+ ARM_INSN (0xe59f1000), /* ldr r1, [pc] */ |
+ ARM_INSN (0xe08ff001), /* add pc, pc, r1 */ |
+ DATA_WORD (0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X-4) */ |
}; |
/* V4T Thumb -> TLS trampoline. lowest common denominator, which is a |
long PIC stub. We can use r1 as a scratch -- and cannot use ip. */ |
static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_tls_pic[] = |
{ |
- THUMB16_INSN(0x4778), /* bx pc */ |
- THUMB16_INSN(0x46c0), /* nop */ |
- ARM_INSN(0xe59f1000), /* ldr r1, [pc, #0] */ |
- ARM_INSN(0xe081f00f), /* add pc, r1, pc */ |
- DATA_WORD(0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X) */ |
+ THUMB16_INSN (0x4778), /* bx pc */ |
+ THUMB16_INSN (0x46c0), /* nop */ |
+ ARM_INSN (0xe59f1000), /* ldr r1, [pc, #0] */ |
+ ARM_INSN (0xe081f00f), /* add pc, r1, pc */ |
+ DATA_WORD (0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X) */ |
}; |
/* Cortex-A8 erratum-workaround stubs. */ |
@@ -2329,32 +2419,32 @@ static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_tls_pic[] = |
can't use a conditional branch to reach this stub). */ |
static const insn_sequence elf32_arm_stub_a8_veneer_b_cond[] = |
- { |
- THUMB16_BCOND_INSN(0xd001), /* b<cond>.n true. */ |
- THUMB32_B_INSN(0xf000b800, -4), /* b.w insn_after_original_branch. */ |
- THUMB32_B_INSN(0xf000b800, -4) /* true: b.w original_branch_dest. */ |
- }; |
+{ |
+ THUMB16_BCOND_INSN (0xd001), /* b<cond>.n true. */ |
+ THUMB32_B_INSN (0xf000b800, -4), /* b.w insn_after_original_branch. */ |
+ THUMB32_B_INSN (0xf000b800, -4) /* true: b.w original_branch_dest. */ |
+}; |
/* Stub used for b.w and bl.w instructions. */ |
static const insn_sequence elf32_arm_stub_a8_veneer_b[] = |
- { |
- THUMB32_B_INSN(0xf000b800, -4) /* b.w original_branch_dest. */ |
- }; |
+{ |
+ THUMB32_B_INSN (0xf000b800, -4) /* b.w original_branch_dest. */ |
+}; |
static const insn_sequence elf32_arm_stub_a8_veneer_bl[] = |
- { |
- THUMB32_B_INSN(0xf000b800, -4) /* b.w original_branch_dest. */ |
- }; |
+{ |
+ THUMB32_B_INSN (0xf000b800, -4) /* b.w original_branch_dest. */ |
+}; |
/* Stub used for Thumb-2 blx.w instructions. We modified the original blx.w |
instruction (which switches to ARM mode) to point to this stub. Jump to the |
real destination using an ARM-mode branch. */ |
static const insn_sequence elf32_arm_stub_a8_veneer_blx[] = |
- { |
- ARM_REL_INSN(0xea000000, -8) /* b original_branch_dest. */ |
- }; |
+{ |
+ ARM_REL_INSN (0xea000000, -8) /* b original_branch_dest. */ |
+}; |
/* For each section group there can be a specially created linker section |
to hold the stubs for that group. The name of the stub section is based |
@@ -2364,7 +2454,7 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] = |
PR 13049: STUB_SUFFIX used to be ".stub", but this allowed the user to |
create what appeared to be a linker stub section when it actually |
contained user code/data. For example, consider this fragment: |
- |
+ |
const char * stubborn_problems[] = { "np" }; |
If this is compiled with "-fPIC -fdata-sections" then gcc produces a |
@@ -2405,7 +2495,8 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] = |
DEF_STUB(a8_veneer_blx) |
#define DEF_STUB(x) arm_stub_##x, |
-enum elf32_arm_stub_type { |
+enum elf32_arm_stub_type |
+{ |
arm_stub_none, |
DEF_STUBS |
/* Note the first a8_veneer type */ |
@@ -2420,7 +2511,8 @@ typedef struct |
} stub_def; |
#define DEF_STUB(x) {elf32_arm_stub_##x, ARRAY_SIZE(elf32_arm_stub_##x)}, |
-static const stub_def stub_definitions[] = { |
+static const stub_def stub_definitions[] = |
+{ |
{NULL, 0}, |
DEF_STUBS |
}; |
@@ -2573,7 +2665,8 @@ _arm_elf_section_data; |
relaxing which we can refresh easily, then create stubs for each potentially |
erratum-triggering instruction once we've settled on a solution. */ |
-struct a8_erratum_fix { |
+struct a8_erratum_fix |
+{ |
bfd *input_bfd; |
asection *section; |
bfd_vma offset; |
@@ -2587,7 +2680,8 @@ struct a8_erratum_fix { |
/* A table of relocs applied to branches which might trigger Cortex-A8 |
erratum. */ |
-struct a8_erratum_reloc { |
+struct a8_erratum_reloc |
+{ |
bfd_vma from; |
bfd_vma destination; |
struct elf32_arm_link_hash_entry *hash; |
@@ -2602,7 +2696,8 @@ struct a8_erratum_reloc { |
/* ARM-specific information about a PLT entry, over and above the usual |
gotplt_union. */ |
-struct arm_plt_info { |
+struct arm_plt_info |
+{ |
/* We reference count Thumb references to a PLT entry separately, |
so that we can emit the Thumb trampoline only if needed. */ |
bfd_signed_vma thumb_refcount; |
@@ -2625,7 +2720,8 @@ struct arm_plt_info { |
}; |
/* Information about an .iplt entry for a local STT_GNU_IFUNC symbol. */ |
-struct arm_local_iplt_info { |
+struct arm_local_iplt_info |
+{ |
/* The information that is usually found in the generic ELF part of |
the hash table entry. */ |
union gotplt_union root; |
@@ -2686,14 +2782,14 @@ elf32_arm_mkobject (bfd *abfd) |
/* Arm ELF linker hash entry. */ |
struct elf32_arm_link_hash_entry |
- { |
- struct elf_link_hash_entry root; |
+{ |
+ struct elf_link_hash_entry root; |
- /* Track dynamic relocs copied for this symbol. */ |
- struct elf_dyn_relocs *dyn_relocs; |
+ /* Track dynamic relocs copied for this symbol. */ |
+ struct elf_dyn_relocs *dyn_relocs; |
- /* ARM-specific PLT information. */ |
- struct arm_plt_info plt; |
+ /* ARM-specific PLT information. */ |
+ struct arm_plt_info plt; |
#define GOT_UNKNOWN 0 |
#define GOT_NORMAL 1 |
@@ -2701,25 +2797,25 @@ struct elf32_arm_link_hash_entry |
#define GOT_TLS_IE 4 |
#define GOT_TLS_GDESC 8 |
#define GOT_TLS_GD_ANY_P(type) ((type & GOT_TLS_GD) || (type & GOT_TLS_GDESC)) |
- unsigned int tls_type : 8; |
+ unsigned int tls_type : 8; |
- /* True if the symbol's PLT entry is in .iplt rather than .plt. */ |
- unsigned int is_iplt : 1; |
+ /* True if the symbol's PLT entry is in .iplt rather than .plt. */ |
+ unsigned int is_iplt : 1; |
- unsigned int unused : 23; |
+ unsigned int unused : 23; |
- /* Offset of the GOTPLT entry reserved for the TLS descriptor, |
- starting at the end of the jump table. */ |
- bfd_vma tlsdesc_got; |
+ /* Offset of the GOTPLT entry reserved for the TLS descriptor, |
+ starting at the end of the jump table. */ |
+ bfd_vma tlsdesc_got; |
- /* The symbol marking the real symbol location for exported thumb |
- symbols with Arm stubs. */ |
- struct elf_link_hash_entry *export_glue; |
+ /* The symbol marking the real symbol location for exported thumb |
+ symbols with Arm stubs. */ |
+ struct elf_link_hash_entry *export_glue; |
- /* A pointer to the most recently used stub hash entry against this |
+ /* A pointer to the most recently used stub hash entry against this |
symbol. */ |
- struct elf32_arm_stub_hash_entry *stub_cache; |
- }; |
+ struct elf32_arm_stub_hash_entry *stub_cache; |
+}; |
/* Traverse an arm ELF linker hash table. */ |
#define elf32_arm_link_hash_traverse(table, func, info) \ |
@@ -2829,6 +2925,9 @@ struct elf32_arm_link_hash_table |
/* True if the target system is Symbian OS. */ |
int symbian_p; |
+ /* True if the target system is Native Client. */ |
+ int nacl_p; |
+ |
/* True if the target uses REL relocations. */ |
int use_rel; |
@@ -2853,7 +2952,7 @@ struct elf32_arm_link_hash_table |
/* The offset into sgot of the GOT entry used by the PLT entry |
above. */ |
- bfd_vma dt_tlsdesc_got; |
+ bfd_vma dt_tlsdesc_got; |
/* Offset in .plt section of tls_arm_trampoline. */ |
bfd_vma tls_trampoline; |
@@ -3149,7 +3248,7 @@ create_ifunc_sections (struct bfd_link_info *info) |
bfd *dynobj; |
asection *s; |
flagword flags; |
- |
+ |
htab = elf32_arm_hash_table (info); |
dynobj = htab->root.dynobj; |
bed = get_elf_backend_data (dynobj); |
@@ -3157,27 +3256,28 @@ create_ifunc_sections (struct bfd_link_info *info) |
if (htab->root.iplt == NULL) |
{ |
- s = bfd_make_section_with_flags (dynobj, ".iplt", |
- flags | SEC_READONLY | SEC_CODE); |
+ s = bfd_make_section_anyway_with_flags (dynobj, ".iplt", |
+ flags | SEC_READONLY | SEC_CODE); |
if (s == NULL |
- || !bfd_set_section_alignment (abfd, s, bed->plt_alignment)) |
+ || !bfd_set_section_alignment (dynobj, s, bed->plt_alignment)) |
return FALSE; |
htab->root.iplt = s; |
} |
if (htab->root.irelplt == NULL) |
{ |
- s = bfd_make_section_with_flags (dynobj, RELOC_SECTION (htab, ".iplt"), |
- flags | SEC_READONLY); |
+ s = bfd_make_section_anyway_with_flags (dynobj, |
+ RELOC_SECTION (htab, ".iplt"), |
+ flags | SEC_READONLY); |
if (s == NULL |
- || !bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
+ || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) |
return FALSE; |
htab->root.irelplt = s; |
} |
if (htab->root.igotplt == NULL) |
{ |
- s = bfd_make_section_with_flags (dynobj, ".igot.plt", flags); |
+ s = bfd_make_section_anyway_with_flags (dynobj, ".igot.plt", flags); |
if (s == NULL |
|| !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) |
return FALSE; |
@@ -3205,10 +3305,10 @@ elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) |
if (!_bfd_elf_create_dynamic_sections (dynobj, info)) |
return FALSE; |
- htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss"); |
+ htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); |
if (!info->shared) |
- htab->srelbss = bfd_get_section_by_name (dynobj, |
- RELOC_SECTION (htab, ".bss")); |
+ htab->srelbss = bfd_get_linker_section (dynobj, |
+ RELOC_SECTION (htab, ".bss")); |
if (htab->vxworks_p) |
{ |
@@ -3359,6 +3459,7 @@ elf32_arm_link_hash_table_create (bfd *abfd) |
ret->use_blx = 0; |
ret->vxworks_p = 0; |
ret->symbian_p = 0; |
+ ret->nacl_p = 0; |
ret->use_rel = 1; |
ret->sym_cache.abfd = NULL; |
ret->obfd = abfd; |
@@ -3527,7 +3628,7 @@ arm_type_of_stub (struct bfd_link_info *info, |
else |
splt = globals->root.splt; |
if (splt != NULL) |
- { |
+ { |
use_plt = 1; |
/* Note when dealing with PLT entries: the main PLT stub is in |
@@ -3811,7 +3912,7 @@ elf32_arm_get_stub_entry (const asection *input_section, |
} |
/* Find or create a stub section. Returns a pointer to the stub section, and |
- the section to which the stub section will be attached (in *LINK_SEC_P). |
+ the section to which the stub section will be attached (in *LINK_SEC_P). |
LINK_SEC_P may be NULL. */ |
static asection * |
@@ -3849,10 +3950,10 @@ elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section, |
} |
htab->stub_group[section->id].stub_sec = stub_sec; |
} |
- |
+ |
if (link_sec_p) |
*link_sec_p = link_sec; |
- |
+ |
return stub_sec; |
} |
@@ -3920,7 +4021,7 @@ put_thumb_insn (struct elf32_arm_link_hash_table * htab, |
model, return the new reloc type. */ |
static unsigned |
-elf32_arm_tls_transition (struct bfd_link_info *info, int r_type, |
+elf32_arm_tls_transition (struct bfd_link_info *info, int r_type, |
struct elf_link_hash_entry *h) |
{ |
int is_local = (h == NULL); |
@@ -3928,7 +4029,7 @@ elf32_arm_tls_transition (struct bfd_link_info *info, int r_type, |
if (info->shared || (h && h->root.type == bfd_link_hash_undefweak)) |
return r_type; |
- /* We do not support relaxations for Old TLS models. */ |
+ /* We do not support relaxations for Old TLS models. */ |
switch (r_type) |
{ |
case R_ARM_TLS_GOTDESC: |
@@ -3974,7 +4075,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type stub_type) |
case arm_stub_long_branch_v4t_thumb_tls_pic: |
case arm_stub_a8_veneer_blx: |
return 4; |
- |
+ |
default: |
abort (); /* Should be unreachable. */ |
} |
@@ -4512,7 +4613,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, |
if (elf_section_type (section) != SHT_PROGBITS |
|| (elf_section_flags (section) & SHF_EXECINSTR) == 0 |
|| (section->flags & SEC_EXCLUDE) != 0 |
- || (section->sec_info_type == ELF_INFO_TYPE_JUST_SYMS) |
+ || (section->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) |
|| (section->output_section == bfd_abs_section_ptr)) |
continue; |
@@ -4947,13 +5048,13 @@ elf32_arm_size_stubs (bfd *output_bfd, |
free (internal_relocs); |
goto error_ret_free_local; |
} |
- |
+ |
hash = NULL; |
if (r_indx >= symtab_hdr->sh_info) |
hash = elf32_arm_hash_entry |
(elf_sym_hashes (input_bfd) |
[r_indx - symtab_hdr->sh_info]); |
- |
+ |
/* Only look for stubs on branch instructions, or |
non-relaxed TLSCALL */ |
if ((r_type != (unsigned int) R_ARM_CALL) |
@@ -4979,7 +5080,7 @@ elf32_arm_size_stubs (bfd *output_bfd, |
sym_value = 0; |
destination = 0; |
sym_name = NULL; |
- |
+ |
if (r_type == (unsigned int) R_ARM_TLS_CALL |
|| r_type == (unsigned int) R_ARM_THM_TLS_CALL) |
{ |
@@ -5524,9 +5625,9 @@ static const insn32 a2t3p_bx_r12_insn = 0xe12fff1c; |
.arm mov lr, pc |
b func bx r6 |
.arm |
- ;; back_to_thumb |
+ ;; back_to_thumb |
ldmia r13! {r6, lr} |
- bx lr |
+ bx lr |
__func_addr: |
.word func */ |
@@ -5554,7 +5655,7 @@ arm_allocate_glue_section_space (bfd * abfd, bfd_size_type size, const char * na |
/* Do not include empty glue sections in the output. */ |
if (abfd != NULL) |
{ |
- s = bfd_get_section_by_name (abfd, name); |
+ s = bfd_get_linker_section (abfd, name); |
if (s != NULL) |
s->flags |= SEC_EXCLUDE; |
} |
@@ -5563,7 +5664,7 @@ arm_allocate_glue_section_space (bfd * abfd, bfd_size_type size, const char * na |
BFD_ASSERT (abfd != NULL); |
- s = bfd_get_section_by_name (abfd, name); |
+ s = bfd_get_linker_section (abfd, name); |
BFD_ASSERT (s != NULL); |
contents = (bfd_byte *) bfd_alloc (abfd, size); |
@@ -5619,7 +5720,7 @@ record_arm_to_thumb_glue (struct bfd_link_info * link_info, |
BFD_ASSERT (globals != NULL); |
BFD_ASSERT (globals->bfd_of_glue_owner != NULL); |
- s = bfd_get_section_by_name |
+ s = bfd_get_linker_section |
(globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME); |
BFD_ASSERT (s != NULL); |
@@ -5695,7 +5796,7 @@ record_arm_bx_glue (struct bfd_link_info * link_info, int reg) |
if (globals->bx_glue_offset[reg]) |
return; |
- s = bfd_get_section_by_name |
+ s = bfd_get_linker_section |
(globals->bfd_of_glue_owner, ARM_BX_GLUE_SECTION_NAME); |
BFD_ASSERT (s != NULL); |
@@ -5786,7 +5887,7 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info, |
BFD_ASSERT (hash_table != NULL); |
BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL); |
- s = bfd_get_section_by_name |
+ s = bfd_get_linker_section |
(hash_table->bfd_of_glue_owner, VFP11_ERRATUM_VENEER_SECTION_NAME); |
sec_data = elf32_arm_section_data (s); |
@@ -5893,12 +5994,12 @@ arm_make_glue_section (bfd * abfd, const char * name) |
{ |
asection * sec; |
- sec = bfd_get_section_by_name (abfd, name); |
+ sec = bfd_get_linker_section (abfd, name); |
if (sec != NULL) |
/* Already made. */ |
return TRUE; |
- sec = bfd_make_section_with_flags (abfd, name, ARM_GLUE_SECTION_FLAGS); |
+ sec = bfd_make_section_anyway_with_flags (abfd, name, ARM_GLUE_SECTION_FLAGS); |
if (sec == NULL |
|| !bfd_set_section_alignment (abfd, sec, 2)) |
@@ -5963,7 +6064,7 @@ check_use_blx (struct elf32_arm_link_hash_table *globals) |
{ |
int cpu_arch; |
- cpu_arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, |
+ cpu_arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, |
Tag_CPU_arch); |
if (globals->fix_arm1176) |
@@ -6583,7 +6684,7 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info) |
if (elf_section_type (sec) != SHT_PROGBITS |
|| (elf_section_flags (sec) & SHF_EXECINSTR) == 0 |
|| (sec->flags & SEC_EXCLUDE) != 0 |
- || sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS |
+ || sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS |
|| sec->output_section == bfd_abs_section_ptr |
|| strcmp (sec->name, VFP11_ERRATUM_VENEER_SECTION_NAME) == 0) |
continue; |
@@ -6918,8 +7019,8 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info, |
my_offset = myh->root.u.def.value; |
- s = bfd_get_section_by_name (globals->bfd_of_glue_owner, |
- THUMB2ARM_GLUE_SECTION_NAME); |
+ s = bfd_get_linker_section (globals->bfd_of_glue_owner, |
+ THUMB2ARM_GLUE_SECTION_NAME); |
BFD_ASSERT (s != NULL); |
BFD_ASSERT (s->contents != NULL); |
@@ -7108,8 +7209,8 @@ elf32_arm_to_thumb_stub (struct bfd_link_info * info, |
BFD_ASSERT (globals != NULL); |
BFD_ASSERT (globals->bfd_of_glue_owner != NULL); |
- s = bfd_get_section_by_name (globals->bfd_of_glue_owner, |
- ARM2THUMB_GLUE_SECTION_NAME); |
+ s = bfd_get_linker_section (globals->bfd_of_glue_owner, |
+ ARM2THUMB_GLUE_SECTION_NAME); |
BFD_ASSERT (s != NULL); |
BFD_ASSERT (s->contents != NULL); |
BFD_ASSERT (s->output_section != NULL); |
@@ -7162,8 +7263,8 @@ elf32_arm_to_thumb_export_stub (struct elf_link_hash_entry *h, void * inf) |
BFD_ASSERT (globals != NULL); |
BFD_ASSERT (globals->bfd_of_glue_owner != NULL); |
- s = bfd_get_section_by_name (globals->bfd_of_glue_owner, |
- ARM2THUMB_GLUE_SECTION_NAME); |
+ s = bfd_get_linker_section (globals->bfd_of_glue_owner, |
+ ARM2THUMB_GLUE_SECTION_NAME); |
BFD_ASSERT (s != NULL); |
BFD_ASSERT (s->contents != NULL); |
BFD_ASSERT (s->output_section != NULL); |
@@ -7197,8 +7298,8 @@ elf32_arm_bx_glue (struct bfd_link_info * info, int reg) |
BFD_ASSERT (globals != NULL); |
BFD_ASSERT (globals->bfd_of_glue_owner != NULL); |
- s = bfd_get_section_by_name (globals->bfd_of_glue_owner, |
- ARM_BX_GLUE_SECTION_NAME); |
+ s = bfd_get_linker_section (globals->bfd_of_glue_owner, |
+ ARM_BX_GLUE_SECTION_NAME); |
BFD_ASSERT (s != NULL); |
BFD_ASSERT (s->contents != NULL); |
BFD_ASSERT (s->output_section != NULL); |
@@ -7354,6 +7455,18 @@ elf32_arm_allocate_plt_entry (struct bfd_link_info *info, |
} |
} |
+static bfd_vma |
+arm_movw_immediate (bfd_vma value) |
+{ |
+ return (value & 0x00000fff) | ((value & 0x0000f000) << 4); |
+} |
+ |
+static bfd_vma |
+arm_movt_immediate (bfd_vma value) |
+{ |
+ return ((value & 0x0fff0000) >> 16) | ((value & 0xf0000000) >> 12); |
+} |
+ |
/* Fill in a PLT entry and its associated GOT slot. If DYNINDX == -1, |
the entry lives in .iplt and resolves to (*SYM_VALUE)(). |
Otherwise, DYNINDX is the index of the symbol in the dynamic |
@@ -7514,6 +7627,45 @@ elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info, |
rel.r_addend = 0; |
SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); |
} |
+ else if (htab->nacl_p) |
+ { |
+ /* Calculate the displacement between the PLT slot and the |
+ common tail that's part of the special initial PLT slot. */ |
+ int32_t tail_displacement |
+ = ((splt->output_section->vma + splt->output_offset |
+ + ARM_NACL_PLT_TAIL_OFFSET) |
+ - (plt_address + htab->plt_entry_size + 4)); |
+ BFD_ASSERT ((tail_displacement & 3) == 0); |
+ tail_displacement >>= 2; |
+ |
+ BFD_ASSERT ((tail_displacement & 0xff000000) == 0 |
+ || (-tail_displacement & 0xff000000) == 0); |
+ |
+ /* Calculate the displacement between the PLT slot and the entry |
+ in the GOT. The offset accounts for the value produced by |
+ adding to pc in the penultimate instruction of the PLT stub. */ |
+ got_displacement = (got_address |
+ - (plt_address + htab->plt_entry_size)); |
+ |
+ /* NaCl does not support interworking at all. */ |
+ BFD_ASSERT (!elf32_arm_plt_needs_thumb_stub_p (info, arm_plt)); |
+ |
+ put_arm_insn (htab, output_bfd, |
+ elf32_arm_nacl_plt_entry[0] |
+ | arm_movw_immediate (got_displacement), |
+ ptr + 0); |
+ put_arm_insn (htab, output_bfd, |
+ elf32_arm_nacl_plt_entry[1] |
+ | arm_movt_immediate (got_displacement), |
+ ptr + 4); |
+ put_arm_insn (htab, output_bfd, |
+ elf32_arm_nacl_plt_entry[2], |
+ ptr + 8); |
+ put_arm_insn (htab, output_bfd, |
+ elf32_arm_nacl_plt_entry[3] |
+ | (tail_displacement & 0x00ffffff), |
+ ptr + 12); |
+ } |
else |
{ |
/* Calculate the displacement between the PLT slot and the |
@@ -7654,18 +7806,18 @@ elf32_arm_abs12_reloc (bfd *abfd, void *data, bfd_vma value) |
the pre-relaxed code. It would be nice if the relocs were updated |
to match the optimization. */ |
-static bfd_reloc_status_type |
+static bfd_reloc_status_type |
elf32_arm_tls_relax (struct elf32_arm_link_hash_table *globals, |
- bfd *input_bfd, asection *input_sec, bfd_byte *contents, |
+ bfd *input_bfd, asection *input_sec, bfd_byte *contents, |
Elf_Internal_Rela *rel, unsigned long is_local) |
{ |
unsigned long insn; |
- |
+ |
switch (ELF32_R_TYPE (rel->r_info)) |
{ |
default: |
return bfd_reloc_notsupported; |
- |
+ |
case R_ARM_TLS_GOTDESC: |
if (is_local) |
insn = 0; |
@@ -7721,7 +7873,7 @@ elf32_arm_tls_relax (struct elf32_arm_link_hash_table *globals, |
return bfd_reloc_notsupported; |
} |
break; |
- |
+ |
case R_ARM_TLS_DESCSEQ: |
/* arm insn. */ |
insn = bfd_get_32 (input_bfd, contents + rel->r_offset); |
@@ -7767,7 +7919,7 @@ elf32_arm_tls_relax (struct elf32_arm_link_hash_table *globals, |
insn = is_local ? 0xe1a00000 : 0xe79f0000; |
bfd_put_32 (input_bfd, insn, contents + rel->r_offset); |
break; |
- |
+ |
case R_ARM_THM_TLS_CALL: |
/* GD->IE relaxation */ |
if (!is_local) |
@@ -7779,7 +7931,7 @@ elf32_arm_tls_relax (struct elf32_arm_link_hash_table *globals, |
else |
/* nop; nop */ |
insn = 0xbf00bf00; |
- |
+ |
bfd_put_16 (input_bfd, insn >> 16, contents + rel->r_offset); |
bfd_put_16 (input_bfd, insn & 0xffff, contents + rel->r_offset + 2); |
break; |
@@ -9200,9 +9352,9 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, |
} |
/* Linker relaxations happens from one of the |
- R_ARM_{GOTDESC,CALL,DESCSEQ} relocations to IE or LE. */ |
+ R_ARM_{GOTDESC,CALL,DESCSEQ} relocations to IE or LE. */ |
if (ELF32_R_TYPE(rel->r_info) != r_type) |
- tls_type = GOT_TLS_IE; |
+ tls_type = GOT_TLS_IE; |
BFD_ASSERT (tls_type != GOT_UNKNOWN); |
@@ -9243,7 +9395,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, |
+ globals->root.sgotplt->output_offset |
+ offplt |
+ globals->sgotplt_jump_table_size); |
- |
+ |
outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_DESC); |
sreloc = globals->root.srelplt; |
loc = sreloc->contents; |
@@ -9261,13 +9413,13 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, |
!h ? value - elf_hash_table (info)->tls_sec->vma |
: info->flags & DF_BIND_NOW ? 0 |
: 0x80000000 | ELF32_R_SYM (outrel.r_info), |
- globals->root.sgotplt->contents + offplt + |
- globals->sgotplt_jump_table_size); |
- |
+ globals->root.sgotplt->contents + offplt |
+ + globals->sgotplt_jump_table_size); |
+ |
/* Second word in the relocation is always zero. */ |
bfd_put_32 (output_bfd, 0, |
- globals->root.sgotplt->contents + offplt + |
- globals->sgotplt_jump_table_size + 4); |
+ globals->root.sgotplt->contents + offplt |
+ + globals->sgotplt_jump_table_size + 4); |
} |
if (tls_type & GOT_TLS_GD) |
{ |
@@ -9387,9 +9539,10 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, |
if (ELF32_R_TYPE(rel->r_info) == R_ARM_TLS_CALL) |
{ |
unsigned long inst; |
- |
- offset -= (input_section->output_section->vma + |
- input_section->output_offset + rel->r_offset + 8); |
+ |
+ offset -= (input_section->output_section->vma |
+ + input_section->output_offset |
+ + rel->r_offset + 8); |
inst = offset >> 2; |
inst &= 0x00ffffff; |
@@ -9402,10 +9555,10 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, |
unsigned upper_insn, lower_insn; |
unsigned neg; |
- offset -= (input_section->output_section->vma + |
- input_section->output_offset |
+ offset -= (input_section->output_section->vma |
+ + input_section->output_offset |
+ rel->r_offset + 4); |
- |
+ |
if (stub_type != arm_stub_none |
&& arm_stub_is_thumb (stub_type)) |
{ |
@@ -9438,11 +9591,11 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, |
{ |
unsigned long data, insn; |
unsigned thumb; |
- |
+ |
data = bfd_get_32 (input_bfd, hit_data); |
thumb = data & 1; |
data &= ~1u; |
- |
+ |
if (thumb) |
{ |
insn = bfd_get_16 (input_bfd, contents + rel->r_offset - data); |
@@ -9479,7 +9632,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, |
case 0xe0: /* add */ |
value = -8; |
break; |
- |
+ |
default: |
(*_bfd_error_handler) |
(_("%B(%A+0x%lx):unexpected ARM instruction '0x%x' referenced by TLS_GOTDESC"), |
@@ -9488,7 +9641,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, |
return bfd_reloc_notsupported; |
} |
} |
- |
+ |
value += ((globals->root.sgotplt->output_section->vma |
+ globals->root.sgotplt->output_offset + off) |
- (input_section->output_section->vma |
@@ -9514,7 +9667,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, |
(_("%B(%A+0x%lx): R_ARM_TLS_LE32 relocation not permitted in shared object"), |
input_bfd, input_section, |
(long) rel->r_offset, howto->name); |
- return (bfd_reloc_status_type) FALSE; |
+ return bfd_reloc_notsupported; |
} |
else |
value = tpoff (info, value); |
@@ -10222,7 +10375,7 @@ elf32_arm_relocate_section (bfd * output_bfd, |
rel->r_offset, TRUE)) |
return FALSE; |
} |
- |
+ |
if (globals->use_rel) |
{ |
relocation = (sec->output_section->vma |
@@ -10331,9 +10484,9 @@ elf32_arm_relocate_section (bfd * output_bfd, |
sym_type = h->type; |
} |
- if (sec != NULL && elf_discarded_section (sec)) |
+ if (sec != NULL && discarded_section (sec)) |
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, |
- rel, relend, howto, contents); |
+ rel, 1, relend, howto, 0, contents); |
if (info->relocatable) |
{ |
@@ -10387,7 +10540,7 @@ elf32_arm_relocate_section (bfd * output_bfd, |
both in relaxed and non-relaxed cases */ |
if ((elf32_arm_tls_transition (info, r_type, h) != (unsigned)r_type) |
|| (IS_ARM_TLS_GNU_RELOC (r_type) |
- && !((h ? elf32_arm_hash_entry (h)->tls_type : |
+ && !((h ? elf32_arm_hash_entry (h)->tls_type : |
elf32_arm_local_got_tls_type (input_bfd)[r_symndx]) |
& GOT_TLS_GDESC))) |
{ |
@@ -10399,7 +10552,7 @@ elf32_arm_relocate_section (bfd * output_bfd, |
} |
else |
r = bfd_reloc_continue; |
- |
+ |
if (r == bfd_reloc_continue) |
r = elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, |
input_section, contents, rel, |
@@ -10495,11 +10648,11 @@ add_unwind_table_edit (arm_unwind_table_edit **head, |
{ |
arm_unwind_table_edit *new_edit = (arm_unwind_table_edit *) |
xmalloc (sizeof (arm_unwind_table_edit)); |
- |
+ |
new_edit->type = type; |
new_edit->linked_section = linked_section; |
new_edit->index = tindex; |
- |
+ |
if (tindex > 0) |
{ |
new_edit->next = NULL; |
@@ -10557,7 +10710,7 @@ insert_cantunwind_after(asection *text_sec, asection *exidx_sec) |
/* Scan .ARM.exidx tables, and create a list describing edits which should be |
made to those tables, such that: |
- |
+ |
1. Regions without unwind data are marked with EXIDX_CANTUNWIND entries. |
2. Duplicate entries are merged together (EXIDX_CANTUNWIND, or unwind |
codes which have been inlined into the index). |
@@ -10565,8 +10718,7 @@ insert_cantunwind_after(asection *text_sec, asection *exidx_sec) |
If MERGE_EXIDX_ENTRIES is false, duplicate entries are not merged. |
The edits are applied when the tables are written |
- (in elf32_arm_write_section). |
-*/ |
+ (in elf32_arm_write_section). */ |
bfd_boolean |
elf32_arm_fix_exidx_coverage (asection **text_section_order, |
@@ -10585,15 +10737,15 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order, |
for (inp = info->input_bfds; inp != NULL; inp = inp->link_next) |
{ |
asection *sec; |
- |
+ |
for (sec = inp->sections; sec != NULL; sec = sec->next) |
{ |
struct bfd_elf_section_data *elf_sec = elf_section_data (sec); |
Elf_Internal_Shdr *hdr = &elf_sec->this_hdr; |
- |
+ |
if (!hdr || hdr->sh_type != SHT_ARM_EXIDX) |
continue; |
- |
+ |
if (elf_sec->linked_to) |
{ |
Elf_Internal_Shdr *linked_hdr |
@@ -10655,13 +10807,13 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order, |
hdr = &elf_section_data (exidx_sec)->this_hdr; |
if (hdr->sh_type != SHT_ARM_EXIDX) |
continue; |
- |
+ |
exidx_arm_data = get_arm_elf_section_data (exidx_sec); |
if (exidx_arm_data == NULL) |
continue; |
- |
+ |
ibfd = exidx_sec->owner; |
- |
+ |
if (hdr->contents != NULL) |
contents = hdr->contents; |
else if (! bfd_malloc_and_get_section (ibfd, exidx_sec, &contents)) |
@@ -10713,7 +10865,7 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order, |
/* Record edits to be applied later (in elf32_arm_write_section). */ |
exidx_arm_data->u.exidx.unwind_edit_list = unwind_edit_head; |
exidx_arm_data->u.exidx.unwind_edit_tail = unwind_edit_tail; |
- |
+ |
if (deleted_exidx_bytes > 0) |
adjust_exidx_size(exidx_sec, -deleted_exidx_bytes); |
@@ -10734,7 +10886,7 @@ elf32_arm_output_glue_section (struct bfd_link_info *info, bfd *obfd, |
{ |
asection *sec, *osec; |
- sec = bfd_get_section_by_name (ibfd, name); |
+ sec = bfd_get_linker_section (ibfd, name); |
if (sec == NULL || (sec->flags & SEC_EXCLUDE) != 0) |
return TRUE; |
@@ -10807,6 +10959,43 @@ elf32_arm_final_link (bfd *abfd, struct bfd_link_info *info) |
return TRUE; |
} |
+/* Return a best guess for the machine number based on the attributes. */ |
+ |
+static unsigned int |
+bfd_arm_get_mach_from_attributes (bfd * abfd) |
+{ |
+ int arch = bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_PROC, Tag_CPU_arch); |
+ |
+ switch (arch) |
+ { |
+ case TAG_CPU_ARCH_V4: return bfd_mach_arm_4; |
+ case TAG_CPU_ARCH_V4T: return bfd_mach_arm_4T; |
+ case TAG_CPU_ARCH_V5T: return bfd_mach_arm_5T; |
+ |
+ case TAG_CPU_ARCH_V5TE: |
+ { |
+ char * name; |
+ |
+ BFD_ASSERT (Tag_CPU_name < NUM_KNOWN_OBJ_ATTRIBUTES); |
+ name = elf_known_obj_attributes (abfd) [OBJ_ATTR_PROC][Tag_CPU_name].s; |
+ |
+ if (name) |
+ { |
+ if (strcmp (name, "IWMMXT2") == 0) |
+ return bfd_mach_arm_iWMMXt2; |
+ |
+ if (strcmp (name, "IWMMXT") == 0) |
+ return bfd_mach_arm_iWMMXt; |
+ } |
+ |
+ return bfd_mach_arm_5TE; |
+ } |
+ |
+ default: |
+ return bfd_mach_arm_unknown; |
+ } |
+} |
+ |
/* Set the right machine number. */ |
static bfd_boolean |
@@ -10816,15 +11005,15 @@ elf32_arm_object_p (bfd *abfd) |
mach = bfd_arm_get_mach_from_notes (abfd, ARM_NOTE_SECTION); |
- if (mach != bfd_mach_arm_unknown) |
- bfd_default_set_arch_mach (abfd, bfd_arch_arm, mach); |
- |
- else if (elf_elfheader (abfd)->e_flags & EF_ARM_MAVERICK_FLOAT) |
- bfd_default_set_arch_mach (abfd, bfd_arch_arm, bfd_mach_arm_ep9312); |
- |
- else |
- bfd_default_set_arch_mach (abfd, bfd_arch_arm, mach); |
+ if (mach == bfd_mach_arm_unknown) |
+ { |
+ if (elf_elfheader (abfd)->e_flags & EF_ARM_MAVERICK_FLOAT) |
+ mach = bfd_mach_arm_ep9312; |
+ else |
+ mach = bfd_arm_get_mach_from_attributes (abfd); |
+ } |
+ bfd_default_set_arch_mach (abfd, bfd_arch_arm, mach); |
return TRUE; |
} |
@@ -11219,6 +11408,46 @@ tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out, |
#undef T |
} |
+/* Query attributes object to see if integer divide instructions may be |
+ present in an object. */ |
+static bfd_boolean |
+elf32_arm_attributes_accept_div (const obj_attribute *attr) |
+{ |
+ int arch = attr[Tag_CPU_arch].i; |
+ int profile = attr[Tag_CPU_arch_profile].i; |
+ |
+ switch (attr[Tag_DIV_use].i) |
+ { |
+ case 0: |
+ /* Integer divide allowed if instruction contained in archetecture. */ |
+ if (arch == TAG_CPU_ARCH_V7 && (profile == 'R' || profile == 'M')) |
+ return TRUE; |
+ else if (arch >= TAG_CPU_ARCH_V7E_M) |
+ return TRUE; |
+ else |
+ return FALSE; |
+ |
+ case 1: |
+ /* Integer divide explicitly prohibited. */ |
+ return FALSE; |
+ |
+ default: |
+ /* Unrecognised case - treat as allowing divide everywhere. */ |
+ case 2: |
+ /* Integer divide allowed in ARM state. */ |
+ return TRUE; |
+ } |
+} |
+ |
+/* Query attributes object to see if integer divide instructions are |
+ forbidden to be in the object. This is not the inverse of |
+ elf32_arm_attributes_accept_div. */ |
+static bfd_boolean |
+elf32_arm_attributes_forbid_div (const obj_attribute *attr) |
+{ |
+ return attr[Tag_DIV_use].i == 1; |
+} |
+ |
/* Merge EABI object attributes from IBFD into OBFD. Raise an error if there |
are conflicting attributes. */ |
@@ -11660,29 +11889,22 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) |
break; |
case Tag_DIV_use: |
- /* This tag is set to zero if we can use UDIV and SDIV in Thumb |
- mode on a v7-M or v7-R CPU; to one if we can not use UDIV or |
- SDIV at all; and to two if we can use UDIV or SDIV on a v7-A |
- CPU. We will merge as follows: If the input attribute's value |
- is one then the output attribute's value remains unchanged. If |
- the input attribute's value is zero or two then if the output |
- attribute's value is one the output value is set to the input |
- value, otherwise the output value must be the same as the |
- inputs. */ |
- if (in_attr[i].i != 1 && out_attr[i].i != 1) |
- { |
- if (in_attr[i].i != out_attr[i].i) |
- { |
- _bfd_error_handler |
- (_("DIV usage mismatch between %B and %B"), |
- ibfd, obfd); |
- result = FALSE; |
- } |
- } |
- |
- if (in_attr[i].i != 1) |
- out_attr[i].i = in_attr[i].i; |
- |
+ /* A value of zero on input means that the divide instruction may |
+ be used if available in the base architecture as specified via |
+ Tag_CPU_arch and Tag_CPU_arch_profile. A value of 1 means that |
+ the user did not want divide instructions. A value of 2 |
+ explicitly means that divide instructions were allowed in ARM |
+ and Thumb state. */ |
+ if (in_attr[i].i == out_attr[i].i) |
+ /* Do nothing. */ ; |
+ else if (elf32_arm_attributes_forbid_div (in_attr) |
+ && !elf32_arm_attributes_accept_div (out_attr)) |
+ out_attr[i].i = 1; |
+ else if (elf32_arm_attributes_forbid_div (out_attr) |
+ && elf32_arm_attributes_accept_div (in_attr)) |
+ out_attr[i].i = in_attr[i].i; |
+ else if (in_attr[i].i == 2) |
+ out_attr[i].i = in_attr[i].i; |
break; |
case Tag_MPextension_use_legacy: |
@@ -11694,7 +11916,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) |
{ |
_bfd_error_handler |
(_("%B has has both the current and legacy " |
- "Tag_MPextension_use attributes"), |
+ "Tag_MPextension_use attributes"), |
ibfd); |
result = FALSE; |
} |
@@ -12074,8 +12296,19 @@ elf32_arm_gc_sweep_hook (bfd * abfd, |
if (may_need_local_target_p |
&& elf32_arm_get_plt_info (abfd, eh, r_symndx, &root_plt, &arm_plt)) |
{ |
- BFD_ASSERT (root_plt->refcount > 0); |
- root_plt->refcount -= 1; |
+ /* If PLT refcount book-keeping is wrong and too low, we'll |
+ see a zero value (going to -1) for the root PLT reference |
+ count. */ |
+ if (root_plt->refcount >= 0) |
+ { |
+ BFD_ASSERT (root_plt->refcount != 0); |
+ root_plt->refcount -= 1; |
+ } |
+ else |
+ /* A value of -1 means the symbol has become local, forced |
+ or seeing a hidden definition. Any other negative value |
+ is an error. */ |
+ BFD_ASSERT (root_plt->refcount == -1); |
if (!call_reloc_p) |
arm_plt->noncall_refcount--; |
@@ -12168,7 +12401,7 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, |
symtab_hdr = & elf_symtab_hdr (abfd); |
sym_hashes = elf_sym_hashes (abfd); |
nsyms = NUM_SHDR_ENTRIES (symtab_hdr); |
- |
+ |
rel_end = relocs + sec->reloc_count; |
for (rel = relocs; rel < rel_end; rel++) |
{ |
@@ -12240,14 +12473,14 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, |
switch (r_type) |
{ |
case R_ARM_TLS_GD32: tls_type = GOT_TLS_GD; break; |
- |
+ |
case R_ARM_TLS_IE32: tls_type = GOT_TLS_IE; break; |
- |
+ |
case R_ARM_TLS_GOTDESC: |
case R_ARM_TLS_CALL: case R_ARM_THM_TLS_CALL: |
case R_ARM_TLS_DESCSEQ: case R_ARM_THM_TLS_DESCSEQ: |
tls_type = GOT_TLS_GDESC; break; |
- |
+ |
default: tls_type = GOT_NORMAL; break; |
} |
@@ -12436,7 +12669,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, |
/* If the symbol is a function that doesn't bind locally, |
this relocation will need a PLT entry. */ |
- root_plt->refcount += 1; |
+ if (root_plt->refcount != -1) |
+ root_plt->refcount += 1; |
if (!call_reloc_p) |
arm_plt->noncall_refcount++; |
@@ -12797,13 +13031,6 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, |
if (info->shared || globals->root.is_relocatable_executable) |
return TRUE; |
- if (h->size == 0) |
- { |
- (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), |
- h->root.root.string); |
- return TRUE; |
- } |
- |
/* We must allocate the symbol in our .dynbss section, which will |
become part of the .bss section of the executable. There will be |
an entry for this symbol in the .dynsym section. The dynamic |
@@ -12813,18 +13040,18 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, |
determine the address it must put in the global offset table, so |
both the dynamic object and the regular object will refer to the |
same memory location for the variable. */ |
- s = bfd_get_section_by_name (dynobj, ".dynbss"); |
+ s = bfd_get_linker_section (dynobj, ".dynbss"); |
BFD_ASSERT (s != NULL); |
/* We must generate a R_ARM_COPY reloc to tell the dynamic linker to |
copy the initial value out of the dynamic object and into the |
runtime process image. We need to remember the offset into the |
.rel(a).bss section we are going to use. */ |
- if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) |
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) |
{ |
asection *srel; |
- srel = bfd_get_section_by_name (dynobj, RELOC_SECTION (globals, ".bss")); |
+ srel = bfd_get_linker_section (dynobj, RELOC_SECTION (globals, ".bss")); |
elf32_arm_allocate_dynrelocs (info, srel, 1); |
h->needs_copy = 1; |
} |
@@ -13014,7 +13241,7 @@ allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf) |
if (tls_type & GOT_TLS_GD) |
elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); |
- if (tls_type & GOT_TLS_GDESC) |
+ if (tls_type & GOT_TLS_GDESC) |
{ |
elf32_arm_allocate_dynrelocs (info, htab->root.srelplt, 1); |
/* GDESC needs a trampoline to jump to. */ |
@@ -13023,7 +13250,7 @@ allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf) |
/* Only GD needs it. GDESC just emits one relocation per |
2 entries. */ |
- if ((tls_type & GOT_TLS_GD) && indx != 0) |
+ if ((tls_type & GOT_TLS_GD) && indx != 0) |
elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); |
} |
else if (!SYMBOL_REFERENCES_LOCAL (info, h)) |
@@ -13266,7 +13493,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, |
/* Set the contents of the .interp section to the interpreter. */ |
if (info->executable) |
{ |
- s = bfd_get_section_by_name (dynobj, ".interp"); |
+ s = bfd_get_linker_section (dynobj, ".interp"); |
BFD_ASSERT (s != NULL); |
s->size = sizeof ELF_DYNAMIC_INTERPRETER; |
s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; |
@@ -13478,10 +13705,10 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, |
{ |
if (htab->root.splt->size == 0) |
htab->root.splt->size += htab->plt_header_size; |
- |
+ |
htab->tls_trampoline = htab->root.splt->size; |
htab->root.splt->size += htab->plt_entry_size; |
- |
+ |
/* If we're not using lazy TLS relocations, don't generate the |
PLT and GOT entries they require. */ |
if (!(info->flags & DF_BIND_NOW)) |
@@ -13589,9 +13816,9 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, |
return FALSE; |
if (htab->dt_tlsdesc_plt && |
- (!add_dynamic_entry (DT_TLSDESC_PLT,0) |
+ (!add_dynamic_entry (DT_TLSDESC_PLT,0) |
|| !add_dynamic_entry (DT_TLSDESC_GOT,0))) |
- return FALSE; |
+ return FALSE; |
} |
if (relocs) |
@@ -13664,7 +13891,7 @@ elf32_arm_always_size_sections (bfd *output_bfd, |
tls_sec, 0, NULL, FALSE, |
bed->collect, &bh))) |
return FALSE; |
- |
+ |
tlsbase->type = STT_TLS; |
tlsbase = (struct elf_link_hash_entry *)bh; |
tlsbase->def_regular = 1; |
@@ -13765,7 +13992,7 @@ arm_put_trampoline (struct elf32_arm_link_hash_table *htab, bfd *output_bfd, |
const unsigned long *template, unsigned count) |
{ |
unsigned ix; |
- |
+ |
for (ix = 0; ix != count; ix++) |
{ |
unsigned long insn = template[ix]; |
@@ -13798,7 +14025,7 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info |
Catch this here so that we do not seg-fault later on. */ |
if (sgot != NULL && bfd_is_abs_section (sgot->output_section)) |
return FALSE; |
- sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); |
+ sdyn = bfd_get_linker_section (dynobj, ".dynamic"); |
if (elf_hash_table (info)->dynamic_sections_created) |
{ |
@@ -14007,6 +14234,25 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info |
SWAP_RELOC_OUT (htab) (output_bfd, &rel, |
htab->srelplt2->contents); |
} |
+ else if (htab->nacl_p) |
+ { |
+ unsigned int i; |
+ |
+ got_displacement = got_address + 8 - (plt_address + 16); |
+ |
+ put_arm_insn (htab, output_bfd, |
+ elf32_arm_nacl_plt0_entry[0] |
+ | arm_movw_immediate (got_displacement), |
+ splt->contents + 0); |
+ put_arm_insn (htab, output_bfd, |
+ elf32_arm_nacl_plt0_entry[1] |
+ | arm_movt_immediate (got_displacement), |
+ splt->contents + 4); |
+ for (i = 2; i < ARRAY_SIZE (elf32_arm_nacl_plt0_entry); ++i) |
+ put_arm_insn (htab, output_bfd, |
+ elf32_arm_nacl_plt0_entry[i], |
+ splt->contents + (i * 4)); |
+ } |
else |
{ |
got_displacement = got_address - (plt_address + 16); |
@@ -14045,7 +14291,7 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info |
bfd_vma plt_address |
= splt->output_section->vma + splt->output_offset; |
- arm_put_trampoline (htab, output_bfd, |
+ arm_put_trampoline (htab, output_bfd, |
splt->contents + htab->dt_tlsdesc_plt, |
dl_tlsdesc_lazy_trampoline, 6); |
@@ -14062,13 +14308,13 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info |
if (htab->tls_trampoline) |
{ |
- arm_put_trampoline (htab, output_bfd, |
+ arm_put_trampoline (htab, output_bfd, |
splt->contents + htab->tls_trampoline, |
tls_trampoline, 3); |
#ifdef FOUR_WORD_PLT |
bfd_put_32 (output_bfd, 0x00000000, |
splt->contents + htab->tls_trampoline + 12); |
-#endif |
+#endif |
} |
if (htab->vxworks_p && !info->shared && htab->root.splt->size > 0) |
@@ -14235,7 +14481,7 @@ get_arm_elf_section_data (asection * sec) |
typedef struct |
{ |
- void *finfo; |
+ void *flaginfo; |
struct bfd_link_info *info; |
asection *sec; |
int sec_shndx; |
@@ -14270,7 +14516,7 @@ elf32_arm_output_map_sym (output_arch_syminfo *osi, |
sym.st_shndx = osi->sec_shndx; |
sym.st_target_internal = 0; |
elf32_arm_section_map_add (osi->sec, names[type][1], offset); |
- return osi->func (osi->finfo, names[type], &sym, osi->sec, NULL) == 1; |
+ return osi->func (osi->flaginfo, names[type], &sym, osi->sec, NULL) == 1; |
} |
/* Output mapping symbols for the PLT entry described by ROOT_PLT and ARM_PLT. |
@@ -14324,6 +14570,11 @@ elf32_arm_output_plt_map_1 (output_arch_syminfo *osi, |
if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 20)) |
return FALSE; |
} |
+ else if (htab->nacl_p) |
+ { |
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) |
+ return FALSE; |
+ } |
else |
{ |
bfd_boolean thumb_stub_p; |
@@ -14392,7 +14643,7 @@ elf32_arm_output_stub_sym (output_arch_syminfo *osi, const char *name, |
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FUNC); |
sym.st_shndx = osi->sec_shndx; |
sym.st_target_internal = 0; |
- return osi->func (osi->finfo, name, &sym, osi->sec, NULL) == 1; |
+ return osi->func (osi->flaginfo, name, &sym, osi->sec, NULL) == 1; |
} |
static bfd_boolean |
@@ -14504,7 +14755,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, |
static bfd_boolean |
elf32_arm_output_arch_local_syms (bfd *output_bfd, |
struct bfd_link_info *info, |
- void *finfo, |
+ void *flaginfo, |
int (*func) (void *, const char *, |
Elf_Internal_Sym *, |
asection *, |
@@ -14522,7 +14773,7 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, |
check_use_blx (htab); |
- osi.finfo = finfo; |
+ osi.flaginfo = flaginfo; |
osi.info = info; |
osi.func = func; |
@@ -14559,8 +14810,8 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, |
/* ARM->Thumb glue. */ |
if (htab->arm_glue_size > 0) |
{ |
- osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner, |
- ARM2THUMB_GLUE_SECTION_NAME); |
+ osi.sec = bfd_get_linker_section (htab->bfd_of_glue_owner, |
+ ARM2THUMB_GLUE_SECTION_NAME); |
osi.sec_shndx = _bfd_elf_section_from_bfd_section |
(output_bfd, osi.sec->output_section); |
@@ -14582,8 +14833,8 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, |
/* Thumb->ARM glue. */ |
if (htab->thumb_glue_size > 0) |
{ |
- osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner, |
- THUMB2ARM_GLUE_SECTION_NAME); |
+ osi.sec = bfd_get_linker_section (htab->bfd_of_glue_owner, |
+ THUMB2ARM_GLUE_SECTION_NAME); |
osi.sec_shndx = _bfd_elf_section_from_bfd_section |
(output_bfd, osi.sec->output_section); |
@@ -14599,8 +14850,8 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, |
/* ARMv4 BX veneers. */ |
if (htab->bx_glue_size > 0) |
{ |
- osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner, |
- ARM_BX_GLUE_SECTION_NAME); |
+ osi.sec = bfd_get_linker_section (htab->bfd_of_glue_owner, |
+ ARM_BX_GLUE_SECTION_NAME); |
osi.sec_shndx = _bfd_elf_section_from_bfd_section |
(output_bfd, osi.sec->output_section); |
@@ -14650,6 +14901,11 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, |
return FALSE; |
} |
} |
+ else if (htab->nacl_p) |
+ { |
+ if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) |
+ return FALSE; |
+ } |
else if (!htab->symbian_p) |
{ |
if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) |
@@ -14689,7 +14945,7 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, |
/* Mapping symbols for the lazy tls trampoline. */ |
if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, htab->dt_tlsdesc_plt)) |
return FALSE; |
- |
+ |
if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, |
htab->dt_tlsdesc_plt + 24)) |
return FALSE; |
@@ -14703,9 +14959,9 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, |
if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, |
htab->tls_trampoline + 12)) |
return FALSE; |
-#endif |
+#endif |
} |
- |
+ |
return TRUE; |
} |
@@ -14768,23 +15024,24 @@ copy_exidx_entry (bfd *output_bfd, bfd_byte *to, bfd_byte *from, bfd_vma offset) |
{ |
unsigned long first_word = bfd_get_32 (output_bfd, from); |
unsigned long second_word = bfd_get_32 (output_bfd, from + 4); |
- |
+ |
/* High bit of first word is supposed to be zero. */ |
if ((first_word & 0x80000000ul) == 0) |
first_word = offset_prel31 (first_word, offset); |
- |
+ |
/* If the high bit of the first word is clear, and the bit pattern is not 0x1 |
(EXIDX_CANTUNWIND), this is an offset to an .ARM.extab entry. */ |
if ((second_word != 0x1) && ((second_word & 0x80000000ul) == 0)) |
second_word = offset_prel31 (second_word, offset); |
- |
+ |
bfd_put_32 (output_bfd, first_word, to); |
bfd_put_32 (output_bfd, second_word, to + 4); |
} |
/* Data for make_branch_to_a8_stub(). */ |
-struct a8_branch_to_stub_data { |
+struct a8_branch_to_stub_data |
+{ |
asection *writing_section; |
bfd_byte *contents; |
}; |
@@ -15022,7 +15279,7 @@ elf32_arm_write_section (bfd *output_bfd, |
if (edit_node) |
{ |
unsigned int edit_index = edit_node->index; |
- |
+ |
if (in_index < edit_index && in_index * 8 < input_size) |
{ |
copy_exidx_entry (output_bfd, edited_contents + out_index * 8, |
@@ -15040,7 +15297,7 @@ elf32_arm_write_section (bfd *output_bfd, |
in_index++; |
add_to_offsets += 8; |
break; |
- |
+ |
case INSERT_EXIDX_CANTUNWIND_AT_END: |
{ |
asection *text_sec = edit_node->linked_section; |
@@ -15070,7 +15327,7 @@ elf32_arm_write_section (bfd *output_bfd, |
} |
break; |
} |
- |
+ |
edit_node = edit_node->next; |
} |
} |
@@ -15360,7 +15617,7 @@ const struct elf_size_info elf32_arm_size_info = |
#define bfd_elf32_bfd_link_hash_table_create elf32_arm_link_hash_table_create |
#define bfd_elf32_bfd_link_hash_table_free elf32_arm_hash_table_free |
#define bfd_elf32_bfd_reloc_type_lookup elf32_arm_reloc_type_lookup |
-#define bfd_elf32_bfd_reloc_name_lookup elf32_arm_reloc_name_lookup |
+#define bfd_elf32_bfd_reloc_name_lookup elf32_arm_reloc_name_lookup |
#define bfd_elf32_find_nearest_line elf32_arm_find_nearest_line |
#define bfd_elf32_find_inliner_info elf32_arm_find_inliner_info |
#define bfd_elf32_new_section_hook elf32_arm_new_section_hook |
@@ -15414,11 +15671,78 @@ const struct elf_size_info elf32_arm_size_info = |
#define elf_backend_obj_attrs_arg_type elf32_arm_obj_attrs_arg_type |
#undef elf_backend_obj_attrs_section_type |
#define elf_backend_obj_attrs_section_type SHT_ARM_ATTRIBUTES |
-#define elf_backend_obj_attrs_order elf32_arm_obj_attrs_order |
-#define elf_backend_obj_attrs_handle_unknown elf32_arm_obj_attrs_handle_unknown |
+#define elf_backend_obj_attrs_order elf32_arm_obj_attrs_order |
+#define elf_backend_obj_attrs_handle_unknown elf32_arm_obj_attrs_handle_unknown |
#include "elf32-target.h" |
+/* Native Client targets. */ |
+ |
+#undef TARGET_LITTLE_SYM |
+#define TARGET_LITTLE_SYM bfd_elf32_littlearm_nacl_vec |
+#undef TARGET_LITTLE_NAME |
+#define TARGET_LITTLE_NAME "elf32-littlearm-nacl" |
+#undef TARGET_BIG_SYM |
+#define TARGET_BIG_SYM bfd_elf32_bigarm_nacl_vec |
+#undef TARGET_BIG_NAME |
+#define TARGET_BIG_NAME "elf32-bigarm-nacl" |
+ |
+/* Like elf32_arm_link_hash_table_create -- but overrides |
+ appropriately for NaCl. */ |
+ |
+static struct bfd_link_hash_table * |
+elf32_arm_nacl_link_hash_table_create (bfd *abfd) |
+{ |
+ struct bfd_link_hash_table *ret; |
+ |
+ ret = elf32_arm_link_hash_table_create (abfd); |
+ if (ret) |
+ { |
+ struct elf32_arm_link_hash_table *htab |
+ = (struct elf32_arm_link_hash_table *) ret; |
+ |
+ htab->nacl_p = 1; |
+ |
+ htab->plt_header_size = 4 * ARRAY_SIZE (elf32_arm_nacl_plt0_entry); |
+ htab->plt_entry_size = 4 * ARRAY_SIZE (elf32_arm_nacl_plt_entry); |
+ } |
+ return ret; |
+} |
+ |
+/* Since NaCl doesn't use the ARM-specific unwind format, we don't |
+ really need to use elf32_arm_modify_segment_map. But we do it |
+ anyway just to reduce gratuitous differences with the stock ARM backend. */ |
+ |
+static bfd_boolean |
+elf32_arm_nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info) |
+{ |
+ return (elf32_arm_modify_segment_map (abfd, info) |
+ && nacl_modify_segment_map (abfd, info)); |
+} |
+ |
+#undef elf32_bed |
+#define elf32_bed elf32_arm_nacl_bed |
+#undef bfd_elf32_bfd_link_hash_table_create |
+#define bfd_elf32_bfd_link_hash_table_create \ |
+ elf32_arm_nacl_link_hash_table_create |
+#undef elf_backend_plt_alignment |
+#define elf_backend_plt_alignment 4 |
+#undef elf_backend_modify_segment_map |
+#define elf_backend_modify_segment_map elf32_arm_nacl_modify_segment_map |
+#undef elf_backend_modify_program_headers |
+#define elf_backend_modify_program_headers nacl_modify_program_headers |
+ |
+#undef ELF_MAXPAGESIZE |
+#define ELF_MAXPAGESIZE 0x10000 |
+ |
+#include "elf32-target.h" |
+ |
+/* Reset to defaults. */ |
+#undef elf_backend_plt_alignment |
+#undef elf_backend_modify_segment_map |
+#define elf_backend_modify_segment_map elf32_arm_modify_segment_map |
+#undef elf_backend_modify_program_headers |
+ |
/* VxWorks Targets. */ |
#undef TARGET_LITTLE_SYM |