X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-arm.c;h=f42b2bf8138c9b8d73abbfc04a1b8b6c5d8c2950;hb=b3364cb9c21f33b0f0de633d10f6729134b9bd6f;hp=53a084665dcbd5a709f52abaa0d805fb0d2d99c3;hpb=3de4a297ec739ba0111d80a5b9060d9bffc2d899;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 53a084665d..f42b2bf813 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 Free Software Foundation, Inc. + 2008, 2009, 2010, 2011 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -229,8 +229,8 @@ static reloc_howto_type elf32_arm_howto_table_1[] = bfd_elf_generic_reloc, /* special_function */ "R_ARM_THM_CALL", /* name */ FALSE, /* partial_inplace */ - 0x07ff07ff, /* src_mask */ - 0x07ff07ff, /* dst_mask */ + 0x07ff2fff, /* src_mask */ + 0x07ff2fff, /* dst_mask */ TRUE), /* pcrel_offset */ HOWTO (R_ARM_THM_PC8, /* type */ @@ -261,18 +261,18 @@ static reloc_howto_type elf32_arm_howto_table_1[] = 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ - HOWTO (R_ARM_SWI24, /* type */ + HOWTO (R_ARM_TLS_DESC, /* type */ 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ + complain_overflow_bitfield,/* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ - "R_ARM_SWI24", /* name */ + "R_ARM_TLS_DESC", /* name */ FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00000000, /* dst_mask */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_ARM_THM_SWI8, /* type */ @@ -293,7 +293,7 @@ static reloc_howto_type elf32_arm_howto_table_1[] = HOWTO (R_ARM_XPC25, /* type */ 2, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 25, /* bitsize */ + 24, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed,/* complain_on_overflow */ @@ -308,15 +308,15 @@ static reloc_howto_type elf32_arm_howto_table_1[] = HOWTO (R_ARM_THM_XPC22, /* type */ 2, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 22, /* bitsize */ + 24, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed,/* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_ARM_THM_XPC22", /* name */ FALSE, /* partial_inplace */ - 0x07ff07ff, /* src_mask */ - 0x07ff07ff, /* dst_mask */ + 0x07ff2fff, /* src_mask */ + 0x07ff2fff, /* dst_mask */ TRUE), /* pcrel_offset */ /* Dynamic TLS relocations. */ @@ -1352,10 +1352,61 @@ static reloc_howto_type elf32_arm_howto_table_1[] = 0x040f70ff, /* dst_mask */ FALSE), /* pcrel_offset */ - EMPTY_HOWTO (90), /* Unallocated. */ - EMPTY_HOWTO (91), - EMPTY_HOWTO (92), - EMPTY_HOWTO (93), + HOWTO (R_ARM_TLS_GOTDESC, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield,/* complain_on_overflow */ + NULL, /* special_function */ + "R_ARM_TLS_GOTDESC", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_ARM_TLS_CALL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 24, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_ARM_TLS_CALL", /* name */ + FALSE, /* partial_inplace */ + 0x00ffffff, /* src_mask */ + 0x00ffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_ARM_TLS_DESCSEQ, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_ARM_TLS_DESCSEQ", /* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x00000000, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_ARM_THM_TLS_CALL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 24, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_ARM_THM_TLS_CALL", /* name */ + FALSE, /* partial_inplace */ + 0x07ff07ff, /* src_mask */ + 0x07ff07ff, /* dst_mask */ + FALSE), /* pcrel_offset */ HOWTO (R_ARM_PLT32_ABS, /* type */ 0, /* rightshift */ @@ -1599,15 +1650,63 @@ static reloc_howto_type elf32_arm_howto_table_1[] = 0x00000fff, /* src_mask */ 0x00000fff, /* dst_mask */ FALSE), /* pcrel_offset */ -}; -/* 112-127 private relocations - 128 R_ARM_ME_TOO, obsolete - 129-255 unallocated in AAELF. + /* 112-127 private relocations. */ + EMPTY_HOWTO (112), + EMPTY_HOWTO (113), + EMPTY_HOWTO (114), + EMPTY_HOWTO (115), + EMPTY_HOWTO (116), + EMPTY_HOWTO (117), + EMPTY_HOWTO (118), + EMPTY_HOWTO (119), + EMPTY_HOWTO (120), + EMPTY_HOWTO (121), + EMPTY_HOWTO (122), + EMPTY_HOWTO (123), + EMPTY_HOWTO (124), + EMPTY_HOWTO (125), + EMPTY_HOWTO (126), + EMPTY_HOWTO (127), + + /* R_ARM_ME_TOO, obsolete. */ + EMPTY_HOWTO (128), + + HOWTO (R_ARM_THM_TLS_DESCSEQ, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_ARM_THM_TLS_DESCSEQ",/* name */ + FALSE, /* partial_inplace */ + 0x00000000, /* src_mask */ + 0x00000000, /* dst_mask */ + FALSE), /* pcrel_offset */ +}; - 249-255 extended, currently unused, relocations: */ +/* 160 onwards: */ +static reloc_howto_type elf32_arm_howto_table_2[1] = +{ + HOWTO (R_ARM_IRELATIVE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_ARM_IRELATIVE", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE) /* pcrel_offset */ +}; -static reloc_howto_type elf32_arm_howto_table_2[4] = +/* 249-255 extended, currently unused, relocations: */ +static reloc_howto_type elf32_arm_howto_table_3[4] = { HOWTO (R_ARM_RREL32, /* type */ 0, /* rightshift */ @@ -1672,9 +1771,12 @@ elf32_arm_howto_from_type (unsigned int r_type) if (r_type < ARRAY_SIZE (elf32_arm_howto_table_1)) return &elf32_arm_howto_table_1[r_type]; + if (r_type == R_ARM_IRELATIVE) + return &elf32_arm_howto_table_2[r_type - R_ARM_IRELATIVE]; + if (r_type >= R_ARM_RREL32 - && r_type < R_ARM_RREL32 + ARRAY_SIZE (elf32_arm_howto_table_2)) - return &elf32_arm_howto_table_2[r_type - R_ARM_RREL32]; + && r_type < R_ARM_RREL32 + ARRAY_SIZE (elf32_arm_howto_table_3)) + return &elf32_arm_howto_table_3[r_type - R_ARM_RREL32]; return NULL; } @@ -1730,6 +1832,12 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] = {BFD_RELOC_ARM_PREL31, R_ARM_PREL31}, {BFD_RELOC_ARM_TARGET2, R_ARM_TARGET2}, {BFD_RELOC_ARM_PLT32, R_ARM_PLT32}, + {BFD_RELOC_ARM_TLS_GOTDESC, R_ARM_TLS_GOTDESC}, + {BFD_RELOC_ARM_TLS_CALL, R_ARM_TLS_CALL}, + {BFD_RELOC_ARM_THM_TLS_CALL, R_ARM_THM_TLS_CALL}, + {BFD_RELOC_ARM_TLS_DESCSEQ, R_ARM_TLS_DESCSEQ}, + {BFD_RELOC_ARM_THM_TLS_DESCSEQ, R_ARM_THM_TLS_DESCSEQ}, + {BFD_RELOC_ARM_TLS_DESC, R_ARM_TLS_DESC}, {BFD_RELOC_ARM_TLS_GD32, R_ARM_TLS_GD32}, {BFD_RELOC_ARM_TLS_LDO32, R_ARM_TLS_LDO32}, {BFD_RELOC_ARM_TLS_LDM32, R_ARM_TLS_LDM32}, @@ -1738,6 +1846,7 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] = {BFD_RELOC_ARM_TLS_TPOFF32, R_ARM_TLS_TPOFF32}, {BFD_RELOC_ARM_TLS_IE32, R_ARM_TLS_IE32}, {BFD_RELOC_ARM_TLS_LE32, R_ARM_TLS_LE32}, + {BFD_RELOC_ARM_IRELATIVE, R_ARM_IRELATIVE}, {BFD_RELOC_VTABLE_INHERIT, R_ARM_GNU_VTINHERIT}, {BFD_RELOC_VTABLE_ENTRY, R_ARM_GNU_VTENTRY}, {BFD_RELOC_ARM_MOVW, R_ARM_MOVW_ABS_NC}, @@ -1808,6 +1917,11 @@ elf32_arm_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, && strcasecmp (elf32_arm_howto_table_2[i].name, r_name) == 0) return &elf32_arm_howto_table_2[i]; + for (i = 0; i < ARRAY_SIZE (elf32_arm_howto_table_3); i++) + if (elf32_arm_howto_table_3[i].name != NULL + && strcasecmp (elf32_arm_howto_table_3[i].name, r_name) == 0) + return &elf32_arm_howto_table_3[i]; + return NULL; } @@ -1829,7 +1943,7 @@ elf32_arm_nabi_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ - elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); + elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); /* pr_reg */ offset = 72; @@ -1912,6 +2026,26 @@ typedef unsigned short int insn16; section. */ #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 */ + }; + +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 + + dl_tlsdesc_lazy_resolver(GOT) */ + 0x00000018, /* 4: .word _GLOBAL_OFFSET_TABLE_ - 2b - 8 */ + }; + #ifdef FOUR_WORD_PLT /* The first entry in a procedure linkage table looks like @@ -2106,7 +2240,7 @@ static const insn_sequence elf32_arm_stub_short_branch_v4t_thumb_arm[] = blx to reach the stub if necessary. */ static const insn_sequence elf32_arm_stub_long_branch_any_arm_pic[] = { - ARM_INSN(0xe59fc000), /* ldr r12, [pc] */ + 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) */ }; @@ -2117,7 +2251,7 @@ static const insn_sequence elf32_arm_stub_long_branch_any_arm_pic[] = ARMv7). */ static const insn_sequence elf32_arm_stub_long_branch_any_thumb_pic[] = { - ARM_INSN(0xe59fc004), /* ldr r12, [pc, #4] */ + 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) */ @@ -2167,6 +2301,26 @@ static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb_pic[] = 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) */ +}; + +/* 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) */ +}; + /* Cortex-A8 erratum-workaround stubs. */ /* Stub used for conditional branches (which may be beyond +/-1MB away, so we @@ -2200,9 +2354,32 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] = ARM_REL_INSN(0xea000000, -8) /* b original_branch_dest. */ }; -/* Section name for stubs is the associated section name plus this - string. */ -#define STUB_SUFFIX ".stub" +/* 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 + upon the name of another section within that group with the suffix below + applied. + + 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 + section called: + + .data.rel.local.stubborn_problems + + This then causes problems in arm32_arm_build_stubs() as it triggers: + + // Ignore non-stub sections. + if (!strstr (stub_sec->name, STUB_SUFFIX)) + continue; + + And so the section would be ignored instead of being processed. Hence + the change in definition of STUB_SUFFIX to a name that cannot be a valid + C identifier. */ +#define STUB_SUFFIX ".__stub" /* One entry per long/short branch stub defined above. */ #define DEF_STUBS \ @@ -2218,6 +2395,8 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] = DEF_STUB(long_branch_v4t_arm_thumb_pic) \ DEF_STUB(long_branch_v4t_thumb_arm_pic) \ DEF_STUB(long_branch_thumb_only_pic) \ + DEF_STUB(long_branch_any_tls_pic) \ + DEF_STUB(long_branch_v4t_thumb_tls_pic) \ DEF_STUB(a8_veneer_b_cond) \ DEF_STUB(a8_veneer_b) \ DEF_STUB(a8_veneer_bl) \ @@ -2279,8 +2458,8 @@ struct elf32_arm_stub_hash_entry /* The symbol table entry, if any, that this was derived from. */ struct elf32_arm_link_hash_entry *h; - /* Destination symbol type (STT_ARM_TFUNC, ...) */ - unsigned char st_type; + /* Type of branch. */ + enum arm_st_branch_type branch_type; /* Where this stub is being called from, or, in the case of combined stub sections, the first input section in the group. */ @@ -2400,7 +2579,7 @@ struct a8_erratum_fix { unsigned long orig_insn; char *stub_name; enum elf32_arm_stub_type stub_type; - int st_type; + enum arm_st_branch_type branch_type; }; /* A table of relocs applied to branches which might trigger Cortex-A8 @@ -2412,13 +2591,51 @@ struct a8_erratum_reloc { struct elf32_arm_link_hash_entry *hash; const char *sym_name; unsigned int r_type; - unsigned char st_type; + enum arm_st_branch_type branch_type; bfd_boolean non_a8_stub; }; /* The size of the thread control block. */ #define TCB_SIZE 8 +/* ARM-specific information about a PLT entry, over and above the usual + gotplt_union. */ +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; + + /* Some references from Thumb code may be eliminated by BL->BLX + conversion, so record them separately. */ + bfd_signed_vma maybe_thumb_refcount; + + /* How many of the recorded PLT accesses were from non-call relocations. + This information is useful when deciding whether anything takes the + address of an STT_GNU_IFUNC PLT. A value of 0 means that all + non-call references to the function should resolve directly to the + real runtime target. */ + unsigned int noncall_refcount; + + /* Since PLT entries have variable size if the Thumb prologue is + used, we need to record the index into .got.plt instead of + recomputing it from the PLT offset. */ + bfd_signed_vma got_offset; +}; + +/* Information about an .iplt entry for a local STT_GNU_IFUNC symbol. */ +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; + + /* The information that is usually found in the ARM-specific part of + the hash table entry. */ + struct arm_plt_info arm; + + /* A list of all potential dynamic relocations against this symbol. */ + struct elf_dyn_relocs *dyn_relocs; +}; + struct elf_arm_obj_tdata { struct elf_obj_tdata root; @@ -2426,6 +2643,12 @@ struct elf_arm_obj_tdata /* tls_type for each local got entry. */ char *local_got_tls_type; + /* GOTPLT entries for TLS descriptors. */ + bfd_vma *local_tlsdesc_gotent; + + /* Information for local symbols that need entries in .iplt. */ + struct arm_local_iplt_info **local_iplt; + /* Zero to warn when linking objects with incompatible enum sizes. */ int no_enum_size_warning; @@ -2439,6 +2662,12 @@ struct elf_arm_obj_tdata #define elf32_arm_local_got_tls_type(bfd) \ (elf_arm_tdata (bfd)->local_got_tls_type) +#define elf32_arm_local_tlsdesc_gotent(bfd) \ + (elf_arm_tdata (bfd)->local_tlsdesc_gotent) + +#define elf32_arm_local_iplt(bfd) \ + (elf_arm_tdata (bfd)->local_iplt) + #define is_arm_elf(bfd) \ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ && elf_tdata (bfd) != NULL \ @@ -2451,26 +2680,6 @@ elf32_arm_mkobject (bfd *abfd) ARM_ELF_DATA); } -/* The ARM linker needs to keep track of the number of relocs that it - decides to copy in check_relocs for each symbol. This is so that - it can discard PC relative relocs if it doesn't need them when - linking with -Bsymbolic. We store the information in a field - extending the regular ELF linker hash table. */ - -/* This structure keeps track of the number of relocs we have copied - for a given symbol. */ -struct elf32_arm_relocs_copied - { - /* Next section. */ - struct elf32_arm_relocs_copied * next; - /* A section in dynobj. */ - asection * section; - /* Number of relocs copied in this section. */ - bfd_size_type count; - /* Number of PC-relative relocs copied in this section. */ - bfd_size_type pc_count; - }; - #define elf32_arm_hash_entry(ent) ((struct elf32_arm_link_hash_entry *)(ent)) /* Arm ELF linker hash entry. */ @@ -2478,27 +2687,28 @@ struct elf32_arm_link_hash_entry { struct elf_link_hash_entry root; - /* Number of PC relative relocs copied for this symbol. */ - struct elf32_arm_relocs_copied * relocs_copied; - - /* We reference count Thumb references to a PLT entry separately, - so that we can emit the Thumb trampoline only if needed. */ - bfd_signed_vma plt_thumb_refcount; + /* Track dynamic relocs copied for this symbol. */ + struct elf_dyn_relocs *dyn_relocs; - /* Some references from Thumb code may be eliminated by BL->BLX - conversion, so record them separately. */ - bfd_signed_vma plt_maybe_thumb_refcount; - - /* Since PLT entries have variable size if the Thumb prologue is - used, we need to record the index into .got.plt instead of - recomputing it from the PLT offset. */ - bfd_signed_vma plt_got_offset; + /* ARM-specific PLT information. */ + struct arm_plt_info plt; #define GOT_UNKNOWN 0 #define GOT_NORMAL 1 #define GOT_TLS_GD 2 #define GOT_TLS_IE 4 - unsigned char tls_type; +#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; + + /* True if the symbol's PLT entry is in .iplt rather than .plt. */ + unsigned int is_iplt : 1; + + 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; /* The symbol marking the real symbol location for exported thumb symbols with Arm stubs. */ @@ -2536,6 +2746,9 @@ struct map_stub asection *stub_sec; }; +#define elf32_arm_compute_jump_table_size(htab) \ + ((htab)->next_tls_desc_index * 4) + /* ARM ELF linker hash table. */ struct elf32_arm_link_hash_table { @@ -2586,6 +2799,9 @@ struct elf32_arm_link_hash_table /* Whether we should fix the Cortex-A8 Thumb-2 branch/TLB erratum. */ int fix_cortex_a8; + /* Whether we should fix the ARM1176 BLX immediate issue. */ + int fix_arm1176; + /* Nonzero if the ARM/Thumb BLX instructions are available for use. */ int use_blx; @@ -2614,18 +2830,32 @@ struct elf32_arm_link_hash_table /* True if the target uses REL relocations. */ int use_rel; + /* The index of the next unused R_ARM_TLS_DESC slot in .rel.plt. */ + bfd_vma next_tls_desc_index; + + /* How many R_ARM_TLS_DESC relocations were generated so far. */ + bfd_vma num_tls_desc; + /* Short-cuts to get to dynamic linker sections. */ - asection *sgot; - asection *sgotplt; - asection *srelgot; - asection *splt; - asection *srelplt; asection *sdynbss; asection *srelbss; /* The (unloaded but important) VxWorks .rela.plt.unloaded section. */ asection *srelplt2; + /* The offset into splt of the PLT entry for the TLS descriptor + resolver. Special values are 0, if not necessary (or not found + to be necessary yet), and -1 if needed but not determined + yet. */ + bfd_vma dt_tlsdesc_plt; + + /* The offset into sgot of the GOT entry used by the PLT entry + above. */ + bfd_vma dt_tlsdesc_got; + + /* Offset in .plt section of tls_arm_trampoline. */ + bfd_vma tls_trampoline; + /* Data for R_ARM_TLS_LDM32 relocations. */ union { @@ -2639,6 +2869,10 @@ struct elf32_arm_link_hash_table /* For convenience in allocate_dynrelocs. */ bfd * obfd; + /* The amount of space used by the reserved portion of the sgotplt + section, plus whatever space is used by the jump slots. */ + bfd_vma sgotplt_jump_table_size; + /* The stub hash table. */ struct bfd_hash_table stub_hash_table; @@ -2686,11 +2920,14 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry, table, string)); if (ret != NULL) { - ret->relocs_copied = NULL; + ret->dyn_relocs = NULL; ret->tls_type = GOT_UNKNOWN; - ret->plt_thumb_refcount = 0; - ret->plt_maybe_thumb_refcount = 0; - ret->plt_got_offset = -1; + ret->tlsdesc_got = (bfd_vma) -1; + ret->plt.thumb_refcount = 0; + ret->plt.maybe_thumb_refcount = 0; + ret->plt.noncall_refcount = 0; + ret->plt.got_offset = -1; + ret->is_iplt = FALSE; ret->export_glue = NULL; ret->stub_cache = NULL; @@ -2699,6 +2936,142 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry, return (struct bfd_hash_entry *) ret; } +/* Ensure that we have allocated bookkeeping structures for ABFD's local + symbols. */ + +static bfd_boolean +elf32_arm_allocate_local_sym_info (bfd *abfd) +{ + if (elf_local_got_refcounts (abfd) == NULL) + { + bfd_size_type num_syms; + bfd_size_type size; + char *data; + + num_syms = elf_tdata (abfd)->symtab_hdr.sh_info; + size = num_syms * (sizeof (bfd_signed_vma) + + sizeof (struct arm_local_iplt_info *) + + sizeof (bfd_vma) + + sizeof (char)); + data = bfd_zalloc (abfd, size); + if (data == NULL) + return FALSE; + + elf_local_got_refcounts (abfd) = (bfd_signed_vma *) data; + data += num_syms * sizeof (bfd_signed_vma); + + elf32_arm_local_iplt (abfd) = (struct arm_local_iplt_info **) data; + data += num_syms * sizeof (struct arm_local_iplt_info *); + + elf32_arm_local_tlsdesc_gotent (abfd) = (bfd_vma *) data; + data += num_syms * sizeof (bfd_vma); + + elf32_arm_local_got_tls_type (abfd) = data; + } + return TRUE; +} + +/* Return the .iplt information for local symbol R_SYMNDX, which belongs + to input bfd ABFD. Create the information if it doesn't already exist. + Return null if an allocation fails. */ + +static struct arm_local_iplt_info * +elf32_arm_create_local_iplt (bfd *abfd, unsigned long r_symndx) +{ + struct arm_local_iplt_info **ptr; + + if (!elf32_arm_allocate_local_sym_info (abfd)) + return NULL; + + BFD_ASSERT (r_symndx < elf_tdata (abfd)->symtab_hdr.sh_info); + ptr = &elf32_arm_local_iplt (abfd)[r_symndx]; + if (*ptr == NULL) + *ptr = bfd_zalloc (abfd, sizeof (**ptr)); + return *ptr; +} + +/* Try to obtain PLT information for the symbol with index R_SYMNDX + in ABFD's symbol table. If the symbol is global, H points to its + hash table entry, otherwise H is null. + + Return true if the symbol does have PLT information. When returning + true, point *ROOT_PLT at the target-independent reference count/offset + union and *ARM_PLT at the ARM-specific information. */ + +static bfd_boolean +elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_entry *h, + unsigned long r_symndx, union gotplt_union **root_plt, + struct arm_plt_info **arm_plt) +{ + struct arm_local_iplt_info *local_iplt; + + if (h != NULL) + { + *root_plt = &h->root.plt; + *arm_plt = &h->plt; + return TRUE; + } + + if (elf32_arm_local_iplt (abfd) == NULL) + return FALSE; + + local_iplt = elf32_arm_local_iplt (abfd)[r_symndx]; + if (local_iplt == NULL) + return FALSE; + + *root_plt = &local_iplt->root; + *arm_plt = &local_iplt->arm; + return TRUE; +} + +/* Return true if the PLT described by ARM_PLT requires a Thumb stub + before it. */ + +static bfd_boolean +elf32_arm_plt_needs_thumb_stub_p (struct bfd_link_info *info, + struct arm_plt_info *arm_plt) +{ + struct elf32_arm_link_hash_table *htab; + + htab = elf32_arm_hash_table (info); + return (arm_plt->thumb_refcount != 0 + || (!htab->use_blx && arm_plt->maybe_thumb_refcount != 0)); +} + +/* Return a pointer to the head of the dynamic reloc list that should + be used for local symbol ISYM, which is symbol number R_SYMNDX in + ABFD's symbol table. Return null if an error occurs. */ + +static struct elf_dyn_relocs ** +elf32_arm_get_local_dynreloc_list (bfd *abfd, unsigned long r_symndx, + Elf_Internal_Sym *isym) +{ + if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) + { + struct arm_local_iplt_info *local_iplt; + + local_iplt = elf32_arm_create_local_iplt (abfd, r_symndx); + if (local_iplt == NULL) + return NULL; + return &local_iplt->dyn_relocs; + } + else + { + /* Track dynamic relocs needed for local syms too. + We really need local syms available to do this + easily. Oh well. */ + asection *s; + void *vpp; + + s = bfd_section_from_elf_index (abfd, isym->st_shndx); + if (s == NULL) + abort (); + + vpp = &elf_section_data (s)->local_dynrel; + return (struct elf_dyn_relocs **) vpp; + } +} + /* Initialize an entry in the stub hash table. */ static struct bfd_hash_entry * @@ -2761,15 +3134,53 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info) if (! _bfd_elf_create_got_section (dynobj, info)) return FALSE; - htab->sgot = bfd_get_section_by_name (dynobj, ".got"); - htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt"); - if (!htab->sgot || !htab->sgotplt) - abort (); + return TRUE; +} - htab->srelgot = bfd_get_section_by_name (dynobj, - RELOC_SECTION (htab, ".got")); - if (htab->srelgot == NULL) - return FALSE; +/* Create the .iplt, .rel(a).iplt and .igot.plt sections. */ + +static bfd_boolean +create_ifunc_sections (struct bfd_link_info *info) +{ + struct elf32_arm_link_hash_table *htab; + const struct elf_backend_data *bed; + bfd *dynobj; + asection *s; + flagword flags; + + htab = elf32_arm_hash_table (info); + dynobj = htab->root.dynobj; + bed = get_elf_backend_data (dynobj); + flags = bed->dynamic_sec_flags; + + if (htab->root.iplt == NULL) + { + s = bfd_make_section_with_flags (dynobj, ".iplt", + flags | SEC_READONLY | SEC_CODE); + if (s == NULL + || !bfd_set_section_alignment (abfd, 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); + if (s == NULL + || !bfd_set_section_alignment (abfd, 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); + if (s == NULL + || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) + return FALSE; + htab->root.igotplt = s; + } return TRUE; } @@ -2786,15 +3197,12 @@ elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) if (htab == NULL) return FALSE; - if (!htab->sgot && !create_got_section (dynobj, info)) + if (!htab->root.sgot && !create_got_section (dynobj, info)) return FALSE; if (!_bfd_elf_create_dynamic_sections (dynobj, info)) return FALSE; - htab->splt = bfd_get_section_by_name (dynobj, ".plt"); - htab->srelplt = bfd_get_section_by_name (dynobj, - RELOC_SECTION (htab, ".plt")); htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss"); if (!info->shared) htab->srelbss = bfd_get_section_by_name (dynobj, @@ -2820,8 +3228,8 @@ elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) } } - if (!htab->splt - || !htab->srelplt + if (!htab->root.splt + || !htab->root.srelplt || !htab->sdynbss || (!info->shared && !htab->srelbss)) abort (); @@ -2841,21 +3249,21 @@ elf32_arm_copy_indirect_symbol (struct bfd_link_info *info, edir = (struct elf32_arm_link_hash_entry *) dir; eind = (struct elf32_arm_link_hash_entry *) ind; - if (eind->relocs_copied != NULL) + if (eind->dyn_relocs != NULL) { - if (edir->relocs_copied != NULL) + if (edir->dyn_relocs != NULL) { - struct elf32_arm_relocs_copied **pp; - struct elf32_arm_relocs_copied *p; + struct elf_dyn_relocs **pp; + struct elf_dyn_relocs *p; /* Add reloc counts against the indirect sym to the direct sym list. Merge any entries against the same section. */ - for (pp = &eind->relocs_copied; (p = *pp) != NULL; ) + for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) { - struct elf32_arm_relocs_copied *q; + struct elf_dyn_relocs *q; - for (q = edir->relocs_copied; q != NULL; q = q->next) - if (q->section == p->section) + for (q = edir->dyn_relocs; q != NULL; q = q->next) + if (q->sec == p->sec) { q->pc_count += p->pc_count; q->count += p->count; @@ -2865,20 +3273,26 @@ elf32_arm_copy_indirect_symbol (struct bfd_link_info *info, if (q == NULL) pp = &p->next; } - *pp = edir->relocs_copied; + *pp = edir->dyn_relocs; } - edir->relocs_copied = eind->relocs_copied; - eind->relocs_copied = NULL; + edir->dyn_relocs = eind->dyn_relocs; + eind->dyn_relocs = NULL; } if (ind->root.type == bfd_link_hash_indirect) { /* Copy over PLT info. */ - edir->plt_thumb_refcount += eind->plt_thumb_refcount; - eind->plt_thumb_refcount = 0; - edir->plt_maybe_thumb_refcount += eind->plt_maybe_thumb_refcount; - eind->plt_maybe_thumb_refcount = 0; + edir->plt.thumb_refcount += eind->plt.thumb_refcount; + eind->plt.thumb_refcount = 0; + edir->plt.maybe_thumb_refcount += eind->plt.maybe_thumb_refcount; + eind->plt.maybe_thumb_refcount = 0; + edir->plt.noncall_refcount += eind->plt.noncall_refcount; + eind->plt.noncall_refcount = 0; + + /* We should only allocate a function to .iplt once the final + symbol information is known. */ + BFD_ASSERT (!eind->is_iplt); if (dir->got.refcount <= 0) { @@ -2911,14 +3325,14 @@ elf32_arm_link_hash_table_create (bfd *abfd) return NULL; } - ret->sgot = NULL; - ret->sgotplt = NULL; - ret->srelgot = NULL; - ret->splt = NULL; - ret->srelplt = NULL; ret->sdynbss = NULL; ret->srelbss = NULL; ret->srelplt2 = NULL; + ret->dt_tlsdesc_plt = 0; + ret->dt_tlsdesc_got = 0; + ret->tls_trampoline = 0; + ret->next_tls_desc_index = 0; + ret->num_tls_desc = 0; ret->thumb_glue_size = 0; ret->arm_glue_size = 0; ret->bx_glue_size = 0; @@ -2927,6 +3341,7 @@ elf32_arm_link_hash_table_create (bfd *abfd) ret->vfp11_erratum_glue_size = 0; ret->num_vfp11_fixes = 0; ret->fix_cortex_a8 = 0; + ret->fix_arm1176 = 0; ret->bfd_of_glue_owner = NULL; ret->byteswap_code = 0; ret->target1_is_rel = 0; @@ -3039,6 +3454,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type) case arm_stub_long_branch_v4t_thumb_arm: case arm_stub_short_branch_v4t_thumb_arm: case arm_stub_long_branch_v4t_thumb_arm_pic: + case arm_stub_long_branch_v4t_thumb_tls_pic: case arm_stub_long_branch_thumb_only_pic: return TRUE; case arm_stub_none: @@ -3056,7 +3472,8 @@ static enum elf32_arm_stub_type arm_type_of_stub (struct bfd_link_info *info, asection *input_sec, const Elf_Internal_Rela *rel, - int *actual_st_type, + unsigned char st_type, + enum arm_st_branch_type *actual_branch_type, struct elf32_arm_link_hash_entry *hash, bfd_vma destination, asection *sym_sec, @@ -3071,11 +3488,11 @@ arm_type_of_stub (struct bfd_link_info *info, int thumb_only; enum elf32_arm_stub_type stub_type = arm_stub_none; int use_plt = 0; - int st_type = *actual_st_type; + enum arm_st_branch_type branch_type = *actual_branch_type; + union gotplt_union *root_plt; + struct arm_plt_info *arm_plt; - /* We don't know the actual type of destination in case it is of - type STT_SECTION: give up. */ - if (st_type == STT_SECTION) + if (branch_type == ST_BRANCH_LONG) return stub_type; globals = elf32_arm_hash_table (info); @@ -3093,31 +3510,47 @@ arm_type_of_stub (struct bfd_link_info *info, r_type = ELF32_R_TYPE (rel->r_info); - /* Keep a simpler condition, for the sake of clarity. */ - if (globals->splt != NULL - && hash != NULL - && hash->root.plt.offset != (bfd_vma) -1) + /* For TLS call relocs, it is the caller's responsibility to provide + the address of the appropriate trampoline. */ + if (r_type != R_ARM_TLS_CALL + && r_type != R_ARM_THM_TLS_CALL + && elf32_arm_get_plt_info (input_bfd, hash, ELF32_R_SYM (rel->r_info), + &root_plt, &arm_plt) + && root_plt->offset != (bfd_vma) -1) { - use_plt = 1; - - /* Note when dealing with PLT entries: the main PLT stub is in - ARM mode, so if the branch is in Thumb mode, another - Thumb->ARM stub will be inserted later just before the ARM - PLT stub. We don't take this extra distance into account - here, because if a long branch stub is needed, we'll add a - Thumb->Arm one and branch directly to the ARM PLT entry - because it avoids spreading offset corrections in several - places. */ + asection *splt; - destination = (globals->splt->output_section->vma - + globals->splt->output_offset - + hash->root.plt.offset); - st_type = STT_FUNC; + if (hash == NULL || hash->is_iplt) + splt = globals->root.iplt; + else + splt = globals->root.splt; + if (splt != NULL) + { + use_plt = 1; + + /* Note when dealing with PLT entries: the main PLT stub is in + ARM mode, so if the branch is in Thumb mode, another + Thumb->ARM stub will be inserted later just before the ARM + PLT stub. We don't take this extra distance into account + here, because if a long branch stub is needed, we'll add a + Thumb->Arm one and branch directly to the ARM PLT entry + because it avoids spreading offset corrections in several + places. */ + + destination = (splt->output_section->vma + + splt->output_offset + + root_plt->offset); + st_type = STT_FUNC; + branch_type = ST_BRANCH_TO_ARM; + } } + /* Calls to STT_GNU_IFUNC symbols should go through a PLT. */ + BFD_ASSERT (st_type != STT_GNU_IFUNC); branch_offset = (bfd_signed_vma)(destination - location); - if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) + if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24 + || r_type == R_ARM_THM_TLS_CALL) { /* Handle cases where: - this call goes too far (different Thumb/Thumb2 max @@ -3133,12 +3566,13 @@ arm_type_of_stub (struct bfd_link_info *info, || (thumb2 && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) - || ((st_type != STT_ARM_TFUNC) - && (((r_type == R_ARM_THM_CALL) && !globals->use_blx) + || (branch_type == ST_BRANCH_TO_ARM + && (((r_type == R_ARM_THM_CALL + || r_type == R_ARM_THM_TLS_CALL) && !globals->use_blx) || (r_type == R_ARM_THM_JUMP24)) && !use_plt)) { - if (st_type == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) { /* Thumb to thumb. */ if (!thumb_only) @@ -3146,7 +3580,7 @@ arm_type_of_stub (struct bfd_link_info *info, stub_type = (info->shared | globals->pic_veneer) /* PIC stubs. */ ? ((globals->use_blx - && (r_type ==R_ARM_THM_CALL)) + && (r_type == R_ARM_THM_CALL)) /* V5T and above. Stub starts with ARM code, so we must be able to switch mode before reaching it, which is only possible for 'bl' @@ -3157,7 +3591,7 @@ arm_type_of_stub (struct bfd_link_info *info, /* non-PIC stubs. */ : ((globals->use_blx - && (r_type ==R_ARM_THM_CALL)) + && (r_type == R_ARM_THM_CALL)) /* V5T and above. */ ? arm_stub_long_branch_any_any /* V4T. */ @@ -3185,18 +3619,21 @@ arm_type_of_stub (struct bfd_link_info *info, sym_sec->owner, input_bfd, name); } - stub_type = (info->shared | globals->pic_veneer) + stub_type = + (info->shared | globals->pic_veneer) /* PIC stubs. */ - ? ((globals->use_blx - && (r_type ==R_ARM_THM_CALL)) - /* V5T and above. */ - ? arm_stub_long_branch_any_arm_pic - /* V4T PIC stub. */ - : arm_stub_long_branch_v4t_thumb_arm_pic) + ? (r_type == R_ARM_THM_TLS_CALL + /* TLS PIC stubs */ + ? (globals->use_blx ? arm_stub_long_branch_any_tls_pic + : arm_stub_long_branch_v4t_thumb_tls_pic) + : ((globals->use_blx && r_type == R_ARM_THM_CALL) + /* V5T PIC and above. */ + ? arm_stub_long_branch_any_arm_pic + /* V4T PIC stub. */ + : arm_stub_long_branch_v4t_thumb_arm_pic)) /* non-PIC stubs. */ - : ((globals->use_blx - && (r_type ==R_ARM_THM_CALL)) + : ((globals->use_blx && r_type == R_ARM_THM_CALL) /* V5T and above. */ ? arm_stub_long_branch_any_any /* V4T. */ @@ -3212,9 +3649,10 @@ arm_type_of_stub (struct bfd_link_info *info, } else if (r_type == R_ARM_CALL || r_type == R_ARM_JUMP24 - || r_type == R_ARM_PLT32) + || r_type == R_ARM_PLT32 + || r_type == R_ARM_TLS_CALL) { - if (st_type == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) { /* Arm to thumb. */ @@ -3232,7 +3670,7 @@ arm_type_of_stub (struct bfd_link_info *info, the mode change (bit 24 (H) of BLX encoding). */ if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2) || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET) - || ((r_type == R_ARM_CALL) && !globals->use_blx) + || (r_type == R_ARM_CALL && !globals->use_blx) || (r_type == R_ARM_JUMP24) || (r_type == R_ARM_PLT32)) { @@ -3258,9 +3696,13 @@ arm_type_of_stub (struct bfd_link_info *info, if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)) { - stub_type = (info->shared | globals->pic_veneer) + stub_type = + (info->shared | globals->pic_veneer) /* PIC stubs. */ - ? arm_stub_long_branch_any_arm_pic + ? (r_type == R_ARM_TLS_CALL + /* TLS PIC Stub */ + ? arm_stub_long_branch_any_tls_pic + : arm_stub_long_branch_any_arm_pic) /* non-PIC stubs. */ : arm_stub_long_branch_any_any; } @@ -3269,9 +3711,7 @@ arm_type_of_stub (struct bfd_link_info *info, /* If a stub is needed, record the actual destination type. */ if (stub_type != arm_stub_none) - { - *actual_st_type = st_type; - } + *actual_branch_type = branch_type; return stub_type; } @@ -3307,7 +3747,9 @@ elf32_arm_stub_name (const asection *input_section, sprintf (stub_name, "%08x_%x:%x+%x_%d", input_section->id & 0xffffffff, sym_sec->id & 0xffffffff, - (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, + ELF32_R_TYPE (rel->r_info) == R_ARM_TLS_CALL + || ELF32_R_TYPE (rel->r_info) == R_ARM_THM_TLS_CALL + ? 0 : (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, (int) rel->r_addend & 0xffffffff, (int) stub_type); } @@ -3378,7 +3820,9 @@ elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section, asection *stub_sec; link_sec = htab->stub_group[section->id].link_sec; + BFD_ASSERT (link_sec != NULL); stub_sec = htab->stub_group[section->id].stub_sec; + if (stub_sec == NULL) { stub_sec = htab->stub_group[link_sec->id].stub_sec; @@ -3470,14 +3914,73 @@ put_thumb_insn (struct elf32_arm_link_hash_table * htab, bfd_putb16 (val, ptr); } +/* If it's possible to change R_TYPE to a more efficient access + model, return the new reloc type. */ + +static unsigned +elf32_arm_tls_transition (struct bfd_link_info *info, int r_type, + struct elf_link_hash_entry *h) +{ + int is_local = (h == NULL); + + if (info->shared || (h && h->root.type == bfd_link_hash_undefweak)) + return r_type; + + /* We do not support relaxations for Old TLS models. */ + switch (r_type) + { + 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: + return is_local ? R_ARM_TLS_LE32 : R_ARM_TLS_IE32; + } + + return r_type; +} + static bfd_reloc_status_type elf32_arm_final_link_relocate (reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *, - const char *, int, struct elf_link_hash_entry *, bfd_boolean *, char **); + const char *, unsigned char, enum arm_st_branch_type, + struct elf_link_hash_entry *, bfd_boolean *, char **); -static bfd_boolean -arm_build_one_stub (struct bfd_hash_entry *gen_entry, - void * in_arg) +static unsigned int +arm_stub_required_alignment (enum elf32_arm_stub_type stub_type) +{ + switch (stub_type) + { + case arm_stub_a8_veneer_b_cond: + case arm_stub_a8_veneer_b: + case arm_stub_a8_veneer_bl: + return 2; + + case arm_stub_long_branch_any_any: + case arm_stub_long_branch_v4t_arm_thumb: + case arm_stub_long_branch_thumb_only: + case arm_stub_long_branch_v4t_thumb_thumb: + case arm_stub_long_branch_v4t_thumb_arm: + case arm_stub_short_branch_v4t_thumb_arm: + case arm_stub_long_branch_any_arm_pic: + case arm_stub_long_branch_any_thumb_pic: + case arm_stub_long_branch_v4t_thumb_thumb_pic: + case arm_stub_long_branch_v4t_arm_thumb_pic: + case arm_stub_long_branch_v4t_thumb_arm_pic: + case arm_stub_long_branch_thumb_only_pic: + case arm_stub_long_branch_any_tls_pic: + case arm_stub_long_branch_v4t_thumb_tls_pic: + case arm_stub_a8_veneer_blx: + return 4; + + default: + abort (); /* Should be unreachable. */ + } +} + +static bfd_boolean +arm_build_one_stub (struct bfd_hash_entry *gen_entry, + void * in_arg) { #define MAXRELOCS 2 struct elf32_arm_stub_hash_entry *stub_entry; @@ -3485,7 +3988,6 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, struct bfd_link_info *info; asection *stub_sec; bfd *stub_bfd; - bfd_vma stub_addr; bfd_byte *loc; bfd_vma sym_value; int template_size; @@ -3507,9 +4009,8 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, stub_sec = stub_entry->stub_sec; if ((globals->fix_cortex_a8 < 0) - != (stub_entry->stub_type >= arm_stub_a8_veneer_lwm)) - /* We have to do the a8 fixes last, as they are less aligned than - the other veneers. */ + != (arm_stub_required_alignment (stub_entry->stub_type) == 2)) + /* We have to do less-strictly-aligned fixes last. */ return TRUE; /* Make a note of the offset within the stubs for this entry. */ @@ -3518,10 +4019,6 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, stub_bfd = stub_sec->owner; - /* This is the address of the start of the stub. */ - stub_addr = stub_sec->output_section->vma + stub_sec->output_offset - + stub_entry->stub_offset; - /* This is the address of the stub destination. */ sym_value = (stub_entry->target_value + stub_entry->target_section->output_offset @@ -3598,7 +4095,7 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, BFD_ASSERT (size == stub_entry->stub_size); /* Destination is Thumb. Force bit 0 to 1 to reflect this. */ - if (stub_entry->st_type == STT_ARM_TFUNC) + if (stub_entry->branch_type == ST_BRANCH_TO_THUMB) sym_value |= 1; /* Assume there is at least one and at most MAXRELOCS entries to relocate @@ -3614,9 +4111,9 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, Elf_Internal_Rela rel; bfd_boolean unresolved_reloc; char *error_message; - int sym_flags - = (template_sequence[stub_reloc_idx[i]].r_type != R_ARM_THM_XPC22) - ? STT_ARM_TFUNC : 0; + enum arm_st_branch_type branch_type + = (template_sequence[stub_reloc_idx[i]].r_type != R_ARM_THM_XPC22 + ? ST_BRANCH_TO_THUMB : ST_BRANCH_TO_ARM); bfd_vma points_to = sym_value + stub_entry->target_addend; rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i]; @@ -3640,9 +4137,9 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, elf32_arm_final_link_relocate (elf32_arm_howto_from_type (template_sequence[stub_reloc_idx[i]].r_type), stub_bfd, info->output_bfd, stub_sec, stub_sec->contents, &rel, - points_to, info, stub_entry->target_section, "", sym_flags, - (struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc, - &error_message); + points_to, info, stub_entry->target_section, "", STT_FUNC, + branch_type, (struct elf_link_hash_entry *) stub_entry->h, + &unresolved_reloc, &error_message); } else { @@ -3660,7 +4157,8 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, elf32_arm_final_link_relocate (elf32_arm_howto_from_type (template_sequence[stub_reloc_idx[i]].r_type), stub_bfd, info->output_bfd, stub_sec, stub_sec->contents, &rel, - points_to, info, stub_entry->target_section, "", stub_entry->st_type, + points_to, info, stub_entry->target_section, "", STT_FUNC, + stub_entry->branch_type, (struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc, &error_message); } @@ -3682,7 +4180,12 @@ find_stub_size_and_template (enum elf32_arm_stub_type stub_type, unsigned int size; template_sequence = stub_definitions[stub_type].template_sequence; + if (stub_template) + *stub_template = template_sequence; + template_size = stub_definitions[stub_type].template_size; + if (stub_template_size) + *stub_template_size = template_size; size = 0; for (i = 0; i < template_size; i++) @@ -3701,16 +4204,10 @@ find_stub_size_and_template (enum elf32_arm_stub_type stub_type, default: BFD_FAIL (); - return FALSE; + return 0; } } - if (stub_template) - *stub_template = template_sequence; - - if (stub_template_size) - *stub_template_size = template_size; - return size; } @@ -3719,16 +4216,14 @@ find_stub_size_and_template (enum elf32_arm_stub_type stub_type, static bfd_boolean arm_size_one_stub (struct bfd_hash_entry *gen_entry, - void * in_arg) + void *in_arg ATTRIBUTE_UNUSED) { struct elf32_arm_stub_hash_entry *stub_entry; - struct elf32_arm_link_hash_table *htab; const insn_sequence *template_sequence; int template_size, size; /* Massage our args to the form they really have. */ stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; - htab = (struct elf32_arm_link_hash_table *) in_arg; BFD_ASSERT((stub_entry->stub_type > arm_stub_none) && stub_entry->stub_type < ARRAY_SIZE(stub_definitions)); @@ -4091,6 +4586,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, bfd_vma target; enum elf32_arm_stub_type stub_type = arm_stub_none; struct a8_erratum_reloc key, *found; + bfd_boolean use_plt = FALSE; key.from = base_vma + i; found = (struct a8_erratum_reloc *) @@ -4102,7 +4598,6 @@ cortex_a8_erratum_scan (bfd *input_bfd, { char *error_message = NULL; struct elf_link_hash_entry *entry; - bfd_boolean use_plt = FALSE; /* We don't care about the error returned from this function, only if there is glue or not. */ @@ -4113,13 +4608,14 @@ cortex_a8_erratum_scan (bfd *input_bfd, found->non_a8_stub = TRUE; /* Keep a simpler condition, for the sake of clarity. */ - if (htab->splt != NULL && found->hash != NULL + if (htab->root.splt != NULL && found->hash != NULL && found->hash->root.plt.offset != (bfd_vma) -1) use_plt = TRUE; if (found->r_type == R_ARM_THM_CALL) { - if (found->st_type != STT_ARM_TFUNC || use_plt) + if (found->branch_type == ST_BRANCH_TO_ARM + || use_plt) force_target_arm = TRUE; else force_target_thumb = TRUE; @@ -4205,6 +4701,12 @@ cortex_a8_erratum_scan (bfd *input_bfd, offset = (bfd_signed_vma) (found->destination - pc_for_insn); + /* If the stub will use a Thumb-mode branch to a + PLT target, redirect it to the preceding Thumb + entry point. */ + if (stub_type != arm_stub_a8_veneer_blx && use_plt) + offset -= PLT_THUMB_STUB_SIZE; + target = pc_for_insn + offset; /* The BLX stub is ARM-mode code. Adjust the offset to @@ -4256,8 +4758,8 @@ cortex_a8_erratum_scan (bfd *input_bfd, a8_fixes[num_a8_fixes].orig_insn = insn; a8_fixes[num_a8_fixes].stub_name = stub_name; a8_fixes[num_a8_fixes].stub_type = stub_type; - a8_fixes[num_a8_fixes].st_type = - is_blx ? STT_FUNC : STT_ARM_TFUNC; + a8_fixes[num_a8_fixes].branch_type = + is_blx ? ST_BRANCH_TO_ARM : ST_BRANCH_TO_THUMB; num_a8_fixes++; } @@ -4428,7 +4930,8 @@ elf32_arm_size_stubs (bfd *output_bfd, const char *sym_name; char *stub_name; const asection *id_sec; - int st_type; + unsigned char st_type; + enum arm_st_branch_type branch_type; bfd_boolean created_stub = FALSE; r_type = ELF32_R_TYPE (irela->r_info); @@ -4442,15 +4945,30 @@ elf32_arm_size_stubs (bfd *output_bfd, free (internal_relocs); goto error_ret_free_local; } - - /* Only look for stubs on branch instructions. */ + + 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) && (r_type != (unsigned int) R_ARM_THM_CALL) && (r_type != (unsigned int) R_ARM_JUMP24) && (r_type != (unsigned int) R_ARM_THM_JUMP19) && (r_type != (unsigned int) R_ARM_THM_XPC22) && (r_type != (unsigned int) R_ARM_THM_JUMP24) - && (r_type != (unsigned int) R_ARM_PLT32)) + && (r_type != (unsigned int) R_ARM_PLT32) + && !((r_type == (unsigned int) R_ARM_TLS_CALL + || r_type == (unsigned int) R_ARM_THM_TLS_CALL) + && r_type == elf32_arm_tls_transition + (info, r_type, &hash->root) + && ((hash ? hash->tls_type + : (elf32_arm_local_got_tls_type + (input_bfd)[r_indx])) + & GOT_TLS_GDESC) != 0)) continue; /* Now determine the call target, its name, value, @@ -4458,13 +4976,25 @@ elf32_arm_size_stubs (bfd *output_bfd, sym_sec = NULL; sym_value = 0; destination = 0; - hash = NULL; sym_name = NULL; - if (r_indx < symtab_hdr->sh_info) + + if (r_type == (unsigned int) R_ARM_TLS_CALL + || r_type == (unsigned int) R_ARM_THM_TLS_CALL) + { + /* A non-relaxed TLS call. The target is the + plt-resident trampoline and nothing to do + with the symbol. */ + BFD_ASSERT (htab->tls_trampoline > 0); + sym_sec = htab->root.splt; + sym_value = htab->tls_trampoline; + hash = 0; + st_type = STT_FUNC; + branch_type = ST_BRANCH_TO_ARM; + } + else if (!hash) { /* It's a local symbol. */ Elf_Internal_Sym *sym; - Elf_Internal_Shdr *hdr; if (local_syms == NULL) { @@ -4480,8 +5010,16 @@ elf32_arm_size_stubs (bfd *output_bfd, } sym = local_syms + r_indx; - hdr = elf_elfsections (input_bfd)[sym->st_shndx]; - sym_sec = hdr->bfd_section; + if (sym->st_shndx == SHN_UNDEF) + sym_sec = bfd_und_section_ptr; + else if (sym->st_shndx == SHN_ABS) + sym_sec = bfd_abs_section_ptr; + else if (sym->st_shndx == SHN_COMMON) + sym_sec = bfd_com_section_ptr; + else + sym_sec = + bfd_section_from_elf_index (input_bfd, sym->st_shndx); + if (!sym_sec) /* This is an undefined symbol. It can never be resolved. */ @@ -4493,6 +5031,7 @@ elf32_arm_size_stubs (bfd *output_bfd, + sym_sec->output_offset + sym_sec->output_section->vma); st_type = ELF_ST_TYPE (sym->st_info); + branch_type = ARM_SYM_BRANCH_TYPE (sym); sym_name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, @@ -4501,12 +5040,6 @@ elf32_arm_size_stubs (bfd *output_bfd, else { /* It's an external symbol. */ - int e_indx; - - e_indx = r_indx - symtab_hdr->sh_info; - hash = ((struct elf32_arm_link_hash_entry *) - elf_sym_hashes (input_bfd)[e_indx]); - while (hash->root.root.type == bfd_link_hash_indirect || hash->root.root.type == bfd_link_hash_warning) hash = ((struct elf32_arm_link_hash_entry *) @@ -4526,11 +5059,11 @@ elf32_arm_size_stubs (bfd *output_bfd, decide whether a branch stub is needed. */ if (globals != NULL - && globals->splt != NULL + && globals->root.splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1) { - sym_sec = globals->splt; + sym_sec = globals->root.splt; sym_value = hash->root.plt.offset; if (sym_sec->output_section != NULL) destination = (sym_value @@ -4553,11 +5086,11 @@ elf32_arm_size_stubs (bfd *output_bfd, elf32_arm_hash_table (info); if (globals != NULL - && globals->splt != NULL + && globals->root.splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1) { - sym_sec = globals->splt; + sym_sec = globals->root.splt; sym_value = hash->root.plt.offset; if (sym_sec->output_section != NULL) destination = (sym_value @@ -4572,7 +5105,8 @@ elf32_arm_size_stubs (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); goto error_ret_free_internal; } - st_type = ELF_ST_TYPE (hash->root.type); + st_type = hash->root.type; + branch_type = hash->root.target_internal; sym_name = hash->root.root.root.string; } @@ -4580,8 +5114,8 @@ elf32_arm_size_stubs (bfd *output_bfd, { /* Determine what (if any) linker stub is needed. */ stub_type = arm_type_of_stub (info, section, irela, - &st_type, hash, - destination, sym_sec, + st_type, &branch_type, + hash, destination, sym_sec, input_bfd, sym_name); if (stub_type == arm_stub_none) break; @@ -4622,7 +5156,7 @@ elf32_arm_size_stubs (bfd *output_bfd, stub_entry->target_section = sym_sec; stub_entry->stub_type = stub_type; stub_entry->h = hash; - stub_entry->st_type = st_type; + stub_entry->branch_type = branch_type; if (sym_name == NULL) sym_name = "unnamed"; @@ -4638,14 +5172,14 @@ elf32_arm_size_stubs (bfd *output_bfd, /* For historical reasons, use the existing names for ARM-to-Thumb and Thumb-to-ARM stubs. */ - if ( ((r_type == (unsigned int) R_ARM_THM_CALL) - || (r_type == (unsigned int) R_ARM_THM_JUMP24)) - && st_type != STT_ARM_TFUNC) + if ((r_type == (unsigned int) R_ARM_THM_CALL + || r_type == (unsigned int) R_ARM_THM_JUMP24) + && branch_type == ST_BRANCH_TO_ARM) sprintf (stub_entry->output_name, THUMB2ARM_GLUE_ENTRY_NAME, sym_name); - else if ( ((r_type == (unsigned int) R_ARM_CALL) - || (r_type == (unsigned int) R_ARM_JUMP24)) - && st_type == STT_ARM_TFUNC) + else if ((r_type == (unsigned int) R_ARM_CALL + || r_type == (unsigned int) R_ARM_JUMP24) + && branch_type == ST_BRANCH_TO_THUMB) sprintf (stub_entry->output_name, ARM2THUMB_GLUE_ENTRY_NAME, sym_name); else @@ -4687,7 +5221,7 @@ elf32_arm_size_stubs (bfd *output_bfd, a8_relocs[num_a8_relocs].from = from; a8_relocs[num_a8_relocs].destination = destination; a8_relocs[num_a8_relocs].r_type = r_type; - a8_relocs[num_a8_relocs].st_type = st_type; + a8_relocs[num_a8_relocs].branch_type = branch_type; a8_relocs[num_a8_relocs].sym_name = sym_name; a8_relocs[num_a8_relocs].non_a8_stub = created_stub; a8_relocs[num_a8_relocs].hash = hash; @@ -4792,7 +5326,7 @@ elf32_arm_size_stubs (bfd *output_bfd, stub_entry->target_value = a8_fixes[i].offset; stub_entry->target_addend = a8_fixes[i].addend; stub_entry->orig_insn = a8_fixes[i].orig_insn; - stub_entry->st_type = a8_fixes[i].st_type; + stub_entry->branch_type = a8_fixes[i].branch_type; size = find_stub_size_and_template (a8_fixes[i].stub_type, &template_sequence, @@ -5244,7 +5778,6 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info, struct bfd_link_hash_entry *bh; bfd_vma val; struct _arm_elf_section_data *sec_data; - int errcount; elf32_vfp11_erratum_list *newerr; hash_table = elf32_arm_hash_table (link_info); @@ -5282,7 +5815,7 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info, myh->forced_local = 1; /* Link veneer back to calling location. */ - errcount = ++(sec_data->erratumcount); + sec_data->erratumcount += 1; newerr = (elf32_vfp11_erratum_list *) bfd_zmalloc (sizeof (elf32_vfp11_erratum_list)); @@ -5426,9 +5959,21 @@ bfd_elf32_arm_get_bfd_for_interworking (bfd *abfd, struct bfd_link_info *info) static void check_use_blx (struct elf32_arm_link_hash_table *globals) { - if (bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, - Tag_CPU_arch) > 2) - globals->use_blx = 1; + int cpu_arch; + + cpu_arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, + Tag_CPU_arch); + + if (globals->fix_arm1176) + { + if (cpu_arch == TAG_CPU_ARCH_V6T2 || cpu_arch > TAG_CPU_ARCH_V6K) + globals->use_blx = 1; + } + else + { + if (cpu_arch > TAG_CPU_ARCH_V4T) + globals->use_blx = 1; + } } bfd_boolean @@ -5549,7 +6094,7 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd, /* If the call will go through a PLT entry then we do not need glue. */ - if (globals->splt != NULL && h->plt.offset != (bfd_vma) -1) + if (globals->root.splt != NULL && h->plt.offset != (bfd_vma) -1) continue; switch (r_type) @@ -5558,7 +6103,7 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd, /* This one is a call from arm code. We need to look up the target of the call. If it is a thumb target, we insert glue. */ - if (ELF_ST_TYPE (h->type) == STT_ARM_TFUNC) + if (h->target_internal == ST_BRANCH_TO_THUMB) record_arm_to_thumb_glue (link_info, h); break; @@ -6138,9 +6683,8 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info) { elf32_vfp11_erratum_list *newerr =(elf32_vfp11_erratum_list *) bfd_zmalloc (sizeof (elf32_vfp11_erratum_list)); - int errcount; - errcount = ++(elf32_arm_section_data (sec)->erratumcount); + elf32_arm_section_data (sec)->erratumcount += 1; newerr->u.b.vfp_insn = veneer_of_insn; @@ -6283,7 +6827,8 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd, int use_blx, bfd_arm_vfp11_fix vfp11_fix, int no_enum_warn, int no_wchar_warn, - int pic_veneer, int fix_cortex_a8) + int pic_veneer, int fix_cortex_a8, + int fix_arm1176) { struct elf32_arm_link_hash_table *globals; @@ -6308,6 +6853,7 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd, globals->vfp11_fix = vfp11_fix; globals->pic_veneer = pic_veneer; globals->fix_cortex_a8 = fix_cortex_a8; + globals->fix_arm1176 = fix_arm1176; BFD_ASSERT (is_arm_elf (output_bfd)); elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn; @@ -6385,7 +6931,7 @@ elf32_thumb_to_arm_stub (struct bfd_link_info * info, { (*_bfd_error_handler) (_("%B(%s): warning: interworking not enabled.\n" - " first occurrence: %B: thumb call to arm"), + " first occurrence: %B: Thumb call to ARM"), sym_sec->owner, input_bfd, name); return FALSE; @@ -6695,6 +7241,339 @@ elf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED, link_info); } +/* Reserve space for COUNT dynamic relocations in relocation selection + SRELOC. */ + +static void +elf32_arm_allocate_dynrelocs (struct bfd_link_info *info, asection *sreloc, + bfd_size_type count) +{ + struct elf32_arm_link_hash_table *htab; + + htab = elf32_arm_hash_table (info); + BFD_ASSERT (htab->root.dynamic_sections_created); + if (sreloc == NULL) + abort (); + sreloc->size += RELOC_SIZE (htab) * count; +} + +/* Reserve space for COUNT R_ARM_IRELATIVE relocations. If the link is + dynamic, the relocations should go in SRELOC, otherwise they should + go in the special .rel.iplt section. */ + +static void +elf32_arm_allocate_irelocs (struct bfd_link_info *info, asection *sreloc, + bfd_size_type count) +{ + struct elf32_arm_link_hash_table *htab; + + htab = elf32_arm_hash_table (info); + if (!htab->root.dynamic_sections_created) + htab->root.irelplt->size += RELOC_SIZE (htab) * count; + else + { + BFD_ASSERT (sreloc != NULL); + sreloc->size += RELOC_SIZE (htab) * count; + } +} + +/* Add relocation REL to the end of relocation section SRELOC. */ + +static void +elf32_arm_add_dynreloc (bfd *output_bfd, struct bfd_link_info *info, + asection *sreloc, Elf_Internal_Rela *rel) +{ + bfd_byte *loc; + struct elf32_arm_link_hash_table *htab; + + htab = elf32_arm_hash_table (info); + if (!htab->root.dynamic_sections_created + && ELF32_R_TYPE (rel->r_info) == R_ARM_IRELATIVE) + sreloc = htab->root.irelplt; + if (sreloc == NULL) + abort (); + loc = sreloc->contents; + loc += sreloc->reloc_count++ * RELOC_SIZE (htab); + if (sreloc->reloc_count * RELOC_SIZE (htab) > sreloc->size) + abort (); + SWAP_RELOC_OUT (htab) (output_bfd, rel, loc); +} + +/* Allocate room for a PLT entry described by ROOT_PLT and ARM_PLT. + IS_IPLT_ENTRY says whether the entry belongs to .iplt rather than + to .plt. */ + +static void +elf32_arm_allocate_plt_entry (struct bfd_link_info *info, + bfd_boolean is_iplt_entry, + union gotplt_union *root_plt, + struct arm_plt_info *arm_plt) +{ + struct elf32_arm_link_hash_table *htab; + asection *splt; + asection *sgotplt; + + htab = elf32_arm_hash_table (info); + + if (is_iplt_entry) + { + splt = htab->root.iplt; + sgotplt = htab->root.igotplt; + + /* Allocate room for an R_ARM_IRELATIVE relocation in .rel.iplt. */ + elf32_arm_allocate_irelocs (info, htab->root.irelplt, 1); + } + else + { + splt = htab->root.splt; + sgotplt = htab->root.sgotplt; + + /* Allocate room for an R_JUMP_SLOT relocation in .rel.plt. */ + elf32_arm_allocate_dynrelocs (info, htab->root.srelplt, 1); + + /* If this is the first .plt entry, make room for the special + first entry. */ + if (splt->size == 0) + splt->size += htab->plt_header_size; + } + + /* Allocate the PLT entry itself, including any leading Thumb stub. */ + if (elf32_arm_plt_needs_thumb_stub_p (info, arm_plt)) + splt->size += PLT_THUMB_STUB_SIZE; + root_plt->offset = splt->size; + splt->size += htab->plt_entry_size; + + if (!htab->symbian_p) + { + /* We also need to make an entry in the .got.plt section, which + will be placed in the .got section by the linker script. */ + arm_plt->got_offset = sgotplt->size - 8 * htab->num_tls_desc; + sgotplt->size += 4; + } +} + +/* 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 + symbol table and SYM_VALUE is undefined. + + ROOT_PLT points to the offset of the PLT entry from the start of its + section (.iplt or .plt). ARM_PLT points to the symbol's ARM-specific + bookkeeping information. */ + +static void +elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info, + union gotplt_union *root_plt, + struct arm_plt_info *arm_plt, + int dynindx, bfd_vma sym_value) +{ + struct elf32_arm_link_hash_table *htab; + asection *sgot; + asection *splt; + asection *srel; + bfd_byte *loc; + bfd_vma plt_index; + Elf_Internal_Rela rel; + bfd_vma plt_header_size; + bfd_vma got_header_size; + + htab = elf32_arm_hash_table (info); + + /* Pick the appropriate sections and sizes. */ + if (dynindx == -1) + { + splt = htab->root.iplt; + sgot = htab->root.igotplt; + srel = htab->root.irelplt; + + /* There are no reserved entries in .igot.plt, and no special + first entry in .iplt. */ + got_header_size = 0; + plt_header_size = 0; + } + else + { + splt = htab->root.splt; + sgot = htab->root.sgotplt; + srel = htab->root.srelplt; + + got_header_size = get_elf_backend_data (output_bfd)->got_header_size; + plt_header_size = htab->plt_header_size; + } + BFD_ASSERT (splt != NULL && srel != NULL); + + /* Fill in the entry in the procedure linkage table. */ + if (htab->symbian_p) + { + BFD_ASSERT (dynindx >= 0); + put_arm_insn (htab, output_bfd, + elf32_arm_symbian_plt_entry[0], + splt->contents + root_plt->offset); + bfd_put_32 (output_bfd, + elf32_arm_symbian_plt_entry[1], + splt->contents + root_plt->offset + 4); + + /* Fill in the entry in the .rel.plt section. */ + rel.r_offset = (splt->output_section->vma + + splt->output_offset + + root_plt->offset + 4); + rel.r_info = ELF32_R_INFO (dynindx, R_ARM_GLOB_DAT); + + /* Get the index in the procedure linkage table which + corresponds to this symbol. This is the index of this symbol + in all the symbols for which we are making plt entries. The + first entry in the procedure linkage table is reserved. */ + plt_index = ((root_plt->offset - plt_header_size) + / htab->plt_entry_size); + } + else + { + bfd_vma got_offset, got_address, plt_address; + bfd_vma got_displacement, initial_got_entry; + bfd_byte * ptr; + + BFD_ASSERT (sgot != NULL); + + /* Get the offset into the .(i)got.plt table of the entry that + corresponds to this function. */ + got_offset = (arm_plt->got_offset & -2); + + /* Get the index in the procedure linkage table which + corresponds to this symbol. This is the index of this symbol + in all the symbols for which we are making plt entries. + After the reserved .got.plt entries, all symbols appear in + the same order as in .plt. */ + plt_index = (got_offset - got_header_size) / 4; + + /* Calculate the address of the GOT entry. */ + got_address = (sgot->output_section->vma + + sgot->output_offset + + got_offset); + + /* ...and the address of the PLT entry. */ + plt_address = (splt->output_section->vma + + splt->output_offset + + root_plt->offset); + + ptr = splt->contents + root_plt->offset; + if (htab->vxworks_p && info->shared) + { + unsigned int i; + bfd_vma val; + + for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4) + { + val = elf32_arm_vxworks_shared_plt_entry[i]; + if (i == 2) + val |= got_address - sgot->output_section->vma; + if (i == 5) + val |= plt_index * RELOC_SIZE (htab); + if (i == 2 || i == 5) + bfd_put_32 (output_bfd, val, ptr); + else + put_arm_insn (htab, output_bfd, val, ptr); + } + } + else if (htab->vxworks_p) + { + unsigned int i; + bfd_vma val; + + for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4) + { + val = elf32_arm_vxworks_exec_plt_entry[i]; + if (i == 2) + val |= got_address; + if (i == 4) + val |= 0xffffff & -((root_plt->offset + i * 4 + 8) >> 2); + if (i == 5) + val |= plt_index * RELOC_SIZE (htab); + if (i == 2 || i == 5) + bfd_put_32 (output_bfd, val, ptr); + else + put_arm_insn (htab, output_bfd, val, ptr); + } + + loc = (htab->srelplt2->contents + + (plt_index * 2 + 1) * RELOC_SIZE (htab)); + + /* Create the .rela.plt.unloaded R_ARM_ABS32 relocation + referencing the GOT for this PLT entry. */ + rel.r_offset = plt_address + 8; + rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32); + rel.r_addend = got_offset; + SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); + loc += RELOC_SIZE (htab); + + /* Create the R_ARM_ABS32 relocation referencing the + beginning of the PLT for this GOT entry. */ + rel.r_offset = got_address; + rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_ARM_ABS32); + rel.r_addend = 0; + SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); + } + else + { + /* Calculate the displacement between the PLT slot and the + entry in the GOT. The eight-byte offset accounts for the + value produced by adding to pc in the first instruction + of the PLT stub. */ + got_displacement = got_address - (plt_address + 8); + + BFD_ASSERT ((got_displacement & 0xf0000000) == 0); + + if (elf32_arm_plt_needs_thumb_stub_p (info, arm_plt)) + { + put_thumb_insn (htab, output_bfd, + elf32_arm_plt_thumb_stub[0], ptr - 4); + put_thumb_insn (htab, output_bfd, + elf32_arm_plt_thumb_stub[1], ptr - 2); + } + + put_arm_insn (htab, output_bfd, + elf32_arm_plt_entry[0] + | ((got_displacement & 0x0ff00000) >> 20), + ptr + 0); + put_arm_insn (htab, output_bfd, + elf32_arm_plt_entry[1] + | ((got_displacement & 0x000ff000) >> 12), + ptr+ 4); + put_arm_insn (htab, output_bfd, + elf32_arm_plt_entry[2] + | (got_displacement & 0x00000fff), + ptr + 8); +#ifdef FOUR_WORD_PLT + bfd_put_32 (output_bfd, elf32_arm_plt_entry[3], ptr + 12); +#endif + } + + /* Fill in the entry in the .rel(a).(i)plt section. */ + rel.r_offset = got_address; + rel.r_addend = 0; + if (dynindx == -1) + { + /* .igot.plt entries use IRELATIVE relocations against SYM_VALUE. + The dynamic linker or static executable then calls SYM_VALUE + to determine the correct run-time value of the .igot.plt entry. */ + rel.r_info = ELF32_R_INFO (0, R_ARM_IRELATIVE); + initial_got_entry = sym_value; + } + else + { + rel.r_info = ELF32_R_INFO (dynindx, R_ARM_JUMP_SLOT); + initial_got_entry = (splt->output_section->vma + + splt->output_offset); + } + + /* Fill in the entry in the global offset table. */ + bfd_put_32 (output_bfd, initial_got_entry, + sgot->contents + got_offset); + } + + loc = srel->contents + plt_index * RELOC_SIZE (htab); + SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); +} + /* Some relocations map to different relocations depending on the target. Return the real relocation. */ @@ -6761,6 +7640,151 @@ elf32_arm_abs12_reloc (bfd *abfd, void *data, bfd_vma value) return bfd_reloc_ok; } +/* Handle TLS relaxations. Relaxing is possible for symbols that use + R_ARM_GOTDESC, R_ARM_{,THM_}TLS_CALL or + R_ARM_{,THM_}TLS_DESCSEQ relocations, during a static link. + + Return bfd_reloc_ok if we're done, bfd_reloc_continue if the caller + is to then call final_link_relocate. Return other values in the + case of error. + + FIXME:When --emit-relocs is in effect, we'll emit relocs describing + the pre-relaxed code. It would be nice if the relocs were updated + to match the optimization. */ + +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, + 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; + else + { + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + if (insn & 1) + insn -= 5; /* THUMB */ + else + insn -= 8; /* ARM */ + } + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); + return bfd_reloc_continue; + + case R_ARM_THM_TLS_DESCSEQ: + /* Thumb insn. */ + insn = bfd_get_16 (input_bfd, contents + rel->r_offset); + if ((insn & 0xff78) == 0x4478) /* add rx, pc */ + { + if (is_local) + /* nop */ + bfd_put_16 (input_bfd, 0x46c0, contents + rel->r_offset); + } + else if ((insn & 0xffc0) == 0x6840) /* ldr rx,[ry,#4] */ + { + if (is_local) + /* nop */ + bfd_put_16 (input_bfd, 0x46c0, contents + rel->r_offset); + else + /* ldr rx,[ry] */ + bfd_put_16 (input_bfd, insn & 0xf83f, contents + rel->r_offset); + } + else if ((insn & 0xff87) == 0x4780) /* blx rx */ + { + if (is_local) + /* nop */ + bfd_put_16 (input_bfd, 0x46c0, contents + rel->r_offset); + else + /* mov r0, rx */ + bfd_put_16 (input_bfd, 0x4600 | (insn & 0x78), + contents + rel->r_offset); + } + else + { + if ((insn & 0xf000) == 0xf000 || (insn & 0xf800) == 0xe800) + /* It's a 32 bit instruction, fetch the rest of it for + error generation. */ + insn = (insn << 16) + | bfd_get_16 (input_bfd, contents + rel->r_offset + 2); + (*_bfd_error_handler) + (_("%B(%A+0x%lx):unexpected Thumb instruction '0x%x' in TLS trampoline"), + input_bfd, input_sec, (unsigned long)rel->r_offset, insn); + return bfd_reloc_notsupported; + } + break; + + case R_ARM_TLS_DESCSEQ: + /* arm insn. */ + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + if ((insn & 0xffff0ff0) == 0xe08f0000) /* add rx,pc,ry */ + { + if (is_local) + /* mov rx, ry */ + bfd_put_32 (input_bfd, 0xe1a00000 | (insn & 0xffff), + contents + rel->r_offset); + } + else if ((insn & 0xfff00fff) == 0xe5900004) /* ldr rx,[ry,#4]*/ + { + if (is_local) + /* nop */ + bfd_put_32 (input_bfd, 0xe1a00000, contents + rel->r_offset); + else + /* ldr rx,[ry] */ + bfd_put_32 (input_bfd, insn & 0xfffff000, + contents + rel->r_offset); + } + else if ((insn & 0xfffffff0) == 0xe12fff30) /* blx rx */ + { + if (is_local) + /* nop */ + bfd_put_32 (input_bfd, 0xe1a00000, contents + rel->r_offset); + else + /* mov r0, rx */ + bfd_put_32 (input_bfd, 0xe1a00000 | (insn & 0xf), + contents + rel->r_offset); + } + else + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx):unexpected ARM instruction '0x%x' in TLS trampoline"), + input_bfd, input_sec, (unsigned long)rel->r_offset, insn); + return bfd_reloc_notsupported; + } + break; + + case R_ARM_TLS_CALL: + /* GD->IE relaxation, turn the instruction into 'nop' or + 'ldr r0, [pc,r0]' */ + 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) + /* add r0,pc; ldr r0, [r0] */ + insn = 0x44786800; + else if (arch_has_thumb2_nop (globals)) + /* nop.w */ + insn = 0xf3af8000; + 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; + } + return bfd_reloc_ok; +} + /* For a given value of n, calculate the value of G_n as required to deal with group relocations. We return it in the form of an encoded constant-and-rotation, together with the final residual. If n is @@ -6843,7 +7867,8 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, struct bfd_link_info * info, asection * sym_sec, const char * sym_name, - int sym_flags, + unsigned char st_type, + enum arm_st_branch_type branch_type, struct elf_link_hash_entry * h, bfd_boolean * unresolved_reloc_p, char ** error_message) @@ -6851,16 +7876,23 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, unsigned long r_type = howto->type; unsigned long r_symndx; bfd_byte * hit_data = contents + rel->r_offset; - bfd * dynobj = NULL; - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; bfd_vma * local_got_offsets; - asection * sgot = NULL; - asection * splt = NULL; + bfd_vma * local_tlsdesc_gotents; + asection * sgot; + asection * splt; asection * sreloc = NULL; + asection * srelgot; bfd_vma addend; bfd_signed_vma signed_addend; + unsigned char dynreloc_st_type; + bfd_vma dynreloc_value; struct elf32_arm_link_hash_table * globals; + struct elf32_arm_link_hash_entry *eh; + union gotplt_union *root_plt; + struct arm_plt_info *arm_plt; + bfd_vma plt_offset; + bfd_vma gotplt_offset; + bfd_boolean has_iplt_entry; globals = elf32_arm_hash_table (info); if (globals == NULL) @@ -6871,6 +7903,11 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, /* Some relocation types map to different relocations depending on the target. We pick the right one here. */ r_type = arm_real_reloc_type (globals, r_type); + + /* It is possible to have linker relaxations on some TLS access + models. Update our information here. */ + r_type = elf32_arm_tls_transition (info, r_type, h); + if (r_type != howto->type) howto = elf32_arm_howto_from_type (r_type); @@ -6886,15 +7923,16 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, if (bfd_get_start_address (output_bfd) != 0) elf_elfheader (output_bfd)->e_flags |= EF_ARM_HASENTRY; - dynobj = elf_hash_table (info)->dynobj; - if (dynobj) - { - sgot = bfd_get_section_by_name (dynobj, ".got"); - splt = bfd_get_section_by_name (dynobj, ".plt"); - } - symtab_hdr = & elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); + eh = (struct elf32_arm_link_hash_entry *) h; + sgot = globals->root.sgot; local_got_offsets = elf_local_got_offsets (input_bfd); + local_tlsdesc_gotents = elf32_arm_local_tlsdesc_gotent (input_bfd); + + if (globals->root.dynamic_sections_created) + srelgot = globals->root.srelgot; + else + srelgot = NULL; + r_symndx = ELF32_R_SYM (rel->r_info); if (globals->use_rel) @@ -6913,15 +7951,74 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, else addend = signed_addend = rel->r_addend; - switch (r_type) + /* Record the symbol information that should be used in dynamic + relocations. */ + dynreloc_st_type = st_type; + dynreloc_value = value; + if (branch_type == ST_BRANCH_TO_THUMB) + dynreloc_value |= 1; + + /* Find out whether the symbol has a PLT. Set ST_VALUE, BRANCH_TYPE and + VALUE appropriately for relocations that we resolve at link time. */ + has_iplt_entry = FALSE; + if (elf32_arm_get_plt_info (input_bfd, eh, r_symndx, &root_plt, &arm_plt) + && root_plt->offset != (bfd_vma) -1) { - case R_ARM_NONE: - /* We don't need to find a value for this symbol. It's just a - marker. */ - *unresolved_reloc_p = FALSE; - return bfd_reloc_ok; + plt_offset = root_plt->offset; + gotplt_offset = arm_plt->got_offset; - case R_ARM_ABS12: + if (h == NULL || eh->is_iplt) + { + has_iplt_entry = TRUE; + splt = globals->root.iplt; + + /* Populate .iplt entries here, because not all of them will + be seen by finish_dynamic_symbol. The lower bit is set if + we have already populated the entry. */ + if (plt_offset & 1) + plt_offset--; + else + { + elf32_arm_populate_plt_entry (output_bfd, info, root_plt, arm_plt, + -1, dynreloc_value); + root_plt->offset |= 1; + } + + /* Static relocations always resolve to the .iplt entry. */ + st_type = STT_FUNC; + value = (splt->output_section->vma + + splt->output_offset + + plt_offset); + branch_type = ST_BRANCH_TO_ARM; + + /* If there are non-call relocations that resolve to the .iplt + entry, then all dynamic ones must too. */ + if (arm_plt->noncall_refcount != 0) + { + dynreloc_st_type = st_type; + dynreloc_value = value; + } + } + else + /* We populate the .plt entry in finish_dynamic_symbol. */ + splt = globals->root.splt; + } + else + { + splt = NULL; + plt_offset = (bfd_vma) -1; + gotplt_offset = (bfd_vma) -1; + } + + switch (r_type) + { + case R_ARM_NONE: + /* We don't need to find a value for this symbol. It's just a + marker. */ + *unresolved_reloc_p = FALSE; + return bfd_reloc_ok; + + case R_ARM_ABS12: if (!globals->vxworks_p) return elf32_arm_abs12_reloc (input_bfd, hit_data, value + addend); @@ -6945,18 +8042,17 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, && r_type != R_ARM_CALL && r_type != R_ARM_JUMP24 && r_type != R_ARM_PLT32) - && h != NULL - && splt != NULL - && h->plt.offset != (bfd_vma) -1) + && plt_offset != (bfd_vma) -1) { - /* If we've created a .plt section, and assigned a PLT entry to - this function, it should not be known to bind locally. If - it were, we would have cleared the PLT entry. */ - BFD_ASSERT (!SYMBOL_CALLS_LOCAL (info, h)); + /* If we've created a .plt section, and assigned a PLT entry + to this function, it must either be a STT_GNU_IFUNC reference + or not be known to bind locally. In other cases, we should + have cleared the PLT entry by now. */ + BFD_ASSERT (has_iplt_entry || !SYMBOL_CALLS_LOCAL (info, h)); value = (splt->output_section->vma + splt->output_offset - + h->plt.offset); + + plt_offset); *unresolved_reloc_p = FALSE; return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, value, @@ -6984,12 +8080,11 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, && r_type != R_ARM_PLT32) { Elf_Internal_Rela outrel; - bfd_byte *loc; bfd_boolean skip, relocate; *unresolved_reloc_p = FALSE; - if (sreloc == NULL) + if (sreloc == NULL && globals->root.dynamic_sections_created) { sreloc = _bfd_elf_get_dynamic_reloc_section (input_bfd, input_section, ! globals->use_rel); @@ -7025,8 +8120,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, int symbol; /* This symbol is local, or marked to become local. */ - if (sym_flags == STT_ARM_TFUNC) - value |= 1; + BFD_ASSERT (r_type == R_ARM_ABS32 || r_type == R_ARM_ABS32_NOI); if (globals->symbian_p) { asection *osec; @@ -7066,16 +8160,21 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, relocate the text and data segments independently, so the symbol does not matter. */ symbol = 0; - outrel.r_info = ELF32_R_INFO (symbol, R_ARM_RELATIVE); + if (dynreloc_st_type == STT_GNU_IFUNC) + /* We have an STT_GNU_IFUNC symbol that doesn't resolve + to the .iplt entry. Instead, every non-call reference + must use an R_ARM_IRELATIVE relocation to obtain the + correct run-time address. */ + outrel.r_info = ELF32_R_INFO (symbol, R_ARM_IRELATIVE); + else + outrel.r_info = ELF32_R_INFO (symbol, R_ARM_RELATIVE); if (globals->use_rel) relocate = TRUE; else - outrel.r_addend += value; + outrel.r_addend += dynreloc_value; } - loc = sreloc->contents; - loc += sreloc->reloc_count++ * RELOC_SIZE (globals); - SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc); + elf32_arm_add_dynreloc (output_bfd, info, sreloc, &outrel); /* If this reloc is against an external symbol, we do not want to fiddle with the addend. Otherwise, we need to include the symbol @@ -7084,8 +8183,8 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, return bfd_reloc_ok; return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, value, - (bfd_vma) 0); + contents, rel->r_offset, + dynreloc_value, (bfd_vma) 0); } else switch (r_type) { @@ -7105,7 +8204,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, /* Check for Arm calling Arm function. */ /* FIXME: Should we translate the instruction into a BL instruction instead ? */ - if (sym_flags != STT_ARM_TFUNC) + if (branch_type != ST_BRANCH_TO_THUMB) (*_bfd_error_handler) (_("\%B: Warning: Arm BLX instruction targets Arm function '%s'."), input_bfd, @@ -7114,7 +8213,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, else if (r_type == R_ARM_PC24) { /* Check for Arm calling Thumb function. */ - if (sym_flags == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) { if (elf32_arm_to_thumb_stub (info, sym_name, input_bfd, output_bfd, input_section, @@ -7138,39 +8237,41 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, hash = (struct elf32_arm_link_hash_entry *) h; stub_type = arm_type_of_stub (info, input_section, rel, - &sym_flags, hash, - value, sym_sec, + st_type, &branch_type, + hash, value, sym_sec, input_bfd, sym_name); if (stub_type != arm_stub_none) { /* The target is out of reach, so redirect the branch to the local stub for this function. */ - stub_entry = elf32_arm_get_stub_entry (input_section, sym_sec, h, rel, globals, stub_type); - if (stub_entry != NULL) - value = (stub_entry->stub_offset - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); + { + if (stub_entry != NULL) + value = (stub_entry->stub_offset + + stub_entry->stub_sec->output_offset + + stub_entry->stub_sec->output_section->vma); + + if (plt_offset != (bfd_vma) -1) + *unresolved_reloc_p = FALSE; + } } else { /* If the call goes through a PLT entry, make sure to check distance to the right destination address. */ - if (h != NULL - && splt != NULL - && h->plt.offset != (bfd_vma) -1) + if (plt_offset != (bfd_vma) -1) { value = (splt->output_section->vma + splt->output_offset - + h->plt.offset); + + plt_offset); *unresolved_reloc_p = FALSE; /* The PLT entry is in ARM mode, regardless of the target function. */ - sym_flags = STT_FUNC; + branch_type = ST_BRANCH_TO_ARM; } } } @@ -7208,12 +8309,12 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, /* A branch to an undefined weak symbol is turned into a jump to the next instruction unless a PLT entry will be created. - Do the same for local undefined symbols. + Do the same for local undefined symbols (but not for STN_UNDEF). The jump to the next instruction is optimized as a NOP depending on the architecture. */ if (h ? (h->root.type == bfd_link_hash_undefweak - && !(splt != NULL && h->plt.offset != (bfd_vma) -1)) - : bfd_is_und_section (sym_sec)) + && plt_offset == (bfd_vma) -1) + : r_symndx != STN_UNDEF && bfd_is_und_section (sym_sec)) { value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000); @@ -7237,7 +8338,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, if (r_type == R_ARM_CALL) { /* Set the H bit in the BLX instruction. */ - if (sym_flags == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) { if (addend) value |= (1 << 24); @@ -7248,9 +8349,9 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, /* Select the correct instruction (BL or BLX). */ /* Only if we are not handling a BL to a stub. In this case, mode switching is performed by the stub. */ - if (sym_flags == STT_ARM_TFUNC && !stub_entry) + if (branch_type == ST_BRANCH_TO_THUMB && !stub_entry) value |= (1 << 28); - else + else if (stub_entry || branch_type != ST_BRANCH_UNKNOWN) { value &= ~(bfd_vma)(1 << 28); value |= (1 << 24); @@ -7262,7 +8363,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, case R_ARM_ABS32: value += addend; - if (sym_flags == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) value |= 1; break; @@ -7272,7 +8373,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, case R_ARM_REL32: value += addend; - if (sym_flags == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) value |= 1; value -= (input_section->output_section->vma + input_section->output_offset + rel->r_offset); @@ -7296,7 +8397,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, } value &= 0x7fffffff; value |= (bfd_get_32 (input_bfd, hit_data) & 0x80000000); - if (sym_flags == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) value |= 1; break; } @@ -7477,7 +8578,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, The jump to the next instruction is optimized as a NOP.W for Thumb-2 enabled architectures. */ if (h && h->root.type == bfd_link_hash_undefweak - && !(splt != NULL && h->plt.offset != (bfd_vma) -1)) + && plt_offset == (bfd_vma) -1) { if (arch_has_thumb2_nop (globals)) { @@ -7516,7 +8617,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, /* Check for Thumb to Thumb call. */ /* FIXME: Should we translate the instruction into a BL instruction instead ? */ - if (sym_flags == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) (*_bfd_error_handler) (_("%B: Warning: Thumb BLX instruction targets thumb function '%s'."), input_bfd, @@ -7528,9 +8629,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, If it is a call relative to a section name, then it is not a function call at all, but rather a long jump. Calls through the PLT do not require stubs. */ - if (sym_flags != STT_ARM_TFUNC && sym_flags != STT_SECTION - && (h == NULL || splt == NULL - || h->plt.offset == (bfd_vma) -1)) + if (branch_type == ST_BRANCH_TO_ARM && plt_offset == (bfd_vma) -1) { if (globals->use_blx && r_type == R_ARM_THM_CALL) { @@ -7549,7 +8648,8 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, return bfd_reloc_dangerous; } } - else if (sym_flags == STT_ARM_TFUNC && globals->use_blx + else if (branch_type == ST_BRANCH_TO_THUMB + && globals->use_blx && r_type == R_ARM_THM_CALL) { /* Make sure this is a BL. */ @@ -7568,7 +8668,8 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, hash = (struct elf32_arm_link_hash_entry *) h; stub_type = arm_type_of_stub (info, input_section, rel, - &sym_flags, hash, value, sym_sec, + st_type, &branch_type, + hash, value, sym_sec, input_bfd, sym_name); if (stub_type != arm_stub_none) @@ -7581,30 +8682,32 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, rel, globals, stub_type); if (stub_entry != NULL) - value = (stub_entry->stub_offset - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); + { + value = (stub_entry->stub_offset + + stub_entry->stub_sec->output_offset + + stub_entry->stub_sec->output_section->vma); + + if (plt_offset != (bfd_vma) -1) + *unresolved_reloc_p = FALSE; + } /* If this call becomes a call to Arm, force BLX. */ if (globals->use_blx && (r_type == R_ARM_THM_CALL)) { if ((stub_entry && !arm_stub_is_thumb (stub_entry->stub_type)) - || (sym_flags != STT_ARM_TFUNC)) + || branch_type != ST_BRANCH_TO_THUMB) lower_insn = (lower_insn & ~0x1000) | 0x0800; } } } /* Handle calls via the PLT. */ - if (stub_type == arm_stub_none - && h != NULL - && splt != NULL - && h->plt.offset != (bfd_vma) -1) + if (stub_type == arm_stub_none && plt_offset != (bfd_vma) -1) { value = (splt->output_section->vma + splt->output_offset - + h->plt.offset); + + plt_offset); if (globals->use_blx && r_type == R_ARM_THM_CALL) { @@ -7612,13 +8715,13 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, the BL to a BLX instruction to call the ARM-mode PLT entry. */ lower_insn = (lower_insn & ~0x1000) | 0x0800; - sym_flags = STT_FUNC; + branch_type = ST_BRANCH_TO_ARM; } else { /* Target the Thumb stub before the ARM PLT entry. */ value -= PLT_THUMB_STUB_SIZE; - sym_flags = STT_ARM_TFUNC; + branch_type = ST_BRANCH_TO_THUMB; } *unresolved_reloc_p = FALSE; } @@ -7709,11 +8812,11 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, } /* Handle calls via the PLT. */ - if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) + if (plt_offset != (bfd_vma) -1) { value = (splt->output_section->vma + splt->output_offset - + h->plt.offset); + + plt_offset); /* Target the Thumb stub before the ARM PLT entry. */ value -= PLT_THUMB_STUB_SIZE; *unresolved_reloc_p = FALSE; @@ -7846,7 +8949,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, /* If we are addressing a Thumb function, we need to adjust the address by one, so that attempts to call the function pointer will correctly interpret it as Thumb code. */ - if (sym_flags == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) value += 1; /* Note that sgot->output_offset is not involved in this @@ -7879,48 +8982,82 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, if (sgot == NULL) return bfd_reloc_notsupported; - if (h != NULL) + if (dynreloc_st_type == STT_GNU_IFUNC + && plt_offset != (bfd_vma) -1 + && (h == NULL || SYMBOL_REFERENCES_LOCAL (info, h))) + { + /* We have a relocation against a locally-binding STT_GNU_IFUNC + symbol, and the relocation resolves directly to the runtime + target rather than to the .iplt entry. This means that any + .got entry would be the same value as the .igot.plt entry, + so there's no point creating both. */ + sgot = globals->root.igotplt; + value = sgot->output_offset + gotplt_offset; + } + else if (h != NULL) { bfd_vma off; - bfd_boolean dyn; off = h->got.offset; BFD_ASSERT (off != (bfd_vma) -1); - dyn = globals->root.dynamic_sections_created; - - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) - || (info->shared - && SYMBOL_REFERENCES_LOCAL (info, h)) - || (ELF_ST_VISIBILITY (h->other) - && h->root.type == bfd_link_hash_undefweak)) + if ((off & 1) != 0) + { + /* We have already processsed one GOT relocation against + this symbol. */ + off &= ~1; + if (globals->root.dynamic_sections_created + && !SYMBOL_REFERENCES_LOCAL (info, h)) + *unresolved_reloc_p = FALSE; + } + else { - /* This is actually a static link, or it is a -Bsymbolic link - and the symbol is defined locally. We must initialize this - entry in the global offset table. Since the offset must - always be a multiple of 4, we use the least significant bit - to record whether we have initialized it already. - - When doing a dynamic link, we create a .rel(a).got relocation - entry to initialize the value. This is done in the - finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; + Elf_Internal_Rela outrel; + + if (!SYMBOL_REFERENCES_LOCAL (info, h)) + { + /* If the symbol doesn't resolve locally in a static + object, we have an undefined reference. If the + symbol doesn't resolve locally in a dynamic object, + it should be resolved by the dynamic linker. */ + if (globals->root.dynamic_sections_created) + { + outrel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT); + *unresolved_reloc_p = FALSE; + } + else + outrel.r_info = 0; + outrel.r_addend = 0; + } else { - /* If we are addressing a Thumb function, we need to - adjust the address by one, so that attempts to - call the function pointer will correctly - interpret it as Thumb code. */ - if (sym_flags == STT_ARM_TFUNC) - value |= 1; - - bfd_put_32 (output_bfd, value, sgot->contents + off); - h->got.offset |= 1; + if (dynreloc_st_type == STT_GNU_IFUNC) + outrel.r_info = ELF32_R_INFO (0, R_ARM_IRELATIVE); + else if (info->shared) + outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); + else + outrel.r_info = 0; + outrel.r_addend = dynreloc_value; } - } - else - *unresolved_reloc_p = FALSE; + /* The GOT entry is initialized to zero by default. + See if we should install a different value. */ + if (outrel.r_addend != 0 + && (outrel.r_info == 0 || globals->use_rel)) + { + bfd_put_32 (output_bfd, outrel.r_addend, + sgot->contents + off); + outrel.r_addend = 0; + } + + if (outrel.r_info != 0) + { + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + off); + elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel); + } + h->got.offset |= 1; + } value = sgot->output_offset + off; } else @@ -7939,34 +9076,22 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, off &= ~1; else { - /* If we are addressing a Thumb function, we need to - adjust the address by one, so that attempts to - call the function pointer will correctly - interpret it as Thumb code. */ - if (sym_flags == STT_ARM_TFUNC) - value |= 1; - if (globals->use_rel) - bfd_put_32 (output_bfd, value, sgot->contents + off); + bfd_put_32 (output_bfd, dynreloc_value, sgot->contents + off); - if (info->shared) + if (info->shared || dynreloc_st_type == STT_GNU_IFUNC) { - asection * srelgot; Elf_Internal_Rela outrel; - bfd_byte *loc; - srelgot = (bfd_get_section_by_name - (dynobj, RELOC_SECTION (globals, ".got"))); - BFD_ASSERT (srelgot != NULL); - - outrel.r_addend = addend + value; + outrel.r_addend = addend + dynreloc_value; outrel.r_offset = (sgot->output_section->vma + sgot->output_offset + off); - outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); - loc = srelgot->contents; - loc += srelgot->reloc_count++ * RELOC_SIZE (globals); - SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc); + if (dynreloc_st_type == STT_GNU_IFUNC) + outrel.r_info = ELF32_R_INFO (0, R_ARM_IRELATIVE); + else + outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); + elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel); } local_got_offsets[r_symndx] |= 1; @@ -7992,7 +9117,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, { bfd_vma off; - if (globals->sgot == NULL) + if (sgot == NULL) abort (); off = globals->tls_ldm_got.offset; @@ -8006,31 +9131,28 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, if (info->shared) { Elf_Internal_Rela outrel; - bfd_byte *loc; - if (globals->srelgot == NULL) + if (srelgot == NULL) abort (); outrel.r_addend = 0; - outrel.r_offset = (globals->sgot->output_section->vma - + globals->sgot->output_offset + off); + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + off); outrel.r_info = ELF32_R_INFO (0, R_ARM_TLS_DTPMOD32); if (globals->use_rel) bfd_put_32 (output_bfd, outrel.r_addend, - globals->sgot->contents + off); + sgot->contents + off); - loc = globals->srelgot->contents; - loc += globals->srelgot->reloc_count++ * RELOC_SIZE (globals); - SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc); + elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel); } else - bfd_put_32 (output_bfd, 1, globals->sgot->contents + off); + bfd_put_32 (output_bfd, 1, sgot->contents + off); globals->tls_ldm_got.offset |= 1; } - value = globals->sgot->output_section->vma + globals->sgot->output_offset + off + value = sgot->output_section->vma + sgot->output_offset + off - (input_section->output_section->vma + input_section->output_offset + rel->r_offset); return _bfd_final_link_relocate (howto, input_bfd, input_section, @@ -8038,17 +9160,20 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, rel->r_addend); } + case R_ARM_TLS_CALL: + case R_ARM_THM_TLS_CALL: case R_ARM_TLS_GD32: case R_ARM_TLS_IE32: + case R_ARM_TLS_GOTDESC: + case R_ARM_TLS_DESCSEQ: + case R_ARM_THM_TLS_DESCSEQ: { - bfd_vma off; - int indx; + bfd_vma off, offplt; + int indx = 0; char tls_type; - if (globals->sgot == NULL) - abort (); + BFD_ASSERT (sgot != NULL); - indx = 0; if (h != NULL) { bfd_boolean dyn; @@ -8061,18 +9186,23 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, indx = h->dynindx; } off = h->got.offset; + offplt = elf32_arm_hash_entry (h)->tlsdesc_got; tls_type = ((struct elf32_arm_link_hash_entry *) h)->tls_type; } else { - if (local_got_offsets == NULL) - abort (); + BFD_ASSERT (local_got_offsets != NULL); off = local_got_offsets[r_symndx]; + offplt = local_tlsdesc_gotents[r_symndx]; tls_type = elf32_arm_local_got_tls_type (input_bfd)[r_symndx]; } - if (tls_type == GOT_UNKNOWN) - abort (); + /* Linker relaxations happens from one of the + R_ARM_{GOTDESC,CALL,DESCSEQ} relocations to IE or LE. */ + if (ELF32_R_TYPE(rel->r_info) != r_type) + tls_type = GOT_TLS_IE; + + BFD_ASSERT (tls_type != GOT_UNKNOWN); if ((off & 1) != 0) off &= ~1; @@ -8080,7 +9210,6 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, { bfd_boolean need_relocs = FALSE; Elf_Internal_Rela outrel; - bfd_byte *loc = NULL; int cur_off = off; /* The GOT entries have not been initialized yet. Do it @@ -8093,33 +9222,70 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, || h->root.type != bfd_link_hash_undefweak)) { need_relocs = TRUE; - if (globals->srelgot == NULL) - abort (); - loc = globals->srelgot->contents; - loc += globals->srelgot->reloc_count * RELOC_SIZE (globals); + BFD_ASSERT (srelgot != NULL); } + if (tls_type & GOT_TLS_GDESC) + { + bfd_byte *loc; + + /* We should have relaxed, unless this is an undefined + weak symbol. */ + BFD_ASSERT ((h && (h->root.type == bfd_link_hash_undefweak)) + || info->shared); + BFD_ASSERT (globals->sgotplt_jump_table_size + offplt + 8 + <= globals->root.sgotplt->size); + + outrel.r_addend = 0; + outrel.r_offset = (globals->root.sgotplt->output_section->vma + + 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; + loc += globals->next_tls_desc_index++ * RELOC_SIZE (globals); + BFD_ASSERT (loc + RELOC_SIZE (globals) + <= sreloc->contents + sreloc->size); + + SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc); + + /* For globals, the first word in the relocation gets + the relocation index and the top bit set, or zero, + if we're binding now. For locals, it gets the + symbol's offset in the tls section. */ + bfd_put_32 (output_bfd, + !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); + + /* 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); + } if (tls_type & GOT_TLS_GD) { if (need_relocs) { outrel.r_addend = 0; - outrel.r_offset = (globals->sgot->output_section->vma - + globals->sgot->output_offset + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + cur_off); outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_DTPMOD32); if (globals->use_rel) bfd_put_32 (output_bfd, outrel.r_addend, - globals->sgot->contents + cur_off); + sgot->contents + cur_off); - SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc); - globals->srelgot->reloc_count++; - loc += RELOC_SIZE (globals); + elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel); if (indx == 0) bfd_put_32 (output_bfd, value - dtpoff_base (info), - globals->sgot->contents + cur_off + 4); + sgot->contents + cur_off + 4); else { outrel.r_addend = 0; @@ -8129,12 +9295,10 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, if (globals->use_rel) bfd_put_32 (output_bfd, outrel.r_addend, - globals->sgot->contents + cur_off + 4); - + sgot->contents + cur_off + 4); - SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc); - globals->srelgot->reloc_count++; - loc += RELOC_SIZE (globals); + elf32_arm_add_dynreloc (output_bfd, info, + srelgot, &outrel); } } else @@ -8145,9 +9309,9 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, symbol binding locally. Mark it as belonging to module 1, the executable. */ bfd_put_32 (output_bfd, 1, - globals->sgot->contents + cur_off); + sgot->contents + cur_off); bfd_put_32 (output_bfd, value - dtpoff_base (info), - globals->sgot->contents + cur_off + 4); + sgot->contents + cur_off + 4); } cur_off += 8; @@ -8161,22 +9325,20 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, outrel.r_addend = value - dtpoff_base (info); else outrel.r_addend = 0; - outrel.r_offset = (globals->sgot->output_section->vma - + globals->sgot->output_offset + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + cur_off); outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_TPOFF32); if (globals->use_rel) bfd_put_32 (output_bfd, outrel.r_addend, - globals->sgot->contents + cur_off); + sgot->contents + cur_off); - SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc); - globals->srelgot->reloc_count++; - loc += RELOC_SIZE (globals); + elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel); } else bfd_put_32 (output_bfd, tpoff (info, value), - globals->sgot->contents + cur_off); + sgot->contents + cur_off); cur_off += 4; } @@ -8188,8 +9350,155 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32) off += 8; - value = globals->sgot->output_section->vma + globals->sgot->output_offset + off - - (input_section->output_section->vma + input_section->output_offset + rel->r_offset); + else if (tls_type & GOT_TLS_GDESC) + off = offplt; + + if (ELF32_R_TYPE(rel->r_info) == R_ARM_TLS_CALL + || ELF32_R_TYPE(rel->r_info) == R_ARM_THM_TLS_CALL) + { + bfd_signed_vma offset; + /* TLS stubs are arm mode. The original symbol is a + data object, so branch_type is bogus. */ + branch_type = ST_BRANCH_TO_ARM; + enum elf32_arm_stub_type stub_type + = arm_type_of_stub (info, input_section, rel, + st_type, &branch_type, + (struct elf32_arm_link_hash_entry *)h, + globals->tls_trampoline, globals->root.splt, + input_bfd, sym_name); + + if (stub_type != arm_stub_none) + { + struct elf32_arm_stub_hash_entry *stub_entry + = elf32_arm_get_stub_entry + (input_section, globals->root.splt, 0, rel, + globals, stub_type); + offset = (stub_entry->stub_offset + + stub_entry->stub_sec->output_offset + + stub_entry->stub_sec->output_section->vma); + } + else + offset = (globals->root.splt->output_section->vma + + globals->root.splt->output_offset + + globals->tls_trampoline); + + 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); + + inst = offset >> 2; + inst &= 0x00ffffff; + value = inst | (globals->use_blx ? 0xfa000000 : 0xeb000000); + } + else + { + /* Thumb blx encodes the offset in a complicated + fashion. */ + unsigned upper_insn, lower_insn; + unsigned neg; + + 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)) + { + lower_insn = 0xd000; + } + else + { + lower_insn = 0xc000; + /* Round up the offset to a word boundary */ + offset = (offset + 2) & ~2; + } + + neg = offset < 0; + upper_insn = (0xf000 + | ((offset >> 12) & 0x3ff) + | (neg << 10)); + lower_insn |= (((!((offset >> 23) & 1)) ^ neg) << 13) + | (((!((offset >> 22) & 1)) ^ neg) << 11) + | ((offset >> 1) & 0x7ff); + bfd_put_16 (input_bfd, upper_insn, hit_data); + bfd_put_16 (input_bfd, lower_insn, hit_data + 2); + return bfd_reloc_ok; + } + } + /* These relocations needs special care, as besides the fact + they point somewhere in .gotplt, the addend must be + adjusted accordingly depending on the type of instruction + we refer to */ + else if ((r_type == R_ARM_TLS_GOTDESC) && (tls_type & GOT_TLS_GDESC)) + { + 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); + if ((insn & 0xf000) == 0xf000 || (insn & 0xf800) == 0xe800) + insn = (insn << 16) + | bfd_get_16 (input_bfd, + contents + rel->r_offset - data + 2); + if ((insn & 0xf800c000) == 0xf000c000) + /* bl/blx */ + value = -6; + else if ((insn & 0xffffff00) == 0x4400) + /* add */ + value = -5; + else + { + (*_bfd_error_handler) + (_("%B(%A+0x%lx):unexpected Thumb instruction '0x%x' referenced by TLS_GOTDESC"), + input_bfd, input_section, + (unsigned long)rel->r_offset, insn); + return bfd_reloc_notsupported; + } + } + else + { + insn = bfd_get_32 (input_bfd, contents + rel->r_offset - data); + + switch (insn >> 24) + { + case 0xeb: /* bl */ + case 0xfa: /* blx */ + value = -4; + break; + + case 0xe0: /* add */ + value = -8; + break; + + default: + (*_bfd_error_handler) + (_("%B(%A+0x%lx):unexpected ARM instruction '0x%x' referenced by TLS_GOTDESC"), + input_bfd, input_section, + (unsigned long)rel->r_offset, insn); + return bfd_reloc_notsupported; + } + } + + value += ((globals->root.sgotplt->output_section->vma + + globals->root.sgotplt->output_offset + off) + - (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset) + + globals->sgotplt_jump_table_size); + } + else + value = ((globals->root.sgot->output_section->vma + + globals->root.sgot->output_offset + off) + - (input_section->output_section->vma + + input_section->output_offset + rel->r_offset)); return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, value, @@ -8197,7 +9506,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, } case R_ARM_TLS_LE32: - if (info->shared) + if (info->shared && !info->pie) { (*_bfd_error_handler) (_("%B(%A+0x%lx): R_ARM_TLS_LE32 relocation not permitted in shared object"), @@ -8271,7 +9580,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, if (r_type == R_ARM_MOVW_BREL && value >= 0x10000) return bfd_reloc_overflow; - if (sym_flags == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) value |= 1; if (r_type == R_ARM_MOVT_ABS || r_type == R_ARM_MOVT_PREL @@ -8321,7 +9630,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, if (r_type == R_ARM_THM_MOVW_BREL && value >= 0x10000) return bfd_reloc_overflow; - if (sym_flags == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) value |= 1; if (r_type == R_ARM_THM_MOVT_ABS || r_type == R_ARM_THM_MOVT_PREL @@ -8438,7 +9747,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, /* If the target symbol is a Thumb function, then set the Thumb bit in the address. */ - if (sym_flags == STT_ARM_TFUNC) + if (branch_type == ST_BRANCH_TO_THUMB) signed_value |= 1; /* Calculate the value of the relevant G_n, in encoded @@ -8817,7 +10126,16 @@ arm_add_to_rel (bfd * abfd, || (R_TYPE) == R_ARM_TLS_DTPMOD32 \ || (R_TYPE) == R_ARM_TLS_TPOFF32 \ || (R_TYPE) == R_ARM_TLS_LE32 \ - || (R_TYPE) == R_ARM_TLS_IE32) + || (R_TYPE) == R_ARM_TLS_IE32 \ + || IS_ARM_TLS_GNU_RELOC (R_TYPE)) + +/* Specific set of relocations for the gnu tls dialect. */ +#define IS_ARM_TLS_GNU_RELOC(R_TYPE) \ + ((R_TYPE) == R_ARM_TLS_GOTDESC \ + || (R_TYPE) == R_ARM_TLS_CALL \ + || (R_TYPE) == R_ARM_THM_TLS_CALL \ + || (R_TYPE) == R_ARM_TLS_DESCSEQ \ + || (R_TYPE) == R_ARM_THM_TLS_DESCSEQ) /* Relocate an ARM ELF section. */ @@ -8887,9 +10205,11 @@ elf32_arm_relocate_section (bfd * output_bfd, undefined symbol. This is a daft object file, but we should at least do something about it. V4BX & NONE relocations do not use the symbol and are explicitly - allowed to use the undefined symbol, so allow those. */ + allowed to use the undefined symbol, so allow those. + Likewise for relocations against STN_UNDEF. */ if (r_type != R_ARM_V4BX && r_type != R_ARM_NONE + && r_symndx != STN_UNDEF && bfd_is_und_section (sec) && ELF_ST_BIND (sym->st_info) != STB_WEAK) { @@ -8965,7 +10285,7 @@ elf32_arm_relocate_section (bfd * output_bfd, - relocation; addend += msec->output_section->vma + msec->output_offset; - /* Cases here must match those in the preceeding + /* Cases here must match those in the preceding switch statement. */ switch (r_type) { @@ -9010,15 +10330,8 @@ elf32_arm_relocate_section (bfd * output_bfd, } if (sec != NULL && elf_discarded_section (sec)) - { - /* For relocs against symbols from removed linkonce sections, - or sections discarded by a linker script, we just want the - section contents zeroed. Avoid any special processing. */ - _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); - rel->r_info = 0; - rel->r_addend = 0; - continue; - } + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, relend, howto, contents); if (info->relocatable) { @@ -9047,7 +10360,7 @@ elf32_arm_relocate_section (bfd * output_bfd, name = bfd_section_name (input_bfd, sec); } - if (r_symndx != 0 + if (r_symndx != STN_UNDEF && r_type != R_ARM_NONE && (h == NULL || h->root.type == bfd_link_hash_defined @@ -9065,19 +10378,42 @@ elf32_arm_relocate_section (bfd * output_bfd, name); } - r = elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, - input_section, contents, rel, - relocation, info, sec, name, - (h ? ELF_ST_TYPE (h->type) : - ELF_ST_TYPE (sym->st_info)), h, - &unresolved_reloc, &error_message); + /* We call elf32_arm_final_link_relocate unless we're completely + done, i.e., the relaxation produced the final output we want, + and we won't let anybody mess with it. Also, we have to do + addend adjustments in case of a R_ARM_TLS_GOTDESC relocation + 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 : + elf32_arm_local_got_tls_type (input_bfd)[r_symndx]) + & GOT_TLS_GDESC))) + { + r = elf32_arm_tls_relax (globals, input_bfd, input_section, + contents, rel, h == NULL); + /* This may have been marked unresolved because it came from + a shared library. But we've just dealt with that. */ + unresolved_reloc = 0; + } + 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, + relocation, info, sec, name, sym_type, + (h ? h->target_internal + : ARM_SYM_BRANCH_TYPE (sym)), h, + &unresolved_reloc, &error_message); /* Dynamic relocs are not propagated for SEC_DEBUGGING sections because such sections are not SEC_ALLOC and thus ld.so will not process them. */ if (unresolved_reloc && !((input_section->flags & SEC_DEBUGGING) != 0 - && h->def_dynamic)) + && h->def_dynamic) + && _bfd_elf_section_offset (output_bfd, info, input_section, + rel->r_offset) != (bfd_vma) -1) { (*_bfd_error_handler) (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), @@ -9427,16 +10763,19 @@ elf32_arm_final_link (bfd *abfd, struct bfd_link_info *info) /* Process stub sections (eg BE8 encoding, ...). */ struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); int i; - for(i=0; itop_id; i++) { - sec = htab->stub_group[i].stub_sec; - if (sec) { - osec = sec->output_section; - elf32_arm_write_section (abfd, info, sec, sec->contents); - if (! bfd_set_section_contents (abfd, osec, sec->contents, - sec->output_offset, sec->size)) - return FALSE; + for (i=0; itop_id; i++) + { + sec = htab->stub_group[i].stub_sec; + /* Only process it once, in its link_sec slot. */ + if (sec && i == htab->stub_group[i].link_sec->id) + { + osec = sec->output_section; + elf32_arm_write_section (abfd, info, sec, sec->contents); + if (! bfd_set_section_contents (abfd, osec, sec->contents, + sec->output_offset, sec->size)) + return FALSE; + } } - } /* Write out any glue sections now that we have created all the stubs. */ @@ -9635,6 +10974,27 @@ elf32_arm_obj_attrs_order (int num) return num; } +/* Attribute numbers >=64 (mod 128) can be safely ignored. */ +static bfd_boolean +elf32_arm_obj_attrs_handle_unknown (bfd *abfd, int tag) +{ + if ((tag & 127) < 64) + { + _bfd_error_handler + (_("%B: Unknown mandatory EABI object attribute %d"), + abfd, tag); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + else + { + _bfd_error_handler + (_("Warning: %B: Unknown EABI object attribute %d"), + abfd, tag); + return TRUE; + } +} + /* Read the architecture from the Tag_also_compatible_with attribute, if any. Returns -1 if no architecture could be read. */ @@ -9865,9 +11225,6 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) { obj_attribute *in_attr; obj_attribute *out_attr; - obj_attribute_list *in_list; - obj_attribute_list *out_list; - obj_attribute_list **out_listp; /* Some tags have 0 = don't care, 1 = strong requirement, 2 = weak requirement. */ static const int order_021[3] = {0, 2, 1}; @@ -10192,7 +11549,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) case Tag_PCS_config: if (out_attr[i].i == 0) out_attr[i].i = in_attr[i].i; - else if (in_attr[i].i != 0 && out_attr[i].i != 0) + else if (in_attr[i].i != 0 && out_attr[i].i != in_attr[i].i) { /* It's sometimes ok to mix different configs, so this is only a warning. */ @@ -10364,45 +11721,8 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) break; default: - { - bfd *err_bfd = NULL; - - /* The "known_obj_attributes" table does contain some undefined - attributes. Ensure that there are unused. */ - if (out_attr[i].i != 0 || out_attr[i].s != NULL) - err_bfd = obfd; - else if (in_attr[i].i != 0 || in_attr[i].s != NULL) - err_bfd = ibfd; - - if (err_bfd != NULL) - { - /* Attribute numbers >=64 (mod 128) can be safely ignored. */ - if ((i & 127) < 64) - { - _bfd_error_handler - (_("%B: Unknown mandatory EABI object attribute %d"), - err_bfd, i); - bfd_set_error (bfd_error_bad_value); - result = FALSE; - } - else - { - _bfd_error_handler - (_("Warning: %B: Unknown EABI object attribute %d"), - err_bfd, i); - } - } - - /* Only pass on attributes that match in both inputs. */ - if (in_attr[i].i != out_attr[i].i - || in_attr[i].s != out_attr[i].s - || (in_attr[i].s != NULL && out_attr[i].s != NULL - && strcmp (in_attr[i].s, out_attr[i].s) != 0)) - { - out_attr[i].i = 0; - out_attr[i].s = NULL; - } - } + result + = result && _bfd_elf_merge_unknown_attribute_low (ibfd, obfd, i); } /* If out_attr was copied from in_attr then it won't have a type yet. */ @@ -10415,78 +11735,8 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) return FALSE; /* Check for any attributes not known on ARM. */ - in_list = elf_other_obj_attributes_proc (ibfd); - out_listp = &elf_other_obj_attributes_proc (obfd); - out_list = *out_listp; - - for (; in_list || out_list; ) - { - bfd *err_bfd = NULL; - int err_tag = 0; - - /* The tags for each list are in numerical order. */ - /* If the tags are equal, then merge. */ - if (out_list && (!in_list || in_list->tag > out_list->tag)) - { - /* This attribute only exists in obfd. We can't merge, and we don't - know what the tag means, so delete it. */ - err_bfd = obfd; - err_tag = out_list->tag; - *out_listp = out_list->next; - out_list = *out_listp; - } - else if (in_list && (!out_list || in_list->tag < out_list->tag)) - { - /* This attribute only exists in ibfd. We can't merge, and we don't - know what the tag means, so ignore it. */ - err_bfd = ibfd; - err_tag = in_list->tag; - in_list = in_list->next; - } - else /* The tags are equal. */ - { - /* As present, all attributes in the list are unknown, and - therefore can't be merged meaningfully. */ - err_bfd = obfd; - err_tag = out_list->tag; - - /* Only pass on attributes that match in both inputs. */ - if (in_list->attr.i != out_list->attr.i - || in_list->attr.s != out_list->attr.s - || (in_list->attr.s && out_list->attr.s - && strcmp (in_list->attr.s, out_list->attr.s) != 0)) - { - /* No match. Delete the attribute. */ - *out_listp = out_list->next; - out_list = *out_listp; - } - else - { - /* Matched. Keep the attribute and move to the next. */ - out_list = out_list->next; - in_list = in_list->next; - } - } + result &= _bfd_elf_merge_unknown_attribute_list (ibfd, obfd); - if (err_bfd) - { - /* Attribute numbers >=64 (mod 128) can be safely ignored. */ - if ((err_tag & 127) < 64) - { - _bfd_error_handler - (_("%B: Unknown mandatory EABI object attribute %d"), - err_bfd, err_tag); - bfd_set_error (bfd_error_bad_value); - result = FALSE; - } - else - { - _bfd_error_handler - (_("Warning: %B: Unknown EABI object attribute %d"), - err_bfd, err_tag); - } - } - } return result; } @@ -10721,7 +11971,13 @@ elf32_arm_gc_sweep_hook (bfd * abfd, { unsigned long r_symndx; struct elf_link_hash_entry *h = NULL; + struct elf32_arm_link_hash_entry *eh; int r_type; + bfd_boolean call_reloc_p; + bfd_boolean may_become_dynamic_p; + bfd_boolean may_need_local_target_p; + union gotplt_union *root_plt; + struct arm_plt_info *arm_plt; r_symndx = ELF32_R_SYM (rel->r_info); if (r_symndx >= symtab_hdr->sh_info) @@ -10731,6 +11987,11 @@ elf32_arm_gc_sweep_hook (bfd * abfd, || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; } + eh = (struct elf32_arm_link_hash_entry *) h; + + call_reloc_p = FALSE; + may_become_dynamic_p = FALSE; + may_need_local_target_p = FALSE; r_type = ELF32_R_TYPE (rel->r_info); r_type = arm_real_reloc_type (globals, r_type); @@ -10756,10 +12017,6 @@ elf32_arm_gc_sweep_hook (bfd * abfd, globals->tls_ldm_got.refcount -= 1; break; - case R_ARM_ABS32: - case R_ARM_ABS32_NOI: - case R_ARM_REL32: - case R_ARM_REL32_NOI: case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_CALL: @@ -10768,6 +12025,21 @@ elf32_arm_gc_sweep_hook (bfd * abfd, case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: case R_ARM_THM_JUMP19: + call_reloc_p = TRUE; + may_need_local_target_p = TRUE; + break; + + case R_ARM_ABS12: + if (!globals->vxworks_p) + { + may_need_local_target_p = TRUE; + break; + } + /* Fall through. */ + case R_ARM_ABS32: + case R_ARM_ABS32_NOI: + case R_ARM_REL32: + case R_ARM_REL32_NOI: case R_ARM_MOVW_ABS_NC: case R_ARM_MOVT_ABS: case R_ARM_MOVW_PREL_NC: @@ -10777,50 +12049,70 @@ elf32_arm_gc_sweep_hook (bfd * abfd, case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: /* Should the interworking branches be here also? */ - - if (h != NULL) + if ((info->shared || globals->root.is_relocatable_executable) + && (sec->flags & SEC_ALLOC) != 0) { - struct elf32_arm_link_hash_entry *eh; - struct elf32_arm_relocs_copied **pp; - struct elf32_arm_relocs_copied *p; - - eh = (struct elf32_arm_link_hash_entry *) h; - - if (h->plt.refcount > 0) - { - h->plt.refcount -= 1; - if (r_type == R_ARM_THM_CALL) - eh->plt_maybe_thumb_refcount--; - - if (r_type == R_ARM_THM_JUMP24 - || r_type == R_ARM_THM_JUMP19) - eh->plt_thumb_refcount--; - } - - if (r_type == R_ARM_ABS32 - || r_type == R_ARM_REL32 - || r_type == R_ARM_ABS32_NOI - || r_type == R_ARM_REL32_NOI) + if (h == NULL + && (r_type == R_ARM_REL32 || r_type == R_ARM_REL32_NOI)) { - for (pp = &eh->relocs_copied; (p = *pp) != NULL; - pp = &p->next) - if (p->section == sec) - { - p->count -= 1; - if (ELF32_R_TYPE (rel->r_info) == R_ARM_REL32 - || ELF32_R_TYPE (rel->r_info) == R_ARM_REL32_NOI) - p->pc_count -= 1; - if (p->count == 0) - *pp = p->next; - break; - } + call_reloc_p = TRUE; + may_need_local_target_p = TRUE; } + else + may_become_dynamic_p = TRUE; } + else + may_need_local_target_p = TRUE; break; default: break; } + + 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 (!call_reloc_p) + arm_plt->noncall_refcount--; + + if (r_type == R_ARM_THM_CALL) + arm_plt->maybe_thumb_refcount--; + + if (r_type == R_ARM_THM_JUMP24 + || r_type == R_ARM_THM_JUMP19) + arm_plt->thumb_refcount--; + } + + if (may_become_dynamic_p) + { + struct elf_dyn_relocs **pp; + struct elf_dyn_relocs *p; + + if (h != NULL) + pp = &(eh->dyn_relocs); + else + { + Elf_Internal_Sym *isym; + + isym = bfd_sym_from_r_symndx (&globals->sym_cache, + abfd, r_symndx); + if (isym == NULL) + return FALSE; + pp = elf32_arm_get_local_dynreloc_list (abfd, r_symndx, isym); + if (pp == NULL) + return FALSE; + } + for (; (p = *pp) != NULL; pp = &p->next) + if (p->sec == sec) + { + /* Everything must go for SEC. */ + *pp = p->next; + break; + } + } } return TRUE; @@ -10838,9 +12130,10 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Rela *rel_end; bfd *dynobj; asection *sreloc; - bfd_vma *local_got_offsets; struct elf32_arm_link_hash_table *htab; - bfd_boolean needs_plt; + bfd_boolean call_reloc_p; + bfd_boolean may_become_dynamic_p; + bfd_boolean may_need_local_target_p; unsigned long nsyms; if (info->relocatable) @@ -10863,8 +12156,12 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, return FALSE; } - dynobj = elf_hash_table (info)->dynobj; - local_got_offsets = elf_local_got_offsets (abfd); + if (htab->root.dynobj == NULL) + htab->root.dynobj = abfd; + if (!create_ifunc_sections (info)) + return FALSE; + + dynobj = htab->root.dynobj; symtab_hdr = & elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); @@ -10873,6 +12170,7 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, rel_end = relocs + sec->reloc_count; for (rel = relocs; rel < rel_end; rel++) { + Elf_Internal_Sym *isym; struct elf_link_hash_entry *h; struct elf32_arm_link_hash_entry *eh; unsigned long r_symndx; @@ -10886,31 +12184,53 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, /* PR 9934: It is possible to have relocations that do not refer to symbols, thus it is also possible to have an object file containing relocations but no symbol table. */ - && (r_symndx > 0 || nsyms > 0)) + && (r_symndx > STN_UNDEF || nsyms > 0)) { (*_bfd_error_handler) (_("%B: bad symbol index: %d"), abfd, r_symndx); return FALSE; } - if (nsyms == 0 || r_symndx < symtab_hdr->sh_info) - h = NULL; - else + h = NULL; + isym = NULL; + if (nsyms > 0) { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - eh = (struct elf32_arm_link_hash_entry *) h; - - switch (r_type) + if (r_symndx < symtab_hdr->sh_info) + { + /* A local symbol. */ + isym = bfd_sym_from_r_symndx (&htab->sym_cache, + abfd, r_symndx); + if (isym == NULL) + return FALSE; + } + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + } + + eh = (struct elf32_arm_link_hash_entry *) h; + + call_reloc_p = FALSE; + may_become_dynamic_p = FALSE; + may_need_local_target_p = FALSE; + + /* Could be done earlier, if h were already available. */ + r_type = elf32_arm_tls_transition (info, r_type, h); + switch (r_type) { case R_ARM_GOT32: case R_ARM_GOT_PREL: case R_ARM_TLS_GD32: case R_ARM_TLS_IE32: + case R_ARM_TLS_GOTDESC: + case R_ARM_TLS_DESCSEQ: + case R_ARM_THM_TLS_DESCSEQ: + case R_ARM_TLS_CALL: + case R_ARM_THM_TLS_CALL: /* This symbol requires a global offset table entry. */ { int tls_type, old_tls_type; @@ -10918,7 +12238,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; } @@ -10929,36 +12256,33 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, } else { - bfd_signed_vma *local_got_refcounts; - /* This is a global offset table entry for a local symbol. */ - local_got_refcounts = elf_local_got_refcounts (abfd); - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= (sizeof (bfd_signed_vma) + sizeof (char)); - local_got_refcounts = (bfd_signed_vma *) - bfd_zalloc (abfd, size); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - elf32_arm_local_got_tls_type (abfd) - = (char *) (local_got_refcounts + symtab_hdr->sh_info); - } - local_got_refcounts[r_symndx] += 1; + if (!elf32_arm_allocate_local_sym_info (abfd)) + return FALSE; + elf_local_got_refcounts (abfd)[r_symndx] += 1; old_tls_type = elf32_arm_local_got_tls_type (abfd) [r_symndx]; } - /* We will already have issued an error message if there is a - TLS / non-TLS mismatch, based on the symbol type. We don't - support any linker relaxations. So just combine any TLS - types needed. */ + /* If a variable is accessed with both tls methods, two + slots may be created. */ + if (GOT_TLS_GD_ANY_P (old_tls_type) + && GOT_TLS_GD_ANY_P (tls_type)) + tls_type |= old_tls_type; + + /* We will already have issued an error message if there + is a TLS/non-TLS mismatch, based on the symbol + type. So just combine any TLS types needed. */ if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL && tls_type != GOT_NORMAL) tls_type |= old_tls_type; + /* If the symbol is accessed in both IE and GDESC + method, we're able to relax. Turn off the GDESC flag, + without messing up with any other kind of tls types + that may be involved */ + if ((tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_GDESC)) + tls_type &= ~GOT_TLS_GDESC; + if (old_tls_type != tls_type) { if (h != NULL) @@ -10976,22 +12300,11 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_ARM_GOTOFF32: case R_ARM_GOTPC: - if (htab->sgot == NULL) - { - if (htab->root.dynobj == NULL) - htab->root.dynobj = abfd; - if (!create_got_section (htab->root.dynobj, info)) - return FALSE; - } + if (htab->root.sgot == NULL + && !create_got_section (htab->root.dynobj, info)) + return FALSE; break; - case R_ARM_ABS12: - /* VxWorks uses dynamic R_ARM_ABS12 relocations for - ldr __GOTT_INDEX__ offsets. */ - if (!htab->vxworks_p) - break; - /* Fall through. */ - case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_CALL: @@ -11000,8 +12313,19 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: case R_ARM_THM_JUMP19: - needs_plt = 1; - goto normal_reloc; + call_reloc_p = TRUE; + may_need_local_target_p = TRUE; + break; + + case R_ARM_ABS12: + /* VxWorks uses dynamic R_ARM_ABS12 relocations for + ldr __GOTT_INDEX__ offsets. */ + if (!htab->vxworks_p) + { + may_need_local_target_p = TRUE; + break; + } + /* Fall through. */ case R_ARM_MOVW_ABS_NC: case R_ARM_MOVT_ABS: @@ -11026,134 +12350,30 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_ARM_MOVT_PREL: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: - needs_plt = 0; - normal_reloc: /* Should the interworking branches be listed here? */ - if (h != NULL) - { - /* If this reloc is in a read-only section, we might - need a copy reloc. We can't check reliably at this - stage whether the section is read-only, as input - sections have not yet been mapped to output sections. - Tentatively set the flag for now, and correct in - adjust_dynamic_symbol. */ - if (!info->shared) - h->non_got_ref = 1; - - /* We may need a .plt entry if the function this reloc - refers to is in a different object. We can't tell for - sure yet, because something later might force the - symbol local. */ - if (needs_plt) - h->needs_plt = 1; - - /* If we create a PLT entry, this relocation will reference - it, even if it's an ABS32 relocation. */ - h->plt.refcount += 1; - - /* It's too early to use htab->use_blx here, so we have to - record possible blx references separately from - relocs that definitely need a thumb stub. */ - - if (r_type == R_ARM_THM_CALL) - eh->plt_maybe_thumb_refcount += 1; - - if (r_type == R_ARM_THM_JUMP24 - || r_type == R_ARM_THM_JUMP19) - eh->plt_thumb_refcount += 1; - } - - /* If we are creating a shared library or relocatable executable, - and this is a reloc against a global symbol, or a non PC - relative reloc against a local symbol, then we need to copy - the reloc into the shared library. However, if we are linking - with -Bsymbolic, we do not need to copy a reloc against a - global symbol which is defined in an object we are - including in the link (i.e., DEF_REGULAR is set). At - this point we have not seen all the input files, so it is - possible that DEF_REGULAR is not set now but will be set - later (it is never cleared). We account for that - possibility below by storing information in the - relocs_copied field of the hash table entry. */ if ((info->shared || htab->root.is_relocatable_executable) - && (sec->flags & SEC_ALLOC) != 0 - && ((r_type == R_ARM_ABS32 || r_type == R_ARM_ABS32_NOI) - || (h != NULL && ! h->needs_plt - && (! info->symbolic || ! h->def_regular)))) + && (sec->flags & SEC_ALLOC) != 0) { - struct elf32_arm_relocs_copied *p, **head; - - /* When creating a shared object, we must copy these - reloc types into the output file. We create a reloc - section in dynobj and make room for this reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, ! htab->use_rel); - - if (sreloc == NULL) - return FALSE; - - /* BPABI objects never have dynamic relocations mapped. */ - if (htab->symbian_p) - { - flagword flags; - - flags = bfd_get_section_flags (dynobj, sreloc); - flags &= ~(SEC_LOAD | SEC_ALLOC); - bfd_set_section_flags (dynobj, sreloc, flags); - } - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) + if (h == NULL + && (r_type == R_ARM_REL32 || r_type == R_ARM_REL32_NOI)) { - head = &((struct elf32_arm_link_hash_entry *) h)->relocs_copied; + /* In shared libraries and relocatable executables, + we treat local relative references as calls; + see the related SYMBOL_CALLS_LOCAL code in + allocate_dynrelocs. */ + call_reloc_p = TRUE; + may_need_local_target_p = TRUE; } else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - asection *s; - void *vpp; - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf32_arm_relocs_copied **) vpp; - } - - p = *head; - if (p == NULL || p->section != sec) - { - bfd_size_type amt = sizeof *p; - - p = (struct elf32_arm_relocs_copied *) - bfd_alloc (htab->root.dynobj, amt); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->section = sec; - p->count = 0; - p->pc_count = 0; - } - - if (r_type == R_ARM_REL32 || r_type == R_ARM_REL32_NOI) - p->pc_count += 1; - p->count += 1; + /* We are creating a shared library or relocatable + executable, and this is a reloc against a global symbol, + or a non-PC-relative reloc against a local symbol. + We may need to copy the reloc into the output. */ + may_become_dynamic_p = TRUE; } + else + may_need_local_target_p = TRUE; break; /* This relocation describes the C++ object vtable hierarchy. @@ -11172,6 +12392,119 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, return FALSE; break; } + + if (h != NULL) + { + if (call_reloc_p) + /* We may need a .plt entry if the function this reloc + refers to is in a different object, regardless of the + symbol's type. We can't tell for sure yet, because + something later might force the symbol local. */ + h->needs_plt = 1; + else if (may_need_local_target_p) + /* If this reloc is in a read-only section, we might + need a copy reloc. We can't check reliably at this + stage whether the section is read-only, as input + sections have not yet been mapped to output sections. + Tentatively set the flag for now, and correct in + adjust_dynamic_symbol. */ + h->non_got_ref = 1; + } + + if (may_need_local_target_p + && (h != NULL || ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)) + { + union gotplt_union *root_plt; + struct arm_plt_info *arm_plt; + struct arm_local_iplt_info *local_iplt; + + if (h != NULL) + { + root_plt = &h->plt; + arm_plt = &eh->plt; + } + else + { + local_iplt = elf32_arm_create_local_iplt (abfd, r_symndx); + if (local_iplt == NULL) + return FALSE; + root_plt = &local_iplt->root; + arm_plt = &local_iplt->arm; + } + + /* If the symbol is a function that doesn't bind locally, + this relocation will need a PLT entry. */ + root_plt->refcount += 1; + + if (!call_reloc_p) + arm_plt->noncall_refcount++; + + /* It's too early to use htab->use_blx here, so we have to + record possible blx references separately from + relocs that definitely need a thumb stub. */ + + if (r_type == R_ARM_THM_CALL) + arm_plt->maybe_thumb_refcount += 1; + + if (r_type == R_ARM_THM_JUMP24 + || r_type == R_ARM_THM_JUMP19) + arm_plt->thumb_refcount += 1; + } + + if (may_become_dynamic_p) + { + struct elf_dyn_relocs *p, **head; + + /* Create a reloc section in dynobj. */ + if (sreloc == NULL) + { + sreloc = _bfd_elf_make_dynamic_reloc_section + (sec, dynobj, 2, abfd, ! htab->use_rel); + + if (sreloc == NULL) + return FALSE; + + /* BPABI objects never have dynamic relocations mapped. */ + if (htab->symbian_p) + { + flagword flags; + + flags = bfd_get_section_flags (dynobj, sreloc); + flags &= ~(SEC_LOAD | SEC_ALLOC); + bfd_set_section_flags (dynobj, sreloc, flags); + } + } + + /* If this is a global symbol, count the number of + relocations we need for this symbol. */ + if (h != NULL) + head = &((struct elf32_arm_link_hash_entry *) h)->dyn_relocs; + else + { + head = elf32_arm_get_local_dynreloc_list (abfd, r_symndx, isym); + if (head == NULL) + return FALSE; + } + + p = *head; + if (p == NULL || p->sec != sec) + { + bfd_size_type amt = sizeof *p; + + p = (struct elf_dyn_relocs *) bfd_alloc (htab->root.dynobj, amt); + if (p == NULL) + return FALSE; + p->next = *head; + *head = p; + p->sec = sec; + p->count = 0; + p->pc_count = 0; + } + + if (r_type == R_ARM_REL32 || r_type == R_ARM_REL32_NOI) + p->pc_count += 1; + p->count += 1; + } } return TRUE; @@ -11188,6 +12521,8 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info, Elf_Internal_Shdr **elf_shdrp; bfd_boolean again; + _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook); + /* Marking EH data may cause additional code sections to be marked, requiring multiple passes. */ again = TRUE; @@ -11312,7 +12647,8 @@ elf32_arm_find_nearest_line (bfd * abfd, /* We skip _bfd_dwarf1_find_nearest_line since no known ARM toolchain uses it. */ - if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, + if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections, + section, symbols, offset, filename_ptr, functionname_ptr, line_ptr, 0, & elf_tdata (abfd)->dwarf2_find_line_info)) @@ -11382,6 +12718,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, /* Make sure we know what is going on here. */ BFD_ASSERT (dynobj != NULL && (h->needs_plt + || h->type == STT_GNU_IFUNC || h->u.weakdef != NULL || (h->def_dynamic && h->ref_regular @@ -11392,13 +12729,15 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, /* If this is a function, put it in the procedure linkage table. We will fill in the contents of the procedure linkage table later, when we know the address of the .got section. */ - if (h->type == STT_FUNC || h->type == STT_ARM_TFUNC - || h->needs_plt) + if (h->type == STT_FUNC || h->type == STT_GNU_IFUNC || h->needs_plt) { + /* Calls to STT_GNU_IFUNC symbols always use a PLT, even if the + symbol binds locally. */ if (h->plt.refcount <= 0 - || SYMBOL_CALLS_LOCAL (info, h) - || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - && h->root.type == bfd_link_hash_undefweak)) + || (h->type != STT_GNU_IFUNC + && (SYMBOL_CALLS_LOCAL (info, h) + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak)))) { /* This case can occur if we saw a PLT32 reloc in an input file, but the symbol was never referred to by a dynamic @@ -11406,8 +12745,9 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, such a case, we don't actually need to build a procedure linkage table, and we can just do a PC24 reloc instead. */ h->plt.offset = (bfd_vma) -1; - eh->plt_thumb_refcount = 0; - eh->plt_maybe_thumb_refcount = 0; + eh->plt.thumb_refcount = 0; + eh->plt.maybe_thumb_refcount = 0; + eh->plt.noncall_refcount = 0; h->needs_plt = 0; } @@ -11421,8 +12761,9 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, and non-function syms in check-relocs; Objects loaded later in the link may change h->type. So fix it now. */ h->plt.offset = (bfd_vma) -1; - eh->plt_thumb_refcount = 0; - eh->plt_maybe_thumb_refcount = 0; + eh->plt.thumb_refcount = 0; + eh->plt.maybe_thumb_refcount = 0; + eh->plt.noncall_refcount = 0; } /* If this is a weak symbol, and there is a real definition, the @@ -11482,8 +12823,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, asection *srel; srel = bfd_get_section_by_name (dynobj, RELOC_SECTION (globals, ".bss")); - BFD_ASSERT (srel != NULL); - srel->size += RELOC_SIZE (globals); + elf32_arm_allocate_dynrelocs (info, srel, 1); h->needs_copy = 1; } @@ -11494,31 +12834,24 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, dynamic relocs. */ static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) +allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf) { struct bfd_link_info *info; struct elf32_arm_link_hash_table *htab; struct elf32_arm_link_hash_entry *eh; - struct elf32_arm_relocs_copied *p; - bfd_signed_vma thumb_refs; - - eh = (struct elf32_arm_link_hash_entry *) h; + struct elf_dyn_relocs *p; if (h->root.type == bfd_link_hash_indirect) return TRUE; - if (h->root.type == bfd_link_hash_warning) - /* When warning symbols are created, they **replace** the "real" - entry in the hash table, thus we never get to see the real - symbol in a hash traversal. So look at it now. */ - h = (struct elf_link_hash_entry *) h->root.u.i.link; + eh = (struct elf32_arm_link_hash_entry *) h; info = (struct bfd_link_info *) inf; htab = elf32_arm_hash_table (info); if (htab == NULL) return FALSE; - if (htab->root.dynamic_sections_created + if ((htab->root.dynamic_sections_created || h->type == STT_GNU_IFUNC) && h->plt.refcount > 0) { /* Make sure this symbol is output as a dynamic symbol. @@ -11530,29 +12863,29 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) return FALSE; } + /* If the call in the PLT entry binds locally, the associated + GOT entry should use an R_ARM_IRELATIVE relocation instead of + the usual R_ARM_JUMP_SLOT. Put it in the .iplt section rather + than the .plt section. */ + if (h->type == STT_GNU_IFUNC && SYMBOL_CALLS_LOCAL (info, h)) + { + eh->is_iplt = 1; + if (eh->plt.noncall_refcount == 0 + && SYMBOL_REFERENCES_LOCAL (info, h)) + /* All non-call references can be resolved directly. + This means that they can (and in some cases, must) + resolve directly to the run-time target, rather than + to the PLT. That in turns means that any .got entry + would be equal to the .igot.plt entry, so there's + no point having both. */ + h->got.refcount = 0; + } + if (info->shared + || eh->is_iplt || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) { - asection *s = htab->splt; - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - s->size += htab->plt_header_size; - - h->plt.offset = s->size; - - /* If we will insert a Thumb trampoline before this PLT, leave room - for it. */ - thumb_refs = eh->plt_thumb_refcount; - if (!htab->use_blx) - thumb_refs += eh->plt_maybe_thumb_refcount; - - if (thumb_refs > 0) - { - h->plt.offset += PLT_THUMB_STUB_SIZE; - s->size += PLT_THUMB_STUB_SIZE; - } + elf32_arm_allocate_plt_entry (info, eh->is_iplt, &h->plt, &eh->plt); /* If this symbol is not defined in a regular file, and we are not generating a shared library, then set the symbol to this @@ -11562,29 +12895,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) if (! info->shared && !h->def_regular) { - h->root.u.def.section = s; + h->root.u.def.section = htab->root.splt; h->root.u.def.value = h->plt.offset; /* Make sure the function is not marked as Thumb, in case it is the target of an ABS32 relocation, which will point to the PLT entry. */ - if (ELF_ST_TYPE (h->type) == STT_ARM_TFUNC) - h->type = ELF_ST_INFO (ELF_ST_BIND (h->type), STT_FUNC); - } - - /* Make room for this entry. */ - s->size += htab->plt_entry_size; - - if (!htab->symbian_p) - { - /* We also need to make an entry in the .got.plt section, which - will be placed in the .got section by the linker script. */ - eh->plt_got_offset = htab->sgotplt->size; - htab->sgotplt->size += 4; + h->target_internal = ST_BRANCH_TO_ARM; } - /* We also need to make an entry in the .rel(a).plt section. */ - htab->srelplt->size += RELOC_SIZE (htab); + htab->next_tls_desc_index++; /* VxWorks executables have a second set of relocations for each PLT entry. They go in a separate relocation section, @@ -11594,12 +12914,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* There is a relocation for the initial PLT entry: an R_ARM_32 relocation for _GLOBAL_OFFSET_TABLE_. */ if (h->plt.offset == htab->plt_header_size) - htab->srelplt2->size += RELOC_SIZE (htab); + elf32_arm_allocate_dynrelocs (info, htab->srelplt2, 1); /* There are two extra relocations for each subsequent PLT entry: an R_ARM_32 relocation for the GOT entry, and an R_ARM_32 relocation for the PLT entry. */ - htab->srelplt2->size += RELOC_SIZE (htab) * 2; + elf32_arm_allocate_dynrelocs (info, htab->srelplt2, 2); } } else @@ -11614,6 +12934,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) h->needs_plt = 0; } + eh = (struct elf32_arm_link_hash_entry *) h; + eh->tlsdesc_got = (bfd_vma) -1; + if (h->got.refcount > 0) { asection *s; @@ -11632,7 +12955,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) if (!htab->symbian_p) { - s = htab->sgot; + s = htab->root.sgot; h->got.offset = s->size; if (tls_type == GOT_UNKNOWN) @@ -11643,9 +12966,28 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) s->size += 4; else { + if (tls_type & GOT_TLS_GDESC) + { + /* R_ARM_TLS_DESC needs 2 GOT slots. */ + eh->tlsdesc_got + = (htab->root.sgotplt->size + - elf32_arm_compute_jump_table_size (htab)); + htab->root.sgotplt->size += 8; + h->got.offset = (bfd_vma) -2; + /* plt.got_offset needs to know there's a TLS_DESC + reloc in the middle of .got.plt. */ + htab->num_tls_desc++; + } + if (tls_type & GOT_TLS_GD) - /* R_ARM_TLS_GD32 needs 2 consecutive GOT slots. */ - s->size += 8; + { + /* R_ARM_TLS_GD32 needs 2 consecutive GOT slots. If + the symbol is both GD and GDESC, got.offset may + have been overwritten. */ + h->got.offset = s->size; + s->size += 8; + } + if (tls_type & GOT_TLS_IE) /* R_ARM_TLS_IE32 needs one GOT slot. */ s->size += 4; @@ -11665,19 +13007,38 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) || h->root.type != bfd_link_hash_undefweak)) { if (tls_type & GOT_TLS_IE) - htab->srelgot->size += RELOC_SIZE (htab); + elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); if (tls_type & GOT_TLS_GD) - htab->srelgot->size += RELOC_SIZE (htab); + elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); + + if (tls_type & GOT_TLS_GDESC) + { + elf32_arm_allocate_dynrelocs (info, htab->root.srelplt, 1); + /* GDESC needs a trampoline to jump to. */ + htab->tls_trampoline = -1; + } - if ((tls_type & GOT_TLS_GD) && indx != 0) - htab->srelgot->size += RELOC_SIZE (htab); + /* Only GD needs it. GDESC just emits one relocation per + 2 entries. */ + if ((tls_type & GOT_TLS_GD) && indx != 0) + elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); } - else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak) - && (info->shared - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) - htab->srelgot->size += RELOC_SIZE (htab); + else if (!SYMBOL_REFERENCES_LOCAL (info, h)) + { + if (htab->root.dynamic_sections_created) + /* Reserve room for the GOT entry's R_ARM_GLOB_DAT relocation. */ + elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); + } + else if (h->type == STT_GNU_IFUNC + && eh->plt.noncall_refcount == 0) + /* No non-call references resolve the STT_GNU_IFUNC's PLT entry; + they all resolve dynamically instead. Reserve room for the + GOT entry's R_ARM_IRELATIVE relocation. */ + elf32_arm_allocate_irelocs (info, htab->root.srelgot, 1); + else if (info->shared) + /* Reserve room for the GOT entry's R_ARM_RELATIVE relocation. */ + elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); } } else @@ -11686,7 +13047,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* Allocate stubs for exported Thumb functions on v4t. */ if (!htab->use_blx && h->dynindx != -1 && h->def_regular - && ELF_ST_TYPE (h->type) == STT_ARM_TFUNC + && h->target_internal == ST_BRANCH_TO_THUMB && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) { struct elf_link_hash_entry * th; @@ -11704,17 +13065,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) NULL, TRUE, FALSE, &bh); myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC); + myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); myh->forced_local = 1; + myh->target_internal = ST_BRANCH_TO_THUMB; eh->export_glue = myh; th = record_arm_to_thumb_glue (info, h); /* Point the symbol at the stub. */ h->type = ELF_ST_INFO (ELF_ST_BIND (h->type), STT_FUNC); + h->target_internal = ST_BRANCH_TO_ARM; h->root.u.def.section = th->root.u.def.section; h->root.u.def.value = th->root.u.def.value & ~1; } - if (eh->relocs_copied == NULL) + if (eh->dyn_relocs == NULL) return TRUE; /* In the shared -Bsymbolic case, discard space allocated for @@ -11733,9 +13096,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) should avoid writing assembly like ".long foo - .". */ if (SYMBOL_CALLS_LOCAL (info, h)) { - struct elf32_arm_relocs_copied **pp; + struct elf_dyn_relocs **pp; - for (pp = &eh->relocs_copied; (p = *pp) != NULL; ) + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) { p->count -= p->pc_count; p->pc_count = 0; @@ -11748,11 +13111,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) if (htab->vxworks_p) { - struct elf32_arm_relocs_copied **pp; + struct elf_dyn_relocs **pp; - for (pp = &eh->relocs_copied; (p = *pp) != NULL; ) + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) { - if (strcmp (p->section->output_section->name, ".tls_vars") == 0) + if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) *pp = p->next; else pp = &p->next; @@ -11761,11 +13124,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* Also discard relocs on undefined weak syms with non-default visibility. */ - if (eh->relocs_copied != NULL + if (eh->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak) { if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - eh->relocs_copied = NULL; + eh->dyn_relocs = NULL; /* Make sure undefined weak symbols are output as a dynamic symbol in PIEs. */ @@ -11816,16 +13179,21 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) goto keep; } - eh->relocs_copied = NULL; + eh->dyn_relocs = NULL; keep: ; } /* Finally, allocate space. */ - for (p = eh->relocs_copied; p != NULL; p = p->next) + for (p = eh->dyn_relocs; p != NULL; p = p->next) { - asection *sreloc = elf_section_data (p->section)->sreloc; - sreloc->size += p->count * RELOC_SIZE (htab); + asection *sreloc = elf_section_data (p->sec)->sreloc; + if (h->type == STT_GNU_IFUNC + && eh->plt.noncall_refcount == 0 + && SYMBOL_REFERENCES_LOCAL (info, h)) + elf32_arm_allocate_irelocs (info, sreloc, p->count); + else + elf32_arm_allocate_dynrelocs (info, sreloc, p->count); } return TRUE; @@ -11837,15 +13205,12 @@ static bfd_boolean elf32_arm_readonly_dynrelocs (struct elf_link_hash_entry * h, void * inf) { struct elf32_arm_link_hash_entry * eh; - struct elf32_arm_relocs_copied * p; - - if (h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + struct elf_dyn_relocs * p; eh = (struct elf32_arm_link_hash_entry *) h; - for (p = eh->relocs_copied; p != NULL; p = p->next) + for (p = eh->dyn_relocs; p != NULL; p = p->next) { - asection *s = p->section; + asection *s = p->sec; if (s != NULL && (s->flags & SEC_READONLY) != 0) { @@ -11912,24 +13277,27 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, { bfd_signed_vma *local_got; bfd_signed_vma *end_local_got; + struct arm_local_iplt_info **local_iplt_ptr, *local_iplt; char *local_tls_type; + bfd_vma *local_tlsdesc_gotent; bfd_size_type locsymcount; Elf_Internal_Shdr *symtab_hdr; asection *srel; bfd_boolean is_vxworks = htab->vxworks_p; + unsigned int symndx; if (! is_arm_elf (ibfd)) continue; for (s = ibfd->sections; s != NULL; s = s->next) { - struct elf32_arm_relocs_copied *p; + struct elf_dyn_relocs *p; - for (p = (struct elf32_arm_relocs_copied *) + for (p = (struct elf_dyn_relocs *) elf_section_data (s)->local_dynrel; p != NULL; p = p->next) { - if (!bfd_is_abs_section (p->section) - && bfd_is_abs_section (p->section->output_section)) + if (!bfd_is_abs_section (p->sec) + && bfd_is_abs_section (p->sec->output_section)) { /* Input section has been discarded, either because it is a copy of a linkonce section or due to @@ -11937,7 +13305,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, the relocs too. */ } else if (is_vxworks - && strcmp (p->section->output_section->name, + && strcmp (p->sec->output_section->name, ".tls_vars") == 0) { /* Relocations in vxworks .tls_vars sections are @@ -11945,9 +13313,9 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, } else if (p->count != 0) { - srel = elf_section_data (p->section)->sreloc; - srel->size += p->count * RELOC_SIZE (htab); - if ((p->section->output_section->flags & SEC_READONLY) != 0) + srel = elf_section_data (p->sec)->sreloc; + elf32_arm_allocate_dynrelocs (info, srel, p->count); + if ((p->sec->output_section->flags & SEC_READONLY) != 0) info->flags |= DF_TEXTREL; } } @@ -11960,24 +13328,101 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, symtab_hdr = & elf_symtab_hdr (ibfd); locsymcount = symtab_hdr->sh_info; end_local_got = local_got + locsymcount; + local_iplt_ptr = elf32_arm_local_iplt (ibfd); local_tls_type = elf32_arm_local_got_tls_type (ibfd); - s = htab->sgot; - srel = htab->srelgot; - for (; local_got < end_local_got; ++local_got, ++local_tls_type) + local_tlsdesc_gotent = elf32_arm_local_tlsdesc_gotent (ibfd); + symndx = 0; + s = htab->root.sgot; + srel = htab->root.srelgot; + for (; local_got < end_local_got; + ++local_got, ++local_iplt_ptr, ++local_tls_type, + ++local_tlsdesc_gotent, ++symndx) { + *local_tlsdesc_gotent = (bfd_vma) -1; + local_iplt = *local_iplt_ptr; + if (local_iplt != NULL) + { + struct elf_dyn_relocs *p; + + if (local_iplt->root.refcount > 0) + { + elf32_arm_allocate_plt_entry (info, TRUE, + &local_iplt->root, + &local_iplt->arm); + if (local_iplt->arm.noncall_refcount == 0) + /* All references to the PLT are calls, so all + non-call references can resolve directly to the + run-time target. This means that the .got entry + would be the same as the .igot.plt entry, so there's + no point creating both. */ + *local_got = 0; + } + else + { + BFD_ASSERT (local_iplt->arm.noncall_refcount == 0); + local_iplt->root.offset = (bfd_vma) -1; + } + + for (p = local_iplt->dyn_relocs; p != NULL; p = p->next) + { + asection *psrel; + + psrel = elf_section_data (p->sec)->sreloc; + if (local_iplt->arm.noncall_refcount == 0) + elf32_arm_allocate_irelocs (info, psrel, p->count); + else + elf32_arm_allocate_dynrelocs (info, psrel, p->count); + } + } if (*local_got > 0) { + Elf_Internal_Sym *isym; + *local_got = s->size; if (*local_tls_type & GOT_TLS_GD) /* TLS_GD relocs need an 8-byte structure in the GOT. */ s->size += 8; + if (*local_tls_type & GOT_TLS_GDESC) + { + *local_tlsdesc_gotent = htab->root.sgotplt->size + - elf32_arm_compute_jump_table_size (htab); + htab->root.sgotplt->size += 8; + *local_got = (bfd_vma) -2; + /* plt.got_offset needs to know there's a TLS_DESC + reloc in the middle of .got.plt. */ + htab->num_tls_desc++; + } if (*local_tls_type & GOT_TLS_IE) s->size += 4; - if (*local_tls_type == GOT_NORMAL) - s->size += 4; - if (info->shared || *local_tls_type == GOT_TLS_GD) - srel->size += RELOC_SIZE (htab); + if (*local_tls_type & GOT_NORMAL) + { + /* If the symbol is both GD and GDESC, *local_got + may have been overwritten. */ + *local_got = s->size; + s->size += 4; + } + + isym = bfd_sym_from_r_symndx (&htab->sym_cache, ibfd, symndx); + if (isym == NULL) + return FALSE; + + /* If all references to an STT_GNU_IFUNC PLT are calls, + then all non-call references, including this GOT entry, + resolve directly to the run-time target. */ + if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC + && (local_iplt == NULL + || local_iplt->arm.noncall_refcount == 0)) + elf32_arm_allocate_irelocs (info, srel, 1); + else if ((info->shared && !(*local_tls_type & GOT_TLS_GDESC)) + || *local_tls_type & GOT_TLS_GD) + elf32_arm_allocate_dynrelocs (info, srel, 1); + + if (info->shared && *local_tls_type & GOT_TLS_GDESC) + { + elf32_arm_allocate_dynrelocs (info, htab->root.srelplt, 1); + htab->tls_trampoline = -1; + } } else *local_got = (bfd_vma) -1; @@ -11988,17 +13433,17 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, { /* Allocate two GOT entries and one dynamic relocation (if necessary) for R_ARM_TLS_LDM32 relocations. */ - htab->tls_ldm_got.offset = htab->sgot->size; - htab->sgot->size += 8; + htab->tls_ldm_got.offset = htab->root.sgot->size; + htab->root.sgot->size += 8; if (info->shared) - htab->srelgot->size += RELOC_SIZE (htab); + elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); } else htab->tls_ldm_got.offset = -1; /* Allocate global sym .plt and .got entries, and space for global sym dynamic relocs. */ - elf_link_hash_traverse (& htab->root, allocate_dynrelocs, info); + elf_link_hash_traverse (& htab->root, allocate_dynrelocs_for_symbol, info); /* Here we rummage through the found bfds to collect glue information. */ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) @@ -12019,6 +13464,34 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, /* Allocate space for the glue sections now that we've sized them. */ bfd_elf32_arm_allocate_interworking_sections (info); + /* For every jump slot reserved in the sgotplt, reloc_count is + incremented. However, when we reserve space for TLS descriptors, + it's not incremented, so in order to compute the space reserved + for them, it suffices to multiply the reloc count by the jump + slot size. */ + if (htab->root.srelplt) + htab->sgotplt_jump_table_size = elf32_arm_compute_jump_table_size(htab); + + if (htab->tls_trampoline) + { + 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)) + { + htab->dt_tlsdesc_got = htab->root.sgot->size; + htab->root.sgot->size += 4; + + htab->dt_tlsdesc_plt = htab->root.splt->size; + htab->root.splt->size += 4 * ARRAY_SIZE (dl_tlsdesc_lazy_trampoline); + } + } + /* The check_relocs and adjust_dynamic_symbol entry points have determined the sizes of the various dynamic sections. Allocate memory for them. */ @@ -12035,7 +13508,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, of the dynobj section names depend upon the input files. */ name = bfd_get_section_name (dynobj, s); - if (strcmp (name, ".plt") == 0) + if (s == htab->root.splt) { /* Remember whether there is a PLT. */ plt = s->size != 0; @@ -12046,7 +13519,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, { /* Remember whether there are any reloc sections other than .rel(a).plt and .rela.plt.unloaded. */ - if (s != htab->srelplt && s != htab->srelplt2) + if (s != htab->root.srelplt && s != htab->srelplt2) relocs = TRUE; /* We use the reloc_count field as a counter if we need @@ -12054,8 +13527,11 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, s->reloc_count = 0; } } - else if (! CONST_STRNEQ (name, ".got") - && strcmp (name, ".dynbss") != 0) + else if (s != htab->root.sgot + && s != htab->root.sgotplt + && s != htab->root.iplt + && s != htab->root.igotplt + && s != htab->sdynbss) { /* It's not one of our sections, so don't allocate space. */ continue; @@ -12109,6 +13585,11 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, htab->use_rel ? DT_REL : DT_RELA) || !add_dynamic_entry (DT_JMPREL, 0)) return FALSE; + + if (htab->dt_tlsdesc_plt && + (!add_dynamic_entry (DT_TLSDESC_PLT,0) + || !add_dynamic_entry (DT_TLSDESC_GOT,0))) + return FALSE; } if (relocs) @@ -12149,6 +13630,49 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, return TRUE; } +/* Size sections even though they're not dynamic. We use it to setup + _TLS_MODULE_BASE_, if needed. */ + +static bfd_boolean +elf32_arm_always_size_sections (bfd *output_bfd, + struct bfd_link_info *info) +{ + asection *tls_sec; + + if (info->relocatable) + return TRUE; + + tls_sec = elf_hash_table (info)->tls_sec; + + if (tls_sec) + { + struct elf_link_hash_entry *tlsbase; + + tlsbase = elf_link_hash_lookup + (elf_hash_table (info), "_TLS_MODULE_BASE_", TRUE, TRUE, FALSE); + + if (tlsbase) + { + struct bfd_link_hash_entry *bh = NULL; + const struct elf_backend_data *bed + = get_elf_backend_data (output_bfd); + + if (!(_bfd_generic_link_add_one_symbol + (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL, + 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; + tlsbase->other = STV_HIDDEN; + (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); + } + } + return TRUE; +} + /* Finish up dynamic symbol handling. We set the contents of various dynamic sections here. */ @@ -12158,11 +13682,9 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct elf_link_hash_entry * h, Elf_Internal_Sym * sym) { - bfd * dynobj; struct elf32_arm_link_hash_table *htab; struct elf32_arm_link_hash_entry *eh; - dynobj = elf_hash_table (info)->dynobj; htab = elf32_arm_hash_table (info); if (htab == NULL) return FALSE; @@ -12171,187 +13693,13 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, if (h->plt.offset != (bfd_vma) -1) { - asection * splt; - asection * srel; - bfd_byte *loc; - bfd_vma plt_index; - Elf_Internal_Rela rel; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - - BFD_ASSERT (h->dynindx != -1); - - splt = bfd_get_section_by_name (dynobj, ".plt"); - srel = bfd_get_section_by_name (dynobj, RELOC_SECTION (htab, ".plt")); - BFD_ASSERT (splt != NULL && srel != NULL); - - /* Fill in the entry in the procedure linkage table. */ - if (htab->symbian_p) + if (!eh->is_iplt) { - put_arm_insn (htab, output_bfd, - elf32_arm_symbian_plt_entry[0], - splt->contents + h->plt.offset); - bfd_put_32 (output_bfd, - elf32_arm_symbian_plt_entry[1], - splt->contents + h->plt.offset + 4); - - /* Fill in the entry in the .rel.plt section. */ - rel.r_offset = (splt->output_section->vma - + splt->output_offset - + h->plt.offset + 4); - rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT); - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first entry in the procedure linkage table is reserved. */ - plt_index = ((h->plt.offset - htab->plt_header_size) - / htab->plt_entry_size); - } - else - { - bfd_vma got_offset, got_address, plt_address; - bfd_vma got_displacement; - asection * sgot; - bfd_byte * ptr; - - sgot = bfd_get_section_by_name (dynobj, ".got.plt"); - BFD_ASSERT (sgot != NULL); - - /* Get the offset into the .got.plt table of the entry that - corresponds to this function. */ - got_offset = eh->plt_got_offset; - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first three entries in .got.plt are reserved; after that - symbols appear in the same order as in .plt. */ - plt_index = (got_offset - 12) / 4; - - /* Calculate the address of the GOT entry. */ - got_address = (sgot->output_section->vma - + sgot->output_offset - + got_offset); - - /* ...and the address of the PLT entry. */ - plt_address = (splt->output_section->vma - + splt->output_offset - + h->plt.offset); - - ptr = htab->splt->contents + h->plt.offset; - if (htab->vxworks_p && info->shared) - { - unsigned int i; - bfd_vma val; - - for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4) - { - val = elf32_arm_vxworks_shared_plt_entry[i]; - if (i == 2) - val |= got_address - sgot->output_section->vma; - if (i == 5) - val |= plt_index * RELOC_SIZE (htab); - if (i == 2 || i == 5) - bfd_put_32 (output_bfd, val, ptr); - else - put_arm_insn (htab, output_bfd, val, ptr); - } - } - else if (htab->vxworks_p) - { - unsigned int i; - bfd_vma val; - - for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4) - { - val = elf32_arm_vxworks_exec_plt_entry[i]; - if (i == 2) - val |= got_address; - if (i == 4) - val |= 0xffffff & -((h->plt.offset + i * 4 + 8) >> 2); - if (i == 5) - val |= plt_index * RELOC_SIZE (htab); - if (i == 2 || i == 5) - bfd_put_32 (output_bfd, val, ptr); - else - put_arm_insn (htab, output_bfd, val, ptr); - } - - loc = (htab->srelplt2->contents - + (plt_index * 2 + 1) * RELOC_SIZE (htab)); - - /* Create the .rela.plt.unloaded R_ARM_ABS32 relocation - referencing the GOT for this PLT entry. */ - rel.r_offset = plt_address + 8; - rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32); - rel.r_addend = got_offset; - SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); - loc += RELOC_SIZE (htab); - - /* Create the R_ARM_ABS32 relocation referencing the - beginning of the PLT for this GOT entry. */ - rel.r_offset = got_address; - rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_ARM_ABS32); - rel.r_addend = 0; - SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); - } - else - { - bfd_signed_vma thumb_refs; - /* Calculate the displacement between the PLT slot and the - entry in the GOT. The eight-byte offset accounts for the - value produced by adding to pc in the first instruction - of the PLT stub. */ - got_displacement = got_address - (plt_address + 8); - - BFD_ASSERT ((got_displacement & 0xf0000000) == 0); - - thumb_refs = eh->plt_thumb_refcount; - if (!htab->use_blx) - thumb_refs += eh->plt_maybe_thumb_refcount; - - if (thumb_refs > 0) - { - put_thumb_insn (htab, output_bfd, - elf32_arm_plt_thumb_stub[0], ptr - 4); - put_thumb_insn (htab, output_bfd, - elf32_arm_plt_thumb_stub[1], ptr - 2); - } - - put_arm_insn (htab, output_bfd, - elf32_arm_plt_entry[0] - | ((got_displacement & 0x0ff00000) >> 20), - ptr + 0); - put_arm_insn (htab, output_bfd, - elf32_arm_plt_entry[1] - | ((got_displacement & 0x000ff000) >> 12), - ptr+ 4); - put_arm_insn (htab, output_bfd, - elf32_arm_plt_entry[2] - | (got_displacement & 0x00000fff), - ptr + 8); -#ifdef FOUR_WORD_PLT - bfd_put_32 (output_bfd, elf32_arm_plt_entry[3], ptr + 12); -#endif - } - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset), - sgot->contents + got_offset); - - /* Fill in the entry in the .rel(a).plt section. */ - rel.r_addend = 0; - rel.r_offset = got_address; - rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_JUMP_SLOT); + BFD_ASSERT (h->dynindx != -1); + elf32_arm_populate_plt_entry (output_bfd, info, &h->plt, &eh->plt, + h->dynindx, 0); } - loc = srel->contents + plt_index * RELOC_SIZE (htab); - SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); - if (!h->def_regular) { /* Mark the symbol as undefined, rather than as defined in @@ -12364,70 +13712,31 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, if (!h->ref_regular_nonweak) sym->st_value = 0; } - } - - if (h->got.offset != (bfd_vma) -1 - && (elf32_arm_hash_entry (h)->tls_type & GOT_TLS_GD) == 0 - && (elf32_arm_hash_entry (h)->tls_type & GOT_TLS_IE) == 0) - { - asection * sgot; - asection * srel; - Elf_Internal_Rela rel; - bfd_byte *loc; - bfd_vma offset; - - /* This symbol has an entry in the global offset table. Set it - up. */ - sgot = bfd_get_section_by_name (dynobj, ".got"); - srel = bfd_get_section_by_name (dynobj, RELOC_SECTION (htab, ".got")); - BFD_ASSERT (sgot != NULL && srel != NULL); - - offset = (h->got.offset & ~(bfd_vma) 1); - rel.r_addend = 0; - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + offset); - - /* If this is a static link, or it is a -Bsymbolic link and the - symbol is defined locally or was forced to be local because - of a version file, we just want to emit a RELATIVE reloc. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (info->shared - && SYMBOL_REFERENCES_LOCAL (info, h)) - { - BFD_ASSERT ((h->got.offset & 1) != 0); - rel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); - if (!htab->use_rel) - { - rel.r_addend = bfd_get_32 (output_bfd, sgot->contents + offset); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + offset); - } - } - else + else if (eh->is_iplt && eh->plt.noncall_refcount != 0) { - BFD_ASSERT ((h->got.offset & 1) == 0); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + offset); - rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT); + /* At least one non-call relocation references this .iplt entry, + so the .iplt entry is the function's canonical address. */ + sym->st_info = ELF_ST_INFO (ELF_ST_BIND (sym->st_info), STT_FUNC); + sym->st_target_internal = ST_BRANCH_TO_ARM; + sym->st_shndx = (_bfd_elf_section_from_bfd_section + (output_bfd, htab->root.iplt->output_section)); + sym->st_value = (h->plt.offset + + htab->root.iplt->output_section->vma + + htab->root.iplt->output_offset); } - - loc = srel->contents + srel->reloc_count++ * RELOC_SIZE (htab); - SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); } if (h->needs_copy) { asection * s; Elf_Internal_Rela rel; - bfd_byte *loc; /* This symbol needs a copy reloc. Set it up. */ BFD_ASSERT (h->dynindx != -1 && (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak)); - s = bfd_get_section_by_name (h->root.u.def.section->owner, - RELOC_SECTION (htab, ".bss")); + s = htab->srelbss; BFD_ASSERT (s != NULL); rel.r_addend = 0; @@ -12435,8 +13744,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, + h->root.u.def.section->output_section->vma + h->root.u.def.section->output_offset); rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_COPY); - loc = s->contents + s->reloc_count++ * RELOC_SIZE (htab); - SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); + elf32_arm_add_dynreloc (output_bfd, info, s, &rel); } /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. On VxWorks, @@ -12449,6 +13757,24 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, return TRUE; } +static void +arm_put_trampoline (struct elf32_arm_link_hash_table *htab, bfd *output_bfd, + void *contents, + const unsigned long *template, unsigned count) +{ + unsigned ix; + + for (ix = 0; ix != count; ix++) + { + unsigned long insn = template[ix]; + + /* Emit mov pc,rx if bx is not permitted. */ + if (htab->fix_v4bx == 1 && (insn & 0x0ffffff0) == 0x012fff10) + insn = (insn & 0xf000000f) | 0x01a0f000; + put_arm_insn (htab, output_bfd, insn, (char *)contents + ix*4); + } +} + /* Finish up the dynamic sections. */ static bfd_boolean @@ -12465,8 +13791,11 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info dynobj = elf_hash_table (info)->dynobj; - sgot = bfd_get_section_by_name (dynobj, ".got.plt"); - BFD_ASSERT (htab->symbian_p || sgot != NULL); + sgot = htab->root.sgotplt; + /* A broken linker script might have discarded the dynamic sections. + 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"); if (elf_hash_table (info)->dynamic_sections_created) @@ -12474,8 +13803,9 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info asection *splt; Elf32_External_Dyn *dyncon, *dynconend; - splt = bfd_get_section_by_name (dynobj, ".plt"); + splt = htab->root.splt; BFD_ASSERT (splt != NULL && sdyn != NULL); + BFD_ASSERT (htab->symbian_p || sgot != NULL); dyncon = (Elf32_External_Dyn *) sdyn->contents; dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); @@ -12541,8 +13871,7 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info break; case DT_PLTRELSZ: - s = bfd_get_section_by_name (output_bfd, - RELOC_SECTION (htab, ".plt")); + s = htab->root.srelplt; BFD_ASSERT (s != NULL); dyn.d_un.d_val = s->size; bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); @@ -12561,8 +13890,7 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info the linker script arranges for .rel(a).plt to follow all other relocation sections, we don't have to worry about changing the DT_REL entry. */ - s = bfd_get_section_by_name (output_bfd, - RELOC_SECTION (htab, ".plt")); + s = htab->root.srelplt; if (s != NULL) dyn.d_un.d_val -= s->size; bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); @@ -12604,6 +13932,20 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info } break; + case DT_TLSDESC_PLT: + s = htab->root.splt; + dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset + + htab->dt_tlsdesc_plt); + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_TLSDESC_GOT: + s = htab->root.sgot; + dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset + + htab->dt_tlsdesc_got); + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + /* Set the bottom bit of DT_INIT/FINI if the corresponding function is Thumb. */ case DT_INIT: @@ -12620,8 +13962,7 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info eh = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, TRUE); - if (eh != NULL - && ELF_ST_TYPE (eh->type) == STT_ARM_TFUNC) + if (eh != NULL && eh->target_internal == ST_BRANCH_TO_THUMB) { dyn.d_un.d_val |= 1; bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); @@ -12693,14 +14034,49 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info if (splt->output_section->owner == output_bfd) elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; - if (htab->vxworks_p && !info->shared && htab->splt->size > 0) + if (htab->dt_tlsdesc_plt) + { + bfd_vma got_address + = sgot->output_section->vma + sgot->output_offset; + bfd_vma gotplt_address = (htab->root.sgot->output_section->vma + + htab->root.sgot->output_offset); + bfd_vma plt_address + = splt->output_section->vma + splt->output_offset; + + arm_put_trampoline (htab, output_bfd, + splt->contents + htab->dt_tlsdesc_plt, + dl_tlsdesc_lazy_trampoline, 6); + + bfd_put_32 (output_bfd, + gotplt_address + htab->dt_tlsdesc_got + - (plt_address + htab->dt_tlsdesc_plt) + - dl_tlsdesc_lazy_trampoline[6], + splt->contents + htab->dt_tlsdesc_plt + 24); + bfd_put_32 (output_bfd, + got_address - (plt_address + htab->dt_tlsdesc_plt) + - dl_tlsdesc_lazy_trampoline[7], + splt->contents + htab->dt_tlsdesc_plt + 24 + 4); + } + + if (htab->tls_trampoline) + { + 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 + } + + if (htab->vxworks_p && !info->shared && htab->root.splt->size > 0) { /* Correct the .rel(a).plt.unloaded relocations. They will have incorrect symbol indexes. */ int num_plts; unsigned char *p; - num_plts = ((htab->splt->size - htab->plt_header_size) + num_plts = ((htab->root.splt->size - htab->plt_header_size) / htab->plt_entry_size); p = htab->srelplt2->contents + RELOC_SIZE (htab); @@ -12780,17 +14156,6 @@ elf32_arm_reloc_type_class (const Elf_Internal_Rela *rela) } } -/* Set the right machine number for an Arm ELF file. */ - -static bfd_boolean -elf32_arm_section_flags (flagword *flags, const Elf_Internal_Shdr *hdr) -{ - if (hdr->sh_type == SHT_NOTE) - *flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_CONTENTS; - - return TRUE; -} - static void elf32_arm_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) { @@ -12901,39 +14266,44 @@ elf32_arm_output_map_sym (output_arch_syminfo *osi, sym.st_other = 0; sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE); 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; } - -/* Output mapping symbols for PLT entries associated with H. */ +/* Output mapping symbols for the PLT entry described by ROOT_PLT and ARM_PLT. + IS_IPLT_ENTRY_P says whether the PLT is in .iplt rather than .plt. */ static bfd_boolean -elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf) +elf32_arm_output_plt_map_1 (output_arch_syminfo *osi, + bfd_boolean is_iplt_entry_p, + union gotplt_union *root_plt, + struct arm_plt_info *arm_plt) { - output_arch_syminfo *osi = (output_arch_syminfo *) inf; struct elf32_arm_link_hash_table *htab; - struct elf32_arm_link_hash_entry *eh; - bfd_vma addr; + bfd_vma addr, plt_header_size; - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - if (h->root.type == bfd_link_hash_warning) - /* When warning symbols are created, they **replace** the "real" - entry in the hash table, thus we never get to see the real - symbol in a hash traversal. So look at it now. */ - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - if (h->plt.offset == (bfd_vma) -1) + if (root_plt->offset == (bfd_vma) -1) return TRUE; htab = elf32_arm_hash_table (osi->info); if (htab == NULL) return FALSE; - eh = (struct elf32_arm_link_hash_entry *) h; - addr = h->plt.offset; + if (is_iplt_entry_p) + { + osi->sec = htab->root.iplt; + plt_header_size = 0; + } + else + { + osi->sec = htab->root.splt; + plt_header_size = htab->plt_header_size; + } + osi->sec_shndx = (_bfd_elf_section_from_bfd_section + (osi->info->output_bfd, osi->sec->output_section)); + + addr = root_plt->offset & -2; if (htab->symbian_p) { if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) @@ -12954,13 +14324,10 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf) } else { - bfd_signed_vma thumb_refs; - - thumb_refs = eh->plt_thumb_refcount; - if (!htab->use_blx) - thumb_refs += eh->plt_maybe_thumb_refcount; + bfd_boolean thumb_stub_p; - if (thumb_refs > 0) + thumb_stub_p = elf32_arm_plt_needs_thumb_stub_p (osi->info, arm_plt); + if (thumb_stub_p) { if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr - 4)) return FALSE; @@ -12974,7 +14341,7 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf) /* A three-word PLT with no Thumb thunk contains only Arm code, so only need to output a mapping symbol for the first PLT entry and entries with thumb thunks. */ - if (thumb_refs > 0 || addr == 20) + if (thumb_stub_p || addr == plt_header_size) { if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) return FALSE; @@ -12985,6 +14352,28 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf) return TRUE; } +/* Output mapping symbols for PLT entries associated with H. */ + +static bfd_boolean +elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf) +{ + output_arch_syminfo *osi = (output_arch_syminfo *) inf; + struct elf32_arm_link_hash_entry *eh; + + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + if (h->root.type == bfd_link_hash_warning) + /* When warning symbols are created, they **replace** the "real" + entry in the hash table, thus we never get to see the real + symbol in a hash traversal. So look at it now. */ + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + eh = (struct elf32_arm_link_hash_entry *) h; + return elf32_arm_output_plt_map_1 (osi, SYMBOL_CALLS_LOCAL (osi->info, h), + &h->plt, &eh->plt); +} + /* Output a single local symbol for a generated stub. */ static bfd_boolean @@ -13000,6 +14389,7 @@ elf32_arm_output_stub_sym (output_arch_syminfo *osi, const char *name, sym.st_other = 0; 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; } @@ -13008,7 +14398,6 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, void * in_arg) { struct elf32_arm_stub_hash_entry *stub_entry; - struct bfd_link_info *info; asection *stub_sec; bfd_vma addr; char *stub_name; @@ -13023,8 +14412,6 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; osi = (output_arch_syminfo *) in_arg; - info = osi->info; - stub_sec = stub_entry->stub_sec; /* Ensure this stub is attached to the current section being @@ -13156,7 +14543,8 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, == SEC_HAS_CONTENTS && get_arm_elf_section_data (osi.sec) != NULL && get_arm_elf_section_data (osi.sec)->mapcount == 0 - && osi.sec->size > 0) + && osi.sec->size > 0 + && (osi.sec->flags & SEC_EXCLUDE) == 0) { osi.sec_shndx = _bfd_elf_section_from_bfd_section (output_bfd, osi.sec->output_section); @@ -13241,36 +14629,81 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, } /* Finally, output mapping symbols for the PLT. */ - if (!htab->splt || htab->splt->size == 0) - return TRUE; - - osi.sec_shndx = _bfd_elf_section_from_bfd_section (output_bfd, - htab->splt->output_section); - osi.sec = htab->splt; - /* Output mapping symbols for the plt header. SymbianOS does not have a - plt header. */ - if (htab->vxworks_p) + if (htab->root.splt && htab->root.splt->size > 0) { - /* VxWorks shared libraries have no PLT header. */ - if (!info->shared) + osi.sec = htab->root.splt; + osi.sec_shndx = (_bfd_elf_section_from_bfd_section + (output_bfd, osi.sec->output_section)); + + /* Output mapping symbols for the plt header. SymbianOS does not have a + plt header. */ + if (htab->vxworks_p) + { + /* VxWorks shared libraries have no PLT header. */ + if (!info->shared) + { + if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) + return FALSE; + if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 12)) + return FALSE; + } + } + else if (!htab->symbian_p) { if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) return FALSE; - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 12)) +#ifndef FOUR_WORD_PLT + if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 16)) return FALSE; +#endif + } + } + if ((htab->root.splt && htab->root.splt->size > 0) + || (htab->root.iplt && htab->root.iplt->size > 0)) + { + elf_link_hash_traverse (&htab->root, elf32_arm_output_plt_map, &osi); + for (input_bfd = info->input_bfds; + input_bfd != NULL; + input_bfd = input_bfd->link_next) + { + struct arm_local_iplt_info **local_iplt; + unsigned int i, num_syms; + + local_iplt = elf32_arm_local_iplt (input_bfd); + if (local_iplt != NULL) + { + num_syms = elf_symtab_hdr (input_bfd).sh_info; + for (i = 0; i < num_syms; i++) + if (local_iplt[i] != NULL + && !elf32_arm_output_plt_map_1 (&osi, TRUE, + &local_iplt[i]->root, + &local_iplt[i]->arm)) + return FALSE; + } } } - else if (!htab->symbian_p) + if (htab->dt_tlsdesc_plt != 0) { - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) + /* Mapping symbols for the lazy tls trampoline. */ + if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, htab->dt_tlsdesc_plt)) return FALSE; -#ifndef FOUR_WORD_PLT - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 16)) + + if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, + htab->dt_tlsdesc_plt + 24)) return FALSE; -#endif } - - elf_link_hash_traverse (&htab->root, elf32_arm_output_plt_map, (void *) &osi); + if (htab->tls_trampoline != 0) + { + /* Mapping symbols for the tls trampoline. */ + if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, htab->tls_trampoline)) + return FALSE; +#ifdef FOUR_WORD_PLT + if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, + htab->tls_trampoline + 12)) + return FALSE; +#endif + } + return TRUE; } @@ -13375,7 +14808,7 @@ make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry, data = (struct a8_branch_to_stub_data *) in_arg; if (stub_entry->target_section != data->writing_section - || stub_entry->stub_type < arm_stub_a8_veneer_b_cond) + || stub_entry->stub_type < arm_stub_a8_veneer_lwm) return TRUE; contents = data->contents; @@ -13727,19 +15160,6 @@ elf32_arm_write_section (bfd *output_bfd, return FALSE; } -/* Display STT_ARM_TFUNC symbols as functions. */ - -static void -elf32_arm_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, - asymbol *asym) -{ - elf_symbol_type *elfsym = (elf_symbol_type *) asym; - - if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_ARM_TFUNC) - elfsym->symbol.flags |= BSF_FUNCTION; -} - - /* Mangle thumb function symbols as we read them in. */ static bfd_boolean @@ -13752,13 +15172,28 @@ elf32_arm_swap_symbol_in (bfd * abfd, return FALSE; /* New EABI objects mark thumb function symbols by setting the low bit of - the address. Turn these into STT_ARM_TFUNC. */ - if ((ELF_ST_TYPE (dst->st_info) == STT_FUNC) - && (dst->st_value & 1)) + the address. */ + if (ELF_ST_TYPE (dst->st_info) == STT_FUNC + || ELF_ST_TYPE (dst->st_info) == STT_GNU_IFUNC) + { + if (dst->st_value & 1) + { + dst->st_value &= ~(bfd_vma) 1; + dst->st_target_internal = ST_BRANCH_TO_THUMB; + } + else + dst->st_target_internal = ST_BRANCH_TO_ARM; + } + else if (ELF_ST_TYPE (dst->st_info) == STT_ARM_TFUNC) { - dst->st_info = ELF_ST_INFO (ELF_ST_BIND (dst->st_info), STT_ARM_TFUNC); - dst->st_value &= ~(bfd_vma) 1; + dst->st_info = ELF_ST_INFO (ELF_ST_BIND (dst->st_info), STT_FUNC); + dst->st_target_internal = ST_BRANCH_TO_THUMB; } + else if (ELF_ST_TYPE (dst->st_info) == STT_SECTION) + dst->st_target_internal = ST_BRANCH_LONG; + else + dst->st_target_internal = ST_BRANCH_UNKNOWN; + return TRUE; } @@ -13777,10 +15212,11 @@ elf32_arm_swap_symbol_out (bfd *abfd, of the address set, as per the new EABI. We do this unconditionally because objcopy does not set the elf header flags until after it writes out the symbol table. */ - if (ELF_ST_TYPE (src->st_info) == STT_ARM_TFUNC) + if (src->st_target_internal == ST_BRANCH_TO_THUMB) { newsym = *src; - newsym.st_info = ELF_ST_INFO (ELF_ST_BIND (src->st_info), STT_FUNC); + if (ELF_ST_TYPE (src->st_info) != STT_GNU_IFUNC) + newsym.st_info = ELF_ST_INFO (ELF_ST_BIND (src->st_info), STT_FUNC); if (newsym.st_shndx != SHN_UNDEF) { /* Do this only for defined symbols. At link type, the static @@ -13850,12 +15286,25 @@ elf32_arm_additional_program_headers (bfd *abfd, return 0; } -/* We have two function types: STT_FUNC and STT_ARM_TFUNC. */ +/* Hook called by the linker routine which adds symbols from an object + file. */ static bfd_boolean -elf32_arm_is_function_type (unsigned int type) -{ - return (type == STT_FUNC) || (type == STT_ARM_TFUNC); +elf32_arm_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, + Elf_Internal_Sym *sym, const char **namep, + flagword *flagsp, asection **secp, bfd_vma *valp) +{ + if ((abfd->flags & DYNAMIC) == 0 + && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC + || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)) + elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; + + if (elf32_arm_hash_table (info)->vxworks_p + && !elf_vxworks_add_symbol_hook (abfd, info, sym, namep, + flagsp, secp, valp)) + return FALSE; + + return TRUE; } /* We use this to override swap_symbol_in and swap_symbol_out. */ @@ -13890,6 +15339,7 @@ const struct elf_size_info elf32_arm_size_info = }; #define ELF_ARCH bfd_arch_arm +#define ELF_TARGET_ID ARM_ELF_DATA #define ELF_MACHINE_CODE EM_ARM #ifdef __QNXTARGET__ #define ELF_MAXPAGESIZE 0x1000 @@ -13927,22 +15377,21 @@ const struct elf_size_info elf32_arm_size_info = #define elf_backend_finish_dynamic_symbol elf32_arm_finish_dynamic_symbol #define elf_backend_finish_dynamic_sections elf32_arm_finish_dynamic_sections #define elf_backend_size_dynamic_sections elf32_arm_size_dynamic_sections +#define elf_backend_always_size_sections elf32_arm_always_size_sections #define elf_backend_init_index_section _bfd_elf_init_2_index_sections #define elf_backend_post_process_headers elf32_arm_post_process_headers #define elf_backend_reloc_type_class elf32_arm_reloc_type_class #define elf_backend_object_p elf32_arm_object_p -#define elf_backend_section_flags elf32_arm_section_flags #define elf_backend_fake_sections elf32_arm_fake_sections #define elf_backend_section_from_shdr elf32_arm_section_from_shdr #define elf_backend_final_write_processing elf32_arm_final_write_processing #define elf_backend_copy_indirect_symbol elf32_arm_copy_indirect_symbol -#define elf_backend_symbol_processing elf32_arm_symbol_processing #define elf_backend_size_info elf32_arm_size_info #define elf_backend_modify_segment_map elf32_arm_modify_segment_map #define elf_backend_additional_program_headers elf32_arm_additional_program_headers #define elf_backend_output_arch_local_syms elf32_arm_output_arch_local_syms #define elf_backend_begin_write_processing elf32_arm_begin_write_processing -#define elf_backend_is_function_type elf32_arm_is_function_type +#define elf_backend_add_symbol_hook elf32_arm_add_symbol_hook #define elf_backend_can_refcount 1 #define elf_backend_can_gc_sections 1 @@ -13964,6 +15413,7 @@ const struct elf_size_info elf32_arm_size_info = #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 #include "elf32-target.h" @@ -14009,8 +15459,6 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) #undef bfd_elf32_bfd_link_hash_table_create #define bfd_elf32_bfd_link_hash_table_create elf32_arm_vxworks_link_hash_table_create -#undef elf_backend_add_symbol_hook -#define elf_backend_add_symbol_hook elf_vxworks_add_symbol_hook #undef elf_backend_final_write_processing #define elf_backend_final_write_processing elf32_arm_vxworks_final_write_processing #undef elf_backend_emit_relocs @@ -14041,7 +15489,7 @@ elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd) bfd_boolean flags_compatible = TRUE; asection *sec; - /* Check if we have the same endianess. */ + /* Check if we have the same endianness. */ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) return FALSE; @@ -14378,7 +15826,6 @@ elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt, #define ELF_DYNAMIC_SEC_FLAGS \ (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED) -#undef elf_backend_add_symbol_hook #undef elf_backend_emit_relocs #undef bfd_elf32_bfd_link_hash_table_create