2014-03-12 Aldy Hernandez * Partial PowerPC little endian patch for binutils. diff --git a/IBM-binutils-2.24-2013-11-11-ppc64le_abiv2.patch.gz b/IBM-binutils-2.24-2013-11-11-ppc64le_abiv2.patch.gz new file mode 100644 index 0000000..e869701 Binary files /dev/null and b/IBM-binutils-2.24-2013-11-11-ppc64le_abiv2.patch.gz differ diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 8c9903f..af72703 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3189,6 +3189,8 @@ instruction. */ BFD_RELOC_PPC64_TOC16_LO_DS, BFD_RELOC_PPC64_PLTGOT16_DS, BFD_RELOC_PPC64_PLTGOT16_LO_DS, + BFD_RELOC_PPC64_ADDR16_HIGH, + BFD_RELOC_PPC64_ADDR16_HIGHA, /* PowerPC and PowerPC64 thread-local storage relocations. */ BFD_RELOC_PPC_TLS, @@ -3233,6 +3235,10 @@ instruction. */ BFD_RELOC_PPC64_DTPREL16_HIGHERA, BFD_RELOC_PPC64_DTPREL16_HIGHEST, BFD_RELOC_PPC64_DTPREL16_HIGHESTA, + BFD_RELOC_PPC64_TPREL16_HIGH, + BFD_RELOC_PPC64_TPREL16_HIGHA, + BFD_RELOC_PPC64_DTPREL16_HIGH, + BFD_RELOC_PPC64_DTPREL16_HIGHA, /* IBM 370/390 relocations */ BFD_RELOC_I370_D12, diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index fbc4e54..a3680f2 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -6443,7 +6443,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (!htab->no_tls_get_addr_opt && htab->tls_get_addr != NULL && htab->tls_get_addr->plt.plist != NULL - && !add_dynamic_entry (DT_PPC_TLSOPT, 0)) + && !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS)) return FALSE; } diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 8872673..80c2a4d 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -81,7 +81,8 @@ 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 @@ -108,6 +109,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 @@ -117,16 +119,25 @@ static bfd_vma opd_entry_value #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. ABIv2 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 +148,35 @@ 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_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 +187,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 @@ -309,7 +327,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC64_ADDR16_HI", /* name */ FALSE, /* partial_inplace */ @@ -325,7 +343,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_ha_reloc, /* special_function */ "R_PPC64_ADDR16_HA", /* name */ FALSE, /* partial_inplace */ @@ -487,7 +505,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ + complain_overflow_signed,/* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_GOT16_HI", /* name */ FALSE, /* partial_inplace */ @@ -503,7 +521,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ + complain_overflow_signed,/* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_GOT16_HA", /* name */ FALSE, /* partial_inplace */ @@ -680,7 +698,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_PLT16_HI", /* name */ FALSE, /* partial_inplace */ @@ -696,7 +714,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_PLT16_HA", /* name */ FALSE, /* partial_inplace */ @@ -741,7 +759,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_sectoff_reloc, /* special_function */ "R_PPC64_SECTOFF_HI", /* name */ FALSE, /* partial_inplace */ @@ -756,7 +774,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_sectoff_ha_reloc, /* special_function */ "R_PPC64_SECTOFF_HA", /* name */ FALSE, /* partial_inplace */ @@ -963,7 +981,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_toc_reloc, /* special_function */ "R_PPC64_TOC16_HI", /* name */ FALSE, /* partial_inplace */ @@ -982,7 +1000,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_toc_ha_reloc, /* special_function */ "R_PPC64_TOC16_HA", /* name */ FALSE, /* partial_inplace */ @@ -1054,7 +1072,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_PLTGOT16_HI", /* name */ FALSE, /* partial_inplace */ @@ -1072,7 +1090,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_PLTGOT16_HA", /* name */ FALSE, /* partial_inplace */ @@ -1374,7 +1392,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_DTPREL16_HI", /* name */ FALSE, /* partial_inplace */ @@ -1389,7 +1407,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_DTPREL16_HA", /* name */ FALSE, /* partial_inplace */ @@ -1540,7 +1558,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_TPREL16_HI", /* name */ FALSE, /* partial_inplace */ @@ -1555,7 +1573,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_TPREL16_HA", /* name */ FALSE, /* partial_inplace */ @@ -1692,7 +1710,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_GOT_TLSGD16_HI", /* name */ FALSE, /* partial_inplace */ @@ -1707,7 +1725,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_GOT_TLSGD16_HA", /* name */ FALSE, /* partial_inplace */ @@ -1754,7 +1772,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_GOT_TLSLD16_HI", /* name */ FALSE, /* partial_inplace */ @@ -1769,7 +1787,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_GOT_TLSLD16_HA", /* name */ FALSE, /* partial_inplace */ @@ -1815,7 +1833,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_GOT_DTPREL16_HI", /* name */ FALSE, /* partial_inplace */ @@ -1830,7 +1848,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_GOT_DTPREL16_HA", /* name */ FALSE, /* partial_inplace */ @@ -1876,7 +1894,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_GOT_TPREL16_HI", /* name */ FALSE, /* partial_inplace */ @@ -1891,7 +1909,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_unhandled_reloc, /* special_function */ "R_PPC64_GOT_TPREL16_HA", /* name */ FALSE, /* partial_inplace */ @@ -1964,7 +1982,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC64_REL16_HI", /* name */ FALSE, /* partial_inplace */ @@ -1980,7 +1998,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 16, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ ppc64_elf_ha_reloc, /* special_function */ "R_PPC64_REL16_HA", /* name */ FALSE, /* partial_inplace */ @@ -1988,6 +2006,96 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 0xffff, /* dst_mask */ TRUE), /* pcrel_offset */ + /* Like R_PPC64_ADDR16_HI, but no overflow. */ + HOWTO (R_PPC64_ADDR16_HIGH, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC64_ADDR16_HIGH", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Like R_PPC64_ADDR16_HA, but no overflow. */ + HOWTO (R_PPC64_ADDR16_HIGHA, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc64_elf_ha_reloc, /* special_function */ + "R_PPC64_ADDR16_HIGHA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Like R_PPC64_DTPREL16_HI, but no overflow. */ + HOWTO (R_PPC64_DTPREL16_HIGH, + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc64_elf_unhandled_reloc, /* special_function */ + "R_PPC64_DTPREL16_HIGH", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Like R_PPC64_DTPREL16_HA, but no overflow. */ + HOWTO (R_PPC64_DTPREL16_HIGHA, + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc64_elf_unhandled_reloc, /* special_function */ + "R_PPC64_DTPREL16_HIGHA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Like R_PPC64_TPREL16_HI, but no overflow. */ + HOWTO (R_PPC64_TPREL16_HIGH, + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc64_elf_unhandled_reloc, /* special_function */ + "R_PPC64_TPREL16_HIGH", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Like R_PPC64_TPREL16_HA, but no overflow. */ + HOWTO (R_PPC64_TPREL16_HIGHA, + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc64_elf_unhandled_reloc, /* special_function */ + "R_PPC64_TPREL16_HIGHA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_PPC64_GNU_VTINHERIT, /* type */ 0, /* rightshift */ @@ -2066,8 +2174,12 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, break; case BFD_RELOC_HI16: r = R_PPC64_ADDR16_HI; break; + case BFD_RELOC_PPC64_ADDR16_HIGH: r = R_PPC64_ADDR16_HIGH; + break; case BFD_RELOC_HI16_S: r = R_PPC64_ADDR16_HA; break; + case BFD_RELOC_PPC64_ADDR16_HIGHA: r = R_PPC64_ADDR16_HIGHA; + break; case BFD_RELOC_PPC_BA16: r = R_PPC64_ADDR14; break; case BFD_RELOC_PPC_BA16_BRTAKEN: r = R_PPC64_ADDR14_BRTAKEN; @@ -2186,8 +2298,12 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, break; case BFD_RELOC_PPC_TPREL16_HI: r = R_PPC64_TPREL16_HI; break; + case BFD_RELOC_PPC64_TPREL16_HIGH: r = R_PPC64_TPREL16_HIGH; + break; case BFD_RELOC_PPC_TPREL16_HA: r = R_PPC64_TPREL16_HA; break; + case BFD_RELOC_PPC64_TPREL16_HIGHA: r = R_PPC64_TPREL16_HIGHA; + break; case BFD_RELOC_PPC_TPREL: r = R_PPC64_TPREL64; break; case BFD_RELOC_PPC_DTPREL16: r = R_PPC64_DTPREL16; @@ -2196,8 +2312,12 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, break; case BFD_RELOC_PPC_DTPREL16_HI: r = R_PPC64_DTPREL16_HI; break; + case BFD_RELOC_PPC64_DTPREL16_HIGH: r = R_PPC64_DTPREL16_HIGH; + break; case BFD_RELOC_PPC_DTPREL16_HA: r = R_PPC64_DTPREL16_HA; break; + case BFD_RELOC_PPC64_DTPREL16_HIGHA: r = R_PPC64_DTPREL16_HIGHA; + break; case BFD_RELOC_PPC_DTPREL: r = R_PPC64_DTPREL64; break; case BFD_RELOC_PPC_GOT_TLSGD16: r = R_PPC64_GOT_TLSGD16; @@ -2836,6 +2956,19 @@ get_opd_info (asection * sec) return &ppc64_elf_section_data (sec)->u.opd; return NULL; } + +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; +} /* Parameters for the qsort hook. */ static bfd_boolean synthetic_relocatable; @@ -2982,15 +3115,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) @@ -3159,20 +3296,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; } @@ -3221,9 +3356,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. */ @@ -3241,13 +3376,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) @@ -3400,8 +3543,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; @@ -3452,13 +3600,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 @@ -3509,6 +3657,8 @@ must_be_dyn_reloc (struct bfd_link_info *info, case R_PPC64_TPREL16_HA: case R_PPC64_TPREL16_DS: case R_PPC64_TPREL16_LO_DS: + case R_PPC64_TPREL16_HIGH: + case R_PPC64_TPREL16_HIGHA: case R_PPC64_TPREL16_HIGHER: case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: @@ -3548,21 +3698,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 @@ -3575,11 +3725,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 @@ -3624,6 +3774,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 { @@ -3772,6 +3925,9 @@ struct ppc_link_hash_table /* Alignment of PLT call stubs. */ unsigned int plt_stub_align:4; + /* Set if we're linking code with function descriptors. */ + unsigned int opd_abi:1; + /* Set if PLT call stubs should load r11. */ unsigned int plt_static_chain:1; @@ -3867,7 +4023,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; @@ -4452,6 +4610,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) @@ -4610,7 +4769,7 @@ 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) @@ -4630,9 +4789,35 @@ ppc64_elf_add_symbol_hook (bfd *ibfd, && strcmp ((*sec)->name, ".opd") == 0) isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC); + 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; + } + } + 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 @@ -4959,6 +5144,15 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, information about the associated function section. */ bfd_size_type amt; + if (abiversion (abfd) == 0) + set_abiversion (abfd, 1); + else if (abiversion (abfd) == 2) + { + info->callbacks->einfo (_("%P: .opd not allowed in ABI version %d\n"), + abiversion (abfd)); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } amt = sec->size * sizeof (*opd_sym_map) / 8; opd_sym_map = bfd_zalloc (abfd, amt); if (opd_sym_map == NULL) @@ -5134,6 +5328,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) == 2) + { + if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) + return FALSE; + } break; case R_PPC64_PLT16_HA: @@ -5179,6 +5381,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_DTPREL16_HA: case R_PPC64_DTPREL16_DS: case R_PPC64_DTPREL16_LO_DS: + case R_PPC64_DTPREL16_HIGH: + case R_PPC64_DTPREL16_HIGHA: case R_PPC64_DTPREL16_HIGHER: case R_PPC64_DTPREL16_HIGHERA: case R_PPC64_DTPREL16_HIGHEST: @@ -5339,6 +5543,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_TPREL16_HA: case R_PPC64_TPREL16_DS: case R_PPC64_TPREL16_LO_DS: + case R_PPC64_TPREL16_HIGH: + case R_PPC64_TPREL16_HIGHA: case R_PPC64_TPREL16_HIGHER: case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: @@ -5382,22 +5588,35 @@ 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: case R_PPC64_ADDR16_HI: + case R_PPC64_ADDR16_HIGH: + case R_PPC64_ADDR16_HIGHA: case R_PPC64_ADDR16_HIGHER: case R_PPC64_ADDR16_HIGHERA: case R_PPC64_ADDR16_HIGHEST: case R_PPC64_ADDR16_HIGHESTA: case R_PPC64_ADDR16_LO: case R_PPC64_ADDR16_LO_DS: + if (h != NULL && !info->shared && abiversion (abfd) == 2 + && 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: @@ -5518,6 +5737,78 @@ 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 (!elf_flags_init (obfd) || oflags == 0) + { + elf_flags_init (obfd) = TRUE; + elf_elfheader (obfd)->e_flags = iflags; + } + else if (iflags == oflags || iflags == 0) + ; + else 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 + { + (*_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. */ @@ -6177,7 +6468,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; @@ -6193,7 +6484,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); @@ -6248,7 +6539,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; @@ -6264,7 +6555,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); @@ -6510,6 +6801,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 @@ -6547,6 +6857,26 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, h->plt.plist = NULL; h->needs_plt = 0; } + else if (abiversion (info->output_bfd) == 2) + { + /* 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. */ + 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 h->plt.plist = NULL; @@ -6581,26 +6911,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) @@ -6980,6 +7296,8 @@ dec_dynrel_count (bfd_vma r_info, case R_PPC64_TPREL16_HA: case R_PPC64_TPREL16_DS: case R_PPC64_TPREL16_LO_DS: + case R_PPC64_TPREL16_HIGH: + case R_PPC64_TPREL16_HIGHA: case R_PPC64_TPREL16_HIGHER: case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: @@ -7001,6 +7319,8 @@ dec_dynrel_count (bfd_vma r_info, case R_PPC64_ADDR16_DS: case R_PPC64_ADDR16_HA: case R_PPC64_ADDR16_HI: + case R_PPC64_ADDR16_HIGH: + case R_PPC64_ADDR16_HIGHA: case R_PPC64_ADDR16_HIGHER: case R_PPC64_ADDR16_HIGHERA: case R_PPC64_ADDR16_HIGHEST: @@ -7504,6 +7824,9 @@ ppc64_elf_tls_setup (struct bfd_link_info *info, if (htab == NULL) return NULL; + if (abiversion (info->output_bfd) == 1) + htab->opd_abi = 1; + if (*no_multi_toc) htab->do_multi_toc = 0; else if (!htab->do_multi_toc) @@ -8287,7 +8610,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) @@ -8886,7 +9209,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { s = htab->iplt; pent->plt.offset = s->size; - s->size += PLT_ENTRY_SIZE; + s->size += PLT_ENTRY_SIZE (htab); s = htab->reliplt; } else @@ -8895,21 +9218,26 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) first entry. */ s = htab->plt; 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; @@ -9002,7 +9330,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (eh->dyn_relocs == NULL || (!htab->elf.dynamic_sections_created - && h->type != STT_GNU_IFUNC)) + && (h->type != STT_GNU_IFUNC + || !htab->opd_abi))) return TRUE; /* In the shared -Bsymbolic case, discard space allocated for @@ -9098,28 +9427,65 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) 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; - info->flags |= DF_TEXTREL; + if (h->def_regular) + return TRUE; - /* Not an error, just cut short the traversal. */ - return FALSE; - } + info = inf; + htab = ppc_hash_table (info); + if (htab == NULL) + 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; } @@ -9127,7 +9493,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; @@ -9258,7 +9624,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, { s = htab->iplt; ent->plt.offset = s->size; - s->size += PLT_ENTRY_SIZE; + s->size += PLT_ENTRY_SIZE (htab); htab->reliplt->size += sizeof (Elf64_External_Rela); } @@ -9270,6 +9636,12 @@ 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) @@ -9415,6 +9787,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 @@ -9439,18 +9813,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->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) { @@ -9462,7 +9839,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) { @@ -9476,6 +9853,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 @@ -9483,7 +9873,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; @@ -9552,7 +9943,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; @@ -9569,9 +9960,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 @@ -9591,19 +9982,23 @@ 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->plt_static_chain) + size += 4; + if (htab->plt_thread_safe) + size += 8; + if (PPC_HA (off + 8 + 8 * htab->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) @@ -9637,12 +10032,14 @@ build_plt_stub (struct ppc_link_hash_table *htab, bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r) { bfd *obfd = htab->stub_bfd; + bfd_boolean plt_load_toc = htab->opd_abi; bfd_boolean plt_static_chain = htab->plt_static_chain; bfd_boolean plt_thread_safe = htab->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 @@ -9650,7 +10047,8 @@ build_plt_stub (struct ppc_link_hash_table *htab, && !htab->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; @@ -9684,44 +10082,51 @@ 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)) - { - 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 + if (plt_load_toc) { - 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[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 + 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) + { + 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; + 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; + 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 { @@ -9731,45 +10136,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)) + if (plt_load_toc) { - 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) + 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; @@ -9789,11 +10201,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 * @@ -9811,15 +10221,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; @@ -9868,6 +10278,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; @@ -9920,9 +10332,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 @@ -9939,7 +10353,7 @@ 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->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc); loc += 4; size = 12; if (PPC_HA (r2off) != 0) @@ -10025,6 +10439,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); @@ -10093,7 +10509,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) r[0].r_offset = loc - stub_entry->stub_sec->contents; if (bfd_big_endian (info->output_bfd)) r[0].r_offset += 2; - if (stub_entry->stub_type == ppc_stub_plt_branch_r2off) + if (stub_entry->stub_type == ppc_stub_plt_branch_r2off + && htab->opd_abi) r[0].r_offset += 4; r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); r[0].r_addend = dest; @@ -10106,19 +10523,20 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) } } - if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) + if (stub_entry->stub_type != ppc_stub_plt_branch_r2off + || !htab->opd_abi) { if (PPC_HA (off) != 0) { size = 16; - bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc); + bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc); loc += 4; - bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc); + bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc); } else { size = 12; - bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc); + bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc); } } else @@ -10131,20 +10549,20 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; } - bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc); + bfd_put_32 (htab->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc); loc += 4; size = 20; if (PPC_HA (off) != 0) { size += 4; - bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc); + bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc); loc += 4; - bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc); + bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc); loc += 4; } else { - bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc); + bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc); loc += 4; } @@ -10157,7 +10575,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) 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->stub_bfd, MTCTR_R12, loc); loc += 4; bfd_put_32 (htab->stub_bfd, BCTR, loc); break; @@ -10202,7 +10620,10 @@ 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); @@ -10354,10 +10775,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) 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->plt_static_chain + && PPC_HA (off + 16) == PPC_HA (off)) + : 1)); stub_entry->stub_sec->flags |= SEC_RELOC; } } @@ -10366,6 +10788,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 @@ -10383,7 +10806,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; @@ -10394,8 +10817,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; @@ -10438,7 +10866,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) stub_entry->stub_sec->flags |= SEC_RELOC; } - if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) + if (stub_entry->stub_type != ppc_stub_plt_branch_r2off + || !htab->opd_abi) { size = 12; if (PPC_HA (off) != 0) @@ -10991,7 +11420,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; @@ -11338,7 +11770,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, 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->opd_abi) + plt_thread_safe = 0; + else if (plt_thread_safe == -1) { static const char *const thread_starter[] = { @@ -11447,6 +11881,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; @@ -11523,12 +11958,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; @@ -11565,7 +12004,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) { @@ -11828,6 +12268,72 @@ ppc64_elf_toc (bfd *obfd) return TOCstart; } +/* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to + write out any global entry stubs. */ + +static bfd_boolean +build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) +{ + 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; + + 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->plt; + if (!htab->elf.dynamic_sections_created + || h->dynindx == -1) + plt = htab->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; + } + + 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. */ @@ -11903,26 +12409,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) @@ -11933,26 +12469,33 @@ 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) @@ -12056,7 +12599,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, bfd_put_32 (htab->elf.dynobj, val, p); p += 4; /* .glink size. */ - bfd_put_32 (htab->elf.dynobj, htab->glink->rawsize - 8, p); + bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p); p += 4; /* Augmentation. */ p += 1; @@ -12106,7 +12649,6 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, } 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)) { @@ -12849,6 +13391,39 @@ 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 + && 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. */ @@ -12871,7 +13446,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; @@ -13001,6 +13577,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) @@ -13154,7 +13734,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 @@ -13329,13 +13909,14 @@ ppc64_elf_relocate_section (bfd *output_bfd, { 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 + ent->plt.offset); unresolved_reloc = FALSE; + break; } } break; @@ -13395,6 +13976,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_TPREL16_HA: case R_PPC64_TPREL16_DS: case R_PPC64_TPREL16_LO_DS: + case R_PPC64_TPREL16_HIGH: + case R_PPC64_TPREL16_HIGHA: case R_PPC64_TPREL16_HIGHER: case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: @@ -13429,6 +14012,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_DTPREL16_HA: case R_PPC64_DTPREL16_DS: case R_PPC64_DTPREL16_LO_DS: + case R_PPC64_DTPREL16_HIGH: + case R_PPC64_DTPREL16_HIGHA: case R_PPC64_DTPREL16_HIGHER: case R_PPC64_DTPREL16_HIGHERA: case R_PPC64_DTPREL16_HIGHEST: @@ -13461,6 +14046,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_ADDR16_DS: case R_PPC64_ADDR16_HA: case R_PPC64_ADDR16_HI: + case R_PPC64_ADDR16_HIGH: + case R_PPC64_ADDR16_HIGHA: case R_PPC64_ADDR16_HIGHER: case R_PPC64_ADDR16_HIGHERA: case R_PPC64_ADDR16_HIGHEST: @@ -13532,7 +14119,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) { @@ -13776,21 +14363,20 @@ ppc64_elf_relocate_section (bfd *output_bfd, default: break; - case R_PPC64_ADDR16_HA: case R_PPC64_REL16_HA: + case R_PPC64_ADDR16_HA: + case R_PPC64_ADDR16_HIGHA: case R_PPC64_ADDR16_HIGHERA: case R_PPC64_ADDR16_HIGHESTA: case R_PPC64_TOC16_HA: case R_PPC64_SECTOFF_HA: case R_PPC64_TPREL16_HA: - case R_PPC64_DTPREL16_HA: - case R_PPC64_TPREL16_HIGHER: + case R_PPC64_TPREL16_HIGHA: case R_PPC64_TPREL16_HIGHERA: - case R_PPC64_TPREL16_HIGHEST: case R_PPC64_TPREL16_HIGHESTA: - case R_PPC64_DTPREL16_HIGHER: + case R_PPC64_DTPREL16_HA: + case R_PPC64_DTPREL16_HIGHA: case R_PPC64_DTPREL16_HIGHERA: - case R_PPC64_DTPREL16_HIGHEST: case R_PPC64_DTPREL16_HIGHESTA: /* It's just possible that this symbol is a weak symbol that's not actually defined anywhere. In that case, @@ -14017,7 +14603,10 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, rela.r_offset = (htab->iplt->output_section->vma + htab->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 @@ -14034,10 +14623,34 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, 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)))); + + ((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) @@ -14130,7 +14743,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: @@ -14140,6 +14753,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) @@ -14203,7 +14821,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, { /* Set .plt entry size. */ elf_section_data (htab->plt->output_section)->this_hdr.sh_entsize - = PLT_ENTRY_SIZE; + = PLT_ENTRY_SIZE (htab); } /* brlt is SEC_LINKER_CREATED, so we need to write out relocs for diff --git a/bfd/libbfd.h b/bfd/libbfd.h index bcd76a0..d3b7950 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1396,6 +1396,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_PPC64_TOC16_LO_DS", "BFD_RELOC_PPC64_PLTGOT16_DS", "BFD_RELOC_PPC64_PLTGOT16_LO_DS", + "BFD_RELOC_PPC64_ADDR16_HIGH", + "BFD_RELOC_PPC64_ADDR16_HIGHA", "BFD_RELOC_PPC_TLS", "BFD_RELOC_PPC_TLSGD", "BFD_RELOC_PPC_TLSLD", @@ -1438,6 +1440,10 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_PPC64_DTPREL16_HIGHERA", "BFD_RELOC_PPC64_DTPREL16_HIGHEST", "BFD_RELOC_PPC64_DTPREL16_HIGHESTA", + "BFD_RELOC_PPC64_TPREL16_HIGH", + "BFD_RELOC_PPC64_TPREL16_HIGHA", + "BFD_RELOC_PPC64_DTPREL16_HIGH", + "BFD_RELOC_PPC64_DTPREL16_HIGHA", "BFD_RELOC_I370_D12", "BFD_RELOC_CTOR", "BFD_RELOC_ARM_PCREL_BRANCH", diff --git a/bfd/reloc.c b/bfd/reloc.c index 626c818..b924974 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -2892,6 +2892,10 @@ ENUMX BFD_RELOC_PPC64_PLTGOT16_DS ENUMX BFD_RELOC_PPC64_PLTGOT16_LO_DS +ENUMX + BFD_RELOC_PPC64_ADDR16_HIGH +ENUMX + BFD_RELOC_PPC64_ADDR16_HIGHA ENUMDOC Power(rs6000) and PowerPC relocations. @@ -2979,6 +2983,14 @@ ENUMX BFD_RELOC_PPC64_DTPREL16_HIGHEST ENUMX BFD_RELOC_PPC64_DTPREL16_HIGHESTA +ENUMX + BFD_RELOC_PPC64_TPREL16_HIGH +ENUMX + BFD_RELOC_PPC64_TPREL16_HIGHA +ENUMX + BFD_RELOC_PPC64_DTPREL16_HIGH +ENUMX + BFD_RELOC_PPC64_DTPREL16_HIGHA ENUMDOC PowerPC and PowerPC64 thread-local storage relocations. diff --git a/binutils/readelf.c b/binutils/readelf.c index 67aeaa8..2046ec5 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -1556,7 +1556,7 @@ get_ppc_dynamic_type (unsigned long type) switch (type) { case DT_PPC_GOT: return "PPC_GOT"; - case DT_PPC_TLSOPT: return "PPC_TLSOPT"; + case DT_PPC_OPT: return "PPC_OPT"; default: return NULL; } @@ -1570,7 +1570,7 @@ get_ppc64_dynamic_type (unsigned long type) case DT_PPC64_GLINK: return "PPC64_GLINK"; case DT_PPC64_OPD: return "PPC64_OPD"; case DT_PPC64_OPDSZ: return "PPC64_OPDSZ"; - case DT_PPC64_TLSOPT: return "PPC64_TLSOPT"; + case DT_PPC64_OPT: return "PPC64_OPT"; default: return NULL; } @@ -2442,6 +2442,16 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) strcat (buf, _(", relocatable-lib")); break; + case EM_PPC64: + if (e_flags & EF_PPC64_ABI) + { + char abi[] = ", abiv0"; + + abi[6] += e_flags & EF_PPC64_ABI; + strcat (buf, abi); + } + break; + case EM_V800: if ((e_flags & EF_RH850_ABI) == EF_RH850_ABI) strcat (buf, ", RH850 ABI"); @@ -9122,6 +9132,19 @@ get_ia64_symbol_other (unsigned int other) } static const char * +get_ppc64_symbol_other (unsigned int other) +{ + if (PPC64_LOCAL_ENTRY_OFFSET (other) != 0) + { + static char buf[32]; + snprintf (buf, sizeof buf, _(": %d"), + PPC64_LOCAL_ENTRY_OFFSET (other)); + return buf; + } + return NULL; +} + +static const char * get_symbol_other (unsigned int other) { const char * result = NULL; @@ -9138,6 +9161,9 @@ get_symbol_other (unsigned int other) case EM_IA_64: result = get_ia64_symbol_other (other); break; + case EM_PPC64: + result = get_ppc64_symbol_other (other); + break; default: break; } diff --git a/elfcpp/powerpc.h b/elfcpp/powerpc.h index 2c803af..879055e 100644 --- a/elfcpp/powerpc.h +++ b/elfcpp/powerpc.h @@ -164,11 +164,17 @@ enum R_PPC_EMB_SDA21 = 109, R_PPC64_TOCSAVE = 109, R_PPC_EMB_MRKREF = 110, + R_PPC64_ADDR16_HIGH = 110, R_PPC_EMB_RELSEC16 = 111, + R_PPC64_ADDR16_HIGHA = 111, R_PPC_EMB_RELST_LO = 112, + R_PPC64_TPREL16_HIGH = 112, R_PPC_EMB_RELST_HI = 113, + R_PPC64_TPREL16_HIGHA = 113, R_PPC_EMB_RELST_HA = 114, + R_PPC64_DTPREL16_HIGH = 114, R_PPC_EMB_BIT_FLD = 115, + R_PPC64_DTPREL16_HIGHA = 115, R_PPC_EMB_RELSDA = 116, R_PPC_VLE_REL8 = 216, @@ -208,6 +214,59 @@ enum EF_PPC_RELOCATABLE_LIB = 0x00008000, // PowerPC -mrelocatable-lib flag. */ }; +// e_flags values defined for powerpc64 +enum +{ + // ABI version + // 1 for original function descriptor using ABI, + // 2 for revised ABI without function descriptors, + // 0 for unspecified or not using any features affected by the differences. + EF_PPC64_ABI = 3 +}; + +enum +{ + // The ELFv2 ABI uses three bits in the symbol st_other field of a + // function definition to specify the number of instructions between a + // function's global entry point and local entry point. + // The global entry point is used when it is necessary to set up the + // toc pointer (r2) for the function. Callers must enter the global + // entry point with r12 set to the global entry point address. On + // return from the function, r2 may have a different value to that + // which it had on entry. + // The local entry point is used when r2 is known to already be valid + // for the function. There is no requirement on r12 when using the + // local entry point, and on return r2 will contain the same value as + // at entry. + // A value of zero in these bits means that the function has a single + // entry point with no requirement on r12 or r2, and that on return r2 + // will contain the same value as at entry. + // Values of one and seven are reserved. + + STO_PPC64_LOCAL_BIT = 5, + STO_PPC64_LOCAL_MASK = 0xE0 +}; + +// 3 bit other field to bytes. +static inline unsigned int +ppc64_decode_local_entry(unsigned int other) +{ + return ((1 << other) >> 2) << 2; +} + +// bytes to field value. +static inline unsigned int +ppc64_encode_local_entry(unsigned int val) +{ + return (val >= 4 * 4 + ? (val >= 8 * 4 + ? (val >= 16 * 4 ? 6 : 5) + : 4) + : (val >= 2 * 4 + ? 3 + : (val >= 1 * 4 ? 2 : 0))); +} + } // End namespace elfcpp. #endif // !defined(ELFCPP_POWERPC_H) diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index e55d8a9..99e893d 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -29,6 +29,7 @@ #ifdef OBJ_ELF #include "elf/ppc.h" +#include "elf/ppc64.h" #include "dwarf2dbg.h" #endif @@ -112,7 +113,11 @@ static int set_target_endian = 0; compensating for #lo being treated as a signed number. */ #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000) -#define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000) +#define SEX16(val) (((val) ^ 0x8000) - 0x8000) + +/* For the time being on ppc64, don't report overflow on @h and @ha + applied to constants. */ +#define REPORT_OVERFLOW_HI 0 static bfd_boolean reg_names_p = TARGET_REG_NAMES_P; @@ -155,6 +160,8 @@ static void ppc_vbyte (int); static void ppc_elf_cons (int); static void ppc_elf_rdata (int); static void ppc_elf_lcomm (int); +static void ppc_elf_localentry (int); +static void ppc_elf_abiversion (int); #endif #ifdef TE_PE @@ -225,6 +232,9 @@ unsigned long nop_limit = 4; ppc_cpu_t ppc_cpu = 0; ppc_cpu_t sticky = 0; +/* Value for ELF e_flags EF_PPC64_ABI. */ +unsigned int ppc_abiversion = 0; + /* Flags set on encountering toc relocs. */ enum { has_large_toc_reloc = 1, @@ -283,6 +293,8 @@ const pseudo_typeS md_pseudo_table[] = { "rdata", ppc_elf_rdata, 0 }, { "rodata", ppc_elf_rdata, 0 }, { "lcomm", ppc_elf_lcomm, 0 }, + { "localentry", ppc_elf_localentry, 0 }, + { "abiversion", ppc_elf_abiversion, 0 }, #endif #ifdef TE_PE @@ -1949,6 +1961,8 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p) MAP32 ("bitfld", BFD_RELOC_PPC_EMB_BIT_FLD), MAP32 ("relsda", BFD_RELOC_PPC_EMB_RELSDA), MAP32 ("xgot", BFD_RELOC_PPC_TOC16), + MAP64 ("high", BFD_RELOC_PPC64_ADDR16_HIGH), + MAP64 ("higha", BFD_RELOC_PPC64_ADDR16_HIGHA), MAP64 ("higher", BFD_RELOC_PPC64_HIGHER), MAP64 ("highera", BFD_RELOC_PPC64_HIGHER_S), MAP64 ("highest", BFD_RELOC_PPC64_HIGHEST), @@ -1958,10 +1972,14 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p) MAP64 ("toc@l", BFD_RELOC_PPC64_TOC16_LO), MAP64 ("toc@h", BFD_RELOC_PPC64_TOC16_HI), MAP64 ("toc@ha", BFD_RELOC_PPC64_TOC16_HA), + MAP64 ("dtprel@high", BFD_RELOC_PPC64_DTPREL16_HIGH), + MAP64 ("dtprel@higha", BFD_RELOC_PPC64_DTPREL16_HIGHA), MAP64 ("dtprel@higher", BFD_RELOC_PPC64_DTPREL16_HIGHER), MAP64 ("dtprel@highera", BFD_RELOC_PPC64_DTPREL16_HIGHERA), MAP64 ("dtprel@highest", BFD_RELOC_PPC64_DTPREL16_HIGHEST), MAP64 ("dtprel@highesta", BFD_RELOC_PPC64_DTPREL16_HIGHESTA), + MAP64 ("tprel@high", BFD_RELOC_PPC64_TPREL16_HIGH), + MAP64 ("tprel@higha", BFD_RELOC_PPC64_TPREL16_HIGHA), MAP64 ("tprel@higher", BFD_RELOC_PPC64_TPREL16_HIGHER), MAP64 ("tprel@highera", BFD_RELOC_PPC64_TPREL16_HIGHERA), MAP64 ("tprel@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST), @@ -2237,6 +2255,101 @@ ppc_elf_lcomm (int xxx ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } +/* Pseudo op to set symbol local entry point. */ +static void +ppc_elf_localentry (int ignore ATTRIBUTE_UNUSED) +{ + char *name = input_line_pointer; + char c = get_symbol_end (); + char *p; + expressionS exp; + symbolS *sym; + asymbol *bfdsym; + elf_symbol_type *elfsym; + + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + *p = 0; + as_bad (_("expected comma after name `%s' in .localentry directive"), + name); + *p = c; + ignore_rest_of_line (); + return; + } + input_line_pointer++; + expression (&exp); + if (exp.X_op == O_absent) + { + as_bad (_("missing expression in .localentry directive")); + exp.X_op = O_constant; + exp.X_add_number = 0; + } + *p = 0; + sym = symbol_find_or_make (name); + *p = c; + + if (resolve_expression (&exp) + && exp.X_op == O_constant) + { + unsigned char encoded = PPC64_SET_LOCAL_ENTRY_OFFSET (exp.X_add_number); + + if (exp.X_add_number != PPC64_LOCAL_ENTRY_OFFSET (encoded)) + as_bad (_(".localentry expression for `%s' " + "is not a valid power of 2"), S_GET_NAME (sym)); + else + { + bfdsym = symbol_get_bfdsym (sym); + elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); + gas_assert (elfsym); + elfsym->internal_elf_sym.st_other &= ~STO_PPC64_LOCAL_MASK; + elfsym->internal_elf_sym.st_other |= encoded; + if (ppc_abiversion == 0) + ppc_abiversion = 2; + } + } + else + as_bad (_(".localentry expression for `%s' " + "does not evaluate to a constant"), S_GET_NAME (sym)); + + demand_empty_rest_of_line (); +} + +/* Pseudo op to set ABI version. */ +static void +ppc_elf_abiversion (int ignore ATTRIBUTE_UNUSED) +{ + expressionS exp; + + expression (&exp); + if (exp.X_op == O_absent) + { + as_bad (_("missing expression in .abiversion directive")); + exp.X_op = O_constant; + exp.X_add_number = 0; + } + + if (resolve_expression (&exp) + && exp.X_op == O_constant) + ppc_abiversion = exp.X_add_number; + else + as_bad (_(".abiversion expression does not evaluate to a constant")); + demand_empty_rest_of_line (); +} + +/* Set ABI version in output file. */ +void +ppc_elf_end (void) +{ + if (ppc_obj64 && ppc_abiversion != 0) + { + elf_elfheader (stdoutput)->e_flags &= ~EF_PPC64_ABI; + elf_elfheader (stdoutput)->e_flags |= ppc_abiversion & EF_PPC64_ABI; + } +} + /* Validate any relocations emitted for -mrelocatable, possibly adding fixups for word relocations in writable segments, so we can adjust them at runtime. */ @@ -2838,55 +2951,76 @@ md_assemble (char *str) break; case BFD_RELOC_LO16: - /* X_unsigned is the default, so if the user has done - something which cleared it, we always produce a - signed value. */ - if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) - ex.X_add_number &= 0xffff; - else + ex.X_add_number &= 0xffff; + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) ex.X_add_number = SEX16 (ex.X_add_number); break; case BFD_RELOC_HI16: - if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) - ex.X_add_number = PPC_HI (ex.X_add_number); - else - ex.X_add_number = SEX16 (PPC_HI (ex.X_add_number)); + if (REPORT_OVERFLOW_HI && ppc_obj64) + { + /* PowerPC64 @h is tested for overflow. */ + ex.X_add_number = (addressT) ex.X_add_number >> 16; + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + { + addressT sign = (((addressT) -1 >> 16) + 1) >> 1; + ex.X_add_number + = ((addressT) ex.X_add_number ^ sign) - sign; + } + break; + } + /* Fall thru */ + + case BFD_RELOC_PPC64_ADDR16_HIGH: + ex.X_add_number = PPC_HI (ex.X_add_number); + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + ex.X_add_number = SEX16 (ex.X_add_number); break; case BFD_RELOC_HI16_S: - if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) - ex.X_add_number = PPC_HA (ex.X_add_number); - else - ex.X_add_number = SEX16 (PPC_HA (ex.X_add_number)); + if (REPORT_OVERFLOW_HI && ppc_obj64) + { + /* PowerPC64 @ha is tested for overflow. */ + ex.X_add_number + = ((addressT) ex.X_add_number + 0x8000) >> 16; + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + { + addressT sign = (((addressT) -1 >> 16) + 1) >> 1; + ex.X_add_number + = ((addressT) ex.X_add_number ^ sign) - sign; + } + break; + } + /* Fall thru */ + + case BFD_RELOC_PPC64_ADDR16_HIGHA: + ex.X_add_number = PPC_HA (ex.X_add_number); + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + ex.X_add_number = SEX16 (ex.X_add_number); break; case BFD_RELOC_PPC64_HIGHER: - if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) - ex.X_add_number = PPC_HIGHER (ex.X_add_number); - else - ex.X_add_number = SEX16 (PPC_HIGHER (ex.X_add_number)); + ex.X_add_number = PPC_HIGHER (ex.X_add_number); + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + ex.X_add_number = SEX16 (ex.X_add_number); break; case BFD_RELOC_PPC64_HIGHER_S: - if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) - ex.X_add_number = PPC_HIGHERA (ex.X_add_number); - else - ex.X_add_number = SEX16 (PPC_HIGHERA (ex.X_add_number)); + ex.X_add_number = PPC_HIGHERA (ex.X_add_number); + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + ex.X_add_number = SEX16 (ex.X_add_number); break; case BFD_RELOC_PPC64_HIGHEST: - if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) - ex.X_add_number = PPC_HIGHEST (ex.X_add_number); - else - ex.X_add_number = SEX16 (PPC_HIGHEST (ex.X_add_number)); + ex.X_add_number = PPC_HIGHEST (ex.X_add_number); + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + ex.X_add_number = SEX16 (ex.X_add_number); break; case BFD_RELOC_PPC64_HIGHEST_S: - if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) - ex.X_add_number = PPC_HIGHESTA (ex.X_add_number); - else - ex.X_add_number = SEX16 (PPC_HIGHESTA (ex.X_add_number)); + ex.X_add_number = PPC_HIGHESTA (ex.X_add_number); + if ((operand->flags & PPC_OPERAND_SIGNED) != 0) + ex.X_add_number = SEX16 (ex.X_add_number); break; } #endif /* OBJ_ELF */ @@ -6172,6 +6306,22 @@ ppc_force_relocation (fixS *fix) case BFD_RELOC_24_PLT_PCREL: case BFD_RELOC_PPC64_TOC: return 1; + case BFD_RELOC_PPC_B26: + case BFD_RELOC_PPC_BA26: + case BFD_RELOC_PPC_B16: + case BFD_RELOC_PPC_BA16: + /* All branch fixups targeting a localentry symbol must + force a relocation. */ + if (fix->fx_addsy) + { + asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy); + elf_symbol_type *elfsym + = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); + gas_assert (elfsym); + if ((STO_PPC64_LOCAL_MASK & elfsym->internal_elf_sym.st_other) != 0) + return 1; + } + break; default: break; } @@ -6186,6 +6336,32 @@ ppc_force_relocation (fixS *fix) int ppc_fix_adjustable (fixS *fix) { + switch (fix->fx_r_type) + { + /* All branch fixups targeting a localentry symbol must + continue using the symbol. */ + case BFD_RELOC_PPC_B26: + case BFD_RELOC_PPC_BA26: + case BFD_RELOC_PPC_B16: + case BFD_RELOC_PPC_BA16: + case BFD_RELOC_PPC_B16_BRTAKEN: + case BFD_RELOC_PPC_B16_BRNTAKEN: + case BFD_RELOC_PPC_BA16_BRTAKEN: + case BFD_RELOC_PPC_BA16_BRNTAKEN: + if (fix->fx_addsy) + { + asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy); + elf_symbol_type *elfsym + = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); + gas_assert (elfsym); + if ((STO_PPC64_LOCAL_MASK & elfsym->internal_elf_sym.st_other) != 0) + return 0; + } + break; + default: + break; + } + return (fix->fx_r_type != BFD_RELOC_16_GOTOFF && fix->fx_r_type != BFD_RELOC_LO16_GOTOFF && fix->fx_r_type != BFD_RELOC_HI16_GOTOFF @@ -6465,10 +6641,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) case BFD_RELOC_PPC_GOT_DTPREL16_HA: case BFD_RELOC_PPC64_TPREL16_DS: case BFD_RELOC_PPC64_TPREL16_LO_DS: + case BFD_RELOC_PPC64_TPREL16_HIGH: + case BFD_RELOC_PPC64_TPREL16_HIGHA: case BFD_RELOC_PPC64_TPREL16_HIGHER: case BFD_RELOC_PPC64_TPREL16_HIGHERA: case BFD_RELOC_PPC64_TPREL16_HIGHEST: case BFD_RELOC_PPC64_TPREL16_HIGHESTA: + case BFD_RELOC_PPC64_DTPREL16_HIGH: + case BFD_RELOC_PPC64_DTPREL16_HIGHA: case BFD_RELOC_PPC64_DTPREL16_DS: case BFD_RELOC_PPC64_DTPREL16_LO_DS: case BFD_RELOC_PPC64_DTPREL16_HIGHER: @@ -6836,10 +7016,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) case BFD_RELOC_PPC64_TOC16_LO: case BFD_RELOC_PPC64_TOC16_HI: case BFD_RELOC_PPC64_TOC16_HA: + case BFD_RELOC_PPC64_DTPREL16_HIGH: + case BFD_RELOC_PPC64_DTPREL16_HIGHA: case BFD_RELOC_PPC64_DTPREL16_HIGHER: case BFD_RELOC_PPC64_DTPREL16_HIGHERA: case BFD_RELOC_PPC64_DTPREL16_HIGHEST: case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: + case BFD_RELOC_PPC64_TPREL16_HIGH: + case BFD_RELOC_PPC64_TPREL16_HIGHA: case BFD_RELOC_PPC64_TPREL16_HIGHER: case BFD_RELOC_PPC64_TPREL16_HIGHERA: case BFD_RELOC_PPC64_TPREL16_HIGHEST: diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h index 3dd3f81..6095416 100644 --- a/gas/config/tc-ppc.h +++ b/gas/config/tc-ppc.h @@ -238,6 +238,9 @@ extern void ppc_frob_file_before_adjust (void); #define tc_adjust_symtab() ppc_elf_adjust_symtab () extern void ppc_elf_adjust_symtab (void); +extern void ppc_elf_end (void); +#define md_end ppc_elf_end + #endif /* OBJ_ELF */ #if defined (OBJ_ELF) || defined (OBJ_XCOFF) diff --git a/gold/powerpc.cc b/gold/powerpc.cc index e192885..38a36ac 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -72,12 +72,19 @@ public: const typename elfcpp::Ehdr& ehdr) : Sized_relobj_file(name, input_file, offset, ehdr), special_(0), has_small_toc_reloc_(false), opd_valid_(false), - opd_ent_(), access_from_map_(), has14_(), stub_table_() - { } + opd_ent_(), access_from_map_(), has14_(), stub_table_(), + e_flags_(ehdr.get_e_flags()), st_other_() + { + this->set_abiversion(0); + } ~Powerpc_relobj() { } + // Read the symbols then set up st_other vector. + void + do_read_symbols(Read_symbols_data*); + // The .got2 section shndx. unsigned int got2_shndx() const @@ -263,6 +270,22 @@ public: return NULL; } + int + abiversion() const + { return this->e_flags_ & elfcpp::EF_PPC64_ABI; } + + // Set ABI version for input and output + void + set_abiversion(int ver); + + unsigned int + ppc64_local_entry_offset(const Symbol* sym) const + { return elfcpp::ppc64_decode_local_entry(sym->nonvis() >> 3); } + + unsigned int + ppc64_local_entry_offset(unsigned int symndx) const + { return elfcpp::ppc64_decode_local_entry(this->st_other_[symndx] >> 5); } + private: struct Opd_ent { @@ -316,6 +339,12 @@ private: // The stub table to use for a given input section. std::vector*> stub_table_; + + // Header e_flags + elfcpp::Elf_Word e_flags_; + + // ELF st_other field for local symbols. + std::vector st_other_; }; template @@ -1305,6 +1334,14 @@ public: STATUS_OVERFLOW }; + int + abiversion() const + { return this->e_flags_ & elfcpp::EF_PPC64_ABI; } + + // Set ABI version for input and output. + void + set_abiversion(int ver); + private: typedef Powerpc_relocate_functions This; typedef typename elfcpp::Elf_types::Elf_Addr Address; @@ -1930,6 +1967,24 @@ class Stub_control output_section() { return output_section_; } + int + abiversion () const + { return this->processor_specific_flags() & elfcpp::EF_PPC64_ABI; } + + void + set_abiversion (int ver) + { + elfcpp::Elf_Word flags = this->processor_specific_flags(); + flags &= ~elfcpp::EF_PPC64_ABI; + flags |= ver & elfcpp::EF_PPC64_ABI; + this->set_processor_specific_flags(flags); + } + + // Offset to to save stack slot + int + stk_toc () const + { return this->abiversion() < 2 ? 40 : 24; } + private: typedef enum { @@ -3605,6 +3660,26 @@ Stub_table::do_write(Output_file* of) } } } + else + { + // Define .TOC. as for 32-bit _GLOBAL_OFFSET_TABLE_ + Symbol *gotsym = symtab->lookup(".TOC.", NULL); + if (gotsym != NULL && gotsym->is_undefined()) + { + Target_powerpc* target = + static_cast*>( + parameters->sized_target()); + Output_data_got_powerpc* got + = target->got_section(symtab, layout); + symtab->define_in_output_data(".TOC.", NULL, + Symbol_table::PREDEFINED, + got, 0x8000, 0, + elfcpp::STT_OBJECT, + elfcpp::STB_LOCAL, + elfcpp::STV_HIDDEN, 0, + false, false); + } + } } // Write out .glink. @@ -3632,16 +3707,34 @@ Output_data_glink::do_write(Output_file* of) elfcpp::Swap<64, big_endian>::writeval(p, pltoff), p += 8; - write_insn(p, mflr_12), p += 4; - write_insn(p, bcl_20_31), p += 4; - write_insn(p, mflr_11), p += 4; - write_insn(p, ld_2_11 + l(-16)), p += 4; - write_insn(p, mtlr_12), p += 4; - write_insn(p, add_12_2_11), p += 4; - write_insn(p, ld_11_12 + 0), p += 4; - write_insn(p, ld_2_12 + 8), p += 4; - write_insn(p, mtctr_11), p += 4; - write_insn(p, ld_11_12 + 16), p += 4; + if (this->targ_->abiversion() < 2) + { + write_insn(p, mflr_12), p += 4; + write_insn(p, bcl_20_31), p += 4; + write_insn(p, mflr_11), p += 4; + write_insn(p, ld_2_11 + l(-16)), p += 4; + write_insn(p, mtlr_12), p += 4; + write_insn(p, add_11_2_11), p += 4; + write_insn(p, ld_12_11 + 0), p += 4; + write_insn(p, ld_2_11 + 8), p += 4; + write_insn(p, mtctr_12), p += 4; + write_insn(p, ld_11_11 + 16), p += 4; + } + else + { + write_insn(p, mflr_0), p += 4; + write_insn(p, bcl_20_31), p += 4; + write_insn(p, mflr_11), p += 4; + write_insn(p, ld_2_11 + l(-16)), p += 4; + write_insn(p, mtlr_0), p += 4; + write_insn(p, sub_12_12_11), p += 4; + write_insn(p, add_11_2_11), p += 4; + write_insn(p, addi_0_12 + l(-48)), p += 4; + write_insn(p, ld_12_11 + 0), p += 4; + write_insn(p, srdi_0_0_2), p += 4; + write_insn(p, mtctr_12), p += 4; + write_insn(p, ld_11_11 + 8), p += 4; + } write_insn(p, bctr), p += 4; while (p < oview + this->pltresolve_size) write_insn(p, nop), p += 4; @@ -3650,14 +3743,17 @@ Output_data_glink::do_write(Output_file* of) uint32_t indx = 0; while (p < oview + oview_size) { - if (indx < 0x8000) - { - write_insn(p, li_0_0 + indx), p += 4; - } - else + if (this->targ_->abiversion() < 2) { - write_insn(p, lis_0_0 + hi(indx)), p += 4; - write_insn(p, ori_0_0_0 + l(indx)), p += 4; + if (indx < 0x8000) + { + write_insn(p, li_0_0 + indx), p += 4; + } + else + { + write_insn(p, lis_0_0 + hi(indx)), p += 4; + write_insn(p, ori_0_0_0 + l(indx)), p += 4; + } } uint32_t branch_off = 8 - (p - oview); write_insn(p, b + (branch_off & 0x3fffffc)), p += 4; @@ -4144,24 +4240,6 @@ Target_powerpc::plt_entry_count() const return count; } -// Return the offset of the first non-reserved PLT entry. - -template -unsigned int -Target_powerpc::first_plt_entry_offset() const -{ - return this->plt_->first_plt_entry_offset(); -} - -// Return the size of each PLT entry. - -template -unsigned int -Target_powerpc::plt_entry_size() const -{ - return Output_data_plt_powerpc::get_plt_entry_size(); -} - // Create a GOT entry for local dynamic __tls_get_addr calls. template @@ -4189,8 +4267,12 @@ Target_powerpc::tlsld_got_offset( template int -Target_powerpc::Scan::get_reference_flags(unsigned int r_type) +Target_powerpc::Scan::get_reference_flags( + unsigned int r_type, + const Target_powerpc* target) { + int ref = 0; + switch (r_type) { case elfcpp::R_POWERPC_NONE: @@ -4198,7 +4280,7 @@ Target_powerpc::Scan::get_reference_flags(unsigned int r_type) case elfcpp::R_POWERPC_GNU_VTENTRY: case elfcpp::R_PPC64_TOC: // No symbol reference. - return 0; + break; case elfcpp::R_PPC64_ADDR64: case elfcpp::R_PPC64_UADDR64: @@ -4209,13 +4291,15 @@ Target_powerpc::Scan::get_reference_flags(unsigned int r_type) case elfcpp::R_POWERPC_ADDR16_LO: case elfcpp::R_POWERPC_ADDR16_HI: case elfcpp::R_POWERPC_ADDR16_HA: - return Symbol::ABSOLUTE_REF; + ref = Symbol::ABSOLUTE_REF; + break; case elfcpp::R_POWERPC_ADDR24: case elfcpp::R_POWERPC_ADDR14: case elfcpp::R_POWERPC_ADDR14_BRTAKEN: case elfcpp::R_POWERPC_ADDR14_BRNTAKEN: - return Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF; + ref = Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF; + break; case elfcpp::R_PPC64_REL64: case elfcpp::R_POWERPC_REL32: @@ -4224,14 +4308,16 @@ Target_powerpc::Scan::get_reference_flags(unsigned int r_type) case elfcpp::R_POWERPC_REL16_LO: case elfcpp::R_POWERPC_REL16_HI: case elfcpp::R_POWERPC_REL16_HA: - return Symbol::RELATIVE_REF; + ref = Symbol::RELATIVE_REF; + break; case elfcpp::R_POWERPC_REL24: case elfcpp::R_PPC_PLTREL24: case elfcpp::R_POWERPC_REL14: case elfcpp::R_POWERPC_REL14_BRTAKEN: case elfcpp::R_POWERPC_REL14_BRNTAKEN: - return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF; + ref = Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF; + break; case elfcpp::R_POWERPC_GOT16: case elfcpp::R_POWERPC_GOT16_LO: @@ -4246,11 +4332,13 @@ Target_powerpc::Scan::get_reference_flags(unsigned int r_type) case elfcpp::R_PPC64_TOC16_DS: case elfcpp::R_PPC64_TOC16_LO_DS: // Absolute in GOT. - return Symbol::ABSOLUTE_REF; + ref = Symbol::ABSOLUTE_REF; + break; case elfcpp::R_POWERPC_GOT_TPREL16: case elfcpp::R_POWERPC_TLS: - return Symbol::TLS_REF; + ref = Symbol::TLS_REF; + break; case elfcpp::R_POWERPC_COPY: case elfcpp::R_POWERPC_GLOB_DAT: @@ -4259,8 +4347,12 @@ Target_powerpc::Scan::get_reference_flags(unsigned int r_type) case elfcpp::R_POWERPC_DTPMOD: default: // Not expected. We will give an error later. - return 0; + break; } + + if (size == 64 && target->abiversion() < 2) + ref |= Symbol::FUNC_DESC_ABI; + return ref; } // Report an unsupported relocation against a local symbol. @@ -4331,6 +4423,8 @@ Target_powerpc::Scan::check_non_pic(Relobj* object, case elfcpp::R_PPC64_JMP_IREL: case elfcpp::R_PPC64_ADDR16_DS: case elfcpp::R_PPC64_ADDR16_LO_DS: + case elfcpp::R_PPC64_ADDR16_HIGH: + case elfcpp::R_PPC64_ADDR16_HIGHA: case elfcpp::R_PPC64_ADDR16_HIGHER: case elfcpp::R_PPC64_ADDR16_HIGHEST: case elfcpp::R_PPC64_ADDR16_HIGHERA: @@ -4339,6 +4433,8 @@ Target_powerpc::Scan::check_non_pic(Relobj* object, case elfcpp::R_POWERPC_ADDR30: case elfcpp::R_PPC64_TPREL16_DS: case elfcpp::R_PPC64_TPREL16_LO_DS: + case elfcpp::R_PPC64_TPREL16_HIGH: + case elfcpp::R_PPC64_TPREL16_HIGHA: case elfcpp::R_PPC64_TPREL16_HIGHER: case elfcpp::R_PPC64_TPREL16_HIGHEST: case elfcpp::R_PPC64_TPREL16_HIGHERA: @@ -4509,7 +4605,6 @@ Target_powerpc::Scan::local( case elfcpp::R_POWERPC_GNU_VTINHERIT: case elfcpp::R_POWERPC_GNU_VTENTRY: case elfcpp::R_PPC64_TOCSAVE: - case elfcpp::R_PPC_EMB_MRKREF: case elfcpp::R_POWERPC_TLS: break; @@ -4546,6 +4641,8 @@ Target_powerpc::Scan::local( case elfcpp::R_POWERPC_ADDR16_HI: case elfcpp::R_POWERPC_ADDR16_HA: case elfcpp::R_POWERPC_UADDR16: + case elfcpp::R_PPC64_ADDR16_HIGH: + case elfcpp::R_PPC64_ADDR16_HIGHA: case elfcpp::R_PPC64_ADDR16_HIGHER: case elfcpp::R_PPC64_ADDR16_HIGHERA: case elfcpp::R_PPC64_ADDR16_HIGHEST: @@ -4612,31 +4709,35 @@ Target_powerpc::Scan::local( case elfcpp::R_POWERPC_REL16_HI: case elfcpp::R_POWERPC_REL16_HA: case elfcpp::R_POWERPC_SECTOFF: - case elfcpp::R_POWERPC_TPREL16: - case elfcpp::R_POWERPC_DTPREL16: case elfcpp::R_POWERPC_SECTOFF_LO: - case elfcpp::R_POWERPC_TPREL16_LO: - case elfcpp::R_POWERPC_DTPREL16_LO: case elfcpp::R_POWERPC_SECTOFF_HI: - case elfcpp::R_POWERPC_TPREL16_HI: - case elfcpp::R_POWERPC_DTPREL16_HI: case elfcpp::R_POWERPC_SECTOFF_HA: + case elfcpp::R_PPC64_SECTOFF_DS: + case elfcpp::R_PPC64_SECTOFF_LO_DS: + case elfcpp::R_POWERPC_TPREL16: + case elfcpp::R_POWERPC_TPREL16_LO: + case elfcpp::R_POWERPC_TPREL16_HI: case elfcpp::R_POWERPC_TPREL16_HA: - case elfcpp::R_POWERPC_DTPREL16_HA: - case elfcpp::R_PPC64_DTPREL16_HIGHER: + case elfcpp::R_PPC64_TPREL16_DS: + case elfcpp::R_PPC64_TPREL16_LO_DS: + case elfcpp::R_PPC64_TPREL16_HIGH: + case elfcpp::R_PPC64_TPREL16_HIGHA: case elfcpp::R_PPC64_TPREL16_HIGHER: - case elfcpp::R_PPC64_DTPREL16_HIGHERA: case elfcpp::R_PPC64_TPREL16_HIGHERA: - case elfcpp::R_PPC64_DTPREL16_HIGHEST: case elfcpp::R_PPC64_TPREL16_HIGHEST: - case elfcpp::R_PPC64_DTPREL16_HIGHESTA: case elfcpp::R_PPC64_TPREL16_HIGHESTA: - case elfcpp::R_PPC64_TPREL16_DS: - case elfcpp::R_PPC64_TPREL16_LO_DS: + case elfcpp::R_POWERPC_DTPREL16: + case elfcpp::R_POWERPC_DTPREL16_LO: + case elfcpp::R_POWERPC_DTPREL16_HI: + case elfcpp::R_POWERPC_DTPREL16_HA: case elfcpp::R_PPC64_DTPREL16_DS: case elfcpp::R_PPC64_DTPREL16_LO_DS: - case elfcpp::R_PPC64_SECTOFF_DS: - case elfcpp::R_PPC64_SECTOFF_LO_DS: + case elfcpp::R_PPC64_DTPREL16_HIGH: + case elfcpp::R_PPC64_DTPREL16_HIGHA: + case elfcpp::R_PPC64_DTPREL16_HIGHER: + case elfcpp::R_PPC64_DTPREL16_HIGHERA: + case elfcpp::R_PPC64_DTPREL16_HIGHEST: + case elfcpp::R_PPC64_DTPREL16_HIGHESTA: case elfcpp::R_PPC64_TLSGD: case elfcpp::R_PPC64_TLSLD: break; @@ -4870,7 +4971,6 @@ Target_powerpc::Scan::global( case elfcpp::R_POWERPC_GNU_VTINHERIT: case elfcpp::R_POWERPC_GNU_VTENTRY: case elfcpp::R_PPC_LOCAL24PC: - case elfcpp::R_PPC_EMB_MRKREF: case elfcpp::R_POWERPC_TLS: break; @@ -4919,6 +5019,8 @@ Target_powerpc::Scan::global( case elfcpp::R_POWERPC_ADDR16_HI: case elfcpp::R_POWERPC_ADDR16_HA: case elfcpp::R_POWERPC_UADDR16: + case elfcpp::R_PPC64_ADDR16_HIGH: + case elfcpp::R_PPC64_ADDR16_HIGHA: case elfcpp::R_PPC64_ADDR16_HIGHER: case elfcpp::R_PPC64_ADDR16_HIGHERA: case elfcpp::R_PPC64_ADDR16_HIGHEST: @@ -5005,7 +5107,7 @@ Target_powerpc::Scan::global( case elfcpp::R_PPC64_REL64: case elfcpp::R_POWERPC_REL32: // Make a dynamic relocation if necessary. - if (needs_dynamic_reloc(gsym, Scan::get_reference_flags(r_type))) + if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type, target))) { if (gsym->may_need_copy_reloc()) { @@ -5037,31 +5139,35 @@ Target_powerpc::Scan::global( case elfcpp::R_POWERPC_REL16_HI: case elfcpp::R_POWERPC_REL16_HA: case elfcpp::R_POWERPC_SECTOFF: - case elfcpp::R_POWERPC_TPREL16: - case elfcpp::R_POWERPC_DTPREL16: case elfcpp::R_POWERPC_SECTOFF_LO: - case elfcpp::R_POWERPC_TPREL16_LO: - case elfcpp::R_POWERPC_DTPREL16_LO: case elfcpp::R_POWERPC_SECTOFF_HI: - case elfcpp::R_POWERPC_TPREL16_HI: - case elfcpp::R_POWERPC_DTPREL16_HI: case elfcpp::R_POWERPC_SECTOFF_HA: + case elfcpp::R_PPC64_SECTOFF_DS: + case elfcpp::R_PPC64_SECTOFF_LO_DS: + case elfcpp::R_POWERPC_TPREL16: + case elfcpp::R_POWERPC_TPREL16_LO: + case elfcpp::R_POWERPC_TPREL16_HI: case elfcpp::R_POWERPC_TPREL16_HA: - case elfcpp::R_POWERPC_DTPREL16_HA: - case elfcpp::R_PPC64_DTPREL16_HIGHER: + case elfcpp::R_PPC64_TPREL16_DS: + case elfcpp::R_PPC64_TPREL16_LO_DS: + case elfcpp::R_PPC64_TPREL16_HIGH: + case elfcpp::R_PPC64_TPREL16_HIGHA: case elfcpp::R_PPC64_TPREL16_HIGHER: - case elfcpp::R_PPC64_DTPREL16_HIGHERA: case elfcpp::R_PPC64_TPREL16_HIGHERA: - case elfcpp::R_PPC64_DTPREL16_HIGHEST: case elfcpp::R_PPC64_TPREL16_HIGHEST: - case elfcpp::R_PPC64_DTPREL16_HIGHESTA: case elfcpp::R_PPC64_TPREL16_HIGHESTA: - case elfcpp::R_PPC64_TPREL16_DS: - case elfcpp::R_PPC64_TPREL16_LO_DS: + case elfcpp::R_POWERPC_DTPREL16: + case elfcpp::R_POWERPC_DTPREL16_LO: + case elfcpp::R_POWERPC_DTPREL16_HI: + case elfcpp::R_POWERPC_DTPREL16_HA: case elfcpp::R_PPC64_DTPREL16_DS: case elfcpp::R_PPC64_DTPREL16_LO_DS: - case elfcpp::R_PPC64_SECTOFF_DS: - case elfcpp::R_PPC64_SECTOFF_LO_DS: + case elfcpp::R_PPC64_DTPREL16_HIGH: + case elfcpp::R_PPC64_DTPREL16_HIGHA: + case elfcpp::R_PPC64_DTPREL16_HIGHER: + case elfcpp::R_PPC64_DTPREL16_HIGHERA: + case elfcpp::R_PPC64_DTPREL16_HIGHEST: + case elfcpp::R_PPC64_DTPREL16_HIGHESTA: case elfcpp::R_PPC64_TLSGD: case elfcpp::R_PPC64_TLSLD: break; @@ -5794,7 +5900,8 @@ Target_powerpc::Relocate::relocate( && (insn2 == nop || insn2 == cror_15_15_15 || insn2 == cror_31_31_31)) { - elfcpp::Swap<32, big_endian>::writeval(wv + 1, ld_2_1 + 40); + elfcpp::Swap<32, big_endian>:: + writeval(wv + 1, ld_2_1 + target->stk_toc()); can_plt_call = true; } } @@ -6083,6 +6190,10 @@ Target_powerpc::Relocate::relocate( if (r_type != elfcpp::R_PPC_PLTREL24) addend = rela.get_r_addend(); value = psymval->value(object, addend); + if (gsym != NULL) + value += object->ppc64_local_entry_offset(gsym); + else + value += object->ppc64_local_entry_offset(r_sym); if (size == 64 && is_branch_reloc(r_type)) value = target->symval_for_branch(value, gsym, object, &dest_shndx); unsigned int max_branch_offset = 0; @@ -6146,8 +6257,10 @@ Target_powerpc::Relocate::relocate( case elfcpp::R_PPC64_TPREL16_DS: case elfcpp::R_PPC64_TPREL16_LO_DS: + case elfcpp::R_PPC64_TPREL16_HIGH: + case elfcpp::R_PPC64_TPREL16_HIGHA: if (size != 64) - // R_PPC_TLSGD and R_PPC_TLSLD + // R_PPC_TLSGD, R_PPC_TLSLD, R_PPC_EMB_RELST_LO, R_PPC_EMB_RELST_HI break; case elfcpp::R_POWERPC_TPREL16: case elfcpp::R_POWERPC_TPREL16_LO: @@ -6177,6 +6290,8 @@ Target_powerpc::Relocate::relocate( case elfcpp::R_POWERPC_DTPREL16_HI: case elfcpp::R_POWERPC_DTPREL16_HA: case elfcpp::R_POWERPC_DTPREL: + case elfcpp::R_PPC64_DTPREL16_HIGH: + case elfcpp::R_PPC64_DTPREL16_HIGHA: // tls symbol values are relative to tls_segment()->vaddr() value -= dtp_offset; break; @@ -6317,6 +6432,34 @@ Target_powerpc::Relocate::relocate( overflow = Reloc::CHECK_BITFIELD; break; + case elfcpp::R_POWERPC_ADDR16_HI: + case elfcpp::R_POWERPC_ADDR16_HA: + case elfcpp::R_POWERPC_GOT16_HI: + case elfcpp::R_POWERPC_GOT16_HA: + case elfcpp::R_POWERPC_PLT16_HI: + case elfcpp::R_POWERPC_PLT16_HA: + case elfcpp::R_POWERPC_SECTOFF_HI: + case elfcpp::R_POWERPC_SECTOFF_HA: + case elfcpp::R_PPC64_TOC16_HI: + case elfcpp::R_PPC64_TOC16_HA: + case elfcpp::R_PPC64_PLTGOT16_HI: + case elfcpp::R_PPC64_PLTGOT16_HA: + case elfcpp::R_POWERPC_TPREL16_HI: + case elfcpp::R_POWERPC_TPREL16_HA: + case elfcpp::R_POWERPC_DTPREL16_HI: + case elfcpp::R_POWERPC_DTPREL16_HA: + case elfcpp::R_POWERPC_GOT_TLSGD16_HI: + case elfcpp::R_POWERPC_GOT_TLSGD16_HA: + case elfcpp::R_POWERPC_GOT_TLSLD16_HI: + case elfcpp::R_POWERPC_GOT_TLSLD16_HA: + case elfcpp::R_POWERPC_GOT_TPREL16_HI: + case elfcpp::R_POWERPC_GOT_TPREL16_HA: + case elfcpp::R_POWERPC_GOT_DTPREL16_HI: + case elfcpp::R_POWERPC_GOT_DTPREL16_HA: + case elfcpp::R_POWERPC_REL16_HI: + case elfcpp::R_POWERPC_REL16_HA: + if (size == 32) + break; case elfcpp::R_POWERPC_REL24: case elfcpp::R_PPC_PLTREL24: case elfcpp::R_PPC_LOCAL24PC: @@ -6350,7 +6493,6 @@ Target_powerpc::Relocate::relocate( case elfcpp::R_POWERPC_TLS: case elfcpp::R_POWERPC_GNU_VTINHERIT: case elfcpp::R_POWERPC_GNU_VTENTRY: - case elfcpp::R_PPC_EMB_MRKREF: break; case elfcpp::R_PPC64_ADDR64: @@ -6421,6 +6563,12 @@ Target_powerpc::Relocate::relocate( status = Reloc::addr16_u(view, value, overflow); break; + case elfcpp::R_PPC64_ADDR16_HIGH: + case elfcpp::R_PPC64_TPREL16_HIGH: + case elfcpp::R_PPC64_DTPREL16_HIGH: + if (size == 32) + // R_PPC_EMB_MRKREF, R_PPC_EMB_RELST_LO, R_PPC_EMB_RELST_HA + goto unsupp; case elfcpp::R_POWERPC_ADDR16_HI: case elfcpp::R_POWERPC_REL16_HI: case elfcpp::R_PPC64_TOC16_HI: @@ -6435,6 +6583,12 @@ Target_powerpc::Relocate::relocate( Reloc::addr16_hi(view, value); break; + case elfcpp::R_PPC64_ADDR16_HIGHA: + case elfcpp::R_PPC64_TPREL16_HIGHA: + case elfcpp::R_PPC64_DTPREL16_HIGHA: + if (size == 32) + // R_PPC_EMB_RELSEC16, R_PPC_EMB_RELST_HI, R_PPC_EMB_BIT_FLD + goto unsupp; case elfcpp::R_POWERPC_ADDR16_HA: case elfcpp::R_POWERPC_REL16_HA: case elfcpp::R_PPC64_TOC16_HA: @@ -6559,11 +6713,6 @@ Target_powerpc::Relocate::relocate( case elfcpp::R_PPC64_PLT16_LO_DS: case elfcpp::R_PPC64_PLTGOT16_DS: case elfcpp::R_PPC64_PLTGOT16_LO_DS: - case elfcpp::R_PPC_EMB_RELSEC16: - case elfcpp::R_PPC_EMB_RELST_LO: - case elfcpp::R_PPC_EMB_RELST_HI: - case elfcpp::R_PPC_EMB_RELST_HA: - case elfcpp::R_PPC_EMB_BIT_FLD: case elfcpp::R_PPC_EMB_RELSDA: case elfcpp::R_PPC_TOC16: default: diff --git a/gold/symtab.h b/gold/symtab.h index f26d4b9..457b8bd 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -634,7 +634,10 @@ class Symbol // A TLS-related reference. TLS_REF = 4, // A reference that can always be treated as a function call. - FUNCTION_CALL = 8 + FUNCTION_CALL = 8, + // When set, says that dynamic relocations are needed even if a + // symbol has a plt entry. + FUNC_DESC_ABI = 16, }; // Given a direct absolute or pc-relative static relocation against @@ -671,7 +674,8 @@ class Symbol // A reference to any PLT entry in a non-position-independent executable // does not need a dynamic relocation. - if (!parameters->options().output_is_position_independent() + if (!(flags & FUNC_DESC_ABI) + && !parameters->options().output_is_position_independent() && this->has_plt_offset()) return false; diff --git a/include/elf/ppc.h b/include/elf/ppc.h index f80a1e8..da00df8 100644 --- a/include/elf/ppc.h +++ b/include/elf/ppc.h @@ -176,7 +176,8 @@ END_RELOC_NUMBERS (R_PPC_max) #define DT_PPC_GOT (DT_LOPROC) /* Specify that tls descriptors should be optimized. */ -#define DT_PPC_TLSOPT (DT_LOPROC + 1) +#define DT_PPC_OPT (DT_LOPROC + 1) +#define PPC_OPT_TLS 1 /* Processor specific flags for the ELF header e_flags field. */ diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h index f1c80f1..78d947b 100644 --- a/include/elf/ppc64.h +++ b/include/elf/ppc64.h @@ -141,6 +141,14 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type) RELOC_NUMBER (R_PPC64_TLSLD, 108) RELOC_NUMBER (R_PPC64_TOCSAVE, 109) +/* Added when HA and HI relocs were changed to report overflows. */ + RELOC_NUMBER (R_PPC64_ADDR16_HIGH, 110) + RELOC_NUMBER (R_PPC64_ADDR16_HIGHA, 111) + RELOC_NUMBER (R_PPC64_TPREL16_HIGH, 112) + RELOC_NUMBER (R_PPC64_TPREL16_HIGHA, 113) + RELOC_NUMBER (R_PPC64_DTPREL16_HIGH, 114) + RELOC_NUMBER (R_PPC64_DTPREL16_HIGHA, 115) + #ifndef RELOC_MACROS_GEN_FUNC /* Fake relocation only used internally by ld. */ RELOC_NUMBER (R_PPC64_LO_DS_OPT, 128) @@ -161,8 +169,63 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type) END_RELOC_NUMBERS (R_PPC64_max) -#define IS_PPC64_TLS_RELOC(R) \ - ((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) +#define IS_PPC64_TLS_RELOC(R) \ + (((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) \ + || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA)) + + +/* e_flags bits specifying ABI. + 1 for original function descriptor using ABI, + 2 for revised ABI without function descriptors, + 0 for unspecified or not using any features affected by the differences. */ +#define EF_PPC64_ABI 3 + +/* The ELFv2 ABI uses three bits in the symbol st_other field of a + function definition to specify the number of instructions between a + function's global entry point and local entry point. + The global entry point is used when it is necessary to set up the + toc pointer (r2) for the function. Callers must enter the global + entry point with r12 set to the global entry point address. On + return from the function, r2 may have a different value to that + which it had on entry. + The local entry point is used when r2 is known to already be valid + for the function. There is no requirement on r12 when using the + local entry point, and on return r2 will contain the same value as + at entry. + A value of zero in these bits means that the function has a single + entry point with no requirement on r12 or r2, and that on return r2 + will contain the same value as at entry. + Values of one and seven are reserved. */ +#define STO_PPC64_LOCAL_BIT 5 +#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) + +// 3 bit other field to bytes. +static inline unsigned int +ppc64_decode_local_entry(unsigned int other) +{ + return ((1 << other) >> 2) << 2; +} + +// bytes to field value. +static inline unsigned int +ppc64_encode_local_entry(unsigned int val) +{ + return (val >= 4 * 4 + ? (val >= 8 * 4 + ? (val >= 16 * 4 ? 6 : 5) + : 4) + : (val >= 2 * 4 + ? 3 + : (val >= 1 * 4 ? 2 : 0))); +} + +/* st_other to number of bytes. */ +#define PPC64_LOCAL_ENTRY_OFFSET(other) \ + ppc64_decode_local_entry (((other) & STO_PPC64_LOCAL_MASK) \ + >> STO_PPC64_LOCAL_BIT) +/* number of bytes to st_other. */ +#define PPC64_SET_LOCAL_ENTRY_OFFSET(val) \ + ppc64_encode_local_entry (val) << STO_PPC64_LOCAL_BIT /* Specify the start of the .glink section. */ #define DT_PPC64_GLINK DT_LOPROC @@ -171,7 +234,9 @@ END_RELOC_NUMBERS (R_PPC64_max) #define DT_PPC64_OPD (DT_LOPROC + 1) #define DT_PPC64_OPDSZ (DT_LOPROC + 2) -/* Specify that tls descriptors should be optimized. */ -#define DT_PPC64_TLSOPT (DT_LOPROC + 3) +/* Specify whether various optimisations are possible. */ +#define DT_PPC64_OPT (DT_LOPROC + 3) +#define PPC64_OPT_TLS 1 +#define PPC64_OPT_MULTI_TOC 2 #endif /* _ELF_PPC64_H */ diff --git a/ld/testsuite/ld-elfvers/vers24.rd b/ld/testsuite/ld-elfvers/vers24.rd index 42e81e4..fb464f9 100644 --- a/ld/testsuite/ld-elfvers/vers24.rd +++ b/ld/testsuite/ld-elfvers/vers24.rd @@ -7,9 +7,9 @@ Symbol table '.dynsym' contains [0-9]+ entries: # And ensure the dynamic symbol table contains at least x@VERS.0 # and foo@@VERS.0 symbols #... - +[0-9]+: [0-9a-f]+ +(4 +OBJECT +GLOBAL +DEFAULT +[0-9]+ _?x|[0-9]+ +FUNC +GLOBAL +DEFAULT +[0-9]+ _?foo@)@VERS\.0 + +[0-9]+: [0-9a-f]+ +(4 +OBJECT +GLOBAL +DEFAULT +[0-9]+ _?x|[0-9]+ +FUNC +GLOBAL +DEFAULT .* [0-9]+ _?foo@)@VERS\.0 #... - +[0-9]+: [0-9a-f]+ +(4 +OBJECT +GLOBAL +DEFAULT +[0-9]+ _?x|[0-9]+ +FUNC +GLOBAL +DEFAULT +[0-9]+ _?foo@)@VERS\.0 + +[0-9]+: [0-9a-f]+ +(4 +OBJECT +GLOBAL +DEFAULT +[0-9]+ _?x|[0-9]+ +FUNC +GLOBAL +DEFAULT .* [0-9]+ _?foo@)@VERS\.0 #... Symbol table '.symtab' contains [0-9]+ entries: #pass diff --git a/ld/testsuite/ld-ifunc/ifunc.exp b/ld/testsuite/ld-ifunc/ifunc.exp index df913d8..d4c4035 100644 --- a/ld/testsuite/ld-ifunc/ifunc.exp +++ b/ld/testsuite/ld-ifunc/ifunc.exp @@ -97,8 +97,9 @@ proc contains_ifunc_symbol { binary_file } { # Look for a line like this: # 58: 0000000000400600 30 IFUNC GLOBAL DEFAULT 12 library_func2 + # with perhaps some other info between the visibility and section - if { ![regexp ".*\[ \]*IFUNC\[ \]+GLOBAL\[ \]+DEFAULT\[ \]+\[UND0-9\]+\[ \]+library_func2\n" [file_contents readelf.out]] } { + if { ![regexp ".*\[ \]*IFUNC\[ \]+GLOBAL\[ \]+DEFAULT .* \[UND0-9\]+\[ \]+library_func2\n" [file_contents readelf.out]] } { return 0 } diff --git a/ld/testsuite/ld-powerpc/elfv2.s b/ld/testsuite/ld-powerpc/elfv2.s new file mode 100644 index 0000000..c2a4c3b --- /dev/null +++ b/ld/testsuite/ld-powerpc/elfv2.s @@ -0,0 +1,32 @@ + .section .toc,"aw",@progbits +.L0: + .quad x + + .data +x: + .quad f1 + + .globl f1 + .type f1,@function + .text +f1: + addis 2,12,.TOC.-f1@ha + addi 2,2,.TOC.-f1@l + .localentry f1,.-f1 + mflr 0 + stdu 1,-32(1) + std 0,48(1) + bl f1 + ld 3,.L0@toc(2) + bl f2 + nop + ld 3,x@got(2) + bl f3 + nop + bl f4 + nop + ld 0,48(1) + addi 1,1,32 + mtlr 0 + blr + .size f1,.-f1 diff --git a/ld/testsuite/ld-powerpc/elfv2exe.d b/ld/testsuite/ld-powerpc/elfv2exe.d new file mode 100644 index 0000000..7ff9d38 --- /dev/null +++ b/ld/testsuite/ld-powerpc/elfv2exe.d @@ -0,0 +1,40 @@ +#source: elfv2.s +#as: -a64 +#ld: -melf64ppc --defsym f2=0x1234 --defsym f3=0x10008888 --defsym f4=0x1200000 --defsym _start=f1 +#objdump: -dr + +.* + +Disassembly of section \.text: + +0+100000c0 <.*\.plt_branch\.f2>: +.*: (ff ff 62 3d|3d 62 ff ff) addis r11,r2,-1 +.*: (f0 7f 8b e9|e9 8b 7f f0) ld r12,32752\(r11\) +.*: (a6 03 89 7d|7d 89 03 a6) mtctr r12 +.*: (20 04 80 4e|4e 80 04 20) bctr + +0+100000d0 <.*\.plt_branch\.f4>: +.*: (ff ff 62 3d|3d 62 ff ff) addis r11,r2,-1 +.*: (f8 7f 8b e9|e9 8b 7f f8) ld r12,32760\(r11\) +.*: (a6 03 89 7d|7d 89 03 a6) mtctr r12 +.*: (20 04 80 4e|4e 80 04 20) bctr + +0+100000e0 <_start>: +.*: (02 10 40 3c|3c 40 10 02) lis r2,4098 +.*: (40 81 42 38|38 42 81 40) addi r2,r2,-32448 +.*: (a6 02 08 7c|7c 08 02 a6) mflr r0 +.*: (e1 ff 21 f8|f8 21 ff e1) stdu r1,-32\(r1\) +.*: (30 00 01 f8|f8 01 00 30) std r0,48\(r1\) +.*: (f5 ff ff 4b|4b ff ff f5) bl .* <_start\+0x8> +.*: (08 80 62 e8|e8 62 80 08) ld r3,-32760\(r2\) +.*: (c5 ff ff 4b|4b ff ff c5) bl .*\.plt_branch\.f2> +.*: (00 00 00 60|60 00 00 00) nop +.*: (10 80 62 e8|e8 62 80 10) ld r3,-32752\(r2\) +.*: (81 87 00 48|48 00 87 81) bl 10008888 +.*: (00 00 00 60|60 00 00 00) nop +.*: (c1 ff ff 4b|4b ff ff c1) bl .*\.plt_branch\.f4> +.*: (00 00 00 60|60 00 00 00) nop +.*: (30 00 01 e8|e8 01 00 30) ld r0,48\(r1\) +.*: (20 00 21 38|38 21 00 20) addi r1,r1,32 +.*: (a6 03 08 7c|7c 08 03 a6) mtlr r0 +.*: (20 00 80 4e|4e 80 00 20) blr diff --git a/ld/testsuite/ld-powerpc/elfv2so.d b/ld/testsuite/ld-powerpc/elfv2so.d new file mode 100644 index 0000000..963dbb6 --- /dev/null +++ b/ld/testsuite/ld-powerpc/elfv2so.d @@ -0,0 +1,82 @@ +#source: elfv2.s +#as: -a64 +#ld: -melf64ppc -shared +#objdump: -dr + +.* + +Disassembly of section \.text: + +0+300 <.*\.plt_call\.f4>: +.*: (18 00 41 f8|f8 41 00 18) std r2,24\(r1\) +.*: (38 80 82 e9|e9 82 80 38) ld r12,-32712\(r2\) +.*: (a6 03 89 7d|7d 89 03 a6) mtctr r12 +.*: (20 04 80 4e|4e 80 04 20) bctr + +0+310 <.*\.plt_call\.f3>: +.*: (18 00 41 f8|f8 41 00 18) std r2,24\(r1\) +.*: (28 80 82 e9|e9 82 80 28) ld r12,-32728\(r2\) +.*: (a6 03 89 7d|7d 89 03 a6) mtctr r12 +.*: (20 04 80 4e|4e 80 04 20) bctr + +0+320 <.*\.plt_call\.f2>: +.*: (18 00 41 f8|f8 41 00 18) std r2,24\(r1\) +.*: (30 80 82 e9|e9 82 80 30) ld r12,-32720\(r2\) +.*: (a6 03 89 7d|7d 89 03 a6) mtctr r12 +.*: (20 04 80 4e|4e 80 04 20) bctr + +0+330 <.*\.plt_call\.f1>: +.*: (18 00 41 f8|f8 41 00 18) std r2,24\(r1\) +.*: (40 80 82 e9|e9 82 80 40) ld r12,-32704\(r2\) +.*: (a6 03 89 7d|7d 89 03 a6) mtctr r12 +.*: (20 04 80 4e|4e 80 04 20) bctr + +0+340 : +.*: (02 00 4c 3c|3c 4c 00 02) addis r2,r12,2 +.*: (e0 81 42 38|38 42 81 e0) addi r2,r2,-32288 +.*: (a6 02 08 7c|7c 08 02 a6) mflr r0 +.*: (e1 ff 21 f8|f8 21 ff e1) stdu r1,-32\(r1\) +.*: (30 00 01 f8|f8 01 00 30) std r0,48\(r1\) +.*: (dd ff ff 4b|4b ff ff dd) bl .*\.plt_call\.f1> +.*: (08 80 62 e8|e8 62 80 08) ld r3,-32760\(r2\) +.*: (c5 ff ff 4b|4b ff ff c5) bl .*\.plt_call\.f2> +.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\) +.*: (10 80 62 e8|e8 62 80 10) ld r3,-32752\(r2\) +.*: (a9 ff ff 4b|4b ff ff a9) bl .*\.plt_call\.f3> +.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\) +.*: (91 ff ff 4b|4b ff ff 91) bl .*\.plt_call\.f4> +.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\) +.*: (30 00 01 e8|e8 01 00 30) ld r0,48\(r1\) +.*: (20 00 21 38|38 21 00 20) addi r1,r1,32 +.*: (a6 03 08 7c|7c 08 03 a6) mtlr r0 +.*: (20 00 80 4e|4e 80 00 20) blr +.*: (a0 01 01 00|00 00 00 00) .* +.*: (00 00 00 00|00 01 01 a0) .* + +0+390 <__glink_PLTresolve>: +.*: (a6 02 08 7c|7c 08 02 a6) mflr r0 +.*: (05 00 9f 42|42 9f 00 05) bcl .* +.*: (a6 02 68 7d|7d 68 02 a6) mflr r11 +.*: (f0 ff 4b e8|e8 4b ff f0) ld r2,-16\(r11\) +.*: (a6 03 08 7c|7c 08 03 a6) mtlr r0 +.*: (50 60 8b 7d|7d 8b 60 50) subf r12,r11,r12 +.*: (14 5a 62 7d|7d 62 5a 14) add r11,r2,r11 +.*: (d0 ff 0c 38|38 0c ff d0) addi r0,r12,-48 +.*: (00 00 8b e9|e9 8b 00 00) ld r12,0\(r11\) +.*: (82 f0 00 78|78 00 f0 82) rldicl r0,r0,62,2 +.*: (a6 03 89 7d|7d 89 03 a6) mtctr r12 +.*: (08 00 6b e9|e9 6b 00 08) ld r11,8\(r11\) +.*: (20 04 80 4e|4e 80 04 20) bctr +.*: (00 00 00 60|60 00 00 00) nop + +.* : +.*: (c8 ff ff 4b|4b ff ff c8) b .* <__glink_PLTresolve> + +.* : +.*: (c4 ff ff 4b|4b ff ff c4) b .* <__glink_PLTresolve> + +.* : +.*: (c0 ff ff 4b|4b ff ff c0) b .* <__glink_PLTresolve> + +.* : +.*: (bc ff ff 4b|4b ff ff bc) b .* <__glink_PLTresolve> diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index f022b95..837ad64 100644 --- a/ld/testsuite/ld-powerpc/powerpc.exp +++ b/ld/testsuite/ld-powerpc/powerpc.exp @@ -269,6 +269,8 @@ run_ld_link_tests $ppcelftests if [ supports_ppc64 ] then { run_ld_link_tests $ppc64elftests run_dump_test "relbrlt" + run_dump_test "elfv2so" + run_dump_test "elfv2exe" } if { [istarget "powerpc*-eabi*"] } { diff --git a/ld/testsuite/ld-powerpc/tls.d b/ld/testsuite/ld-powerpc/tls.d index 3c32980..eb4be24 100644 --- a/ld/testsuite/ld-powerpc/tls.d +++ b/ld/testsuite/ld-powerpc/tls.d @@ -9,7 +9,7 @@ Disassembly of section \.text: -0+100000e8 <_start>: +0+100000e8 <\._start>: .*: (3c 6d 00 00|00 00 6d 3c) addis r3,r13,0 .*: (60 00 00 00|00 00 00 60) nop .*: (38 63 90 78|78 90 63 38) addi r3,r3,-28552 diff --git a/ld/testsuite/ld-powerpc/tls.g b/ld/testsuite/ld-powerpc/tls.g index 83f8e06..2de9e3b 100644 --- a/ld/testsuite/ld-powerpc/tls.g +++ b/ld/testsuite/ld-powerpc/tls.g @@ -8,5 +8,5 @@ .* Contents of section \.got: - 100101e0 (00000000|e0810110) (100181e0|00000000) (ffffffff|1880ffff) (ffff8018|ffffffff) .* - 100101f0 (ffffffff|5880ffff) (ffff8058|ffffffff) .* + 100101f8 (00000000|f8810110) (100181f8|00000000) (ffffffff|1880ffff) (ffff8018|ffffffff) .* + 10010208 (ffffffff|5880ffff) (ffff8058|ffffffff) .* diff --git a/ld/testsuite/ld-powerpc/tls.s b/ld/testsuite/ld-powerpc/tls.s index 5ad9f3d..49828d0 100644 --- a/ld/testsuite/ld-powerpc/tls.s +++ b/ld/testsuite/ld-powerpc/tls.s @@ -19,8 +19,13 @@ ie4: .quad 0x56789abcdef01234 le4: .quad 0x6789abcdef012345 le5: .quad 0x789abcdef0123456 - .text + .section ".opd","aw",@progbits + .p2align 3 _start: + .quad .L_start,.TOC.@tocbase,0 + + .text +.L_start: #extern syms #GD addi 3,2,gd@got@tlsgd #R_PPC64_GOT_TLSGD16 gd diff --git a/ld/testsuite/ld-powerpc/tlsexe.d b/ld/testsuite/ld-powerpc/tlsexe.d index 8390551..0d5ee40 100644 --- a/ld/testsuite/ld-powerpc/tlsexe.d +++ b/ld/testsuite/ld-powerpc/tlsexe.d @@ -19,8 +19,8 @@ Disassembly of section \.text: .* (7d 68 02 a6|a6 02 68 7d) mflr r11 .* (f9 61 00 20|20 00 61 f9) std r11,32\(r1\) .* (f8 41 00 28|28 00 41 f8) std r2,40\(r1\) -.* (e9 62 80 48|48 80 62 e9) ld r11,-32696\(r2\) -.* (7d 69 03 a6|a6 03 69 7d) mtctr r11 +.* (e9 82 80 48|48 80 82 e9) ld r12,-32696\(r2\) +.* (7d 89 03 a6|a6 03 89 7d) mtctr r12 .* (e8 42 80 50|50 80 42 e8) ld r2,-32688\(r2\) .* (4e 80 04 21|21 04 80 4e) bctrl .* (e9 61 00 20|20 00 61 e9) ld r11,32\(r1\) @@ -28,7 +28,7 @@ Disassembly of section \.text: .* (7d 68 03 a6|a6 03 68 7d) mtlr r11 .* (4e 80 00 20|20 00 80 4e) blr -.* <_start>: +.* <._start>: .* (e8 62 80 10|10 80 62 e8) ld r3,-32752\(r2\) .* (60 00 00 00|00 00 00 60) nop .* (7c 63 6a 14|14 6a 63 7c) add r3,r3,r13 @@ -67,22 +67,23 @@ Disassembly of section \.text: .* (e9 4d 90 2a|2a 90 4d e9) lwa r10,-28632\(r13\) .* (3d 2d 00 00|00 00 2d 3d) addis r9,r13,0 .* (a9 49 90 30|30 90 49 a9) lha r10,-28624\(r9\) -.* (00 00 00 00|00 02 01 00) .* -.* (00 01 02 00|00 00 00 00) .* +.* (00 00 00 00|18 02 01 00) .* +.* (00 01 02 18|00 00 00 00) .* .* <__glink_PLTresolve>: .* (7d 88 02 a6|a6 02 88 7d) mflr r12 .* (42 9f 00 05|05 00 9f 42) bcl 20,4\*cr7\+so,.* .* (7d 68 02 a6|a6 02 68 7d) mflr r11 .* (e8 4b ff f0|f0 ff 4b e8) ld r2,-16\(r11\) .* (7d 88 03 a6|a6 03 88 7d) mtlr r12 -.* (7d 82 5a 14|14 5a 82 7d) add r12,r2,r11 -.* (e9 6c 00 00|00 00 6c e9) ld r11,0\(r12\) -.* (e8 4c 00 08|08 00 4c e8) ld r2,8\(r12\) -.* (7d 69 03 a6|a6 03 69 7d) mtctr r11 -.* (e9 6c 00 10|10 00 6c e9) ld r11,16\(r12\) +.* (7d 62 5a 14|14 5a 62 7d) add r11,r2,r11 +.* (e9 8b 00 00|00 00 8b e9) ld r12,0\(r11\) +.* (e8 4b 00 08|08 00 4b e8) ld r2,8\(r11\) +.* (7d 89 03 a6|a6 03 89 7d) mtctr r12 +.* (e9 6b 00 10|10 00 6b e9) ld r11,16\(r11\) .* (4e 80 04 20|20 04 80 4e) bctr .* (60 00 00 00|00 00 00 60) nop .* (60 00 00 00|00 00 00 60) nop .* (60 00 00 00|00 00 00 60) nop +.* <__tls_get_addr_opt@plt>: .* (38 00 00 00|00 00 00 38) li r0,0 .* (4b ff ff c4|c4 ff ff 4b) b .* diff --git a/ld/testsuite/ld-powerpc/tlsexe.g b/ld/testsuite/ld-powerpc/tlsexe.g index 3420d20..fb8dbb3 100644 --- a/ld/testsuite/ld-powerpc/tlsexe.g +++ b/ld/testsuite/ld-powerpc/tlsexe.g @@ -7,6 +7,6 @@ .* Contents of section \.got: -.* (00000000|20860110) (10018620|00000000) (ffffffff|1880ffff) (ffff8018|ffffffff) .* +.* (00000000|38860110) (10018638|00000000) (ffffffff|1880ffff) (ffff8018|ffffffff) .* .* 00000000 00000000 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* diff --git a/ld/testsuite/ld-powerpc/tlsexe.r b/ld/testsuite/ld-powerpc/tlsexe.r index 8d6ff30..72ef3f4 100644 --- a/ld/testsuite/ld-powerpc/tlsexe.r +++ b/ld/testsuite/ld-powerpc/tlsexe.r @@ -20,6 +20,7 @@ Section Headers: +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8 +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8 +\[[ 0-9]+\] \.dynamic +DYNAMIC .* 0+160 10 +WA +4 +0 +8 + +\[[ 0-9]+\] \.opd .* +\[[ 0-9]+\] \.got +PROGBITS .* 0+30 08 +WA +0 +0 +8 +\[[ 0-9]+\] \.plt +.* +\[[ 0-9]+\] \.shstrtab +.* @@ -46,7 +47,7 @@ Program Headers: +0+ + +01 +\.interp +02 +\.interp \.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text - +03 +\.tdata \.dynamic \.got \.plt + +03 +\.tdata \.dynamic \.opd \.got \.plt +04 +\.dynamic +05 +\.tdata \.tbss @@ -66,10 +67,10 @@ Symbol table '\.dynsym' contains [0-9]+ entries: .* TLS +GLOBAL +DEFAULT +UND gd .* TLS +GLOBAL +DEFAULT +UND ld .* TLS +GLOBAL +DEFAULT +9 ld2 -.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start +.* NOTYPE +GLOBAL +DEFAULT +13 __bss_start .* FUNC +GLOBAL +DEFAULT +UND __tls_get_addr_opt -.* NOTYPE +GLOBAL +DEFAULT +12 _edata -.* NOTYPE +GLOBAL +DEFAULT +12 _end +.* NOTYPE +GLOBAL +DEFAULT +13 _edata +.* NOTYPE +GLOBAL +DEFAULT +13 _end Symbol table '\.symtab' contains [0-9]+ entries: +Num: +Value +Size +Type +Bind +Vis +Ndx +Name @@ -86,6 +87,7 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* SECTION +LOCAL +DEFAULT +10 .* SECTION +LOCAL +DEFAULT +11 .* SECTION +LOCAL +DEFAULT +12 +.* SECTION +LOCAL +DEFAULT +13 .* FILE +LOCAL +DEFAULT +ABS .* .* TLS +LOCAL +DEFAULT +8 gd4 .* TLS +LOCAL +DEFAULT +8 ld4 @@ -104,12 +106,12 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* GLOBAL +DEFAULT +9 ld0 .* GLOBAL +DEFAULT +9 le1 .* GLOBAL +DEFAULT +UND ld -.* NOTYPE +GLOBAL +DEFAULT +7 _start +.* FUNC +GLOBAL +DEFAULT +11 _start .* TLS +GLOBAL +DEFAULT +9 ld2 .* TLS +GLOBAL +DEFAULT +9 ld1 -.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start +.* NOTYPE +GLOBAL +DEFAULT +13 __bss_start .* FUNC +GLOBAL +DEFAULT +UND __tls_get_addr_opt -.* NOTYPE +GLOBAL +DEFAULT +12 _edata -.* NOTYPE +GLOBAL +DEFAULT +12 _end +.* NOTYPE +GLOBAL +DEFAULT +13 _edata +.* NOTYPE +GLOBAL +DEFAULT +13 _end .* TLS +GLOBAL +DEFAULT +9 gd0 .* TLS +GLOBAL +DEFAULT +9 ie0 diff --git a/ld/testsuite/ld-powerpc/tlsexetoc.d b/ld/testsuite/ld-powerpc/tlsexetoc.d index fc20992..ee0f3b2 100644 --- a/ld/testsuite/ld-powerpc/tlsexetoc.d +++ b/ld/testsuite/ld-powerpc/tlsexetoc.d @@ -19,8 +19,8 @@ Disassembly of section \.text: .* (7d 68 02 a6|a6 02 68 7d) mflr r11 .* (f9 61 00 20|20 00 61 f9) std r11,32\(r1\) .* (f8 41 00 28|28 00 41 f8) std r2,40\(r1\) -.* (e9 62 80 70|70 80 62 e9) ld r11,-32656\(r2\) -.* (7d 69 03 a6|a6 03 69 7d) mtctr r11 +.* (e9 82 80 70|70 80 82 e9) ld r12,-32656\(r2\) +.* (7d 89 03 a6|a6 03 89 7d) mtctr r12 .* (e8 42 80 78|78 80 42 e8) ld r2,-32648\(r2\) .* (4e 80 04 21|21 04 80 4e) bctrl .* (e9 61 00 20|20 00 61 e9) ld r11,32\(r1\) @@ -28,7 +28,7 @@ Disassembly of section \.text: .* (7d 68 03 a6|a6 03 68 7d) mtlr r11 .* (4e 80 00 20|20 00 80 4e) blr -.* <_start>: +.* <\._start>: .* (38 62 80 08|08 80 62 38) addi r3,r2,-32760 .* (4b ff ff b5|b5 ff ff 4b) bl .* .* (60 00 00 00|00 00 00 60) nop @@ -51,22 +51,23 @@ Disassembly of section \.text: .* (89 4d 90 60|60 90 4d 89) lbz r10,-28576\(r13\) .* (3d 2d 00 00|00 00 2d 3d) addis r9,r13,0 .* (99 49 90 68|68 90 49 99) stb r10,-28568\(r9\) -.* (00 00 00 00|28 02 01 00) .* -.* (00 01 02 28|00 00 00 00) .* +.* (00 00 00 00|40 02 01 00) .* +.* (00 01 02 40|00 00 00 00) .* .* <__glink_PLTresolve>: .* (7d 88 02 a6|a6 02 88 7d) mflr r12 .* (42 9f 00 05|05 00 9f 42) bcl 20,4\*cr7\+so,.* .* (7d 68 02 a6|a6 02 68 7d) mflr r11 .* (e8 4b ff f0|f0 ff 4b e8) ld r2,-16\(r11\) .* (7d 88 03 a6|a6 03 88 7d) mtlr r12 -.* (7d 82 5a 14|14 5a 82 7d) add r12,r2,r11 -.* (e9 6c 00 00|00 00 6c e9) ld r11,0\(r12\) -.* (e8 4c 00 08|08 00 4c e8) ld r2,8\(r12\) -.* (7d 69 03 a6|a6 03 69 7d) mtctr r11 -.* (e9 6c 00 10|10 00 6c e9) ld r11,16\(r12\) +.* (7d 62 5a 14|14 5a 62 7d) add r11,r2,r11 +.* (e9 8b 00 00|00 00 8b e9) ld r12,0\(r11\) +.* (e8 4b 00 08|08 00 4b e8) ld r2,8\(r11\) +.* (7d 89 03 a6|a6 03 89 7d) mtctr r12 +.* (e9 6b 00 10|10 00 6b e9) ld r11,16\(r11\) .* (4e 80 04 20|20 04 80 4e) bctr .* (60 00 00 00|00 00 00 60) nop .* (60 00 00 00|00 00 00 60) nop .* (60 00 00 00|00 00 00 60) nop +.* <__tls_get_addr_opt@plt>: .* (38 00 00 00|00 00 00 38) li r0,0 .* (4b ff ff c4|c4 ff ff 4b) b .* diff --git a/ld/testsuite/ld-powerpc/tlsexetoc.g b/ld/testsuite/ld-powerpc/tlsexetoc.g index e219f0e..dc563ad 100644 --- a/ld/testsuite/ld-powerpc/tlsexetoc.g +++ b/ld/testsuite/ld-powerpc/tlsexetoc.g @@ -7,7 +7,7 @@ .*: +file format elf64-powerpc Contents of section \.got: -.* (00000000|c0850110) (100185c0|00000000) 00000000 00000000 .* +.* (00000000|d8850110) (100185d8|00000000) 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* .* 00000000 00000000 (00000000|01000000) (00000001|00000000) .* .* 00000000 00000000 (00000000|01000000) (00000001|00000000) .* diff --git a/ld/testsuite/ld-powerpc/tlsexetoc.r b/ld/testsuite/ld-powerpc/tlsexetoc.r index 71d6c9e..e6f606b 100644 --- a/ld/testsuite/ld-powerpc/tlsexetoc.r +++ b/ld/testsuite/ld-powerpc/tlsexetoc.r @@ -20,6 +20,7 @@ Section Headers: +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8 +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8 +\[[ 0-9]+\] \.dynamic +DYNAMIC .* 0+160 10 +WA +4 +0 +8 + +\[[ 0-9]+\] \.opd .* +\[[ 0-9]+\] \.got +PROGBITS .* 0+58 08 +WA +0 +0 +8 +\[[ 0-9]+\] \.plt +.* +\[[ 0-9]+\] \.shstrtab +.* @@ -46,7 +47,7 @@ Program Headers: +0+ + +01 +\.interp +02 +\.interp \.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text - +03 +\.tdata \.dynamic \.got \.plt + +03 +\.tdata \.dynamic \.opd \.got \.plt +04 +\.dynamic +05 +\.tdata \.tbss @@ -65,10 +66,10 @@ Symbol table '\.dynsym' contains [0-9]+ entries: .* NOTYPE +LOCAL +DEFAULT +UND .* TLS +GLOBAL +DEFAULT +UND gd .* TLS +GLOBAL +DEFAULT +UND ld -.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start +.* NOTYPE +GLOBAL +DEFAULT +13 __bss_start .* FUNC +GLOBAL +DEFAULT +UND __tls_get_addr_opt -.* NOTYPE +GLOBAL +DEFAULT +12 _edata -.* NOTYPE +GLOBAL +DEFAULT +12 _end +.* NOTYPE +GLOBAL +DEFAULT +13 _edata +.* NOTYPE +GLOBAL +DEFAULT +13 _end Symbol table '\.symtab' contains [0-9]+ entries: +Num: +Value +Size +Type +Bind +Vis +Ndx +Name @@ -85,6 +86,7 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* SECTION +LOCAL +DEFAULT +10 .* SECTION +LOCAL +DEFAULT +11 .* SECTION +LOCAL +DEFAULT +12 +.* SECTION +LOCAL +DEFAULT +13 .* FILE +LOCAL +DEFAULT +ABS .* .* TLS +LOCAL +DEFAULT +8 gd4 .* TLS +LOCAL +DEFAULT +8 ld4 @@ -93,7 +95,7 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* TLS +LOCAL +DEFAULT +8 ie4 .* TLS +LOCAL +DEFAULT +8 le4 .* TLS +LOCAL +DEFAULT +8 le5 -.* NOTYPE +LOCAL +DEFAULT +11 \.Lie0 +.* NOTYPE +LOCAL +DEFAULT +12 \.Lie0 .* (FUNC|NOTYPE) +LOCAL +DEFAULT +UND \.__tls_get_addr(|_opt) .* FILE +LOCAL +DEFAULT +ABS .* .* NOTYPE +LOCAL +DEFAULT +7 00000010\.plt_call\.__tls_get_addr(|_opt) @@ -104,12 +106,12 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* TLS +GLOBAL +DEFAULT +9 ld0 .* TLS +GLOBAL +DEFAULT +9 le1 .* TLS +GLOBAL +DEFAULT +UND ld -.* NOTYPE +GLOBAL +DEFAULT +7 _start +.* FUNC +GLOBAL +DEFAULT +11 _start .* TLS +GLOBAL +DEFAULT +9 ld2 .* TLS +GLOBAL +DEFAULT +9 ld1 -.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start +.* NOTYPE +GLOBAL +DEFAULT +13 __bss_start .* FUNC +GLOBAL +DEFAULT +UND __tls_get_addr_opt -.* NOTYPE +GLOBAL +DEFAULT +12 _edata -.* NOTYPE +GLOBAL +DEFAULT +12 _end +.* NOTYPE +GLOBAL +DEFAULT +13 _edata +.* NOTYPE +GLOBAL +DEFAULT +13 _end .* TLS +GLOBAL +DEFAULT +9 gd0 .* TLS +GLOBAL +DEFAULT +9 ie0 diff --git a/ld/testsuite/ld-powerpc/tlsso.d b/ld/testsuite/ld-powerpc/tlsso.d index 00b00a0..e64184d 100644 --- a/ld/testsuite/ld-powerpc/tlsso.d +++ b/ld/testsuite/ld-powerpc/tlsso.d @@ -10,14 +10,14 @@ Disassembly of section \.text: .* <00000010\.plt_call\.__tls_get_addr(|_opt)>: .* (f8 41 00 28|28 00 41 f8) std r2,40\(r1\) -.* (e9 62 80 78|78 80 62 e9) ld r11,-32648\(r2\) -.* (7d 69 03 a6|a6 03 69 7d) mtctr r11 +.* (e9 82 80 78|78 80 82 e9) ld r12,-32648\(r2\) +.* (7d 89 03 a6|a6 03 89 7d) mtctr r12 .* (e8 42 80 80|80 80 42 e8) ld r2,-32640\(r2\) .* (28 22 00 00|00 00 22 28) cmpldi r2,0 .* (4c e2 04 20|20 04 e2 4c) bnectr\+ -.* (48 00 00 ..|.. 00 00 48) b .* <__glink_PLTresolve\+0x38> +.* (48 00 00 ..|.. 00 00 48) b .* <__tls_get_addr@plt> -.* <_start>: +.* <\._start>: .* (38 62 80 20|20 80 62 38) addi r3,r2,-32736 .* (4b ff ff ..|.. ff ff 4b) bl .*plt_call.__tls_get_addr.* .* (e8 41 00 28|28 00 41 e8) ld r2,40\(r1\) @@ -57,22 +57,23 @@ Disassembly of section \.text: .* (3d 2d 00 00|00 00 2d 3d) addis r9,r13,0 .* (a9 49 00 00|00 00 49 a9) lha r10,0\(r9\) .* (60 00 00 00|00 00 00 60) nop -.* (00 00 00 00|20 02 01 00) .* -.* (00 01 02 20|00 00 00 00) .* +.* (00 00 00 00|38 02 01 00) .* +.* (00 01 02 38|00 00 00 00) .* .* <__glink_PLTresolve>: .* (7d 88 02 a6|a6 02 88 7d) mflr r12 .* (42 9f 00 05|05 00 9f 42) bcl 20,4\*cr7\+so,.* .* (7d 68 02 a6|a6 02 68 7d) mflr r11 .* (e8 4b ff f0|f0 ff 4b e8) ld r2,-16\(r11\) .* (7d 88 03 a6|a6 03 88 7d) mtlr r12 -.* (7d 82 5a 14|14 5a 82 7d) add r12,r2,r11 -.* (e9 6c 00 00|00 00 6c e9) ld r11,0\(r12\) -.* (e8 4c 00 08|08 00 4c e8) ld r2,8\(r12\) -.* (7d 69 03 a6|a6 03 69 7d) mtctr r11 -.* (e9 6c 00 10|10 00 6c e9) ld r11,16\(r12\) +.* (7d 62 5a 14|14 5a 62 7d) add r11,r2,r11 +.* (e9 8b 00 00|00 00 8b e9) ld r12,0\(r11\) +.* (e8 4b 00 08|08 00 4b e8) ld r2,8\(r11\) +.* (7d 89 03 a6|a6 03 89 7d) mtctr r12 +.* (e9 6b 00 10|10 00 6b e9) ld r11,16\(r11\) .* (4e 80 04 20|20 04 80 4e) bctr .* (60 00 00 00|00 00 00 60) nop .* (60 00 00 00|00 00 00 60) nop .* (60 00 00 00|00 00 00 60) nop +.* <__tls_get_addr@plt>: .* (38 00 00 00|00 00 00 38) li r0,0 .* (4b ff ff c4|c4 ff ff 4b) b .* diff --git a/ld/testsuite/ld-powerpc/tlsso.g b/ld/testsuite/ld-powerpc/tlsso.g index 8536803..8fd3ce0 100644 --- a/ld/testsuite/ld-powerpc/tlsso.g +++ b/ld/testsuite/ld-powerpc/tlsso.g @@ -7,7 +7,7 @@ .*: +file format elf64-powerpc Contents of section \.got: - 10788 (00000000|88870100) (00018788|00000000) 00000000 00000000 .* + 107e0 (00000000|e0870100) (000187e0|00000000) 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* diff --git a/ld/testsuite/ld-powerpc/tlsso.r b/ld/testsuite/ld-powerpc/tlsso.r index fab50e0..6464be0 100644 --- a/ld/testsuite/ld-powerpc/tlsso.r +++ b/ld/testsuite/ld-powerpc/tlsso.r @@ -18,6 +18,7 @@ Section Headers: +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8 +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8 +\[[ 0-9]+\] \.dynamic .* + +\[[ 0-9]+\] \.opd .* +\[[ 0-9]+\] \.got .* +\[[ 0-9]+\] \.plt .* +\[[ 0-9]+\] \.shstrtab .* @@ -39,12 +40,14 @@ Program Headers: Section to Segment mapping: +Segment Sections\.\.\. +0+ +\.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text - +01 +\.tdata \.dynamic .got \.plt + +01 +\.tdata \.dynamic \.opd \.got \.plt +02 +\.dynamic +03 +\.tdata \.tbss -Relocation section '\.rela\.dyn' at offset .* contains 16 entries: +Relocation section '\.rela\.dyn' at offset .* contains 18 entries: +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend +[0-9a-f ]+R_PPC64_RELATIVE +55c +[0-9a-f ]+R_PPC64_RELATIVE +187e0 [0-9a-f ]+R_PPC64_TPREL16 +0+60 le0 \+ 0 [0-9a-f ]+R_PPC64_TPREL16_HA +0+68 le1 \+ 0 [0-9a-f ]+R_PPC64_TPREL16_LO +0+68 le1 \+ 0 @@ -77,12 +80,12 @@ Symbol table '\.dynsym' contains [0-9]+ entries: .* TLS +GLOBAL +DEFAULT +8 ld0 .* TLS +GLOBAL +DEFAULT +8 le1 .* TLS +GLOBAL +DEFAULT +UND ld -.* NOTYPE +GLOBAL +DEFAULT +6 _start +.* FUNC +GLOBAL +DEFAULT +10 _start .* TLS +GLOBAL +DEFAULT +8 ld2 .* TLS +GLOBAL +DEFAULT +8 ld1 -.* NOTYPE +GLOBAL +DEFAULT +11 __bss_start -.* NOTYPE +GLOBAL +DEFAULT +11 _edata -.* NOTYPE +GLOBAL +DEFAULT +11 _end +.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start +.* NOTYPE +GLOBAL +DEFAULT +12 _edata +.* NOTYPE +GLOBAL +DEFAULT +12 _end .* TLS +GLOBAL +DEFAULT +8 gd0 .* TLS +GLOBAL +DEFAULT +8 ie0 @@ -100,6 +103,7 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* SECTION +LOCAL +DEFAULT +9 .* SECTION +LOCAL +DEFAULT +10 .* SECTION +LOCAL +DEFAULT +11 +.* SECTION +LOCAL +DEFAULT +12 .* FILE +LOCAL +DEFAULT +ABS .* .* TLS +LOCAL +DEFAULT +7 gd4 .* TLS +LOCAL +DEFAULT +7 ld4 @@ -119,11 +123,11 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* TLS +GLOBAL +DEFAULT +8 ld0 .* TLS +GLOBAL +DEFAULT +8 le1 .* TLS +GLOBAL +DEFAULT +UND ld -.* NOTYPE +GLOBAL +DEFAULT +6 _start +.* FUNC +GLOBAL +DEFAULT +10 _start .* TLS +GLOBAL +DEFAULT +8 ld2 .* TLS +GLOBAL +DEFAULT +8 ld1 -.* NOTYPE +GLOBAL +DEFAULT +11 __bss_start -.* NOTYPE +GLOBAL +DEFAULT +11 _edata -.* NOTYPE +GLOBAL +DEFAULT +11 _end +.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start +.* NOTYPE +GLOBAL +DEFAULT +12 _edata +.* NOTYPE +GLOBAL +DEFAULT +12 _end .* TLS +GLOBAL +DEFAULT +8 gd0 .* TLS +GLOBAL +DEFAULT +8 ie0 diff --git a/ld/testsuite/ld-powerpc/tlstoc.d b/ld/testsuite/ld-powerpc/tlstoc.d index faea1c4..05f61af 100644 --- a/ld/testsuite/ld-powerpc/tlstoc.d +++ b/ld/testsuite/ld-powerpc/tlstoc.d @@ -12,7 +12,7 @@ Disassembly of section \.text: .* <\.__tls_get_addr>: .* (4e 80 00 20|20 00 80 4e) blr -.* <_start>: +.* <\._start>: .* (3c 6d 00 00|00 00 6d 3c) addis r3,r13,0 .* (60 00 00 00|00 00 00 60) nop .* (38 63 90 40|40 90 63 38) addi r3,r3,-28608 diff --git a/ld/testsuite/ld-powerpc/tlstoc.g b/ld/testsuite/ld-powerpc/tlstoc.g index 9ca4302..e3fe1d3 100644 --- a/ld/testsuite/ld-powerpc/tlstoc.g +++ b/ld/testsuite/ld-powerpc/tlstoc.g @@ -8,8 +8,8 @@ .* Contents of section \.got: - 100101a0 (00000000|01000000) (00000001|00000000) 00000000 00000000 .* - 100101b0 (00000000|01000000) (00000001|00000000) 00000000 00000000 .* - 100101c0 (00000000|01000000) (00000001|00000000) 00000000 00000000 .* - 100101d0 (00000000|01000000) (00000001|00000000) 00000000 00000000 .* - 100101e0 (ffffffff|6080ffff) (ffff8060|ffffffff) 00000000 00000000 .* + 100101b8 (00000000|01000000) (00000001|00000000) 00000000 00000000 .* + 100101c8 (00000000|01000000) (00000001|00000000) 00000000 00000000 .* + 100101d8 (00000000|01000000) (00000001|00000000) 00000000 00000000 .* + 100101e8 (00000000|01000000) (00000001|00000000) 00000000 00000000 .* + 100101f8 (ffffffff|6080ffff) (ffff8060|ffffffff) 00000000 00000000 .* diff --git a/ld/testsuite/ld-powerpc/tlstoc.s b/ld/testsuite/ld-powerpc/tlstoc.s index 5008d89..f5dbfdd 100644 --- a/ld/testsuite/ld-powerpc/tlstoc.s +++ b/ld/testsuite/ld-powerpc/tlstoc.s @@ -19,8 +19,13 @@ ie4: .quad 0x56789abcdef01234 le4: .quad 0x6789abcdef012345 le5: .quad 0x789abcdef0123456 - .text + .section ".opd","aw",@progbits + .p2align 3 _start: + .quad .L_start,.TOC.@tocbase,0 + + .text +.L_start: #extern syms #GD addi 3,2,.Lgd@toc diff --git a/ld/testsuite/ld-powerpc/tlstocso.d b/ld/testsuite/ld-powerpc/tlstocso.d index a0cd08f..fa3b77a 100644 --- a/ld/testsuite/ld-powerpc/tlstocso.d +++ b/ld/testsuite/ld-powerpc/tlstocso.d @@ -10,14 +10,14 @@ Disassembly of section \.text: .* <00000010\.plt_call\.__tls_get_addr(|_opt)>: .* (f8 41 00 28|28 00 41 f8) std r2,40\(r1\) -.* (e9 62 80 70|70 80 62 e9) ld r11,-32656\(r2\) -.* (7d 69 03 a6|a6 03 69 7d) mtctr r11 +.* (e9 82 80 70|70 80 82 e9) ld r12,-32656\(r2\) +.* (7d 89 03 a6|a6 03 89 7d) mtctr r12 .* (e8 42 80 78|78 80 42 e8) ld r2,-32648\(r2\) .* (28 22 00 00|00 00 22 28) cmpldi r2,0 .* (4c e2 04 20|20 04 e2 4c) bnectr\+ -.* (48 00 00 ..|.. 00 00 48) b .* <__glink_PLTresolve\+0x38> +.* (48 00 00 ..|.. 00 00 48) b .* <__tls_get_addr@plt> -.* <_start>: +.* <\._start>: .* (38 62 80 08|08 80 62 38) addi r3,r2,-32760 .* (4b ff ff ..|.. ff ff 4b) bl .*plt_call.__tls_get_addr.* .* (e8 41 00 28|28 00 41 e8) ld r2,40\(r1\) @@ -41,22 +41,23 @@ Disassembly of section \.text: .* (3d 2d 00 00|00 00 2d 3d) addis r9,r13,0 .* (99 49 00 00|00 00 49 99) stb r10,0\(r9\) .* (60 00 00 00|00 00 00 60) nop -.* (00 00 00 00|18 02 01 00) .* -.* (00 01 02 18|00 00 00 00) .* +.* (00 00 00 00|30 02 01 00) .* +.* (00 01 02 30|00 00 00 00) .* .* <__glink_PLTresolve>: .* (7d 88 02 a6|a6 02 88 7d) mflr r12 .* (42 9f 00 05|05 00 9f 42) bcl 20,4\*cr7\+so,.* .* (7d 68 02 a6|a6 02 68 7d) mflr r11 .* (e8 4b ff f0|f0 ff 4b e8) ld r2,-16\(r11\) .* (7d 88 03 a6|a6 03 88 7d) mtlr r12 -.* (7d 82 5a 14|14 5a 82 7d) add r12,r2,r11 -.* (e9 6c 00 00|00 00 6c e9) ld r11,0\(r12\) -.* (e8 4c 00 08|08 00 4c e8) ld r2,8\(r12\) -.* (7d 69 03 a6|a6 03 69 7d) mtctr r11 -.* (e9 6c 00 10|10 00 6c e9) ld r11,16\(r12\) +.* (7d 62 5a 14|14 5a 62 7d) add r11,r2,r11 +.* (e9 8b 00 00|00 00 8b e9) ld r12,0\(r11\) +.* (e8 4b 00 08|08 00 4b e8) ld r2,8\(r11\) +.* (7d 89 03 a6|a6 03 89 7d) mtctr r12 +.* (e9 6b 00 10|10 00 6b e9) ld r11,16\(r11\) .* (4e 80 04 20|20 04 80 4e) bctr .* (60 00 00 00|00 00 00 60) nop .* (60 00 00 00|00 00 00 60) nop .* (60 00 00 00|00 00 00 60) nop +.* <__tls_get_addr@plt>: .* (38 00 00 00|00 00 00 38) li r0,0 .* (4b ff ff c4|c4 ff ff 4b) b .* diff --git a/ld/testsuite/ld-powerpc/tlstocso.r b/ld/testsuite/ld-powerpc/tlstocso.r index 1ec8b63..f397915 100644 --- a/ld/testsuite/ld-powerpc/tlstocso.r +++ b/ld/testsuite/ld-powerpc/tlstocso.r @@ -18,6 +18,7 @@ Section Headers: +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8 +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8 +\[[ 0-9]+\] \.dynamic .* + +\[[ 0-9]+\] \.opd .* +\[[ 0-9]+\] \.got .* +\[[ 0-9]+\] \.plt .* +\[[ 0-9]+\] \.shstrtab .* @@ -39,12 +40,14 @@ Program Headers: Section to Segment mapping: +Segment Sections\.\.\. +0+ +\.hash \.dynsym \.dynstr \.rela\.dyn \.rela\.plt \.text - +01 +\.tdata \.dynamic \.got \.plt + +01 +\.tdata \.dynamic \.opd \.got \.plt +02 +\.dynamic +03 +\.tdata \.tbss -Relocation section '\.rela\.dyn' at offset .* contains 11 entries: +Relocation section '\.rela\.dyn' at offset .* contains 13 entries: +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend +[0-9a-f ]+R_PPC64_RELATIVE +4dc +[0-9a-f ]+R_PPC64_RELATIVE +18720 [0-9a-f ]+R_PPC64_TPREL16 +0+60 le0 \+ 0 [0-9a-f ]+R_PPC64_TPREL16_HA +0+68 le1 \+ 0 [0-9a-f ]+R_PPC64_TPREL16_LO +0+68 le1 \+ 0 @@ -72,12 +75,12 @@ Symbol table '\.dynsym' contains [0-9]+ entries: .* TLS +GLOBAL +DEFAULT +8 ld0 .* TLS +GLOBAL +DEFAULT +8 le1 .* TLS +GLOBAL +DEFAULT +UND ld -.* NOTYPE +GLOBAL +DEFAULT +6 _start +.* FUNC +GLOBAL +DEFAULT +10 _start .* TLS +GLOBAL +DEFAULT +8 ld2 .* TLS +GLOBAL +DEFAULT +8 ld1 -.* NOTYPE +GLOBAL +DEFAULT +11 __bss_start -.* NOTYPE +GLOBAL +DEFAULT +11 _edata -.* NOTYPE +GLOBAL +DEFAULT +11 _end +.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start +.* NOTYPE +GLOBAL +DEFAULT +12 _edata +.* NOTYPE +GLOBAL +DEFAULT +12 _end .* TLS +GLOBAL +DEFAULT +8 gd0 .* TLS +GLOBAL +DEFAULT +8 ie0 @@ -95,6 +98,7 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* SECTION +LOCAL +DEFAULT +9 .* SECTION +LOCAL +DEFAULT +10 .* SECTION +LOCAL +DEFAULT +11 +.* SECTION +LOCAL +DEFAULT +12 .* FILE +LOCAL +DEFAULT +ABS .* .* TLS +LOCAL +DEFAULT +7 gd4 .* TLS +LOCAL +DEFAULT +7 ld4 @@ -103,7 +107,7 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* TLS +LOCAL +DEFAULT +7 ie4 .* TLS +LOCAL +DEFAULT +7 le4 .* TLS +LOCAL +DEFAULT +7 le5 -.* NOTYPE +LOCAL +DEFAULT +10 \.Lie0 +.* NOTYPE +LOCAL +DEFAULT +11 \.Lie0 .* NOTYPE +LOCAL +DEFAULT +UND \.__tls_get_addr .* FILE +LOCAL +DEFAULT +ABS .* .* OBJECT +LOCAL +DEFAULT +9 _DYNAMIC @@ -115,11 +119,11 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* TLS +GLOBAL +DEFAULT +8 ld0 .* TLS +GLOBAL +DEFAULT +8 le1 .* TLS +GLOBAL +DEFAULT +UND ld -.* NOTYPE +GLOBAL +DEFAULT +6 _start +.* FUNC +GLOBAL +DEFAULT +10 _start .* TLS +GLOBAL +DEFAULT +8 ld2 .* TLS +GLOBAL +DEFAULT +8 ld1 -.* NOTYPE +GLOBAL +DEFAULT +11 __bss_start -.* NOTYPE +GLOBAL +DEFAULT +11 _edata -.* NOTYPE +GLOBAL +DEFAULT +11 _end +.* NOTYPE +GLOBAL +DEFAULT +12 __bss_start +.* NOTYPE +GLOBAL +DEFAULT +12 _edata +.* NOTYPE +GLOBAL +DEFAULT +12 _end .* TLS +GLOBAL +DEFAULT +8 gd0 .* TLS +GLOBAL +DEFAULT +8 ie0 diff --git a/ld/testsuite/ld-scripts/crossref.exp b/ld/testsuite/ld-scripts/crossref.exp index 061b5aa..01fdeb4 100644 --- a/ld/testsuite/ld-scripts/crossref.exp +++ b/ld/testsuite/ld-scripts/crossref.exp @@ -31,9 +31,11 @@ if { ![is_remote host] && [which $CC] == 0 } { return } +global CFLAGS +set old_CFLAGS "$CFLAGS" + # Xtensa targets currently default to putting literal values in a separate # section and that requires linker script support, so put literals in text. -global CFLAGS if [istarget xtensa*-*-*] { set CFLAGS "$CFLAGS -mtext-section-literals" } @@ -41,7 +43,7 @@ if [istarget xtensa*-*-*] { # If we have a compiler that doesn't use/reference dot-symbols, then # calls to functions reference the .opd section function descriptor. # This makes NOCROSSREFS rather useless on powerpc64. -if [istarget powerpc64*-*-*] { +if [istarget powerpc64-*-*] { set CFLAGS "$CFLAGS -mcall-aixdesc" } @@ -61,6 +63,7 @@ if { ![ld_compile $CC "$srcdir/$subdir/cross1.c" tmpdir/cross1.o] \ || ![ld_compile $CC "$srcdir/$subdir/cross2.c" tmpdir/cross2.o] } { unresolved $test1 unresolved $test2 + set CFLAGS "$old_CFLAGS" return } @@ -95,6 +98,7 @@ if [string match "" $exec_output] then { if { ![ld_compile $CC "$srcdir/$subdir/cross3.c" tmpdir/cross3.o] } { unresolved $test2 + set CFLAGS "$old_CFLAGS" return } @@ -118,11 +122,13 @@ if [string match "" $exec_output] then { if { ![ld_compile $CC "$srcdir/$subdir/cross4.c" tmpdir/cross4.o] } { unresolved $test3 + set CFLAGS "$old_CFLAGS" return } if ![ld_relocate $ld tmpdir/cross3-partial.o "tmpdir/cross1.o tmpdir/cross4.o"] { unresolved $test3 + set CFLAGS "$old_CFLAGS" return } @@ -138,3 +144,5 @@ if [string match "" $exec_output] then { verbose -log "$exec_output" fail $test3 } + +set CFLAGS "$old_CFLAGS"