X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bfd%2Felf64-ppc.c;h=0245a2c72e109bbf3c2e1e209d78a54c804cdc2a;hb=eab942c64fca084366c2a37a44121966ad225e1d;hp=63d4eb99a85c90fb5efd290faff7083e6b9fb9c7;hpb=f9c6b9078c54ea0f018b673e2ff128e61a0aa666;p=platform%2Fupstream%2Fbinutils.git diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 63d4eb9..0245a2c 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -1,6 +1,5 @@ /* PowerPC64-specific support for 64-bit ELF. - Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2010, 2011, 2012 Free Software Foundation, Inc. + Copyright (C) 1999-2014 Free Software Foundation, Inc. Written by Linus Nordberg, Swox AB , based on elf32-ppc.c by Ian Lance Taylor. Largely rewritten by Alan Modra. @@ -57,9 +56,9 @@ static bfd_reloc_status_type ppc64_elf_unhandled_reloc static bfd_vma opd_entry_value (asection *, bfd_vma, asection **, bfd_vma *, bfd_boolean); -#define TARGET_LITTLE_SYM bfd_elf64_powerpcle_vec +#define TARGET_LITTLE_SYM powerpc_elf64_le_vec #define TARGET_LITTLE_NAME "elf64-powerpcle" -#define TARGET_BIG_SYM bfd_elf64_powerpc_vec +#define TARGET_BIG_SYM powerpc_elf64_vec #define TARGET_BIG_NAME "elf64-powerpc" #define ELF_ARCH bfd_arch_powerpc #define ELF_TARGET_ID PPC64_ELF_DATA @@ -81,10 +80,10 @@ static bfd_vma opd_entry_value #define bfd_elf64_mkobject ppc64_elf_mkobject #define bfd_elf64_bfd_reloc_type_lookup ppc64_elf_reloc_type_lookup #define bfd_elf64_bfd_reloc_name_lookup ppc64_elf_reloc_name_lookup -#define bfd_elf64_bfd_merge_private_bfd_data _bfd_generic_verify_endian_match +#define bfd_elf64_bfd_merge_private_bfd_data ppc64_elf_merge_private_bfd_data +#define bfd_elf64_bfd_print_private_bfd_data ppc64_elf_print_private_bfd_data #define bfd_elf64_new_section_hook ppc64_elf_new_section_hook #define bfd_elf64_bfd_link_hash_table_create ppc64_elf_link_hash_table_create -#define bfd_elf64_bfd_link_hash_table_free ppc64_elf_link_hash_table_free #define bfd_elf64_get_synthetic_symtab ppc64_elf_get_synthetic_symtab #define bfd_elf64_bfd_link_just_syms ppc64_elf_link_just_syms @@ -95,7 +94,7 @@ static bfd_vma opd_entry_value #define elf_backend_create_dynamic_sections ppc64_elf_create_dynamic_sections #define elf_backend_copy_indirect_symbol ppc64_elf_copy_indirect_symbol #define elf_backend_add_symbol_hook ppc64_elf_add_symbol_hook -#define elf_backend_check_directives ppc64_elf_process_dot_syms +#define elf_backend_check_directives ppc64_elf_before_check_relocs #define elf_backend_notice_as_needed ppc64_elf_notice_as_needed #define elf_backend_archive_symbol_lookup ppc64_elf_archive_symbol_lookup #define elf_backend_check_relocs ppc64_elf_check_relocs @@ -108,6 +107,7 @@ static bfd_vma opd_entry_value #define elf_backend_maybe_function_sym ppc64_elf_maybe_function_sym #define elf_backend_always_size_sections ppc64_elf_func_desc_adjust #define elf_backend_size_dynamic_sections ppc64_elf_size_dynamic_sections +#define elf_backend_hash_symbol ppc64_elf_hash_symbol #define elf_backend_init_index_section _bfd_elf_init_2_index_sections #define elf_backend_action_discarded ppc64_elf_action_discarded #define elf_backend_relocate_section ppc64_elf_relocate_section @@ -116,17 +116,25 @@ static bfd_vma opd_entry_value #define elf_backend_finish_dynamic_sections ppc64_elf_finish_dynamic_sections #define elf_backend_link_output_symbol_hook ppc64_elf_output_symbol_hook #define elf_backend_special_sections ppc64_elf_special_sections -#define elf_backend_post_process_headers _bfd_elf_set_osabi +#define elf_backend_merge_symbol_attribute ppc64_elf_merge_symbol_attribute /* The name of the dynamic interpreter. This is put in the .interp section. */ #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" /* The size in bytes of an entry in the procedure linkage table. */ -#define PLT_ENTRY_SIZE 24 +#define PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 8) /* The initial size of the plt reserved for the dynamic linker. */ -#define PLT_INITIAL_ENTRY_SIZE PLT_ENTRY_SIZE +#define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16) + +/* Offsets to some stack save slots. */ +#define STK_LR 16 +#define STK_TOC(htab) (htab->opd_abi ? 40 : 24) +/* This one is dodgy. ELFv2 does not have a linker word, so use the + CR save slot. Used only by optimised __tls_get_addr call stub, + relying on __tls_get_addr_opt not saving CR.. */ +#define STK_LINKER(htab) (htab->opd_abi ? 32 : 8) /* TOC base pointers offset from start of TOC. */ #define TOC_BASE_OFF 0x8000 @@ -137,33 +145,36 @@ static bfd_vma opd_entry_value /* .plt call stub instructions. The normal stub is like this, but sometimes the .plt entry crosses a 64k boundary and we need to - insert an addi to adjust r12. */ -#define PLT_CALL_STUB_SIZE (7*4) -#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ -#define STD_R2_40R1 0xf8410028 /* std %r2,40(%r1) */ -#define LD_R11_0R12 0xe96c0000 /* ld %r11,xxx+0@l(%r12) */ -#define MTCTR_R11 0x7d6903a6 /* mtctr %r11 */ -#define LD_R2_0R12 0xe84c0000 /* ld %r2,xxx+8@l(%r12) */ - /* ld %r11,xxx+16@l(%r12) */ + insert an addi to adjust r11. */ +#define STD_R2_0R1 0xf8410000 /* std %r2,0+40(%r1) */ +#define ADDIS_R11_R2 0x3d620000 /* addis %r11,%r2,xxx@ha */ +#define LD_R12_0R11 0xe98b0000 /* ld %r12,xxx+0@l(%r11) */ +#define MTCTR_R12 0x7d8903a6 /* mtctr %r12 */ +#define LD_R2_0R11 0xe84b0000 /* ld %r2,xxx+8@l(%r11) */ +#define LD_R11_0R11 0xe96b0000 /* ld %r11,xxx+16@l(%r11) */ #define BCTR 0x4e800420 /* bctr */ - -#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,off@ha */ -#define ADDI_R12_R12 0x398c0000 /* addi %r12,%r12,off@l */ +#define ADDI_R11_R11 0x396b0000 /* addi %r11,%r11,off@l */ #define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */ #define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */ -#define XOR_R11_R11_R11 0x7d6b5a78 /* xor %r11,%r11,%r11 */ -#define ADD_R12_R12_R11 0x7d8c5a14 /* add %r12,%r12,%r11 */ +#define XOR_R2_R12_R12 0x7d826278 /* xor %r2,%r12,%r12 */ +#define ADD_R11_R11_R2 0x7d6b1214 /* add %r11,%r11,%r2 */ +#define XOR_R11_R12_R12 0x7d8b6278 /* xor %r11,%r12,%r12 */ #define ADD_R2_R2_R11 0x7c425a14 /* add %r2,%r2,%r11 */ #define CMPLDI_R2_0 0x28220000 /* cmpldi %r2,0 */ #define BNECTR 0x4ca20420 /* bnectr+ */ #define BNECTR_P4 0x4ce20420 /* bnectr+ */ +#define LD_R12_0R2 0xe9820000 /* ld %r12,xxx+0(%r2) */ #define LD_R11_0R2 0xe9620000 /* ld %r11,xxx+0(%r2) */ #define LD_R2_0R2 0xe8420000 /* ld %r2,xxx+0(%r2) */ -#define LD_R2_40R1 0xe8410028 /* ld %r2,40(%r1) */ +#define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */ + +#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ +#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */ +#define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */ /* glink call stub instructions. We enter with the index in R0. */ #define GLINK_CALL_STUB_SIZE (16*4) @@ -174,14 +185,19 @@ static bfd_vma opd_entry_value #define BCL_20_31 0x429f0005 /* bcl 20,31,1f */ /* 1: */ #define MFLR_R11 0x7d6802a6 /* mflr %11 */ -#define LD_R2_M16R11 0xe84bfff0 /* ld %2,(0b-1b)(%11) */ + /* ld %2,(0b-1b)(%11) */ #define MTLR_R12 0x7d8803a6 /* mtlr %12 */ -#define ADD_R12_R2_R11 0x7d825a14 /* add %12,%2,%11 */ - /* ld %11,0(%12) */ - /* ld %2,8(%12) */ - /* mtctr %11 */ - /* ld %11,16(%12) */ +#define ADD_R11_R2_R11 0x7d625a14 /* add %11,%2,%11 */ + /* ld %12,0(%11) */ + /* ld %2,8(%11) */ + /* mtctr %12 */ + /* ld %11,16(%11) */ /* bctr */ +#define MFLR_R0 0x7c0802a6 /* mflr %r0 */ +#define MTLR_R0 0x7c0803a6 /* mtlr %r0 */ +#define SUB_R12_R12_R11 0x7d8b6050 /* subf %r12,%r11,%r12 */ +#define ADDI_R0_R12 0x380c0000 /* addi %r0,%r12,0 */ +#define SRDI_R0_R0_2 0x7800f082 /* rldicl %r0,%r0,62,2 */ /* Pad with this. */ #define NOP 0x60000000 @@ -219,6 +235,19 @@ static bfd_vma opd_entry_value #ifndef NO_OPD_RELOCS #define NO_OPD_RELOCS 0 #endif + +static inline int +abiversion (bfd *abfd) +{ + return elf_elfheader (abfd)->e_flags & EF_PPC64_ABI; +} + +static inline void +set_abiversion (bfd *abfd, int ver) +{ + elf_elfheader (abfd)->e_flags &= ~EF_PPC64_ABI; + elf_elfheader (abfd)->e_flags |= ver & EF_PPC64_ABI; +} #define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1) @@ -341,7 +370,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_branch_reloc, /* special_function */ "R_PPC64_ADDR14", /* name */ FALSE, /* partial_inplace */ @@ -358,7 +387,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_brtaken_reloc, /* special_function */ "R_PPC64_ADDR14_BRTAKEN",/* name */ FALSE, /* partial_inplace */ @@ -375,7 +404,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_brtaken_reloc, /* special_function */ "R_PPC64_ADDR14_BRNTAKEN",/* name */ FALSE, /* partial_inplace */ @@ -616,7 +645,6 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 32, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - /* FIXME: Verify. Was complain_overflow_bitfield. */ complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC64_REL32", /* name */ @@ -711,7 +739,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_sectoff_reloc, /* special_function */ "R_PPC64_SECTOFF", /* name */ FALSE, /* partial_inplace */ @@ -999,7 +1027,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 64, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ ppc64_elf_toc64_reloc, /* special_function */ "R_PPC64_TOC", /* name */ FALSE, /* partial_inplace */ @@ -1087,7 +1115,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC64_ADDR16_DS", /* name */ FALSE, /* partial_inplace */ @@ -1162,7 +1190,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_sectoff_reloc, /* special_function */ "R_PPC64_SECTOFF_DS", /* name */ FALSE, /* partial_inplace */ @@ -1934,7 +1962,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC64_REL16", /* name */ FALSE, /* partial_inplace */ @@ -2078,6 +2106,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ + /* Like ADDR64, but use local entry point of function. */ + HOWTO (R_PPC64_ADDR64_LOCAL, /* type */ + 0, /* rightshift */ + 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ + 64, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC64_ADDR64_LOCAL", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + ONES (64), /* dst_mask */ + FALSE), /* pcrel_offset */ + /* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_PPC64_GNU_VTINHERIT, /* type */ 0, /* rightshift */ @@ -2366,6 +2409,8 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, break; case BFD_RELOC_HI16_S_PCREL: r = R_PPC64_REL16_HA; break; + case BFD_RELOC_PPC64_ADDR64_LOCAL: r = R_PPC64_ADDR64_LOCAL; + break; case BFD_RELOC_VTABLE_INHERIT: r = R_PPC64_GNU_VTINHERIT; break; case BFD_RELOC_VTABLE_ENTRY: r = R_PPC64_GNU_VTENTRY; @@ -2455,6 +2500,29 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + symbol->section->output_section->vma + symbol->section->output_offset); } + else + { + elf_symbol_type *elfsym = (elf_symbol_type *) symbol; + + if (symbol->section->owner != abfd + && abiversion (symbol->section->owner) >= 2) + { + unsigned int i; + + for (i = 0; i < symbol->section->owner->symcount; ++i) + { + asymbol *symdef = symbol->section->owner->outsymbols[i]; + + if (strcmp (symdef->name, symbol->name) == 0) + { + elfsym = (elf_symbol_type *) symdef; + break; + } + } + } + reloc_entry->addend + += PPC64_LOCAL_ENTRY_OFFSET (elfsym->internal_elf_sym.st_other); + } return bfd_reloc_continue; } @@ -3089,15 +3157,19 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, long count; char *names; long symcount, codesecsym, codesecsymend, secsymend, opdsymend; - asection *opd; + asection *opd = NULL; bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0; asymbol **syms; + int abi = abiversion (abfd); *ret = NULL; - opd = bfd_get_section_by_name (abfd, ".opd"); - if (opd == NULL) - return 0; + if (abi < 2) + { + opd = bfd_get_section_by_name (abfd, ".opd"); + if (opd == NULL && abi == 1) + return 0; + } symcount = static_count; if (!relocatable) @@ -3266,20 +3338,18 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, else { bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); - bfd_byte *contents; + bfd_byte *contents = NULL; size_t size; long plt_count = 0; bfd_vma glink_vma = 0, resolv_vma = 0; asection *dynamic, *glink = NULL, *relplt = NULL; arelent *p; - if (!bfd_malloc_and_get_section (abfd, opd, &contents)) + if (opd != NULL && !bfd_malloc_and_get_section (abfd, opd, &contents)) { + free_contents_and_exit: if (contents) - { - free_contents_and_exit: - free (contents); - } + free (contents); count = -1; goto done; } @@ -3328,9 +3398,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, if (dyn.d_tag == DT_PPC64_GLINK) { - /* The first glink stub starts at offset 32; see comment in - ppc64_elf_finish_dynamic_sections. */ - glink_vma = dyn.d_un.d_val + 32; + /* The first glink stub starts at offset 32; see + comment in ppc64_elf_finish_dynamic_sections. */ + glink_vma = dyn.d_un.d_val + GLINK_CALL_STUB_SIZE - 8 * 4; /* The .glink section usually does not survive the final link; search for the section (usually .text) where the glink stubs now reside. */ @@ -3348,13 +3418,21 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, /* Determine __glink trampoline by reading the relative branch from the first glink stub. */ bfd_byte buf[4]; - if (bfd_get_section_contents (abfd, glink, buf, - glink_vma + 4 - glink->vma, 4)) + unsigned int off = 0; + + while (bfd_get_section_contents (abfd, glink, buf, + glink_vma + off - glink->vma, 4)) { unsigned int insn = bfd_get_32 (abfd, buf); insn ^= B_DOT; if ((insn & ~0x3fffffc) == 0) - resolv_vma = glink_vma + 4 + (insn ^ 0x2000000) - 0x2000000; + { + resolv_vma = glink_vma + off + (insn ^ 0x2000000) - 0x2000000; + break; + } + off += 4; + if (off > 4) + break; } if (resolv_vma) @@ -3507,8 +3585,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, memcpy (names, "@plt", sizeof ("@plt")); names += sizeof ("@plt"); s++; - glink_vma += 8; - if (i >= 0x8000) + if (abi < 2) + { + glink_vma += 8; + if (i >= 0x8000) + glink_vma += 4; + } + else glink_vma += 4; } count += plt_count; @@ -3559,13 +3642,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, . . . .foo_stub: - . addis 12,2,Lfoo@toc@ha # in practice, the call stub - . addi 12,12,Lfoo@toc@l # is slightly optimized, but - . std 2,40(1) # this is the general idea - . ld 11,0(12) - . ld 2,8(12) - . mtctr 11 - . ld 11,16(12) + . std 2,40(1) # in practice, the call stub + . addis 11,2,Lfoo@toc@ha # is slightly optimized, but + . addi 11,11,Lfoo@toc@l # this is the general idea + . ld 12,0(11) + . ld 2,8(11) + . mtctr 12 + . ld 11,16(11) . bctr . . .section .plt @@ -3657,21 +3740,21 @@ must_be_dyn_reloc (struct bfd_link_info *info, ppc_stub_plt_branch: Similar to the above, but a 24 bit branch in the stub section won't reach its destination. - . addis %r12,%r2,xxx@toc@ha - . ld %r11,xxx@toc@l(%r12) - . mtctr %r11 + . addis %r11,%r2,xxx@toc@ha + . ld %r12,xxx@toc@l(%r11) + . mtctr %r12 . bctr ppc_stub_plt_call: Used to call a function in a shared library. If it so happens that the plt entry referenced crosses a 64k boundary, then an extra - "addi %r12,%r12,xxx@toc@l" will be inserted before the "mtctr". - . addis %r12,%r2,xxx@toc@ha + "addi %r11,%r11,xxx@toc@l" will be inserted before the "mtctr". . std %r2,40(%r1) - . ld %r11,xxx+0@toc@l(%r12) - . mtctr %r11 - . ld %r2,xxx+8@toc@l(%r12) - . ld %r11,xxx+16@toc@l(%r12) + . addis %r11,%r2,xxx@toc@ha + . ld %r12,xxx+0@toc@l(%r11) + . mtctr %r12 + . ld %r2,xxx+8@toc@l(%r11) + . ld %r11,xxx+16@toc@l(%r11) . bctr ppc_stub_long_branch and ppc_stub_plt_branch may also have additional @@ -3684,11 +3767,11 @@ must_be_dyn_reloc (struct bfd_link_info *info, A ppc_stub_plt_branch with an r2 offset looks like: . std %r2,40(%r1) - . addis %r12,%r2,xxx@toc@ha - . ld %r11,xxx@toc@l(%r12) + . addis %r11,%r2,xxx@toc@ha + . ld %r12,xxx@toc@l(%r11) . addis %r2,%r2,off@ha . addi %r2,%r2,off@l - . mtctr %r11 + . mtctr %r12 . bctr In cases where the "addis" instruction would add zero, the "addis" is @@ -3702,7 +3785,8 @@ enum ppc_stub_type { ppc_stub_plt_branch, ppc_stub_plt_branch_r2off, ppc_stub_plt_call, - ppc_stub_plt_call_r2save + ppc_stub_plt_call_r2save, + ppc_stub_global_entry }; struct ppc_stub_hash_entry { @@ -3730,6 +3814,9 @@ struct ppc_stub_hash_entry { /* Where this stub is being called from, or, in the case of combined stub sections, the first input section in the group. */ asection *id_sec; + + /* Symbol st_other. */ + unsigned char other; }; struct ppc_branch_hash_entry { @@ -3825,12 +3912,8 @@ struct ppc_link_hash_table /* Hash table for function prologue tocsave. */ htab_t tocsave_htab; - /* Linker stub bfd. */ - bfd *stub_bfd; - - /* Linker call-backs. */ - asection * (*add_stub_section) (const char *, asection *); - void (*layout_sections_again) (void); + /* Various options and other info passed from the linker. */ + struct ppc64_elf_params *params; /* Array to keep track of which stub sections have been created, and information on stub grouping. */ @@ -3860,12 +3943,7 @@ struct ppc_link_hash_table /* List of input sections for each output section. */ asection **input_list; - /* Short-cuts to get to dynamic linker sections. */ - asection *got; - asection *plt; - asection *relplt; - asection *iplt; - asection *reliplt; + /* Shortcuts to get to dynamic linker sections. */ asection *dynbss; asection *relbss; asection *glink; @@ -3882,25 +3960,13 @@ struct ppc_link_hash_table bfd_size_type got_reli_size; /* Statistics. */ - unsigned long stub_count[ppc_stub_plt_call_r2save]; + unsigned long stub_count[ppc_stub_global_entry]; /* Number of stubs against global syms. */ unsigned long stub_globals; - /* Alignment of PLT call stubs. */ - unsigned int plt_stub_align:4; - - /* Set if PLT call stubs should load r11. */ - unsigned int plt_static_chain:1; - - /* Set if PLT call stubs need a read-read barrier. */ - unsigned int plt_thread_safe:1; - - /* Set if we should emit symbols for stubs. */ - unsigned int emit_stub_syms:1; - - /* Set if __tls_get_addr optimization should not be done. */ - unsigned int no_tls_get_addr_opt:1; + /* Set if we're linking code with function descriptors. */ + unsigned int opd_abi:1; /* Support for multiple toc sections. */ unsigned int do_multi_toc:1; @@ -3911,7 +3977,7 @@ struct ppc_link_hash_table /* Set on error. */ unsigned int stub_error:1; - /* Temp used by ppc64_elf_process_dot_syms. */ + /* Temp used by ppc64_elf_before_check_relocs. */ unsigned int twiddled_syms:1; /* Incremented every time we size stubs. */ @@ -3985,7 +4051,9 @@ stub_hash_newfunc (struct bfd_hash_entry *entry, eh->target_value = 0; eh->target_section = NULL; eh->h = NULL; + eh->plt_ent = NULL; eh->id_sec = NULL; + eh->other = 0; } return entry; @@ -4097,6 +4165,21 @@ tocsave_htab_eq (const void *p1, const void *p2) return e1->sec == e2->sec && e1->offset == e2->offset; } +/* Destroy a ppc64 ELF linker hash table. */ + +static void +ppc64_elf_link_hash_table_free (bfd *obfd) +{ + struct ppc_link_hash_table *htab; + + htab = (struct ppc_link_hash_table *) obfd->link.hash; + if (htab->tocsave_htab) + htab_delete (htab->tocsave_htab); + bfd_hash_table_free (&htab->branch_hash_table); + bfd_hash_table_free (&htab->stub_hash_table); + _bfd_elf_link_hash_table_free (obfd); +} + /* Create a ppc64 ELF linker hash table. */ static struct bfd_link_hash_table * @@ -4120,19 +4203,30 @@ ppc64_elf_link_hash_table_create (bfd *abfd) /* Init the stub hash table too. */ if (!bfd_hash_table_init (&htab->stub_hash_table, stub_hash_newfunc, sizeof (struct ppc_stub_hash_entry))) - return NULL; + { + _bfd_elf_link_hash_table_free (abfd); + return NULL; + } /* And the branch hash table. */ if (!bfd_hash_table_init (&htab->branch_hash_table, branch_hash_newfunc, sizeof (struct ppc_branch_hash_entry))) - return NULL; + { + bfd_hash_table_free (&htab->stub_hash_table); + _bfd_elf_link_hash_table_free (abfd); + return NULL; + } htab->tocsave_htab = htab_try_create (1024, tocsave_htab_hash, tocsave_htab_eq, NULL); if (htab->tocsave_htab == NULL) - return NULL; + { + ppc64_elf_link_hash_table_free (abfd); + return NULL; + } + htab->elf.root.hash_table_free = ppc64_elf_link_hash_table_free; /* Initializing two fields of the union is just cosmetic. We really only care about glist, but when compiled on a 32-bit host the @@ -4150,20 +4244,6 @@ ppc64_elf_link_hash_table_create (bfd *abfd) return &htab->elf.root; } -/* Free the derived linker hash table. */ - -static void -ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash) -{ - struct ppc_link_hash_table *htab = (struct ppc_link_hash_table *) hash; - - bfd_hash_table_free (&htab->stub_hash_table); - bfd_hash_table_free (&htab->branch_hash_table); - if (htab->tocsave_htab) - htab_delete (htab->tocsave_htab); - _bfd_elf_link_hash_table_free (hash); -} - /* Create sections for linker generated code. */ static bfd_boolean @@ -4203,18 +4283,17 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) } flags = SEC_ALLOC | SEC_LINKER_CREATED; - htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags); - if (htab->iplt == NULL - || ! bfd_set_section_alignment (dynobj, htab->iplt, 3)) + htab->elf.iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags); + if (htab->elf.iplt == NULL + || ! bfd_set_section_alignment (dynobj, htab->elf.iplt, 3)) return FALSE; flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->reliplt = bfd_make_section_anyway_with_flags (dynobj, - ".rela.iplt", - flags); - if (htab->reliplt == NULL - || ! bfd_set_section_alignment (dynobj, htab->reliplt, 3)) + htab->elf.irelplt + = bfd_make_section_anyway_with_flags (dynobj, ".rela.iplt", flags); + if (htab->elf.irelplt == NULL + || ! bfd_set_section_alignment (dynobj, htab->elf.irelplt, 3)) return FALSE; /* Create branch lookup table for plt_branch stubs. */ @@ -4244,11 +4323,12 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) /* Satisfy the ELF linker by filling in some fields in our fake bfd. */ bfd_boolean -ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info) +ppc64_elf_init_stub_bfd (struct bfd_link_info *info, + struct ppc64_elf_params *params) { struct ppc_link_hash_table *htab; - elf_elfheader (abfd)->e_ident[EI_CLASS] = ELFCLASS64; + elf_elfheader (params->stub_bfd)->e_ident[EI_CLASS] = ELFCLASS64; /* Always hook our dynamic sections into the first bfd, which is the linker created stub bfd. This ensures that the GOT header is at @@ -4256,8 +4336,8 @@ ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info) htab = ppc_hash_table (info); if (htab == NULL) return FALSE; - htab->stub_bfd = abfd; - htab->elf.dynobj = abfd; + htab->elf.dynobj = params->stub_bfd; + htab->params = params; if (info->relocatable) return TRUE; @@ -4382,13 +4462,13 @@ ppc_add_stub (const char *stub_name, namelen = strlen (link_sec->name); len = namelen + sizeof (STUB_SUFFIX); - s_name = bfd_alloc (htab->stub_bfd, len); + s_name = bfd_alloc (htab->params->stub_bfd, len); if (s_name == NULL) return NULL; memcpy (s_name, link_sec->name, namelen); memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); - stub_sec = (*htab->add_stub_section) (s_name, link_sec); + stub_sec = (*htab->params->add_stub_section) (s_name, link_sec); if (stub_sec == NULL) return NULL; htab->stub_group[link_sec->id].stub_sec = stub_sec; @@ -4427,15 +4507,9 @@ create_got_section (bfd *abfd, struct bfd_link_info *info) if (htab == NULL) return FALSE; - if (!htab->got) - { - if (! _bfd_elf_create_got_section (htab->elf.dynobj, info)) - return FALSE; - - htab->got = bfd_get_linker_section (htab->elf.dynobj, ".got"); - if (!htab->got) - abort (); - } + if (!htab->elf.sgot + && !_bfd_elf_create_got_section (htab->elf.dynobj, info)) + return FALSE; flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); @@ -4470,15 +4544,11 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) if (htab == NULL) return FALSE; - if (!htab->got) - htab->got = bfd_get_linker_section (dynobj, ".got"); - htab->plt = bfd_get_linker_section (dynobj, ".plt"); - htab->relplt = bfd_get_linker_section (dynobj, ".rela.plt"); htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss"); if (!info->shared) htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss"); - if (!htab->got || !htab->plt || !htab->relplt || !htab->dynbss + if (!htab->elf.sgot || !htab->elf.splt || !htab->elf.srelplt || !htab->dynbss || (!info->shared && !htab->relbss)) abort (); @@ -4573,6 +4643,7 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info, edir->elf.ref_regular |= eind->elf.ref_regular; edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak; edir->elf.needs_plt |= eind->elf.needs_plt; + edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed; /* Copy over any dynamic relocs we may have on the indirect sym. */ if (eind->dyn_relocs != NULL) @@ -4731,29 +4802,68 @@ static bfd_boolean ppc64_elf_add_symbol_hook (bfd *ibfd, struct bfd_link_info *info, Elf_Internal_Sym *isym, - const char **name ATTRIBUTE_UNUSED, + const char **name, flagword *flags ATTRIBUTE_UNUSED, asection **sec, - bfd_vma *value ATTRIBUTE_UNUSED) + bfd_vma *value) { - if ((ibfd->flags & DYNAMIC) == 0 - && ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE) + if ((ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC + || ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE) + && (ibfd->flags & DYNAMIC) == 0 + && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) + if (*sec != NULL + && strcmp ((*sec)->name, ".opd") == 0) { - if ((ibfd->flags & DYNAMIC) == 0) - elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; + asection *code_sec; + + if (!(ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC + || ELF_ST_TYPE (isym->st_info) == STT_FUNC)) + isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC); + + /* If the symbol is a function defined in .opd, and the function + code is in a discarded group, let it appear to be undefined. */ + if (!info->relocatable + && (*sec)->reloc_count != 0 + && opd_entry_value (*sec, *value, &code_sec, NULL, + FALSE) != (bfd_vma) -1 + && discarded_section (code_sec)) + { + *sec = bfd_und_section_ptr; + isym->st_shndx = SHN_UNDEF; + } + } + + if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0) + { + if (abiversion (ibfd) == 0) + set_abiversion (ibfd, 2); + else if (abiversion (ibfd) == 1) + { + info->callbacks->einfo (_("%P: symbol '%s' has invalid st_other" + " for ABI version 1\n"), name); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } } - else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC) - ; - else if (*sec != NULL - && strcmp ((*sec)->name, ".opd") == 0) - isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC); return TRUE; } +/* Merge non-visibility st_other attributes: local entry point. */ + +static void +ppc64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, + const Elf_Internal_Sym *isym, + bfd_boolean definition, + bfd_boolean dynamic) +{ + if (definition && !dynamic) + h->other = ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) + | ELF_ST_VISIBILITY (h->other)); +} + /* This function makes an old ABI object reference to ".bar" cause the inclusion of a new ABI object archive that defines "bar". NAME is a symbol defined in an archive. Return a symbol in the hash @@ -4857,13 +4967,53 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info) return TRUE; } -/* Process list of dot-symbols we made in link_hash_newfunc. */ +/* Set up opd section info and abiversion for IBFD, and process list + of dot-symbols we made in link_hash_newfunc. */ static bfd_boolean -ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info) +ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info) { struct ppc_link_hash_table *htab; struct ppc_link_hash_entry **p, *eh; + asection *opd = bfd_get_section_by_name (ibfd, ".opd"); + + if (opd != NULL && opd->size != 0) + { + if (abiversion (ibfd) == 0) + set_abiversion (ibfd, 1); + else if (abiversion (ibfd) == 2) + { + info->callbacks->einfo (_("%P: %B .opd not allowed in ABI" + " version %d\n"), + ibfd, abiversion (ibfd)); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + if ((ibfd->flags & DYNAMIC) == 0 + && (opd->flags & SEC_RELOC) != 0 + && opd->reloc_count != 0 + && !bfd_is_abs_section (opd->output_section)) + { + /* Garbage collection needs some extra help with .opd sections. + We don't want to necessarily keep everything referenced by + relocs in .opd, as that would keep all functions. Instead, + if we reference an .opd symbol (a function descriptor), we + want to keep the function code symbol's section. This is + easy for global symbols, but for local syms we need to keep + information about the associated function section. */ + bfd_size_type amt; + asection **opd_sym_map; + + amt = opd->size * sizeof (*opd_sym_map) / 8; + opd_sym_map = bfd_zalloc (ibfd, amt); + if (opd_sym_map == NULL) + return FALSE; + ppc64_elf_section_data (opd)->u.opd.func_sec = opd_sym_map; + BFD_ASSERT (ppc64_elf_section_data (opd)->sec_type == sec_normal); + ppc64_elf_section_data (opd)->sec_type = sec_opd; + } + } if (!is_ppc64_elf (info->output_bfd)) return TRUE; @@ -4871,21 +5021,29 @@ ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info) if (htab == NULL) return FALSE; - if (is_ppc64_elf (ibfd)) + /* For input files without an explicit abiversion in e_flags + we should have flagged any with symbol st_other bits set + as ELFv1 and above flagged those with .opd as ELFv2. + Set the output abiversion if not yet set, and for any input + still ambiguous, take its abiversion from the output. + Differences in ABI are reported later. */ + if (abiversion (info->output_bfd) == 0) + set_abiversion (info->output_bfd, abiversion (ibfd)); + else if (abiversion (ibfd) == 0) + set_abiversion (ibfd, abiversion (info->output_bfd)); + + p = &htab->dot_syms; + while ((eh = *p) != NULL) { - p = &htab->dot_syms; - while ((eh = *p) != NULL) - { - *p = NULL; - if (&eh->elf == htab->elf.hgot) - ; - else if (htab->elf.hgot == NULL - && strcmp (eh->elf.root.root.string, ".TOC.") == 0) - htab->elf.hgot = &eh->elf; - else if (!add_symbol_adjust (eh, info)) - return FALSE; - p = &eh->u.next_dot_sym; - } + *p = NULL; + if (&eh->elf == htab->elf.hgot) + ; + else if (htab->elf.hgot == NULL + && strcmp (eh->elf.root.root.string, ".TOC.") == 0) + htab->elf.hgot = &eh->elf; + else if (!add_symbol_adjust (eh, info)) + return FALSE; + p = &eh->u.next_dot_sym; } /* Clear the list for non-ppc64 input files. */ @@ -4936,10 +5094,8 @@ ppc64_elf_link_just_syms (asection *sec, struct bfd_link_info *info) && (sec->owner->flags & (EXEC_P | DYNAMIC)) != 0 && is_ppc64_elf (sec->owner)) { - asection *got = bfd_get_section_by_name (sec->owner, ".got"); - if (got != NULL - && got->size >= elf_backend_got_header_size - && bfd_get_section_by_name (sec->owner, ".opd") != NULL) + if (abiversion (sec->owner) >= 2 + || bfd_get_section_by_name (sec->owner, ".opd") != NULL) sec->has_toc_reloc = 1; } _bfd_elf_link_just_syms (sec, info); @@ -5078,25 +5234,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, sym_hashes = elf_sym_hashes (abfd); sreloc = NULL; opd_sym_map = NULL; - if (strcmp (sec->name, ".opd") == 0) - { - /* Garbage collection needs some extra help with .opd sections. - We don't want to necessarily keep everything referenced by - relocs in .opd, as that would keep all functions. Instead, - if we reference an .opd symbol (a function descriptor), we - want to keep the function code symbol's section. This is - easy for global symbols, but for local syms we need to keep - information about the associated function section. */ - bfd_size_type amt; - - amt = sec->size * sizeof (*opd_sym_map) / 8; - opd_sym_map = bfd_zalloc (abfd, amt); - if (opd_sym_map == NULL) - return FALSE; - ppc64_elf_section_data (sec)->u.opd.func_sec = opd_sym_map; - BFD_ASSERT (ppc64_elf_section_data (sec)->sec_type == sec_normal); - ppc64_elf_section_data (sec)->sec_type = sec_opd; - } + if (ppc64_elf_section_data (sec) != NULL + && ppc64_elf_section_data (sec)->sec_type == sec_opd) + opd_sym_map = ppc64_elf_section_data (sec)->u.opd.func_sec; rel_end = relocs + sec->reloc_count; for (rel = relocs; rel < rel_end; rel++) @@ -5197,7 +5337,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_HI: case R_PPC64_GOT_TPREL16_HA: - if (!info->executable) + if (info->shared) info->flags |= DF_STATIC_TLS; tls_type = TLS_TLS | TLS_TPREL; goto dogottls; @@ -5267,6 +5407,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, rel->r_addend, tls_type)) return FALSE; + + /* We may also need a plt entry if the symbol turns out to be + an ifunc. */ + if (h != NULL && !info->shared && abiversion (abfd) != 1) + { + if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) + return FALSE; + } break; case R_PPC64_PLT16_HA: @@ -5327,6 +5475,21 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_REL16_HA: break; + /* Not supported as a dynamic relocation. */ + case R_PPC64_ADDR64_LOCAL: + if (info->shared) + { + if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) + ppc_howto_init (); + info->callbacks->einfo (_("%P: %H: %s reloc unsupported " + "in shared libraries and PIEs.\n"), + abfd, sec, rel->r_offset, + ppc64_elf_howto_table[r_type]->name); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + break; + case R_PPC64_TOC16: case R_PPC64_TOC16_DS: htab->do_multi_toc = 1; @@ -5404,7 +5567,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_TPREL64: tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL; - if (!info->executable) + if (info->shared) info->flags |= DF_STATIC_TLS; goto dotlstoc; @@ -5482,8 +5645,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_TPREL16_HIGHESTA: if (info->shared) { - if (!info->executable) - info->flags |= DF_STATIC_TLS; + info->flags |= DF_STATIC_TLS; goto dodyn; } break; @@ -5519,12 +5681,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, } /* Fall through. */ - case R_PPC64_REL30: - case R_PPC64_REL32: - case R_PPC64_REL64: - case R_PPC64_ADDR14: - case R_PPC64_ADDR14_BRNTAKEN: - case R_PPC64_ADDR14_BRTAKEN: case R_PPC64_ADDR16: case R_PPC64_ADDR16_DS: case R_PPC64_ADDR16_HA: @@ -5537,6 +5693,23 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_ADDR16_HIGHESTA: case R_PPC64_ADDR16_LO: case R_PPC64_ADDR16_LO_DS: + if (h != NULL && !info->shared && abiversion (abfd) != 1 + && rel->r_addend == 0) + { + /* We may need a .plt entry if this reloc refers to a + function in a shared lib. */ + if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) + return FALSE; + h->pointer_equality_needed = 1; + } + /* Fall through. */ + + case R_PPC64_REL30: + case R_PPC64_REL32: + case R_PPC64_REL64: + case R_PPC64_ADDR14: + case R_PPC64_ADDR14_BRNTAKEN: + case R_PPC64_ADDR14_BRTAKEN: case R_PPC64_ADDR24: case R_PPC64_ADDR32: case R_PPC64_UADDR16: @@ -5674,8 +5847,74 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, return TRUE; } +/* Merge backend specific data from an object file to the output + object file when linking. */ + +static bfd_boolean +ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) +{ + unsigned long iflags, oflags; + + if ((ibfd->flags & BFD_LINKER_CREATED) != 0) + return TRUE; + + if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd)) + return TRUE; + + if (!_bfd_generic_verify_endian_match (ibfd, obfd)) + return FALSE; + + iflags = elf_elfheader (ibfd)->e_flags; + oflags = elf_elfheader (obfd)->e_flags; + + if (iflags & ~EF_PPC64_ABI) + { + (*_bfd_error_handler) + (_("%B uses unknown e_flags 0x%lx"), ibfd, iflags); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + else if (iflags != oflags && iflags != 0) + { + (*_bfd_error_handler) + (_("%B: ABI version %ld is not compatible with ABI version %ld output"), + ibfd, iflags, oflags); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* Merge Tag_compatibility attributes and any common GNU ones. */ + _bfd_elf_merge_object_attributes (ibfd, obfd); + + return TRUE; +} + +static bfd_boolean +ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr) +{ + /* Print normal ELF private data. */ + _bfd_elf_print_private_bfd_data (abfd, ptr); + + if (elf_elfheader (abfd)->e_flags != 0) + { + FILE *file = ptr; + + /* xgettext:c-format */ + fprintf (file, _("private flags = 0x%lx:"), + elf_elfheader (abfd)->e_flags); + + if ((elf_elfheader (abfd)->e_flags & EF_PPC64_ABI) != 0) + fprintf (file, _(" [abiv%ld]"), + elf_elfheader (abfd)->e_flags & EF_PPC64_ABI); + fputc ('\n', file); + } + + return TRUE; +} + /* OFFSET in OPD_SEC specifies a function descriptor. Return the address - of the code entry point, and its section. */ + of the code entry point, and its section, which must be in the same + object as OPD_SEC. Returns (bfd_vma) -1 on error. */ static bfd_vma opd_entry_value (asection *opd_sec, @@ -5758,32 +5997,10 @@ opd_entry_value (asection *opd_sec, && ELF64_R_TYPE ((look + 1)->r_info) == R_PPC64_TOC) { unsigned long symndx = ELF64_R_SYM (look->r_info); - asection *sec; - - if (symndx < symtab_hdr->sh_info - || elf_sym_hashes (opd_bfd) == NULL) - { - Elf_Internal_Sym *sym; + asection *sec = NULL; - sym = (Elf_Internal_Sym *) symtab_hdr->contents; - if (sym == NULL) - { - size_t symcnt = symtab_hdr->sh_info; - if (elf_sym_hashes (opd_bfd) == NULL) - symcnt = symtab_hdr->sh_size / symtab_hdr->sh_entsize; - sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, symcnt, - 0, NULL, NULL, NULL); - if (sym == NULL) - break; - symtab_hdr->contents = (bfd_byte *) sym; - } - - sym += symndx; - val = sym->st_value; - sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx); - BFD_ASSERT ((sec->flags & SEC_MERGE) == 0); - } - else + if (symndx >= symtab_hdr->sh_info + && elf_sym_hashes (opd_bfd) != NULL) { struct elf_link_hash_entry **sym_hashes; struct elf_link_hash_entry *rh; @@ -5797,24 +6014,48 @@ opd_entry_value (asection *opd_sec, || rh->root.type == bfd_link_hash_defweak); val = rh->root.u.def.value; sec = rh->root.u.def.section; + if (sec->owner != opd_bfd) + { + sec = NULL; + val = (bfd_vma) -1; + } + } + } + + if (sec == NULL) + { + Elf_Internal_Sym *sym; + + if (symndx < symtab_hdr->sh_info) + { + sym = (Elf_Internal_Sym *) symtab_hdr->contents; + if (sym == NULL) + { + size_t symcnt = symtab_hdr->sh_info; + sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, + symcnt, 0, + NULL, NULL, NULL); + if (sym == NULL) + break; + symtab_hdr->contents = (bfd_byte *) sym; + } + sym += symndx; } else { - /* Handle the odd case where we can be called - during bfd_elf_link_add_symbols before the - symbol hashes have been fully populated. */ - Elf_Internal_Sym *sym; - - sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, 1, - symndx, NULL, NULL, NULL); + sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, + 1, symndx, + NULL, NULL, NULL); if (sym == NULL) break; - - val = sym->st_value; - sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx); - free (sym); } + sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx); + if (sec == NULL) + break; + BFD_ASSERT ((sec->flags & SEC_MERGE) == 0); + val = sym->st_value; } + val += look->r_addend; if (code_off != NULL) *code_off = val; @@ -5825,7 +6066,7 @@ opd_entry_value (asection *opd_sec, else *code_sec = sec; } - if (sec != NULL && sec->output_section != NULL) + if (sec->output_section != NULL) val += sec->output_section->vma + sec->output_offset; } break; @@ -5979,6 +6220,7 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf) struct bfd_link_info *info = (struct bfd_link_info *) inf; struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h; struct ppc_link_hash_entry *fdh; + struct bfd_elf_dynamic_list *d = info->dynamic_list; /* Dynamic linking info is on the func descriptor sym. */ fdh = defined_func_desc (eh); @@ -5988,10 +6230,14 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf) if ((eh->elf.root.type == bfd_link_hash_defined || eh->elf.root.type == bfd_link_hash_defweak) && (eh->elf.ref_dynamic - || (!info->executable - && eh->elf.def_regular + || (eh->elf.def_regular && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN + && (!info->executable + || info->export_dynamic + || (eh->elf.dynamic + && d != NULL + && (*d->match) (&d->head, NULL, eh->elf.root.root.string))) && (strchr (eh->elf.root.root.string, ELF_VER_CHR) != NULL || !bfd_hide_sym_by_version (info->version_info, eh->elf.root.root.string))))) @@ -6356,7 +6602,7 @@ static bfd_byte * savegpr0_tail (bfd *abfd, bfd_byte *p, int r) { p = savegpr0 (abfd, p, r); - bfd_put_32 (abfd, STD_R0_0R1 + 16, p); + bfd_put_32 (abfd, STD_R0_0R1 + STK_LR, p); p = p + 4; bfd_put_32 (abfd, BLR, p); return p + 4; @@ -6372,7 +6618,7 @@ restgpr0 (bfd *abfd, bfd_byte *p, int r) static bfd_byte * restgpr0_tail (bfd *abfd, bfd_byte *p, int r) { - bfd_put_32 (abfd, LD_R0_0R1 + 16, p); + bfd_put_32 (abfd, LD_R0_0R1 + STK_LR, p); p = p + 4; p = restgpr0 (abfd, p, r); bfd_put_32 (abfd, MTLR_R0, p); @@ -6427,7 +6673,7 @@ static bfd_byte * savefpr0_tail (bfd *abfd, bfd_byte *p, int r) { p = savefpr (abfd, p, r); - bfd_put_32 (abfd, STD_R0_0R1 + 16, p); + bfd_put_32 (abfd, STD_R0_0R1 + STK_LR, p); p = p + 4; bfd_put_32 (abfd, BLR, p); return p + 4; @@ -6443,7 +6689,7 @@ restfpr (bfd *abfd, bfd_byte *p, int r) static bfd_byte * restfpr0_tail (bfd *abfd, bfd_byte *p, int r) { - bfd_put_32 (abfd, LD_R0_0R1 + 16, p); + bfd_put_32 (abfd, LD_R0_0R1 + STK_LR, p); p = p + 4; p = restfpr (abfd, p, r); bfd_put_32 (abfd, MTLR_R0, p); @@ -6672,7 +6918,18 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, if (!info->relocatable && htab->elf.hgot != NULL) - _bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE); + { + _bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE); + /* Make .TOC. defined so as to prevent it being made dynamic. + The wrong value here is fixed later in ppc64_elf_set_toc. */ + htab->elf.hgot->type = STT_OBJECT; + htab->elf.hgot->root.type = bfd_link_hash_defined; + htab->elf.hgot->root.u.def.value = 0; + htab->elf.hgot->root.u.def.section = bfd_abs_section_ptr; + htab->elf.hgot->def_regular = 1; + htab->elf.hgot->other = ((htab->elf.hgot->other & ~ELF_ST_VISIBILITY (-1)) + | STV_HIDDEN); + } if (htab->sfpr == NULL) /* We don't have any relocs. */ @@ -6680,7 +6937,7 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, /* Provide any missing _save* and _rest* functions. */ htab->sfpr->size = 0; - if (!info->relocatable) + if (htab->params->save_restore_funcs) for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++) if (!sfpr_define (info, &funcs[i])) return FALSE; @@ -6693,6 +6950,25 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, return TRUE; } +/* Return true if we have dynamic relocs that apply to read-only sections. */ + +static bfd_boolean +readonly_dynrelocs (struct elf_link_hash_entry *h) +{ + struct ppc_link_hash_entry *eh; + struct elf_dyn_relocs *p; + + eh = (struct ppc_link_hash_entry *) h; + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *s = p->sec->output_section; + + if (s != NULL && (s->flags & SEC_READONLY) != 0) + return TRUE; + } + return FALSE; +} + /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -6729,6 +7005,39 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, { h->plt.plist = NULL; h->needs_plt = 0; + h->pointer_equality_needed = 0; + } + else if (abiversion (info->output_bfd) == 2) + { + /* Taking a function's address in a read/write section + doesn't require us to define the function symbol in the + executable on a global entry stub. A dynamic reloc can + be used instead. */ + if (h->pointer_equality_needed + && h->type != STT_GNU_IFUNC + && !readonly_dynrelocs (h)) + { + h->pointer_equality_needed = 0; + h->non_got_ref = 0; + } + + /* After adjust_dynamic_symbol, non_got_ref set in the + non-shared case means that we have allocated space in + .dynbss for the symbol and thus dyn_relocs for this + symbol should be discarded. + If we get here we know we are making a PLT entry for this + symbol, and in an executable we'd normally resolve + relocations against this symbol to the PLT entry. Allow + dynamic relocs if the reference is weak, and the dynamic + relocs will not cause text relocation. */ + else if (!h->ref_regular_nonweak + && h->non_got_ref + && h->type != STT_GNU_IFUNC + && !readonly_dynrelocs (h)) + h->non_got_ref = 0; + + /* If making a plt entry, then we don't need copy relocs. */ + return TRUE; } } else @@ -6764,26 +7073,12 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, if (!h->def_dynamic || !h->ref_regular || h->def_regular) return TRUE; - if (ELIMINATE_COPY_RELOCS) + /* If we didn't find any dynamic relocs in read-only sections, then + we'll be keeping the dynamic relocs and avoiding the copy reloc. */ + if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h)) { - struct ppc_link_hash_entry * eh; - struct elf_dyn_relocs *p; - - eh = (struct ppc_link_hash_entry *) h; - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - s = p->sec->output_section; - if (s != NULL && (s->flags & SEC_READONLY) != 0) - break; - } - - /* If we didn't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (p == NULL) - { - h->non_got_ref = 0; - return TRUE; - } + h->non_got_ref = 0; + return TRUE; } if (h->plt.plist != NULL) @@ -7299,13 +7594,18 @@ dec_dynrel_count (bfd_vma r_info, applications. */ bfd_boolean -ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping) +ppc64_elf_edit_opd (struct bfd_link_info *info) { bfd *ibfd; bfd_boolean some_edited = FALSE; asection *need_pad = NULL; + struct ppc_link_hash_table *htab; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + htab = ppc_hash_table (info); + if (htab == NULL) + return FALSE; + + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { asection *sec; Elf_Internal_Rela *relstart, *rel, *relend; @@ -7456,7 +7756,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping) goto broken_opd; } - add_aux_fields = non_overlapping && cnt_16b > 0; + add_aux_fields = htab->params->non_overlapping_opd && cnt_16b > 0; if (need_edit || add_aux_fields) { @@ -7547,12 +7847,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping) if (h != NULL && h->root.root.string[0] == '.') { - struct ppc_link_hash_table *htab; - - htab = ppc_hash_table (info); - if (htab != NULL) - fdh = lookup_fdh ((struct ppc_link_hash_entry *) h, - htab); + fdh = lookup_fdh ((struct ppc_link_hash_entry *) h, htab); if (fdh != NULL && fdh->elf.root.type != bfd_link_hash_defined && fdh->elf.root.type != bfd_link_hash_defweak) @@ -7701,9 +7996,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping) /* Set htab->tls_get_addr and call the generic ELF tls_setup function. */ asection * -ppc64_elf_tls_setup (struct bfd_link_info *info, - int no_tls_get_addr_opt, - int *no_multi_toc) +ppc64_elf_tls_setup (struct bfd_link_info *info) { struct ppc_link_hash_table *htab; @@ -7711,10 +8004,13 @@ ppc64_elf_tls_setup (struct bfd_link_info *info, if (htab == NULL) return NULL; - if (*no_multi_toc) + if (abiversion (info->output_bfd) == 1) + htab->opd_abi = 1; + + if (htab->params->no_multi_toc) htab->do_multi_toc = 0; else if (!htab->do_multi_toc) - *no_multi_toc = 1; + htab->params->no_multi_toc = 1; htab->tls_get_addr = ((struct ppc_link_hash_entry *) elf_link_hash_lookup (&htab->elf, ".__tls_get_addr", @@ -7725,7 +8021,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info, htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *) elf_link_hash_lookup (&htab->elf, "__tls_get_addr", FALSE, FALSE, TRUE)); - if (!no_tls_get_addr_opt) + if (!htab->params->no_tls_get_addr_opt) { struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd; @@ -7793,9 +8089,8 @@ ppc64_elf_tls_setup (struct bfd_link_info *info, } } else - no_tls_get_addr_opt = TRUE; + htab->params->no_tls_get_addr_opt = TRUE; } - htab->no_tls_get_addr_opt = no_tls_get_addr_opt; return _bfd_elf_tls_setup (info->output_bfd, info); } @@ -7857,7 +8152,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) and plt refcounts. */ toc_ref = NULL; for (pass = 0; pass < 2; ++pass) - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { Elf_Internal_Sym *locsyms = NULL; asection *toc = bfd_get_section_by_name (ibfd, ".toc"); @@ -7872,7 +8167,10 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, info->keep_memory); if (relstart == NULL) - return FALSE; + { + free (toc_ref); + return FALSE; + } relend = relstart + sec->reloc_count; for (rel = relstart; rel < relend; rel++) @@ -8045,7 +8343,10 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) else value = sym->st_value; value += rel->r_addend; - BFD_ASSERT (value < toc->size && value % 8 == 0); + if (value % 8 != 0) + continue; + BFD_ASSERT (value < toc->size + && toc->output_offset % 8 == 0); toc_ref_index = (value + toc->output_offset) / 8; if (r_type == R_PPC64_TLS || r_type == R_PPC64_TLSGD @@ -8351,7 +8652,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) htab->do_toc_opt = 1; toc_inf.global_toc_syms = TRUE; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { asection *toc, *sec; Elf_Internal_Shdr *symtab_hdr; @@ -8494,7 +8795,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) || discarded_section (sym_sec)) continue; - if (!SYMBOL_CALLS_LOCAL (info, h)) + if (!SYMBOL_REFERENCES_LOCAL (info, h)) continue; if (h != NULL) @@ -8580,7 +8881,10 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, info->keep_memory); if (relstart == NULL) - goto error_ret; + { + free (used); + goto error_ret; + } /* Mark toc entries referenced as used. */ do @@ -9023,7 +9327,7 @@ allocate_got (struct elf_link_hash_entry *h, dyn = htab->elf.dynamic_sections_created; if (h->type == STT_GNU_IFUNC) { - htab->reliplt->size += rentsize; + htab->elf.irelplt->size += rentsize; htab->got_reli_size += rentsize; } else if ((info->shared @@ -9090,35 +9394,40 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (!htab->elf.dynamic_sections_created || h->dynindx == -1) { - s = htab->iplt; + s = htab->elf.iplt; pent->plt.offset = s->size; - s->size += PLT_ENTRY_SIZE; - s = htab->reliplt; + s->size += PLT_ENTRY_SIZE (htab); + s = htab->elf.irelplt; } else { /* If this is the first .plt entry, make room for the special first entry. */ - s = htab->plt; + s = htab->elf.splt; if (s->size == 0) - s->size += PLT_INITIAL_ENTRY_SIZE; + s->size += PLT_INITIAL_ENTRY_SIZE (htab); pent->plt.offset = s->size; /* Make room for this entry. */ - s->size += PLT_ENTRY_SIZE; + s->size += PLT_ENTRY_SIZE (htab); /* Make room for the .glink code. */ s = htab->glink; if (s->size == 0) s->size += GLINK_CALL_STUB_SIZE; - /* We need bigger stubs past index 32767. */ - if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4) + if (htab->opd_abi) + { + /* We need bigger stubs past index 32767. */ + if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4) + s->size += 4; + s->size += 2*4; + } + else s->size += 4; - s->size += 2*4; /* We also need to make an entry in the .rela.plt section. */ - s = htab->relplt; + s = htab->elf.srelplt; } s->size += sizeof (Elf64_External_Rela); doneone = TRUE; @@ -9297,35 +9606,72 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { asection *sreloc = elf_section_data (p->sec)->sreloc; if (eh->elf.type == STT_GNU_IFUNC) - sreloc = htab->reliplt; + sreloc = htab->elf.irelplt; sreloc->size += p->count * sizeof (Elf64_External_Rela); } return TRUE; } -/* Find any dynamic relocs that apply to read-only sections. */ +/* Called via elf_link_hash_traverse from ppc64_elf_size_dynamic_sections + to set up space for global entry stubs. These are put in glink, + after the branch table. */ static bfd_boolean -readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) +size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) { - struct ppc_link_hash_entry *eh; - struct elf_dyn_relocs *p; + struct bfd_link_info *info; + struct ppc_link_hash_table *htab; + struct plt_entry *pent; + asection *s; - eh = (struct ppc_link_hash_entry *) h; - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; + if (h->root.type == bfd_link_hash_indirect) + return TRUE; - if (s != NULL && (s->flags & SEC_READONLY) != 0) - { - struct bfd_link_info *info = inf; + if (!h->pointer_equality_needed) + return TRUE; + + if (h->def_regular) + return TRUE; - info->flags |= DF_TEXTREL; + info = inf; + htab = ppc_hash_table (info); + if (htab == NULL) + return FALSE; - /* Not an error, just cut short the traversal. */ - return FALSE; - } + s = htab->glink; + for (pent = h->plt.plist; pent != NULL; pent = pent->next) + if (pent->plt.offset != (bfd_vma) -1 + && pent->addend == 0) + { + /* For ELFv2, if this symbol is not defined in a regular file + and we are not generating a shared library or pie, then we + need to define the symbol in the executable on a call stub. + This is to avoid text relocations. */ + s->size = (s->size + 15) & -16; + h->root.u.def.section = s; + h->root.u.def.value = s->size; + s->size += 16; + break; + } + return TRUE; +} + +/* Set DF_TEXTREL if we find any dynamic relocs that apply to + read-only sections. */ + +static bfd_boolean +maybe_set_textrel (struct elf_link_hash_entry *h, void *info) +{ + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + if (readonly_dynrelocs (h)) + { + ((struct bfd_link_info *) info)->flags |= DF_TEXTREL; + + /* Not an error, just cut short the traversal. */ + return FALSE; } return TRUE; } @@ -9333,7 +9679,7 @@ readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* Set the sizes of the dynamic sections. */ static bfd_boolean -ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, +ppc64_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { struct ppc_link_hash_table *htab; @@ -9366,7 +9712,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* Set up .got offsets for local syms, and space for local dynamic relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { struct got_entry **lgot_ents; struct got_entry **end_lgot_ents; @@ -9397,7 +9743,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, { asection *srel = elf_section_data (p->sec)->sreloc; if (p->ifunc) - srel = htab->reliplt; + srel = htab->elf.irelplt; srel->size += p->count * sizeof (Elf64_External_Rela); if ((p->sec->output_section->flags & SEC_READONLY) != 0) info->flags |= DF_TEXTREL; @@ -9443,7 +9789,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, s->size += ent_size; if ((*lgot_masks & PLT_IFUNC) != 0) { - htab->reliplt->size += rel_size; + htab->elf.irelplt->size += rel_size; htab->got_reli_size += rel_size; } else if (info->shared) @@ -9466,11 +9812,11 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, for (ent = *local_plt; ent != NULL; ent = ent->next) if (ent->plt.refcount > 0) { - s = htab->iplt; + s = htab->elf.iplt; ent->plt.offset = s->size; - s->size += PLT_ENTRY_SIZE; + s->size += PLT_ENTRY_SIZE (htab); - htab->reliplt->size += sizeof (Elf64_External_Rela); + htab->elf.irelplt->size += sizeof (Elf64_External_Rela); } else ent->plt.offset = (bfd_vma) -1; @@ -9480,9 +9826,15 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* Allocate global sym .plt and .got entries, and space for global sym dynamic relocs. */ elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); + /* Stash the end of glink branch table. */ + if (htab->glink != NULL) + htab->glink->rawsize = htab->glink->size; + + if (!htab->opd_abi && !info->shared) + elf_link_hash_traverse (&htab->elf, size_global_entry_stubs, info); first_tlsld = NULL; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { struct got_entry *ent; @@ -9527,9 +9879,9 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (s == htab->brlt || s == htab->relbrlt) /* These haven't been allocated yet; don't strip. */ continue; - else if (s == htab->got - || s == htab->plt - || s == htab->iplt + else if (s == htab->elf.sgot + || s == htab->elf.splt + || s == htab->elf.iplt || s == htab->glink || s == htab->dynbss) { @@ -9546,7 +9898,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, { if (s->size != 0) { - if (s != htab->relplt) + if (s != htab->elf.srelplt) relocs = TRUE; /* We use the reloc_count field as a counter if we need @@ -9590,13 +9942,13 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, return FALSE; } - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { if (!is_ppc64_elf (ibfd)) continue; s = ppc64_elf_tdata (ibfd)->got; - if (s != NULL && s != htab->got) + if (s != NULL && s != htab->elf.sgot) { if (s->size == 0) s->flags |= SEC_EXCLUDE; @@ -9625,6 +9977,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (htab->elf.dynamic_sections_created) { + bfd_boolean tls_opt; + /* Add some entries to the .dynamic section. We fill in the values later, in ppc64_elf_finish_dynamic_sections, but we must add the entries now so that we get the correct size for @@ -9639,7 +9993,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, return FALSE; } - if (htab->plt != NULL && htab->plt->size != 0) + if (htab->elf.splt != NULL && htab->elf.splt->size != 0) { if (!add_dynamic_entry (DT_PLTGOT, 0) || !add_dynamic_entry (DT_PLTRELSZ, 0) @@ -9649,18 +10003,21 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, return FALSE; } - if (NO_OPD_RELOCS) + if (NO_OPD_RELOCS && abiversion (output_bfd) <= 1) { if (!add_dynamic_entry (DT_PPC64_OPD, 0) || !add_dynamic_entry (DT_PPC64_OPDSZ, 0)) return FALSE; } - if (!htab->no_tls_get_addr_opt - && htab->tls_get_addr_fd != NULL - && htab->tls_get_addr_fd->elf.plt.plist != NULL - && !add_dynamic_entry (DT_PPC64_TLSOPT, 0)) - return FALSE; + tls_opt = (!htab->params->no_tls_get_addr_opt + && htab->tls_get_addr_fd != NULL + && htab->tls_get_addr_fd->elf.plt.plist != NULL); + if (tls_opt || !htab->opd_abi) + { + if (!add_dynamic_entry (DT_PPC64_OPT, tls_opt ? PPC64_OPT_TLS : 0)) + return FALSE; + } if (relocs) { @@ -9672,7 +10029,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* If any dynamic relocs apply to a read-only section, then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, info); + elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info); if ((info->flags & DF_TEXTREL) != 0) { @@ -9686,6 +10043,19 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, return TRUE; } +/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ + +static bfd_boolean +ppc64_elf_hash_symbol (struct elf_link_hash_entry *h) +{ + if (h->plt.plist != NULL + && !h->def_regular + && !h->pointer_equality_needed) + return FALSE; + + return _bfd_elf_hash_symbol (h); +} + /* Determine the type of stub needed, if any, for a call. */ static inline enum ppc_stub_type @@ -9693,7 +10063,8 @@ ppc_type_of_stub (asection *input_sec, const Elf_Internal_Rela *rel, struct ppc_link_hash_entry **hash, struct plt_entry **plt_ent, - bfd_vma destination) + bfd_vma destination, + unsigned long local_off) { struct ppc_link_hash_entry *h = *hash; bfd_vma location; @@ -9762,7 +10133,7 @@ ppc_type_of_stub (asection *input_sec, if (r_type != R_PPC64_REL24) max_branch_offset = 1 << 15; - if (branch_offset + max_branch_offset >= 2 * max_branch_offset) + if (branch_offset + max_branch_offset >= 2 * max_branch_offset - local_off) /* We need a stub. Figure out whether a long_branch or plt_branch is needed later. */ return ppc_stub_long_branch; @@ -9779,9 +10150,9 @@ ppc_type_of_stub (asection *input_sec, the appropriate glink entry if so. . fake dep barrier compare - . ld 11,xxx(2) ld 11,xxx(2) - . mtctr 11 mtctr 11 - . xor 11,11,11 ld 2,xxx+8(2) + . ld 12,xxx(2) ld 12,xxx(2) + . mtctr 12 mtctr 12 + . xor 11,12,12 ld 2,xxx+8(2) . add 2,2,11 cmpldi 2,0 . ld 2,xxx+8(2) bnectr+ . bctr b @@ -9801,23 +10172,27 @@ plt_stub_size (struct ppc_link_hash_table *htab, struct ppc_stub_hash_entry *stub_entry, bfd_vma off) { - unsigned size = PLT_CALL_STUB_SIZE; - - if (!(ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save)) - size -= 4; - if (!htab->plt_static_chain) - size -= 4; - if (htab->plt_thread_safe) - size += 8; - if (PPC_HA (off) == 0) - size -= 4; - if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off)) + unsigned size = 12; + + if (ALWAYS_EMIT_R2SAVE + || stub_entry->stub_type == ppc_stub_plt_call_r2save) + size += 4; + if (PPC_HA (off) != 0) size += 4; + if (htab->opd_abi) + { + size += 4; + if (htab->params->plt_static_chain) + size += 4; + if (htab->params->plt_thread_safe) + size += 8; + if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) != PPC_HA (off)) + size += 4; + } if (stub_entry->h != NULL && (stub_entry->h == htab->tls_get_addr_fd || stub_entry->h == htab->tls_get_addr) - && !htab->no_tls_get_addr_opt) + && !htab->params->no_tls_get_addr_opt) size += 13 * 4; return size; } @@ -9829,7 +10204,7 @@ plt_stub_pad (struct ppc_link_hash_table *htab, struct ppc_stub_hash_entry *stub_entry, bfd_vma plt_off) { - int stub_align = 1 << htab->plt_stub_align; + int stub_align = 1 << htab->params->plt_stub_align; unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off); bfd_vma stub_off = stub_entry->stub_sec->size; @@ -9846,21 +10221,24 @@ build_plt_stub (struct ppc_link_hash_table *htab, struct ppc_stub_hash_entry *stub_entry, bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r) { - bfd *obfd = htab->stub_bfd; - bfd_boolean plt_static_chain = htab->plt_static_chain; - bfd_boolean plt_thread_safe = htab->plt_thread_safe; + bfd *obfd = htab->params->stub_bfd; + bfd_boolean plt_load_toc = htab->opd_abi; + bfd_boolean plt_static_chain = htab->params->plt_static_chain; + bfd_boolean plt_thread_safe = htab->params->plt_thread_safe; bfd_boolean use_fake_dep = plt_thread_safe; bfd_vma cmp_branch_off = 0; if (!ALWAYS_USE_FAKE_DEP + && plt_load_toc && plt_thread_safe && !(stub_entry->h != NULL && (stub_entry->h == htab->tls_get_addr_fd || stub_entry->h == htab->tls_get_addr) - && !htab->no_tls_get_addr_opt)) + && !htab->params->no_tls_get_addr_opt)) { bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1; - bfd_vma pltindex = (pltoff - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE; + bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab)) + / PLT_ENTRY_SIZE (htab)); bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8; bfd_vma to, from; @@ -9894,44 +10272,59 @@ build_plt_stub (struct ppc_link_hash_table *htab, r[1].r_offset = r[0].r_offset + 4; r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); r[1].r_addend = r[0].r_addend; - if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) + if (plt_load_toc) { - r[2].r_offset = r[1].r_offset + 4; - r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO); - r[2].r_addend = r[0].r_addend; - } - else - { - r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep; - r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); - r[2].r_addend = r[0].r_addend + 8; - if (plt_static_chain) + if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) + { + r[2].r_offset = r[1].r_offset + 4; + r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO); + r[2].r_addend = r[0].r_addend; + } + else { - r[3].r_offset = r[2].r_offset + 4; - r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); - r[3].r_addend = r[0].r_addend + 16; + r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep; + r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); + r[2].r_addend = r[0].r_addend + 8; + if (plt_static_chain) + { + r[3].r_offset = r[2].r_offset + 4; + r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); + r[3].r_addend = r[0].r_addend + 16; + } } } } if (ALWAYS_EMIT_R2SAVE || stub_entry->stub_type == ppc_stub_plt_call_r2save) - bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; - bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4; - bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p), p += 4; - if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) + bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p), p += 4; + if (plt_load_toc) + { + bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p), p += 4; + bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p), p += 4; + } + else + { + bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4; + bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (offset), p), p += 4; + } + if (plt_load_toc + && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) { - bfd_put_32 (obfd, ADDI_R12_R12 | PPC_LO (offset), p), p += 4; + bfd_put_32 (obfd, ADDI_R11_R11 | PPC_LO (offset), p), p += 4; offset = 0; } - bfd_put_32 (obfd, MTCTR_R11, p), p += 4; - if (use_fake_dep) + bfd_put_32 (obfd, MTCTR_R12, p), p += 4; + if (plt_load_toc) { - bfd_put_32 (obfd, XOR_R11_R11_R11, p), p += 4; - bfd_put_32 (obfd, ADD_R12_R12_R11, p), p += 4; + if (use_fake_dep) + { + bfd_put_32 (obfd, XOR_R2_R12_R12, p), p += 4; + bfd_put_32 (obfd, ADD_R11_R11_R2, p), p += 4; + } + bfd_put_32 (obfd, LD_R2_0R11 | PPC_LO (offset + 8), p), p += 4; + if (plt_static_chain) + bfd_put_32 (obfd, LD_R11_0R11 | PPC_LO (offset + 16), p), p += 4; } - bfd_put_32 (obfd, LD_R2_0R12 | PPC_LO (offset + 8), p), p += 4; - if (plt_static_chain) - bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset + 16), p), p += 4; } else { @@ -9941,45 +10334,52 @@ build_plt_stub (struct ppc_link_hash_table *htab, || stub_entry->stub_type == ppc_stub_plt_call_r2save) r[0].r_offset += 4; r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); - if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) - { - r[1].r_offset = r[0].r_offset + 4; - r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16); - r[1].r_addend = r[0].r_addend; - } - else + if (plt_load_toc) { - r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep; - r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); - r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain; - if (plt_static_chain) + if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) { - r[2].r_offset = r[1].r_offset + 4; - r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); - r[2].r_addend = r[0].r_addend + 8; + r[1].r_offset = r[0].r_offset + 4; + r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16); + r[1].r_addend = r[0].r_addend; + } + else + { + r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep; + r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); + r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain; + if (plt_static_chain) + { + r[2].r_offset = r[1].r_offset + 4; + r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); + r[2].r_addend = r[0].r_addend + 8; + } } } } if (ALWAYS_EMIT_R2SAVE || stub_entry->stub_type == ppc_stub_plt_call_r2save) - bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; - bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset), p), p += 4; - if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) + bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p), p += 4; + bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (offset), p), p += 4; + if (plt_load_toc + && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) { bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (offset), p), p += 4; offset = 0; } - bfd_put_32 (obfd, MTCTR_R11, p), p += 4; - if (use_fake_dep) + bfd_put_32 (obfd, MTCTR_R12, p), p += 4; + if (plt_load_toc) { - bfd_put_32 (obfd, XOR_R11_R11_R11, p), p += 4; - bfd_put_32 (obfd, ADD_R2_R2_R11, p), p += 4; + if (use_fake_dep) + { + bfd_put_32 (obfd, XOR_R11_R12_R12, p), p += 4; + bfd_put_32 (obfd, ADD_R2_R2_R11, p), p += 4; + } + if (plt_static_chain) + bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4; + bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p), p += 4; } - if (plt_static_chain) - bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4; - bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p), p += 4; } - if (plt_thread_safe && !use_fake_dep) + if (plt_load_toc && plt_thread_safe && !use_fake_dep) { bfd_put_32 (obfd, CMPLDI_R2_0, p), p += 4; bfd_put_32 (obfd, BNECTR_P4, p), p += 4; @@ -9999,11 +10399,9 @@ build_plt_stub (struct ppc_link_hash_table *htab, #define ADD_R3_R12_R13 0x7c6c6a14 #define BEQLR 0x4d820020 #define MR_R3_R0 0x7c030378 -#define MFLR_R11 0x7d6802a6 #define STD_R11_0R1 0xf9610000 #define BCTRL 0x4e800421 #define LD_R11_0R1 0xe9610000 -#define LD_R2_0R1 0xe8410000 #define MTLR_R11 0x7d6803a6 static inline bfd_byte * @@ -10011,7 +10409,7 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab, struct ppc_stub_hash_entry *stub_entry, bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r) { - bfd *obfd = htab->stub_bfd; + bfd *obfd = htab->params->stub_bfd; bfd_put_32 (obfd, LD_R11_0R3 + 0, p), p += 4; bfd_put_32 (obfd, LD_R12_0R3 + 8, p), p += 4; @@ -10021,15 +10419,15 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab, bfd_put_32 (obfd, BEQLR, p), p += 4; bfd_put_32 (obfd, MR_R3_R0, p), p += 4; bfd_put_32 (obfd, MFLR_R11, p), p += 4; - bfd_put_32 (obfd, STD_R11_0R1 + 32, p), p += 4; + bfd_put_32 (obfd, STD_R11_0R1 + STK_LINKER (htab), p), p += 4; if (r != NULL) r[0].r_offset += 9 * 4; p = build_plt_stub (htab, stub_entry, p, offset, r); bfd_put_32 (obfd, BCTRL, p - 4); - bfd_put_32 (obfd, LD_R11_0R1 + 32, p), p += 4; - bfd_put_32 (obfd, LD_R2_0R1 + 40, p), p += 4; + bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p), p += 4; + bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p), p += 4; bfd_put_32 (obfd, MTLR_R11, p), p += 4; bfd_put_32 (obfd, BLR, p), p += 4; @@ -10078,6 +10476,8 @@ get_r2off (struct bfd_link_info *info, /* Support linking -R objects. Get the toc pointer from the opd entry. */ char buf[8]; + if (!htab->opd_abi) + return r2off; asection *opd = stub_entry->h->elf.root.u.def.section; bfd_vma opd_off = stub_entry->h->elf.root.u.def.value; @@ -10130,9 +10530,11 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) case ppc_stub_long_branch: case ppc_stub_long_branch_r2off: /* Branches are relative. This is where we are going to. */ - off = dest = (stub_entry->target_value - + stub_entry->target_section->output_offset - + stub_entry->target_section->output_section->vma); + dest = (stub_entry->target_value + + stub_entry->target_section->output_offset + + stub_entry->target_section->output_section->vma); + dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); + off = dest; /* And this is where we are coming from. */ off -= (stub_entry->stub_offset @@ -10149,20 +10551,21 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) htab->stub_error = TRUE; return FALSE; } - bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc); + bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc); loc += 4; size = 12; if (PPC_HA (r2off) != 0) { size = 16; - bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc); + bfd_put_32 (htab->params->stub_bfd, + ADDIS_R2_R2 | PPC_HA (r2off), loc); loc += 4; } - bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc); + bfd_put_32 (htab->params->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc); loc += 4; off -= size - 4; } - bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc); + bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), loc); if (off + (1 << 25) >= (bfd_vma) (1 << 26)) { @@ -10187,16 +10590,16 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) unsigned long symndx; struct ppc_link_hash_entry *h; - hashes = elf_sym_hashes (htab->stub_bfd); + hashes = elf_sym_hashes (htab->params->stub_bfd); if (hashes == NULL) { bfd_size_type hsize; hsize = (htab->stub_globals + 1) * sizeof (*hashes); - hashes = bfd_zalloc (htab->stub_bfd, hsize); + hashes = bfd_zalloc (htab->params->stub_bfd, hsize); if (hashes == NULL) return FALSE; - elf_sym_hashes (htab->stub_bfd) = hashes; + elf_sym_hashes (htab->params->stub_bfd) = hashes; htab->stub_globals = 1; } symndx = htab->stub_globals++; @@ -10235,6 +10638,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) dest = (stub_entry->target_value + stub_entry->target_section->output_offset + stub_entry->target_section->output_section->vma); + if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) + dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); bfd_put_64 (htab->brlt->owner, dest, htab->brlt->contents + br_entry->offset); @@ -10321,55 +10726,63 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (PPC_HA (off) != 0) { size = 16; - bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc); + bfd_put_32 (htab->params->stub_bfd, + ADDIS_R12_R2 | PPC_HA (off), loc); loc += 4; - bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc); + bfd_put_32 (htab->params->stub_bfd, + LD_R12_0R12 | PPC_LO (off), loc); } else { size = 12; - bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc); + bfd_put_32 (htab->params->stub_bfd, + LD_R12_0R2 | PPC_LO (off), loc); } } else { bfd_vma r2off = get_r2off (info, stub_entry); - if (r2off == 0) + if (r2off == 0 && htab->opd_abi) { htab->stub_error = TRUE; return FALSE; } - bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc); + bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc); loc += 4; - size = 20; + size = 16; if (PPC_HA (off) != 0) { size += 4; - bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc); - loc += 4; - bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc); + bfd_put_32 (htab->params->stub_bfd, + ADDIS_R12_R2 | PPC_HA (off), loc); loc += 4; + bfd_put_32 (htab->params->stub_bfd, + LD_R12_0R12 | PPC_LO (off), loc); } else + bfd_put_32 (htab->params->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc); + + if (PPC_HA (r2off) != 0) { - bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc); + size += 4; loc += 4; + bfd_put_32 (htab->params->stub_bfd, + ADDIS_R2_R2 | PPC_HA (r2off), loc); } - - if (PPC_HA (r2off) != 0) + if (PPC_LO (r2off) != 0) { size += 4; - bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc); loc += 4; + bfd_put_32 (htab->params->stub_bfd, + ADDI_R2_R2 | PPC_LO (r2off), loc); } - bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc); } loc += 4; - bfd_put_32 (htab->stub_bfd, MTCTR_R11, loc); + bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, loc); loc += 4; - bfd_put_32 (htab->stub_bfd, BCTR, loc); + bfd_put_32 (htab->params->stub_bfd, BCTR, loc); break; case ppc_stub_plt_call: @@ -10397,11 +10810,11 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (dest >= (bfd_vma) -2) abort (); - plt = htab->plt; + plt = htab->elf.splt; if (!htab->elf.dynamic_sections_created || stub_entry->h == NULL || stub_entry->h->elf.dynindx == -1) - plt = htab->iplt; + plt = htab->elf.iplt; dest += plt->output_offset + plt->output_section->vma; @@ -10412,13 +10825,16 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) bfd_byte *rl; rela.r_offset = dest; - rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + if (htab->opd_abi) + rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + else + rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); rela.r_addend = (stub_entry->target_value + stub_entry->target_section->output_offset + stub_entry->target_section->output_section->vma); - rl = (htab->reliplt->contents - + (htab->reliplt->reloc_count++ + rl = (htab->elf.irelplt->contents + + (htab->elf.irelplt->reloc_count++ * sizeof (Elf64_External_Rela))); bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl); stub_entry->plt_ent->plt.offset |= 1; @@ -10440,7 +10856,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; } - if (htab->plt_stub_align != 0) + if (htab->params->plt_stub_align != 0) { unsigned pad = plt_stub_pad (htab, stub_entry, off); @@ -10453,10 +10869,11 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (info->emitrelocations) { r = get_relocs (stub_entry->stub_sec, - (2 - + (PPC_HA (off) != 0) - + (htab->plt_static_chain - && PPC_HA (off + 16) == PPC_HA (off)))); + ((PPC_HA (off) != 0) + + (htab->opd_abi + ? 2 + (htab->params->plt_static_chain + && PPC_HA (off + 16) == PPC_HA (off)) + : 1))); if (r == NULL) return FALSE; r[0].r_offset = loc - stub_entry->stub_sec->contents; @@ -10467,7 +10884,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (stub_entry->h != NULL && (stub_entry->h == htab->tls_get_addr_fd || stub_entry->h == htab->tls_get_addr) - && !htab->no_tls_get_addr_opt) + && !htab->params->no_tls_get_addr_opt) p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r); else p = build_plt_stub (htab, stub_entry, loc, off, r); @@ -10481,7 +10898,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) stub_entry->stub_sec->size += size; - if (htab->emit_stub_syms) + if (htab->params->emit_stub_syms) { struct elf_link_hash_entry *h; size_t len1, len2; @@ -10548,26 +10965,27 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1; if (off >= (bfd_vma) -2) abort (); - plt = htab->plt; + plt = htab->elf.splt; if (!htab->elf.dynamic_sections_created || stub_entry->h == NULL || stub_entry->h->elf.dynindx == -1) - plt = htab->iplt; + plt = htab->elf.iplt; off += (plt->output_offset + plt->output_section->vma - elf_gp (plt->output_section->owner) - htab->stub_group[stub_entry->id_sec->id].toc_off); size = plt_stub_size (htab, stub_entry, off); - if (htab->plt_stub_align) + if (htab->params->plt_stub_align) size += plt_stub_pad (htab, stub_entry, off); if (info->emitrelocations) { stub_entry->stub_sec->reloc_count - += (2 - + (PPC_HA (off) != 0) - + (htab->plt_static_chain - && PPC_HA (off + 16) == PPC_HA (off))); + += ((PPC_HA (off) != 0) + + (htab->opd_abi + ? 2 + (htab->params->plt_static_chain + && PPC_HA (off + 16) == PPC_HA (off)) + : 1)); stub_entry->stub_sec->flags |= SEC_RELOC; } } @@ -10576,6 +10994,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) /* ppc_stub_long_branch or ppc_stub_plt_branch, or their r2off variants. */ bfd_vma r2off = 0; + bfd_vma local_off = 0; off = (stub_entry->target_value + stub_entry->target_section->output_offset @@ -10593,7 +11012,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (stub_entry->stub_type == ppc_stub_long_branch_r2off) { r2off = get_r2off (info, stub_entry); - if (r2off == 0) + if (r2off == 0 && htab->opd_abi) { htab->stub_error = TRUE; return FALSE; @@ -10604,8 +11023,13 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) off -= size - 4; } - /* If the branch offset if too big, use a ppc_stub_plt_branch. */ - if (off + (1 << 25) >= (bfd_vma) (1 << 26)) + local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); + + /* If the branch offset if too big, use a ppc_stub_plt_branch. + Do the same for -R objects without function descriptors. */ + if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off + || (stub_entry->stub_type == ppc_stub_long_branch_r2off + && r2off == 0)) { struct ppc_branch_hash_entry *br_entry; @@ -10656,12 +11080,14 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) } else { - size = 20; + size = 16; if (PPC_HA (off) != 0) size += 4; if (PPC_HA (r2off) != 0) size += 4; + if (PPC_LO (r2off) != 0) + size += 4; } } else if (info->emitrelocations) @@ -10680,10 +11106,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) 0 when no stubs will be needed, and 1 on success. */ int -ppc64_elf_setup_section_lists - (struct bfd_link_info *info, - asection *(*add_stub_section) (const char *, asection *), - void (*layout_sections_again) (void)) +ppc64_elf_setup_section_lists (struct bfd_link_info *info) { bfd *input_bfd; int top_id, top_index, id; @@ -10694,14 +11117,11 @@ ppc64_elf_setup_section_lists if (htab == NULL) return -1; - /* Stash our params away. */ - htab->add_stub_section = add_stub_section; - htab->layout_sections_again = layout_sections_again; /* Find the top input section id. */ for (input_bfd = info->input_bfds, top_id = 3; input_bfd != NULL; - input_bfd = input_bfd->link_next) + input_bfd = input_bfd->link.next) { for (section = input_bfd->sections; section != NULL; @@ -10882,7 +11302,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) elf_link_hash_traverse (&htab->elf, merge_global_got, info); /* And tlsld_got. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { struct got_entry *ent, *ent2; @@ -10893,7 +11313,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) if (!ent->is_indirect && ent->got.offset != (bfd_vma) -1) { - for (ibfd2 = ibfd->link_next; ibfd2 != NULL; ibfd2 = ibfd2->link_next) + for (ibfd2 = ibfd->link.next; ibfd2 != NULL; ibfd2 = ibfd2->link.next) { if (!is_ppc64_elf (ibfd2)) continue; @@ -10911,11 +11331,11 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) } /* Zap sizes of got sections. */ - htab->reliplt->rawsize = htab->reliplt->size; - htab->reliplt->size -= htab->got_reli_size; + htab->elf.irelplt->rawsize = htab->elf.irelplt->size; + htab->elf.irelplt->size -= htab->got_reli_size; htab->got_reli_size = 0; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { asection *got, *relgot; @@ -10935,7 +11355,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) /* Now reallocate the got, local syms first. We don't need to allocate section contents again since we never increase size. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { struct got_entry **lgot_ents; struct got_entry **end_lgot_ents; @@ -10978,7 +11398,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) s->size += ent_size; if ((*lgot_masks & PLT_IFUNC) != 0) { - htab->reliplt->size += rel_size; + htab->elf.irelplt->size += rel_size; htab->got_reli_size += rel_size; } else if (info->shared) @@ -10992,7 +11412,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) elf_link_hash_traverse (&htab->elf, reallocate_got, info); - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { struct got_entry *ent; @@ -11014,9 +11434,9 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) } } - done_something = htab->reliplt->rawsize != htab->reliplt->size; + done_something = htab->elf.irelplt->rawsize != htab->elf.irelplt->size; if (!done_something) - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { asection *got; @@ -11033,7 +11453,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) } if (done_something) - (*htab->layout_sections_again) (); + (*htab->params->layout_sections_again) (); /* Set up for second pass over toc sections to recalculate elf_gp on input sections. */ @@ -11202,7 +11622,10 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) need a plt_branch stub. A plt_branch stub uses r2. */ else if (dest - (isec->output_offset + isec->output_section->vma - + rel->r_offset) + (1 << 25) >= (2 << 25)) + + rel->r_offset) + (1 << 25) + >= (2u << 25) - PPC64_LOCAL_ENTRY_OFFSET (h + ? h->other + : sym->st_other)) { ret = 1; break; @@ -11296,42 +11719,25 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec) if (htab->multi_toc_needed) { - /* If a code section has a function that uses the TOC then we need - to use the right TOC (obviously). Also, make sure that .opd gets - the correct TOC value for R_PPC64_TOC relocs that don't have or - can't find their function symbol (shouldn't ever happen now). - Also specially treat .fixup for the linux kernel. .fixup - contains branches, but only back to the function that hit an - exception. */ - if (isec->has_toc_reloc - || (isec->flags & SEC_CODE) == 0 - || strcmp (isec->name, ".fixup") == 0) - { - if (elf_gp (isec->owner) != 0) - htab->toc_curr = elf_gp (isec->owner); - } - else + /* Analyse sections that aren't already flagged as needing a + valid toc pointer. Exclude .fixup for the linux kernel. + .fixup contains branches, but only back to the function that + hit an exception. */ + if (!(isec->has_toc_reloc + || (isec->flags & SEC_CODE) == 0 + || strcmp (isec->name, ".fixup") == 0 + || isec->call_check_done)) { - if (!isec->call_check_done - && toc_adjusting_stub_needed (info, isec) < 0) + if (toc_adjusting_stub_needed (info, isec) < 0) return FALSE; - /* If we make a local call from this section, ie. a branch - without a following nop, then we have no place to put a - toc restoring insn. We must use the same toc group as - the callee. - Testing makes_toc_func_call actually tests for *any* - calls to functions that need a good toc pointer. A more - precise test would be better, as this one will set - incorrect values for pasted .init/.fini fragments. - (Fixed later in check_pasted_section.) */ - if (isec->makes_toc_func_call - && elf_gp (isec->owner) != 0) - htab->toc_curr = elf_gp (isec->owner); - } - } - - /* Functions that don't use the TOC can belong in any TOC group. - Use the last TOC base. */ + } + /* Make all sections use the TOC assigned for this object file. + This will be wrong for pasted sections; We fix that in + check_pasted_section(). */ + if (elf_gp (isec->owner) != 0) + htab->toc_curr = elf_gp (isec->owner); + } + htab->stub_group[isec->id].toc_off = htab->toc_curr; return TRUE; } @@ -11399,7 +11805,7 @@ group_sections (struct ppc_link_hash_table *htab, bfd_boolean suppress_size_errors; suppress_size_errors = FALSE; - stub14_group_size = stub_group_size; + stub14_group_size = stub_group_size >> 10; if (stub_group_size == 1) { /* Default values. */ @@ -11503,7 +11909,8 @@ static const unsigned char glink_eh_frame_cie[] = 65, /* RA reg. */ 1, /* Augmentation size. */ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */ - DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */ + DW_CFA_def_cfa, 1, 0, /* def_cfa: r1 offset 0. */ + 0, 0, 0, 0 }; /* Stripping output sections is normally done before dynamic section @@ -11534,9 +11941,7 @@ maybe_strip_output (struct bfd_link_info *info, asection *isec) instruction. */ bfd_boolean -ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, - bfd_boolean plt_static_chain, int plt_thread_safe, - int plt_stub_align) +ppc64_elf_size_stubs (struct bfd_link_info *info) { bfd_size_type stub_group_size; bfd_boolean stubs_always_before_branch; @@ -11545,11 +11950,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, if (htab == NULL) return FALSE; - htab->plt_static_chain = plt_static_chain; - htab->plt_stub_align = plt_stub_align; - if (plt_thread_safe == -1 && !info->executable) - plt_thread_safe = 1; - if (plt_thread_safe == -1) + if (htab->params->plt_thread_safe == -1 && !info->executable) + htab->params->plt_thread_safe = 1; + if (!htab->opd_abi) + htab->params->plt_thread_safe = 0; + else if (htab->params->plt_thread_safe == -1) { static const char *const thread_starter[] = { @@ -11562,12 +11967,20 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, /* libanl */ "getaddrinfo_a", /* libgomp */ + "GOMP_parallel", "GOMP_parallel_start", + "GOMP_parallel_loop_static", "GOMP_parallel_loop_static_start", + "GOMP_parallel_loop_dynamic", "GOMP_parallel_loop_dynamic_start", + "GOMP_parallel_loop_guided", "GOMP_parallel_loop_guided_start", + "GOMP_parallel_loop_runtime", "GOMP_parallel_loop_runtime_start", + "GOMP_parallel_sections", "GOMP_parallel_sections_start", + /* libgo */ + "__go_go", }; unsigned i; @@ -11576,17 +11989,16 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, struct elf_link_hash_entry *h; h = elf_link_hash_lookup (&htab->elf, thread_starter[i], FALSE, FALSE, TRUE); - plt_thread_safe = h != NULL && h->ref_regular; - if (plt_thread_safe) + htab->params->plt_thread_safe = h != NULL && h->ref_regular; + if (htab->params->plt_thread_safe) break; } } - htab->plt_thread_safe = plt_thread_safe; - stubs_always_before_branch = group_size < 0; - if (group_size < 0) - stub_group_size = -group_size; + stubs_always_before_branch = htab->params->group_size < 0; + if (htab->params->group_size < 0) + stub_group_size = -htab->params->group_size; else - stub_group_size = group_size; + stub_group_size = htab->params->group_size; group_sections (htab, stub_group_size, stubs_always_before_branch); @@ -11600,7 +12012,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, for (input_bfd = info->input_bfds, bfd_indx = 0; input_bfd != NULL; - input_bfd = input_bfd->link_next, bfd_indx++) + input_bfd = input_bfd->link.next, bfd_indx++) { Elf_Internal_Shdr *symtab_hdr; asection *section; @@ -11655,6 +12067,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, asection *sym_sec, *code_sec; bfd_vma sym_value, code_value; bfd_vma destination; + unsigned long local_off; bfd_boolean ok_dest; struct ppc_link_hash_entry *hash; struct ppc_link_hash_entry *fdh; @@ -11731,12 +12144,16 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, } destination = 0; + local_off = 0; if (ok_dest) { sym_value += irela->r_addend; destination = (sym_value + sym_sec->output_offset + sym_sec->output_section->vma); + local_off = PPC64_LOCAL_ENTRY_OFFSET (hash + ? hash->elf.other + : sym->st_other); } code_sec = sym_sec; @@ -11773,7 +12190,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, /* Determine what (if any) linker stub is needed. */ plt_ent = NULL; stub_type = ppc_type_of_stub (section, irela, &hash, - &plt_ent, destination); + &plt_ent, destination, + local_off); if (stub_type != ppc_stub_plt_call) { @@ -11873,6 +12291,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, } stub_entry->h = hash; stub_entry->plt_ent = plt_ent; + stub_entry->other = hash ? hash->elf.other : sym->st_other; if (stub_entry->h != NULL) htab->stub_globals += 1; @@ -11895,7 +12314,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, /* We may have added some stubs. Find out the new size of the stub sections. */ - for (stub_sec = htab->stub_bfd->sections; + for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) @@ -11927,11 +12346,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, { size_t size = 0, align; - for (stub_sec = htab->stub_bfd->sections; + for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - size += 20; + size += 24; if (htab->glink != NULL && htab->glink->size != 0) size += 24; if (size != 0) @@ -11944,15 +12363,16 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, htab->glink_eh_frame->size = size; } - if (htab->plt_stub_align != 0) - for (stub_sec = htab->stub_bfd->sections; + if (htab->params->plt_stub_align != 0) + for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1) - & (-1 << htab->plt_stub_align)); + stub_sec->size = ((stub_sec->size + + (1 << htab->params->plt_stub_align) - 1) + & (-1 << htab->params->plt_stub_align)); - for (stub_sec = htab->stub_bfd->sections; + for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0 @@ -11967,7 +12387,90 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, break; /* Ask the linker to do its stuff. */ - (*htab->layout_sections_again) (); + (*htab->params->layout_sections_again) (); + } + + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->size != 0) + { + bfd_vma val; + bfd_byte *p, *last_fde; + size_t last_fde_len, size, align, pad; + asection *stub_sec; + + p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size); + if (p == NULL) + return FALSE; + htab->glink_eh_frame->contents = p; + last_fde = p; + + memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); + /* CIE length (rewrite in case little-endian). */ + last_fde_len = sizeof (glink_eh_frame_cie) - 4; + bfd_put_32 (htab->elf.dynobj, last_fde_len, p); + p += sizeof (glink_eh_frame_cie); + + for (stub_sec = htab->params->stub_bfd->sections; + stub_sec != NULL; + stub_sec = stub_sec->next) + if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) + { + last_fde = p; + last_fde_len = 20; + /* FDE length. */ + bfd_put_32 (htab->elf.dynobj, 20, p); + p += 4; + /* CIE pointer. */ + val = p - htab->glink_eh_frame->contents; + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* Offset to stub section, written later. */ + p += 4; + /* stub section size. */ + bfd_put_32 (htab->elf.dynobj, stub_sec->size, p); + p += 4; + /* Augmentation. */ + p += 1; + /* Pad. */ + p += 7; + } + if (htab->glink != NULL && htab->glink->size != 0) + { + last_fde = p; + last_fde_len = 20; + /* FDE length. */ + bfd_put_32 (htab->elf.dynobj, 20, p); + p += 4; + /* CIE pointer. */ + val = p - htab->glink_eh_frame->contents; + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* Offset to .glink, written later. */ + p += 4; + /* .glink size. */ + bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p); + p += 4; + /* Augmentation. */ + p += 1; + + *p++ = DW_CFA_advance_loc + 1; + *p++ = DW_CFA_register; + *p++ = 65; + *p++ = 12; + *p++ = DW_CFA_advance_loc + 4; + *p++ = DW_CFA_restore_extended; + *p++ = 65; + } + /* Subsume any padding into the last FDE if user .eh_frame + sections are aligned more than glink_eh_frame. Otherwise any + zero padding will be seen as a terminator. */ + size = p - htab->glink_eh_frame->contents; + align = 1; + align <<= htab->glink_eh_frame->output_section->alignment_power; + align -= 1; + pad = ((size + align) & ~align) - size; + htab->glink_eh_frame->size = size + pad; + bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde); } maybe_strip_output (info, htab->brlt); @@ -12034,49 +12537,145 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd) _bfd_set_gp_value (obfd, TOCstart); - if (info != NULL && s != NULL && is_ppc64_elf (obfd)) + if (info != NULL && s != NULL) { struct ppc_link_hash_table *htab = ppc_hash_table (info); - if (htab != NULL - && htab->elf.hgot != NULL) + if (htab != NULL) + { + if (htab->elf.hgot != NULL) + { + htab->elf.hgot->root.u.def.value = TOC_BASE_OFF; + htab->elf.hgot->root.u.def.section = s; + } + } + else { - htab->elf.hgot->type = STT_OBJECT; - htab->elf.hgot->root.type = bfd_link_hash_defined; - htab->elf.hgot->root.u.def.value = TOC_BASE_OFF; - htab->elf.hgot->root.u.def.section = s; + struct bfd_link_hash_entry *bh = NULL; + _bfd_generic_link_add_one_symbol (info, obfd, ".TOC.", BSF_GLOBAL, + s, TOC_BASE_OFF, NULL, FALSE, + FALSE, &bh); } } return TOCstart; } -/* Build all the stubs associated with the current output file. - The stubs are kept in a hash table attached to the main linker - hash table. This function is called via gldelf64ppc_finish. */ +/* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to + write out any global entry stubs. */ -bfd_boolean -ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, - struct bfd_link_info *info, - char **stats) +static bfd_boolean +build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) { - struct ppc_link_hash_table *htab = ppc_hash_table (info); - asection *stub_sec; - bfd_byte *p; - int stub_sec_count = 0; + struct bfd_link_info *info; + struct ppc_link_hash_table *htab; + struct plt_entry *pent; + asection *s; + + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + if (!h->pointer_equality_needed) + return TRUE; + + if (h->def_regular) + return TRUE; + info = inf; + htab = ppc_hash_table (info); if (htab == NULL) return FALSE; - htab->emit_stub_syms = emit_stub_syms; + s = htab->glink; + for (pent = h->plt.plist; pent != NULL; pent = pent->next) + if (pent->plt.offset != (bfd_vma) -1 + && pent->addend == 0) + { + bfd_byte *p; + asection *plt; + bfd_vma off; + + p = s->contents + h->root.u.def.value; + plt = htab->elf.splt; + if (!htab->elf.dynamic_sections_created + || h->dynindx == -1) + plt = htab->elf.iplt; + off = pent->plt.offset + plt->output_offset + plt->output_section->vma; + off -= h->root.u.def.value + s->output_offset + s->output_section->vma; + + if (off + 0x80008000 > 0xffffffff || (off & 3) != 0) + { + info->callbacks->einfo + (_("%P: linkage table error against `%T'\n"), + h->root.root.string); + bfd_set_error (bfd_error_bad_value); + htab->stub_error = TRUE; + } + + htab->stub_count[ppc_stub_global_entry - 1] += 1; + if (htab->params->emit_stub_syms) + { + size_t len = strlen (h->root.root.string); + char *name = bfd_malloc (sizeof "12345678.global_entry." + len); + + if (name == NULL) + return FALSE; + + sprintf (name, "%08x.global_entry.%s", s->id, h->root.root.string); + h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); + if (h == NULL) + return FALSE; + if (h->root.type == bfd_link_hash_new) + { + h->root.type = bfd_link_hash_defined; + h->root.u.def.section = s; + h->root.u.def.value = p - s->contents; + h->ref_regular = 1; + h->def_regular = 1; + h->ref_regular_nonweak = 1; + h->forced_local = 1; + h->non_elf = 0; + } + } + + if (PPC_HA (off) != 0) + { + bfd_put_32 (s->owner, ADDIS_R12_R12 | PPC_HA (off), p); + p += 4; + } + bfd_put_32 (s->owner, LD_R12_0R12 | PPC_LO (off), p); + p += 4; + bfd_put_32 (s->owner, MTCTR_R12, p); + p += 4; + bfd_put_32 (s->owner, BCTR, p); + break; + } + return TRUE; +} + +/* Build all the stubs associated with the current output file. + The stubs are kept in a hash table attached to the main linker + hash table. This function is called via gldelf64ppc_finish. */ + +bfd_boolean +ppc64_elf_build_stubs (struct bfd_link_info *info, + char **stats) +{ + struct ppc_link_hash_table *htab = ppc_hash_table (info); + asection *stub_sec; + bfd_byte *p; + int stub_sec_count = 0; + + if (htab == NULL) + return FALSE; /* Allocate memory to hold the linker stubs. */ - for (stub_sec = htab->stub_bfd->sections; + for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0 && stub_sec->size != 0) { - stub_sec->contents = bfd_zalloc (htab->stub_bfd, stub_sec->size); + stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, stub_sec->size); if (stub_sec->contents == NULL) return FALSE; /* We want to check that built size is the same as calculated @@ -12091,7 +12690,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, bfd_vma plt0; /* Build the .glink plt call stub. */ - if (htab->emit_stub_syms) + if (htab->params->emit_stub_syms) { struct elf_link_hash_entry *h; h = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve", @@ -12110,7 +12709,9 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, h->non_elf = 0; } } - plt0 = htab->plt->output_section->vma + htab->plt->output_offset - 16; + plt0 = (htab->elf.splt->output_section->vma + + htab->elf.splt->output_offset + - 16); if (info->emitrelocations) { Elf_Internal_Rela *r = get_relocs (htab->glink, 1); @@ -12125,26 +12726,56 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, plt0 -= htab->glink->output_section->vma + htab->glink->output_offset; bfd_put_64 (htab->glink->owner, plt0, p); p += 8; - bfd_put_32 (htab->glink->owner, MFLR_R12, p); - p += 4; - bfd_put_32 (htab->glink->owner, BCL_20_31, p); - p += 4; - bfd_put_32 (htab->glink->owner, MFLR_R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R2_M16R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, MTLR_R12, p); - p += 4; - bfd_put_32 (htab->glink->owner, ADD_R12_R2_R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R11_0R12, p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R2_0R12 | 8, p); - p += 4; - bfd_put_32 (htab->glink->owner, MTCTR_R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R11_0R12 | 16, p); - p += 4; + if (htab->opd_abi) + { + bfd_put_32 (htab->glink->owner, MFLR_R12, p); + p += 4; + bfd_put_32 (htab->glink->owner, BCL_20_31, p); + p += 4; + bfd_put_32 (htab->glink->owner, MFLR_R11, p); + p += 4; + bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p); + p += 4; + bfd_put_32 (htab->glink->owner, MTLR_R12, p); + p += 4; + bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p); + p += 4; + bfd_put_32 (htab->glink->owner, LD_R12_0R11, p); + p += 4; + bfd_put_32 (htab->glink->owner, LD_R2_0R11 | 8, p); + p += 4; + bfd_put_32 (htab->glink->owner, MTCTR_R12, p); + p += 4; + bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 16, p); + p += 4; + } + else + { + bfd_put_32 (htab->glink->owner, MFLR_R0, p); + p += 4; + bfd_put_32 (htab->glink->owner, BCL_20_31, p); + p += 4; + bfd_put_32 (htab->glink->owner, MFLR_R11, p); + p += 4; + bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p); + p += 4; + bfd_put_32 (htab->glink->owner, MTLR_R0, p); + p += 4; + bfd_put_32 (htab->glink->owner, SUB_R12_R12_R11, p); + p += 4; + bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p); + p += 4; + bfd_put_32 (htab->glink->owner, ADDI_R0_R12 | (-48 & 0xffff), p); + p += 4; + bfd_put_32 (htab->glink->owner, LD_R12_0R11, p); + p += 4; + bfd_put_32 (htab->glink->owner, SRDI_R0_R0_2, p); + p += 4; + bfd_put_32 (htab->glink->owner, MTCTR_R12, p); + p += 4; + bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 8, p); + p += 4; + } bfd_put_32 (htab->glink->owner, BCTR, p); p += 4; while (p - htab->glink->contents < GLINK_CALL_STUB_SIZE) @@ -12155,29 +12786,36 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, /* Build the .glink lazy link call stubs. */ indx = 0; - while (p < htab->glink->contents + htab->glink->size) + while (p < htab->glink->contents + htab->glink->rawsize) { - if (indx < 0x8000) - { - bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p); - p += 4; - } - else + if (htab->opd_abi) { - bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p); - p += 4; - bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx), p); - p += 4; + if (indx < 0x8000) + { + bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p); + p += 4; + } + else + { + bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p); + p += 4; + bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx), + p); + p += 4; + } } bfd_put_32 (htab->glink->owner, B_DOT | ((htab->glink->contents - p + 8) & 0x3fffffc), p); indx++; p += 4; } - htab->glink->rawsize = p - htab->glink->contents; + + /* Build .glink global entry stubs. */ + if (htab->glink->size > htab->glink->rawsize) + elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info); } - if (htab->brlt->size != 0) + if (htab->brlt != NULL && htab->brlt->size != 0) { htab->brlt->contents = bfd_zalloc (htab->brlt->owner, htab->brlt->size); @@ -12192,132 +12830,22 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, return FALSE; } - if (htab->glink_eh_frame != NULL - && htab->glink_eh_frame->size != 0) - { - bfd_vma val; - bfd_byte *last_fde; - size_t last_fde_len, size, align, pad; - - p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size); - if (p == NULL) - return FALSE; - htab->glink_eh_frame->contents = p; - last_fde = p; - - htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size; - - memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); - /* CIE length (rewrite in case little-endian). */ - last_fde_len = sizeof (glink_eh_frame_cie) - 4; - bfd_put_32 (htab->elf.dynobj, last_fde_len, p); - p += sizeof (glink_eh_frame_cie); - - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - { - last_fde = p; - last_fde_len = 16; - /* FDE length. */ - bfd_put_32 (htab->elf.dynobj, 16, p); - p += 4; - /* CIE pointer. */ - val = p - htab->glink_eh_frame->contents; - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* Offset to stub section. */ - val = (stub_sec->output_section->vma - + stub_sec->output_offset); - val -= (htab->glink_eh_frame->output_section->vma - + htab->glink_eh_frame->output_offset); - val -= p - htab->glink_eh_frame->contents; - if (val + 0x80000000 > 0xffffffff) - { - info->callbacks->einfo - (_("%P: %s offset too large for .eh_frame sdata4 encoding"), - stub_sec->name); - return FALSE; - } - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* stub section size. */ - bfd_put_32 (htab->elf.dynobj, stub_sec->rawsize, p); - p += 4; - /* Augmentation. */ - p += 1; - /* Pad. */ - p += 3; - } - if (htab->glink != NULL && htab->glink->size != 0) - { - last_fde = p; - last_fde_len = 20; - /* FDE length. */ - bfd_put_32 (htab->elf.dynobj, 20, p); - p += 4; - /* CIE pointer. */ - val = p - htab->glink_eh_frame->contents; - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* Offset to .glink. */ - val = (htab->glink->output_section->vma - + htab->glink->output_offset - + 8); - val -= (htab->glink_eh_frame->output_section->vma - + htab->glink_eh_frame->output_offset); - val -= p - htab->glink_eh_frame->contents; - if (val + 0x80000000 > 0xffffffff) - { - info->callbacks->einfo - (_("%P: %s offset too large for .eh_frame sdata4 encoding"), - htab->glink->name); - return FALSE; - } - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* .glink size. */ - bfd_put_32 (htab->elf.dynobj, htab->glink->rawsize - 8, p); - p += 4; - /* Augmentation. */ - p += 1; - - *p++ = DW_CFA_advance_loc + 1; - *p++ = DW_CFA_register; - *p++ = 65; - *p++ = 12; - *p++ = DW_CFA_advance_loc + 4; - *p++ = DW_CFA_restore_extended; - *p++ = 65; - } - /* Subsume any padding into the last FDE if user .eh_frame - sections are aligned more than glink_eh_frame. Otherwise any - zero padding will be seen as a terminator. */ - size = p - htab->glink_eh_frame->contents; - align = 1; - align <<= htab->glink_eh_frame->output_section->alignment_power; - align -= 1; - pad = ((size + align) & ~align) - size; - htab->glink_eh_frame->size = size + pad; - bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde); - } - /* Build the stubs as directed by the stub hash table. */ bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info); if (htab->relbrlt != NULL) htab->relbrlt->reloc_count = 0; - if (htab->plt_stub_align != 0) - for (stub_sec = htab->stub_bfd->sections; + if (htab->params->plt_stub_align != 0) + for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1) - & (-1 << htab->plt_stub_align)); + stub_sec->size = ((stub_sec->size + + (1 << htab->params->plt_stub_align) - 1) + & (-1 << htab->params->plt_stub_align)); - for (stub_sec = htab->stub_bfd->sections; + for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) @@ -12327,8 +12855,10 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, break; } + /* Note that the glink_eh_frame check here is not only testing that + the generated size matched the calculated size but also that + bfd_elf_discard_info didn't make any changes to the section. */ if (stub_sec != NULL - || htab->glink->rawsize != htab->glink->size || (htab->glink_eh_frame != NULL && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size)) { @@ -12351,7 +12881,8 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, " long branch %lu\n" " long toc adj %lu\n" " plt call %lu\n" - " plt call toc %lu"), + " plt call toc %lu\n" + " global entry %lu"), stub_sec_count, stub_sec_count == 1 ? "" : "s", htab->stub_count[ppc_stub_long_branch - 1], @@ -12359,7 +12890,8 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, htab->stub_count[ppc_stub_plt_branch - 1], htab->stub_count[ppc_stub_plt_branch_r2off - 1], htab->stub_count[ppc_stub_plt_call - 1], - htab->stub_count[ppc_stub_plt_call_r2save - 1]); + htab->stub_count[ppc_stub_plt_call_r2save - 1], + htab->stub_count[ppc_stub_global_entry - 1]); } return TRUE; } @@ -12472,7 +13004,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, return FALSE; /* Don't relocate stub sections. */ - if (input_section->owner == htab->stub_bfd) + if (input_section->owner == htab->params->stub_bfd) return TRUE; BFD_ASSERT (is_ppc64_elf (input_bfd)); @@ -12510,6 +13042,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_vma max_br_offset; bfd_vma from; const Elf_Internal_Rela orig_rel = *rel; + reloc_howto_type *howto; + struct reloc_howto_struct alt_howto; r_type = ELF64_R_TYPE (rel->r_info); r_symndx = ELF64_R_SYM (rel->r_info); @@ -12562,10 +13096,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, } else { + bfd_boolean ignored; + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, r_symndx, symtab_hdr, sym_hashes, h_elf, sec, relocation, - unresolved_reloc, warned); + unresolved_reloc, warned, ignored); sym_name = h_elf->root.root.string; sym_type = h_elf->type; if (sec != NULL @@ -13070,6 +13606,40 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_info = ELF64_R_INFO (r_symndx, r_type); } break; + + case R_PPC64_REL16_HA: + /* If we are generating a non-PIC executable, edit + . 0: addis 2,12,.TOC.-0b@ha + . addi 2,2,.TOC.-0b@l + used by ELFv2 global entry points to set up r2, to + . lis 2,.TOC.@ha + . addi 2,2,.TOC.@l + if .TOC. is in range. */ + if (!info->shared + && !info->traditional_format + && h != NULL && &h->elf == htab->elf.hgot + && rel + 1 < relend + && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO) + && rel[1].r_offset == rel->r_offset + 4 + && rel[1].r_addend == rel->r_addend + 4 + && relocation + 0x80008000 <= 0xffffffff) + { + unsigned int insn1, insn2; + bfd_vma offset = rel->r_offset - d_offset; + insn1 = bfd_get_32 (output_bfd, contents + offset); + insn2 = bfd_get_32 (output_bfd, contents + offset + 4); + if ((insn1 & 0xffff0000) == 0x3c4c0000 /* addis 2,12 */ + && (insn2 & 0xffff0000) == 0x38420000 /* addi 2,2 */) + { + r_type = R_PPC64_ADDR16_HA; + rel->r_info = ELF64_R_INFO (r_symndx, r_type); + rel->r_addend -= d_offset; + rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_ADDR16_LO); + rel[1].r_addend -= d_offset + 4; + bfd_put_32 (output_bfd, 0x3c400000, contents + offset); + } + } + break; } /* Handle other relocations that tweak non-addend part of insn. */ @@ -13092,7 +13662,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, insn = bfd_get_32 (input_bfd, contents + rel->r_offset); if (insn == NOP || insn == CROR_151515 || insn == CROR_313131) - bfd_put_32 (input_bfd, STD_R2_40R1, + bfd_put_32 (input_bfd, + STD_R2_0R1 + STK_TOC (htab), contents + rel->r_offset); } break; @@ -13157,12 +13728,13 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (h != NULL && (h == htab->tls_get_addr_fd || h == htab->tls_get_addr) - && !htab->no_tls_get_addr_opt) + && !htab->params->no_tls_get_addr_opt) { /* Special stub used, leave nop alone. */ } else - bfd_put_32 (input_bfd, LD_R2_40R1, + bfd_put_32 (input_bfd, + LD_R2_0R1 + STK_TOC (htab), contents + rel->r_offset + 4); can_plt_call = TRUE; } @@ -13212,10 +13784,17 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (!can_plt_call) { - info->callbacks->einfo - (_("%P: %H: call to `%T' lacks nop, can't restore toc; " - "recompile with -fPIC"), - input_bfd, input_section, rel->r_offset, sym_name); + if (stub_entry->stub_type == ppc_stub_plt_call + || stub_entry->stub_type == ppc_stub_plt_call_r2save) + info->callbacks->einfo + (_("%P: %H: call to `%T' lacks nop, can't restore toc; " + "recompile with -fPIC\n"), + input_bfd, input_section, rel->r_offset, sym_name); + else + info->callbacks->einfo + (_("%P: %H: call to `%T' lacks nop, can't restore toc; " + "(-mcmodel=small toc adjust stub)\n"), + input_bfd, input_section, rel->r_offset, sym_name); bfd_set_error (bfd_error_bad_value); ret = FALSE; @@ -13251,6 +13830,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, + input_section->output_offset + input_section->output_section->vma); + relocation += PPC64_LOCAL_ENTRY_OFFSET (fdh + ? fdh->elf.other + : sym->st_other); + if (stub_entry != NULL && (stub_entry->stub_type == ppc_stub_long_branch || stub_entry->stub_type == ppc_stub_plt_branch) @@ -13404,7 +13987,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, &h->elf) || (info->shared - && SYMBOL_CALLS_LOCAL (info, &h->elf))) + && SYMBOL_REFERENCES_LOCAL (info, &h->elf))) /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined locally, or the symbol was forced to be local @@ -13461,7 +14044,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, ? h->elf.type == STT_GNU_IFUNC : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC); if (ifunc) - relgot = htab->reliplt; + relgot = htab->elf.irelplt; else if ((info->shared || indx != 0) && (h == NULL || (tls_type == (TLS_TLS | TLS_LD) @@ -13575,17 +14158,18 @@ ppc64_elf_relocate_section (bfd *output_bfd, symbol. This happens when statically linking PIC code, or when using -Bsymbolic. Go find a match if there is a PLT entry. */ - if (htab->plt != NULL) + if (htab->elf.splt != NULL) { struct plt_entry *ent; for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next) - if (ent->addend == orig_rel.r_addend - && ent->plt.offset != (bfd_vma) -1) + if (ent->plt.offset != (bfd_vma) -1 + && ent->addend == orig_rel.r_addend) { - relocation = (htab->plt->output_section->vma - + htab->plt->output_offset + relocation = (htab->elf.splt->output_section->vma + + htab->elf.splt->output_offset + ent->plt.offset); unresolved_reloc = FALSE; + break; } } break; @@ -13690,6 +14274,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, addend -= htab->elf.tls_sec->vma + DTP_OFFSET; break; + case R_PPC64_ADDR64_LOCAL: + addend += PPC64_LOCAL_ENTRY_OFFSET (h != NULL + ? h->elf.other + : sym->st_other); + break; + case R_PPC64_DTPMOD64: relocation = 1; addend = 0; @@ -13788,7 +14378,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (skip) memset (&outrel, 0, sizeof outrel); - else if (!SYMBOL_CALLS_LOCAL (info, &h->elf) + else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf) && !is_opd && r_type != R_PPC64_TOC) { @@ -13891,7 +14481,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (h != NULL ? h->elf.type == STT_GNU_IFUNC : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) - sreloc = htab->reliplt; + sreloc = htab->elf.irelplt; if (sreloc == NULL) abort (); @@ -14026,6 +14616,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, } /* Do any further special processing. */ + howto = ppc64_elf_howto_table[(int) r_type]; switch (r_type) { default: @@ -14100,7 +14691,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, info->callbacks->einfo (_("%P: %H: error: %s not a multiple of %u\n"), input_bfd, input_section, rel->r_offset, - ppc64_elf_howto_table[r_type]->name, + howto->name, mask + 1); bfd_set_error (bfd_error_bad_value); ret = FALSE; @@ -14121,23 +14712,46 @@ ppc64_elf_relocate_section (bfd *output_bfd, info->callbacks->einfo (_("%P: %H: unresolvable %s against `%T'\n"), input_bfd, input_section, rel->r_offset, - ppc64_elf_howto_table[(int) r_type]->name, + howto->name, h->elf.root.root.string); ret = FALSE; } - r = _bfd_final_link_relocate (ppc64_elf_howto_table[(int) r_type], - input_bfd, - input_section, - contents, - rel->r_offset, - relocation, - addend); + /* 16-bit fields in insns mostly have signed values, but a + few insns have 16-bit unsigned values. Really, we should + have different reloc types. */ + if (howto->complain_on_overflow != complain_overflow_dont + && howto->dst_mask == 0xffff + && (input_section->flags & SEC_CODE) != 0) + { + enum complain_overflow complain = complain_overflow_signed; + + insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); + if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */) + complain = complain_overflow_bitfield; + else if (howto->rightshift == 0 + ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */ + || (insn & (0x3f << 26)) == 24u << 26 /* ori */ + || (insn & (0x3f << 26)) == 26u << 26 /* xori */) + : ((insn & (0x3f << 26)) == 29u << 26 /* andis */ + || (insn & (0x3f << 26)) == 25u << 26 /* oris */ + || (insn & (0x3f << 26)) == 27u << 26 /* xoris */)) + complain = complain_overflow_unsigned; + if (howto->complain_on_overflow != complain) + { + alt_howto = *howto; + alt_howto.complain_on_overflow = complain; + howto = &alt_howto; + } + } + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, + rel->r_offset, relocation, addend); if (r != bfd_reloc_ok) { char *more_info = NULL; - const char *reloc_name = ppc64_elf_howto_table[r_type]->name; + const char *reloc_name = howto->name; if (reloc_dest != DEST_NORMAL) { @@ -14157,7 +14771,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, continue; if (h != NULL && h->elf.root.type == bfd_link_hash_undefweak - && ppc64_elf_howto_table[r_type]->pc_relative) + && howto->pc_relative) { /* Assume this is a call protected by other code that detects the symbol is undefined. If this is the case, @@ -14268,30 +14882,57 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, && h->def_regular && (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak)); - rela.r_offset = (htab->iplt->output_section->vma - + htab->iplt->output_offset + rela.r_offset = (htab->elf.iplt->output_section->vma + + htab->elf.iplt->output_offset + ent->plt.offset); - rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + if (htab->opd_abi) + rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); + else + rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); rela.r_addend = (h->root.u.def.value + h->root.u.def.section->output_offset + h->root.u.def.section->output_section->vma + ent->addend); - loc = (htab->reliplt->contents - + (htab->reliplt->reloc_count++ + loc = (htab->elf.irelplt->contents + + (htab->elf.irelplt->reloc_count++ * sizeof (Elf64_External_Rela))); } else { - rela.r_offset = (htab->plt->output_section->vma - + htab->plt->output_offset + rela.r_offset = (htab->elf.splt->output_section->vma + + htab->elf.splt->output_offset + ent->plt.offset); rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT); rela.r_addend = ent->addend; - loc = (htab->relplt->contents - + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) - / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela)))); + loc = (htab->elf.srelplt->contents + + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab)) + / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela))); } bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); + + if (!htab->opd_abi) + { + if (!h->def_regular) + { + /* Mark the symbol as undefined, rather than as + defined in glink. Leave the value if there were + any relocations where pointer equality matters + (this is a clue for the dynamic linker, to make + function pointer comparisons work between an + application and shared library), otherwise set it + to zero. */ + sym->st_shndx = SHN_UNDEF; + if (!h->pointer_equality_needed) + sym->st_value = 0; + else if (!h->ref_regular_nonweak) + { + /* This breaks function pointer comparisons, but + that is better than breaking tests for a NULL + function pointer. */ + sym->st_value = 0; + } + } + } } if (h->needs_copy) @@ -14328,7 +14969,7 @@ ppc64_elf_reloc_type_class (const struct bfd_link_info *info, enum elf_ppc64_reloc_type r_type; struct ppc_link_hash_table *htab = ppc_hash_table (info); - if (rel_sec == htab->reliplt) + if (rel_sec == htab->elf.irelplt) return reloc_class_ifunc; r_type = ELF64_R_TYPE (rela->r_info); @@ -14366,7 +15007,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, { Elf64_External_Dyn *dyncon, *dynconend; - if (sdyn == NULL || htab->got == NULL) + if (sdyn == NULL || htab->elf.sgot == NULL) abort (); dyncon = (Elf64_External_Dyn *) sdyn->contents; @@ -14390,7 +15031,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, of glink rather than the first entry point, which is what ld.so needs, and now have a bigger stub to support automatic multiple TOCs. */ - dyn.d_un.d_ptr += GLINK_CALL_STUB_SIZE - 32; + dyn.d_un.d_ptr += GLINK_CALL_STUB_SIZE - 8 * 4; break; case DT_PPC64_OPD: @@ -14400,6 +15041,11 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, dyn.d_un.d_ptr = s->vma; break; + case DT_PPC64_OPT: + if (htab->do_multi_toc && htab->multi_toc_needed) + dyn.d_un.d_val |= PPC64_OPT_MULTI_TOC; + break; + case DT_PPC64_OPDSZ: s = bfd_get_section_by_name (output_bfd, ".opd"); if (s == NULL) @@ -14408,23 +15054,23 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, break; case DT_PLTGOT: - s = htab->plt; + s = htab->elf.splt; dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; break; case DT_JMPREL: - s = htab->relplt; + s = htab->elf.srelplt; dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; break; case DT_PLTRELSZ: - dyn.d_un.d_val = htab->relplt->size; + dyn.d_un.d_val = htab->elf.srelplt->size; break; case DT_RELASZ: /* Don't count procedure linkage table relocs in the overall reloc count. */ - s = htab->relplt; + s = htab->elf.srelplt; if (s == NULL) continue; dyn.d_un.d_val -= s->size; @@ -14434,7 +15080,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, /* We may not be using the standard ELF linker script. If .rela.plt is the first .rela section, we adjust DT_RELA to not include it. */ - s = htab->relplt; + s = htab->elf.srelplt; if (s == NULL) continue; if (dyn.d_un.d_ptr != s->output_section->vma + s->output_offset) @@ -14447,23 +15093,23 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, } } - if (htab->got != NULL && htab->got->size != 0) + if (htab->elf.sgot != NULL && htab->elf.sgot->size != 0) { /* Fill in the first entry in the global offset table. We use it to hold the link-time TOCbase. */ bfd_put_64 (output_bfd, elf_gp (output_bfd) + TOC_BASE_OFF, - htab->got->contents); + htab->elf.sgot->contents); /* Set .got entry size. */ - elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 8; + elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 8; } - if (htab->plt != NULL && htab->plt->size != 0) + if (htab->elf.splt != NULL && htab->elf.splt->size != 0) { /* Set .plt entry size. */ - elf_section_data (htab->plt->output_section)->this_hdr.sh_entsize - = PLT_ENTRY_SIZE; + elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize + = PLT_ENTRY_SIZE (htab); } /* brlt is SEC_LINKER_CREATED, so we need to write out relocs for @@ -14486,18 +15132,86 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, NULL)) return FALSE; - if (htab->glink_eh_frame != NULL - && htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME - && !_bfd_elf_write_section_eh_frame (output_bfd, info, - htab->glink_eh_frame, - htab->glink_eh_frame->contents)) - return FALSE; + && htab->glink_eh_frame->size != 0) + { + bfd_vma val; + bfd_byte *p; + asection *stub_sec; + + p = htab->glink_eh_frame->contents + sizeof (glink_eh_frame_cie); + for (stub_sec = htab->params->stub_bfd->sections; + stub_sec != NULL; + stub_sec = stub_sec->next) + if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) + { + /* FDE length. */ + p += 4; + /* CIE pointer. */ + p += 4; + /* Offset to stub section. */ + val = (stub_sec->output_section->vma + + stub_sec->output_offset); + val -= (htab->glink_eh_frame->output_section->vma + + htab->glink_eh_frame->output_offset + + (p - htab->glink_eh_frame->contents)); + if (val + 0x80000000 > 0xffffffff) + { + info->callbacks->einfo + (_("%P: %s offset too large for .eh_frame sdata4 encoding"), + stub_sec->name); + return FALSE; + } + bfd_put_32 (dynobj, val, p); + p += 4; + /* stub section size. */ + p += 4; + /* Augmentation. */ + p += 1; + /* Pad. */ + p += 7; + } + if (htab->glink != NULL && htab->glink->size != 0) + { + /* FDE length. */ + p += 4; + /* CIE pointer. */ + p += 4; + /* Offset to .glink. */ + val = (htab->glink->output_section->vma + + htab->glink->output_offset + + 8); + val -= (htab->glink_eh_frame->output_section->vma + + htab->glink_eh_frame->output_offset + + (p - htab->glink_eh_frame->contents)); + if (val + 0x80000000 > 0xffffffff) + { + info->callbacks->einfo + (_("%P: %s offset too large for .eh_frame sdata4 encoding"), + htab->glink->name); + return FALSE; + } + bfd_put_32 (dynobj, val, p); + p += 4; + /* .glink size. */ + p += 4; + /* Augmentation. */ + p += 1; + /* Ops. */ + p += 7; + } + + if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME + && !_bfd_elf_write_section_eh_frame (output_bfd, info, + htab->glink_eh_frame, + htab->glink_eh_frame->contents)) + return FALSE; + } /* We need to handle writing out multiple GOT sections ourselves, since we didn't add them to DYNOBJ. We know dynobj is the first bfd. */ - while ((dynobj = dynobj->link_next) != NULL) + while ((dynobj = dynobj->link.next) != NULL) { asection *s; @@ -14533,7 +15247,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, #undef TARGET_LITTLE_NAME #undef TARGET_BIG_SYM -#define TARGET_BIG_SYM bfd_elf64_powerpc_freebsd_vec +#define TARGET_BIG_SYM powerpc_elf64_fbsd_vec #undef TARGET_BIG_NAME #define TARGET_BIG_NAME "elf64-powerpc-freebsd"