X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-ppc.c;h=eb8ba62557bcdf85c783311f894d30eeb7a9f4cb;hb=dcd2b8a0144f4f5f81887861542609ef858a28c9;hp=6d8b5020f54ff96e4854a724627dc4627b071644;hpb=676ee2b5fa6ae41342a9fcd2b7ca18693fa0535b;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 6d8b5020f5..eb8ba62557 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -134,7 +134,7 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry #define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3 /* The number of relocations in the PLTResolve slot. */ #define VXWORKS_PLTRESOLVE_RELOCS 2 -/* The number of relocations in the PLTResolve slot when when creating +/* The number of relocations in the PLTResolve slot when creating a shared library. */ #define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0 @@ -1656,6 +1656,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0x3e007ff, /* dst_mask */ FALSE), /* pcrel_offset */ + /* e_li split20 format. */ + HOWTO (R_PPC_VLE_ADDR20, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_VLE_ADDR20", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1f07ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_PPC_IRELATIVE, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ @@ -3192,9 +3207,9 @@ struct plt_entry bfd_vma glink_offset; }; -/* Of those relocs that might be copied as dynamic relocs, this function - selects those that must be copied when linking a shared library, - even when the symbol is local. */ +/* Of those relocs that might be copied as dynamic relocs, this + function selects those that must be copied when linking a shared + library or PIE, even when the symbol is local. */ static int must_be_dyn_reloc (struct bfd_link_info *info, @@ -3203,6 +3218,10 @@ must_be_dyn_reloc (struct bfd_link_info *info, switch (r_type) { default: + /* Only relative relocs can be resolved when the object load + address isn't fixed. DTPREL32 is excluded because the + dynamic linker needs to differentiate global dynamic from + local dynamic __tls_index pairs when PPC_OPT_TLS is set. */ return 1; case R_PPC_REL24: @@ -3217,7 +3236,9 @@ must_be_dyn_reloc (struct bfd_link_info *info, case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: case R_PPC_TPREL16_HA: - return !bfd_link_executable (info); + /* These relocations are relative but in a shared library the + linker doesn't know the thread pointer base. */ + return bfd_link_dll (info); } } @@ -3339,6 +3360,9 @@ struct ppc_elf_link_hash_table unsigned int local_ifunc_resolver:1; unsigned int maybe_local_ifunc_resolver:1; + /* Set if tls optimization is enabled. */ + unsigned int do_tls_opt:1; + /* The size of PLT entries. */ int plt_entry_size; /* The distance between adjacent PLT slots. */ @@ -4151,7 +4175,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_GOT_TPREL16_LO: case R_PPC_GOT_TPREL16_HI: case R_PPC_GOT_TPREL16_HA: - if (bfd_link_pic (info)) + if (bfd_link_dll (info)) info->flags |= DF_STATIC_TLS; tls_type = TLS_TLS | TLS_TPREL; goto dogottls; @@ -4259,6 +4283,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_VLE_HI16D: case R_PPC_VLE_HA16A: case R_PPC_VLE_HA16D: + case R_PPC_VLE_ADDR20: break; case R_PPC_EMB_SDA2REL: @@ -4430,13 +4455,13 @@ ppc_elf_check_relocs (bfd *abfd, return FALSE; break; - /* We shouldn't really be seeing these. */ + /* We shouldn't really be seeing TPREL32. */ case R_PPC_TPREL32: case R_PPC_TPREL16: case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: case R_PPC_TPREL16_HA: - if (bfd_link_pic (info)) + if (bfd_link_dll (info)) info->flags |= DF_STATIC_TLS; goto dodyn; @@ -4977,6 +5002,23 @@ ppc_elf_vle_split16 (bfd *input_bfd, insn |= value & 0x7ff; bfd_put_32 (input_bfd, insn, loc); } + +static void +ppc_elf_vle_split20 (bfd *output_bfd, bfd_byte *loc, bfd_vma value) +{ + unsigned int insn; + + insn = bfd_get_32 (output_bfd, loc); + /* We have an li20 field, bits 17..20, 11..15, 21..31. */ + /* Top 4 bits of value to 17..20. */ + insn |= (value & 0xf0000) >> 5; + /* Next 5 bits of the value to 11..15. */ + insn |= (value & 0xf800) << 5; + /* And the final 11 bits of the value to bits 21 to 31. */ + insn |= value & 0x7ff; + bfd_put_32 (output_bfd, insn, loc); +} + /* Choose which PLT scheme to use, and set .plt flags appropriately. Returns -1 on error, 0 for old PLT, 1 for new PLT. */ @@ -5625,6 +5667,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, symtab_hdr->contents = (unsigned char *) locsyms; } } + htab->do_tls_opt = 1; return TRUE; } @@ -5942,17 +5985,18 @@ allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need) return where; } -/* If H is undefined weak, make it dynamic if that makes sense. */ +/* If H is undefined, make it dynamic if that makes sense. */ static bfd_boolean -ensure_undefweak_dynamic (struct bfd_link_info *info, - struct elf_link_hash_entry *h) +ensure_undef_dynamic (struct bfd_link_info *info, + struct elf_link_hash_entry *h) { struct elf_link_hash_table *htab = elf_hash_table (info); if (htab->dynamic_sections_created - && info->dynamic_undefined_weak != 0 - && h->root.type == bfd_link_hash_undefweak + && ((info->dynamic_undefined_weak != 0 + && h->root.type == bfd_link_hash_undefweak) + || h->root.type == bfd_link_hash_undefined) && h->dynindx == -1 && !h->forced_local && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) @@ -5986,9 +6030,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { unsigned int need; - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (!ensure_undefweak_dynamic (info, &eh->elf)) + /* Make sure this symbol is output as a dynamic symbol. */ + if (!ensure_undef_dynamic (info, &eh->elf)) return FALSE; need = 0; @@ -6102,9 +6145,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (eh->dyn_relocs != NULL) { - /* Make sure undefined weak symbols are output as a dynamic - symbol in PIEs. */ - if (!ensure_undefweak_dynamic (info, h)) + /* Make sure this symbol is output as a dynamic symbol. */ + if (!ensure_undef_dynamic (info, h)) return FALSE; } } @@ -6120,9 +6162,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) && eh->has_addr16_lo && htab->params->pic_fixup > 0)) { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (!ensure_undefweak_dynamic (info, h)) + /* Make sure this symbol is output as a dynamic symbol. */ + if (!ensure_undef_dynamic (info, h)) return FALSE; if (h->dynindx == -1) @@ -7910,7 +7951,7 @@ ppc_elf_relocate_section (bfd *output_bfd, wrel->r_addend = 0; /* For ld -r, remove relocations in debug sections against - sections defined in discarded sections. Not done for + symbols defined in discarded sections. Not done for non-debug to preserve relocs in .eh_frame which the eh_frame editing code expects to be present. */ if (bfd_link_relocatable (info) @@ -8422,10 +8463,44 @@ ppc_elf_relocate_section (bfd *output_bfd, } addend = rel->r_addend; - tls_type = 0; howto = NULL; if (r_type < R_PPC_max) howto = ppc_elf_howto_table[r_type]; + + switch (r_type) + { + default: + break; + + case R_PPC_TPREL16_HA: + if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) + { + bfd_byte *p = contents + (rel->r_offset & ~3); + unsigned int insn = bfd_get_32 (input_bfd, p); + if ((insn & ((0x3f << 26) | 0x1f << 16)) + != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */) + /* xgettext:c-format */ + info->callbacks->minfo + (_("%H: warning: %s unexpected insn %#x.\n"), + input_bfd, input_section, rel->r_offset, howto->name, insn); + else + bfd_put_32 (input_bfd, NOP, p); + } + break; + + case R_PPC_TPREL16_LO: + if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) + { + bfd_byte *p = contents + (rel->r_offset & ~3); + unsigned int insn = bfd_get_32 (input_bfd, p); + insn &= ~(0x1f << 16); + insn |= 2 << 16; + bfd_put_32 (input_bfd, insn, p); + } + break; + } + + tls_type = 0; switch (r_type) { default: @@ -8785,8 +8860,8 @@ ppc_elf_relocate_section (bfd *output_bfd, if (htab->elf.tls_sec != NULL) addend -= htab->elf.tls_sec->vma + TP_OFFSET; /* The TPREL16 relocs shouldn't really be used in shared - libs as they will result in DT_TEXTREL being set, but - support them anyway. */ + libs or with non-local symbols as that will result in + DT_TEXTREL being set, but support them anyway. */ goto dodyn; case R_PPC_TPREL32: @@ -9470,6 +9545,10 @@ ppc_elf_relocate_section (bfd *output_bfd, } goto copy_reloc; + case R_PPC_VLE_ADDR20: + ppc_elf_vle_split20 (output_bfd, contents + rel->r_offset, relocation); + continue; + /* Relocate against the beginning of the section. */ case R_PPC_SECTOFF: case R_PPC_SECTOFF_LO: