| Index: bfd/elf64-ppc.c
|
| diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
|
| index 50dad3b10e64ffe9d1abae32a252fbbbd7fd1a3f..f30c009b5c3a512c250c36f7d6e321fee1a0f055 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
|
| @@ -96,7 +97,7 @@ static bfd_vma opd_entry_value
|
| #define elf_backend_copy_indirect_symbol ppc64_elf_copy_indirect_symbol
|
| #define elf_backend_add_symbol_hook ppc64_elf_add_symbol_hook
|
| #define elf_backend_check_directives ppc64_elf_process_dot_syms
|
| -#define elf_backend_as_needed_cleanup ppc64_elf_as_needed_cleanup
|
| +#define elf_backend_notice_as_needed ppc64_elf_notice_as_needed
|
| #define elf_backend_archive_symbol_lookup ppc64_elf_archive_symbol_lookup
|
| #define elf_backend_check_relocs ppc64_elf_check_relocs
|
| #define elf_backend_gc_keep ppc64_elf_gc_keep
|
| @@ -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;
|
| @@ -2472,7 +2592,7 @@ ppc64_elf_toc_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
|
|
|
| TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
|
| if (TOCstart == 0)
|
| - TOCstart = ppc64_elf_toc (input_section->output_section->owner);
|
| + TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner);
|
|
|
| /* Subtract the TOC base address. */
|
| reloc_entry->addend -= TOCstart + TOC_BASE_OFF;
|
| @@ -2495,7 +2615,7 @@ ppc64_elf_toc_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
|
|
|
| TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
|
| if (TOCstart == 0)
|
| - TOCstart = ppc64_elf_toc (input_section->output_section->owner);
|
| + TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner);
|
|
|
| /* Subtract the TOC base address. */
|
| reloc_entry->addend -= TOCstart + TOC_BASE_OFF;
|
| @@ -2522,7 +2642,7 @@ ppc64_elf_toc64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
|
|
|
| TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
|
| if (TOCstart == 0)
|
| - TOCstart = ppc64_elf_toc (input_section->output_section->owner);
|
| + TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner);
|
|
|
| octets = reloc_entry->address * bfd_octets_per_byte (abfd);
|
| bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets);
|
| @@ -2615,8 +2735,13 @@ struct ppc64_elf_obj_tdata
|
| sections means we potentially need one of these for each input bfd. */
|
| struct got_entry tlsld_got;
|
|
|
| - /* A copy of relocs before they are modified for --emit-relocs. */
|
| - Elf_Internal_Rela *opd_relocs;
|
| + union {
|
| + /* A copy of relocs before they are modified for --emit-relocs. */
|
| + Elf_Internal_Rela *relocs;
|
| +
|
| + /* Section contents. */
|
| + bfd_byte *contents;
|
| + } opd;
|
|
|
| /* Nonzero if this bfd has small toc/got relocs, ie. that expect
|
| the reloc to be in the range -32768 to 32767. */
|
| @@ -2677,10 +2802,10 @@ ppc64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
|
| return FALSE;
|
|
|
| /* pr_cursig */
|
| - elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
|
| + elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
|
|
|
| /* pr_pid */
|
| - elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 32);
|
| + elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32);
|
|
|
| /* pr_reg */
|
| offset = 112;
|
| @@ -2697,11 +2822,11 @@ ppc64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
|
| if (note->descsz != 136)
|
| return FALSE;
|
|
|
| - elf_tdata (abfd)->core_pid
|
| + elf_tdata (abfd)->core->pid
|
| = bfd_get_32 (abfd, note->descdata + 24);
|
| - elf_tdata (abfd)->core_program
|
| + elf_tdata (abfd)->core->program
|
| = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16);
|
| - elf_tdata (abfd)->core_command
|
| + elf_tdata (abfd)->core->command
|
| = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80);
|
|
|
| return TRUE;
|
| @@ -2836,6 +2961,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 +3120,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 +3301,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 +3361,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 +3381,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)
|
| @@ -3259,7 +3407,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
|
| slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
|
| if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
|
| goto free_contents_and_exit;
|
| -
|
| +
|
| plt_count = relplt->size / sizeof (Elf64_External_Rela);
|
| size += plt_count * sizeof (asymbol);
|
|
|
| @@ -3400,8 +3548,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 +3605,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 +3662,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 +3703,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 +3730,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
|
| @@ -3618,12 +3773,12 @@ struct ppc_stub_hash_entry {
|
| struct ppc_link_hash_entry *h;
|
| struct plt_entry *plt_ent;
|
|
|
| - /* And the reloc addend that this was derived from. */
|
| - bfd_vma addend;
|
| -
|
| /* 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 {
|
| @@ -3638,6 +3793,21 @@ struct ppc_branch_hash_entry {
|
| unsigned int iter;
|
| };
|
|
|
| +/* Used to track dynamic relocations for local symbols. */
|
| +struct ppc_dyn_relocs
|
| +{
|
| + struct ppc_dyn_relocs *next;
|
| +
|
| + /* The input section of the reloc. */
|
| + asection *sec;
|
| +
|
| + /* Total number of relocs copied for the input section. */
|
| + unsigned int count : 31;
|
| +
|
| + /* Whether this entry is for STT_GNU_IFUNC symbols. */
|
| + unsigned int ifunc : 1;
|
| +};
|
| +
|
| struct ppc_link_hash_entry
|
| {
|
| struct elf_link_hash_entry elf;
|
| @@ -3739,12 +3909,7 @@ struct ppc_link_hash_table
|
| /* List of input sections for each output section. */
|
| asection **input_list;
|
|
|
| - /* Short-cuts to get to dynamic linker sections. */
|
| - asection *got;
|
| - asection *plt;
|
| - asection *relplt;
|
| - asection *iplt;
|
| - asection *reliplt;
|
| + /* Shortcuts to get to dynamic linker sections. */
|
| asection *dynbss;
|
| asection *relbss;
|
| asection *glink;
|
| @@ -3769,6 +3934,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;
|
|
|
| @@ -3864,7 +4032,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;
|
| @@ -4040,12 +4210,88 @@ ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
|
| bfd_hash_table_free (&htab->branch_hash_table);
|
| if (htab->tocsave_htab)
|
| htab_delete (htab->tocsave_htab);
|
| - _bfd_generic_link_hash_table_free (hash);
|
| + _bfd_elf_link_hash_table_free (hash);
|
| +}
|
| +
|
| +/* Create sections for linker generated code. */
|
| +
|
| +static bfd_boolean
|
| +create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
|
| +{
|
| + struct ppc_link_hash_table *htab;
|
| + flagword flags;
|
| +
|
| + htab = ppc_hash_table (info);
|
| +
|
| + /* Create .sfpr for code to save and restore fp regs. */
|
| + flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
|
| + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
| + htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
|
| + flags);
|
| + if (htab->sfpr == NULL
|
| + || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
|
| + return FALSE;
|
| +
|
| + /* Create .glink for lazy dynamic linking support. */
|
| + htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
|
| + flags);
|
| + if (htab->glink == NULL
|
| + || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
|
| + return FALSE;
|
| +
|
| + if (!info->no_ld_generated_unwind_info)
|
| + {
|
| + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
|
| + | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
| + htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj,
|
| + ".eh_frame",
|
| + flags);
|
| + if (htab->glink_eh_frame == NULL
|
| + || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2))
|
| + return FALSE;
|
| + }
|
| +
|
| + flags = SEC_ALLOC | SEC_LINKER_CREATED;
|
| + htab->elf.iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
|
| + if (htab->elf.iplt == NULL
|
| + || ! bfd_set_section_alignment (dynobj, htab->elf.iplt, 3))
|
| + return FALSE;
|
| +
|
| + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
|
| + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
| + htab->elf.irelplt
|
| + = bfd_make_section_anyway_with_flags (dynobj, ".rela.iplt", flags);
|
| + if (htab->elf.irelplt == NULL
|
| + || ! bfd_set_section_alignment (dynobj, htab->elf.irelplt, 3))
|
| + return FALSE;
|
| +
|
| + /* Create branch lookup table for plt_branch stubs. */
|
| + flags = (SEC_ALLOC | SEC_LOAD
|
| + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
| + htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
|
| + flags);
|
| + if (htab->brlt == NULL
|
| + || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
|
| + return FALSE;
|
| +
|
| + if (!info->shared)
|
| + return TRUE;
|
| +
|
| + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
|
| + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
| + htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
|
| + ".rela.branch_lt",
|
| + flags);
|
| + if (htab->relbrlt == NULL
|
| + || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
|
| + return FALSE;
|
| +
|
| + return TRUE;
|
| }
|
|
|
| /* Satisfy the ELF linker by filling in some fields in our fake bfd. */
|
|
|
| -void
|
| +bfd_boolean
|
| ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info)
|
| {
|
| struct ppc_link_hash_table *htab;
|
| @@ -4057,9 +4303,14 @@ ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info)
|
| the start of the output TOC section. */
|
| htab = ppc_hash_table (info);
|
| if (htab == NULL)
|
| - return;
|
| + return FALSE;
|
| htab->stub_bfd = abfd;
|
| htab->elf.dynobj = abfd;
|
| +
|
| + if (info->relocatable)
|
| + return TRUE;
|
| +
|
| + return create_linkage_sections (htab->elf.dynobj, info);
|
| }
|
|
|
| /* Build a name for an entry in the stub hash table. */
|
| @@ -4071,7 +4322,7 @@ ppc_stub_name (const asection *input_section,
|
| const Elf_Internal_Rela *rel)
|
| {
|
| char *stub_name;
|
| - bfd_size_type len;
|
| + ssize_t len;
|
|
|
| /* rel->r_addend is actually 64 bit, but who uses more than +/- 2^31
|
| offsets from a sym as a branch target? In fact, we could
|
| @@ -4085,10 +4336,10 @@ ppc_stub_name (const asection *input_section,
|
| if (stub_name == NULL)
|
| return stub_name;
|
|
|
| - sprintf (stub_name, "%08x.%s+%x",
|
| - input_section->id & 0xffffffff,
|
| - h->elf.root.root.string,
|
| - (int) rel->r_addend & 0xffffffff);
|
| + len = sprintf (stub_name, "%08x.%s+%x",
|
| + input_section->id & 0xffffffff,
|
| + h->elf.root.root.string,
|
| + (int) rel->r_addend & 0xffffffff);
|
| }
|
| else
|
| {
|
| @@ -4097,13 +4348,13 @@ ppc_stub_name (const asection *input_section,
|
| if (stub_name == NULL)
|
| return stub_name;
|
|
|
| - sprintf (stub_name, "%08x.%x:%x+%x",
|
| - input_section->id & 0xffffffff,
|
| - sym_sec->id & 0xffffffff,
|
| - (int) ELF64_R_SYM (rel->r_info) & 0xffffffff,
|
| - (int) rel->r_addend & 0xffffffff);
|
| + len = sprintf (stub_name, "%08x.%x:%x+%x",
|
| + input_section->id & 0xffffffff,
|
| + sym_sec->id & 0xffffffff,
|
| + (int) ELF64_R_SYM (rel->r_info) & 0xffffffff,
|
| + (int) rel->r_addend & 0xffffffff);
|
| }
|
| - if (stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
|
| + if (len > 2 && stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
|
| stub_name[len - 2] = 0;
|
| return stub_name;
|
| }
|
| @@ -4209,110 +4460,25 @@ ppc_add_stub (const char *stub_name,
|
| return stub_entry;
|
| }
|
|
|
| -/* Create sections for linker generated code. */
|
| +/* Create .got and .rela.got sections in ABFD, and .got in dynobj if
|
| + not already done. */
|
|
|
| static bfd_boolean
|
| -create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
|
| +create_got_section (bfd *abfd, struct bfd_link_info *info)
|
| {
|
| - struct ppc_link_hash_table *htab;
|
| + asection *got, *relgot;
|
| flagword flags;
|
| + struct ppc_link_hash_table *htab = ppc_hash_table (info);
|
|
|
| - htab = ppc_hash_table (info);
|
| + if (!is_ppc64_elf (abfd))
|
| + return FALSE;
|
| if (htab == NULL)
|
| return FALSE;
|
|
|
| - /* Create .sfpr for code to save and restore fp regs. */
|
| - flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
|
| - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
| - htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
|
| - flags);
|
| - if (htab->sfpr == NULL
|
| - || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
|
| - return FALSE;
|
| -
|
| - /* Create .glink for lazy dynamic linking support. */
|
| - htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
|
| - flags);
|
| - if (htab->glink == NULL
|
| - || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
|
| - return FALSE;
|
| -
|
| - if (!info->no_ld_generated_unwind_info)
|
| - {
|
| - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
|
| - | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
| - htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj,
|
| - ".eh_frame",
|
| - flags);
|
| - if (htab->glink_eh_frame == NULL
|
| - || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2))
|
| - return FALSE;
|
| - }
|
| -
|
| - flags = SEC_ALLOC | SEC_LINKER_CREATED;
|
| - htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
|
| - if (htab->iplt == NULL
|
| - || ! bfd_set_section_alignment (dynobj, htab->iplt, 3))
|
| - return FALSE;
|
| -
|
| - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
|
| - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
| - htab->reliplt = bfd_make_section_anyway_with_flags (dynobj,
|
| - ".rela.iplt",
|
| - flags);
|
| - if (htab->reliplt == NULL
|
| - || ! bfd_set_section_alignment (dynobj, htab->reliplt, 3))
|
| - return FALSE;
|
| -
|
| - /* Create branch lookup table for plt_branch stubs. */
|
| - flags = (SEC_ALLOC | SEC_LOAD
|
| - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
| - htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
|
| - flags);
|
| - if (htab->brlt == NULL
|
| - || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
|
| - return FALSE;
|
| -
|
| - if (!info->shared)
|
| - return TRUE;
|
| -
|
| - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
|
| - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
| - htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
|
| - ".rela.branch_lt",
|
| - flags);
|
| - if (htab->relbrlt == NULL
|
| - || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
|
| + if (!htab->elf.sgot
|
| + && !_bfd_elf_create_got_section (htab->elf.dynobj, info))
|
| return FALSE;
|
|
|
| - return TRUE;
|
| -}
|
| -
|
| -/* Create .got and .rela.got sections in ABFD, and .got in dynobj if
|
| - not already done. */
|
| -
|
| -static bfd_boolean
|
| -create_got_section (bfd *abfd, struct bfd_link_info *info)
|
| -{
|
| - asection *got, *relgot;
|
| - flagword flags;
|
| - struct ppc_link_hash_table *htab = ppc_hash_table (info);
|
| -
|
| - if (!is_ppc64_elf (abfd))
|
| - return FALSE;
|
| - if (htab == NULL)
|
| - return FALSE;
|
| -
|
| - if (!htab->got)
|
| - {
|
| - if (! _bfd_elf_create_got_section (htab->elf.dynobj, info))
|
| - return FALSE;
|
| -
|
| - htab->got = bfd_get_linker_section (htab->elf.dynobj, ".got");
|
| - if (!htab->got)
|
| - abort ();
|
| - }
|
| -
|
| flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
|
| | SEC_LINKER_CREATED);
|
|
|
| @@ -4346,15 +4512,11 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
|
| if (htab == NULL)
|
| return FALSE;
|
|
|
| - if (!htab->got)
|
| - htab->got = bfd_get_linker_section (dynobj, ".got");
|
| - htab->plt = bfd_get_linker_section (dynobj, ".plt");
|
| - htab->relplt = bfd_get_linker_section (dynobj, ".rela.plt");
|
| htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss");
|
| if (!info->shared)
|
| htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss");
|
|
|
| - if (!htab->got || !htab->plt || !htab->relplt || !htab->dynbss
|
| + if (!htab->elf.sgot || !htab->elf.splt || !htab->elf.srelplt || !htab->dynbss
|
| || (!info->shared && !htab->relbss))
|
| abort ();
|
|
|
| @@ -4449,6 +4611,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)
|
| @@ -4485,7 +4648,7 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
|
| /* If we were called to copy over info for a weak sym, that's all.
|
| You might think dyn_relocs need not be copied over; After all,
|
| both syms will be dynamic or both non-dynamic so we're just
|
| - moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
|
| + moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
|
| code in ppc64_elf_adjust_dynamic_symbol needs to check for
|
| dyn_relocs in read-only sections, and it does so on what is the
|
| DIR sym here. */
|
| @@ -4607,7 +4770,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)
|
| @@ -4627,9 +4790,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
|
| @@ -4753,7 +4942,12 @@ ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
|
| while ((eh = *p) != NULL)
|
| {
|
| *p = NULL;
|
| - if (!add_symbol_adjust (eh, info))
|
| + if (&eh->elf == htab->elf.hgot)
|
| + ;
|
| + else if (htab->elf.hgot == NULL
|
| + && strcmp (eh->elf.root.root.string, ".TOC.") == 0)
|
| + htab->elf.hgot = &eh->elf;
|
| + else if (!add_symbol_adjust (eh, info))
|
| return FALSE;
|
| p = &eh->u.next_dot_sym;
|
| }
|
| @@ -4781,16 +4975,20 @@ ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
|
| not to be needed. */
|
|
|
| static bfd_boolean
|
| -ppc64_elf_as_needed_cleanup (bfd *ibfd ATTRIBUTE_UNUSED,
|
| - struct bfd_link_info *info)
|
| +ppc64_elf_notice_as_needed (bfd *ibfd,
|
| + struct bfd_link_info *info,
|
| + enum notice_asneeded_action act)
|
| {
|
| - struct ppc_link_hash_table *htab = ppc_hash_table (info);
|
| + if (act == notice_not_needed)
|
| + {
|
| + struct ppc_link_hash_table *htab = ppc_hash_table (info);
|
|
|
| - if (htab == NULL)
|
| - return FALSE;
|
| + if (htab == NULL)
|
| + return FALSE;
|
|
|
| - htab->dot_syms = NULL;
|
| - return TRUE;
|
| + htab->dot_syms = NULL;
|
| + }
|
| + return _bfd_elf_notice_as_needed (ibfd, info, act);
|
| }
|
|
|
| /* If --just-symbols against a final linked binary, then assume we need
|
| @@ -4803,10 +5001,8 @@ ppc64_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
|
| && (sec->owner->flags & (EXEC_P | DYNAMIC)) != 0
|
| && is_ppc64_elf (sec->owner))
|
| {
|
| - asection *got = bfd_get_section_by_name (sec->owner, ".got");
|
| - if (got != NULL
|
| - && got->size >= elf_backend_got_header_size
|
| - && bfd_get_section_by_name (sec->owner, ".opd") != NULL)
|
| + if (abiversion (sec->owner) >= 2
|
| + || bfd_get_section_by_name (sec->owner, ".opd") != NULL)
|
| sec->has_toc_reloc = 1;
|
| }
|
| _bfd_elf_link_just_syms (sec, info);
|
| @@ -4956,6 +5152,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)
|
| @@ -4965,10 +5170,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
| ppc64_elf_section_data (sec)->sec_type = sec_opd;
|
| }
|
|
|
| - if (htab->sfpr == NULL
|
| - && !create_linkage_sections (htab->elf.dynobj, info))
|
| - return FALSE;
|
| -
|
| rel_end = relocs + sec->reloc_count;
|
| for (rel = relocs; rel < rel_end; rel++)
|
| {
|
| @@ -4986,6 +5187,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
| {
|
| h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
| h = elf_follow_link (h);
|
| +
|
| + /* PR15323, ref flags aren't set for references in the same
|
| + object. */
|
| + h->root.non_ir_ref = 1;
|
| +
|
| + if (h == htab->elf.hgot)
|
| + sec->has_toc_reloc = 1;
|
| }
|
|
|
| tls_type = 0;
|
| @@ -5131,6 +5339,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:
|
| @@ -5176,6 +5392,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:
|
| @@ -5336,6 +5554,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:
|
| @@ -5379,22 +5599,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:
|
| @@ -5434,7 +5667,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
| if ((info->shared
|
| && (must_be_dyn_reloc (info, r_type)
|
| || (h != NULL
|
| - && (! info->symbolic
|
| + && (!SYMBOLIC_BIND (info, h)
|
| || h->root.type == bfd_link_hash_defweak
|
| || !h->def_regular))))
|
| || (ELIMINATE_COPY_RELOCS
|
| @@ -5445,9 +5678,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
| || (!info->shared
|
| && ifunc != NULL))
|
| {
|
| - struct elf_dyn_relocs *p;
|
| - struct elf_dyn_relocs **head;
|
| -
|
| /* We must copy these reloc types into the output file.
|
| Create a reloc section in dynobj and make room for
|
| this reloc. */
|
| @@ -5464,13 +5694,34 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
| relocations we need for this symbol. */
|
| if (h != NULL)
|
| {
|
| + struct elf_dyn_relocs *p;
|
| + struct elf_dyn_relocs **head;
|
| +
|
| head = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
|
| + p = *head;
|
| + if (p == NULL || p->sec != sec)
|
| + {
|
| + p = bfd_alloc (htab->elf.dynobj, sizeof *p);
|
| + if (p == NULL)
|
| + return FALSE;
|
| + p->next = *head;
|
| + *head = p;
|
| + p->sec = sec;
|
| + p->count = 0;
|
| + p->pc_count = 0;
|
| + }
|
| + p->count += 1;
|
| + if (!must_be_dyn_reloc (info, r_type))
|
| + p->pc_count += 1;
|
| }
|
| else
|
| {
|
| /* Track dynamic relocs needed for local syms too.
|
| We really need local syms available to do this
|
| easily. Oh well. */
|
| + struct ppc_dyn_relocs *p;
|
| + struct ppc_dyn_relocs **head;
|
| + bfd_boolean is_ifunc;
|
| asection *s;
|
| void *vpp;
|
| Elf_Internal_Sym *isym;
|
| @@ -5485,25 +5736,24 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
| s = sec;
|
|
|
| vpp = &elf_section_data (s)->local_dynrel;
|
| - head = (struct elf_dyn_relocs **) vpp;
|
| - }
|
| -
|
| - p = *head;
|
| - if (p == NULL || p->sec != sec)
|
| - {
|
| - p = bfd_alloc (htab->elf.dynobj, sizeof *p);
|
| - if (p == NULL)
|
| - return FALSE;
|
| - p->next = *head;
|
| - *head = p;
|
| - p->sec = sec;
|
| - p->count = 0;
|
| - p->pc_count = 0;
|
| + head = (struct ppc_dyn_relocs **) vpp;
|
| + is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC;
|
| + p = *head;
|
| + if (p != NULL && p->sec == sec && p->ifunc != is_ifunc)
|
| + p = p->next;
|
| + if (p == NULL || p->sec != sec || p->ifunc != is_ifunc)
|
| + {
|
| + p = bfd_alloc (htab->elf.dynobj, sizeof *p);
|
| + if (p == NULL)
|
| + return FALSE;
|
| + p->next = *head;
|
| + *head = p;
|
| + p->sec = sec;
|
| + p->ifunc = is_ifunc;
|
| + p->count = 0;
|
| + }
|
| + p->count += 1;
|
| }
|
| -
|
| - p->count += 1;
|
| - if (!must_be_dyn_reloc (info, r_type))
|
| - p->pc_count += 1;
|
| }
|
| break;
|
|
|
| @@ -5515,6 +5765,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. */
|
|
|
| @@ -5534,12 +5856,16 @@ opd_entry_value (asection *opd_sec,
|
| at a final linked executable with addr2line or somesuch. */
|
| if (opd_sec->reloc_count == 0)
|
| {
|
| - char buf[8];
|
| + bfd_byte *contents = ppc64_elf_tdata (opd_bfd)->opd.contents;
|
|
|
| - if (!bfd_get_section_contents (opd_bfd, opd_sec, buf, offset, 8))
|
| - return (bfd_vma) -1;
|
| + if (contents == NULL)
|
| + {
|
| + if (!bfd_malloc_and_get_section (opd_bfd, opd_sec, &contents))
|
| + return (bfd_vma) -1;
|
| + ppc64_elf_tdata (opd_bfd)->opd.contents = contents;
|
| + }
|
|
|
| - val = bfd_get_64 (opd_bfd, buf);
|
| + val = bfd_get_64 (opd_bfd, contents + offset);
|
| if (code_sec != NULL)
|
| {
|
| asection *sec, *likely = NULL;
|
| @@ -5571,7 +5897,7 @@ opd_entry_value (asection *opd_sec,
|
|
|
| BFD_ASSERT (is_ppc64_elf (opd_bfd));
|
|
|
| - relocs = ppc64_elf_tdata (opd_bfd)->opd_relocs;
|
| + relocs = ppc64_elf_tdata (opd_bfd)->opd.relocs;
|
| if (relocs == NULL)
|
| relocs = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE);
|
|
|
| @@ -5627,11 +5953,30 @@ opd_entry_value (asection *opd_sec,
|
|
|
| sym_hashes = elf_sym_hashes (opd_bfd);
|
| rh = sym_hashes[symndx - symtab_hdr->sh_info];
|
| - rh = elf_follow_link (rh);
|
| - BFD_ASSERT (rh->root.type == bfd_link_hash_defined
|
| - || rh->root.type == bfd_link_hash_defweak);
|
| - val = rh->root.u.def.value;
|
| - sec = rh->root.u.def.section;
|
| + if (rh != NULL)
|
| + {
|
| + rh = elf_follow_link (rh);
|
| + BFD_ASSERT (rh->root.type == bfd_link_hash_defined
|
| + || rh->root.type == bfd_link_hash_defweak);
|
| + val = rh->root.u.def.value;
|
| + sec = rh->root.u.def.section;
|
| + }
|
| + else
|
| + {
|
| + /* Handle the odd case where we can be called
|
| + during bfd_elf_link_add_symbols before the
|
| + symbol hashes have been fully populated. */
|
| + Elf_Internal_Sym *sym;
|
| +
|
| + sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, 1,
|
| + symndx, NULL, NULL, NULL);
|
| + if (sym == NULL)
|
| + break;
|
| +
|
| + val = sym->st_value;
|
| + sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx);
|
| + free (sym);
|
| + }
|
| }
|
| val += look->r_addend;
|
| if (code_off != NULL)
|
| @@ -6174,7 +6519,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;
|
| @@ -6190,7 +6535,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);
|
| @@ -6245,7 +6590,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;
|
| @@ -6261,7 +6606,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);
|
| @@ -6488,6 +6833,21 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
|
| if (htab == NULL)
|
| return FALSE;
|
|
|
| + if (!info->relocatable
|
| + && htab->elf.hgot != NULL)
|
| + {
|
| + _bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE);
|
| + /* Make .TOC. defined so as to prevent it being made dynamic.
|
| + The wrong value here is fixed later in ppc64_elf_set_toc. */
|
| + htab->elf.hgot->type = STT_OBJECT;
|
| + htab->elf.hgot->root.type = bfd_link_hash_defined;
|
| + htab->elf.hgot->root.u.def.value = 0;
|
| + htab->elf.hgot->root.u.def.section = bfd_abs_section_ptr;
|
| + htab->elf.hgot->def_regular = 1;
|
| + htab->elf.hgot->other = ((htab->elf.hgot->other & ~ELF_ST_VISIBILITY (-1))
|
| + | STV_HIDDEN);
|
| + }
|
| +
|
| if (htab->sfpr == NULL)
|
| /* We don't have any relocs. */
|
| return TRUE;
|
| @@ -6507,6 +6867,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
|
| @@ -6544,6 +6923,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;
|
| @@ -6578,26 +6977,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)
|
| @@ -6608,7 +6993,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
|
| sections. Allow them to proceed, but warn that this might
|
| break at runtime. */
|
| info->callbacks->einfo
|
| - (_("%P: copy reloc against `%s' requires lazy plt linking; "
|
| + (_("%P: copy reloc against `%T' requires lazy plt linking; "
|
| "avoid setting LD_BIND_NOW=1 or upgrade gcc\n"),
|
| h->root.root.string);
|
| }
|
| @@ -6948,7 +7333,7 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
|
| }
|
|
|
| /* Handles decrementing dynamic reloc counts for the reloc specified by
|
| - R_INFO in section SEC. If LOCAL_SYMS is NULL, then H and SYM_SEC
|
| + R_INFO in section SEC. If LOCAL_SYMS is NULL, then H and SYM
|
| have already been determined. */
|
|
|
| static bfd_boolean
|
| @@ -6957,11 +7342,10 @@ dec_dynrel_count (bfd_vma r_info,
|
| struct bfd_link_info *info,
|
| Elf_Internal_Sym **local_syms,
|
| struct elf_link_hash_entry *h,
|
| - asection *sym_sec)
|
| + Elf_Internal_Sym *sym)
|
| {
|
| enum elf_ppc64_reloc_type r_type;
|
| - struct elf_dyn_relocs *p;
|
| - struct elf_dyn_relocs **pp;
|
| + asection *sym_sec = NULL;
|
|
|
| /* Can this reloc be dynamic? This switch, and later tests here
|
| should be kept in sync with the code in check_relocs. */
|
| @@ -6977,6 +7361,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:
|
| @@ -6998,6 +7384,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:
|
| @@ -7016,7 +7404,6 @@ dec_dynrel_count (bfd_vma r_info,
|
| if (local_syms != NULL)
|
| {
|
| unsigned long r_symndx;
|
| - Elf_Internal_Sym *sym;
|
| bfd *ibfd = sec->owner;
|
|
|
| r_symndx = ELF64_R_SYM (r_info);
|
| @@ -7027,7 +7414,7 @@ dec_dynrel_count (bfd_vma r_info,
|
| if ((info->shared
|
| && (must_be_dyn_reloc (info, r_type)
|
| || (h != NULL
|
| - && (!info->symbolic
|
| + && (!SYMBOLIC_BIND (info, h)
|
| || h->root.type == bfd_link_hash_defweak
|
| || !h->def_regular))))
|
| || (ELIMINATE_COPY_RELOCS
|
| @@ -7040,39 +7427,62 @@ dec_dynrel_count (bfd_vma r_info,
|
| return TRUE;
|
|
|
| if (h != NULL)
|
| - pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
|
| - else
|
| {
|
| - if (sym_sec != NULL)
|
| - {
|
| - void *vpp = &elf_section_data (sym_sec)->local_dynrel;
|
| - pp = (struct elf_dyn_relocs **) vpp;
|
| - }
|
| - else
|
| - {
|
| - void *vpp = &elf_section_data (sec)->local_dynrel;
|
| - pp = (struct elf_dyn_relocs **) vpp;
|
| - }
|
| + struct elf_dyn_relocs *p;
|
| + struct elf_dyn_relocs **pp;
|
| + pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
|
|
|
| /* elf_gc_sweep may have already removed all dyn relocs associated
|
| - with local syms for a given section. Don't report a dynreloc
|
| - miscount. */
|
| - if (*pp == NULL)
|
| + with local syms for a given section. Also, symbol flags are
|
| + changed by elf_gc_sweep_symbol, confusing the test above. Don't
|
| + report a dynreloc miscount. */
|
| + if (*pp == NULL && info->gc_sections)
|
| return TRUE;
|
| - }
|
|
|
| - while ((p = *pp) != NULL)
|
| + while ((p = *pp) != NULL)
|
| + {
|
| + if (p->sec == sec)
|
| + {
|
| + if (!must_be_dyn_reloc (info, r_type))
|
| + p->pc_count -= 1;
|
| + p->count -= 1;
|
| + if (p->count == 0)
|
| + *pp = p->next;
|
| + return TRUE;
|
| + }
|
| + pp = &p->next;
|
| + }
|
| + }
|
| + else
|
| {
|
| - if (p->sec == sec)
|
| + struct ppc_dyn_relocs *p;
|
| + struct ppc_dyn_relocs **pp;
|
| + void *vpp;
|
| + bfd_boolean is_ifunc;
|
| +
|
| + if (local_syms == NULL)
|
| + sym_sec = bfd_section_from_elf_index (sec->owner, sym->st_shndx);
|
| + if (sym_sec == NULL)
|
| + sym_sec = sec;
|
| +
|
| + vpp = &elf_section_data (sym_sec)->local_dynrel;
|
| + pp = (struct ppc_dyn_relocs **) vpp;
|
| +
|
| + if (*pp == NULL && info->gc_sections)
|
| + return TRUE;
|
| +
|
| + is_ifunc = ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC;
|
| + while ((p = *pp) != NULL)
|
| {
|
| - if (!must_be_dyn_reloc (info, r_type))
|
| - p->pc_count -= 1;
|
| - p->count -= 1;
|
| - if (p->count == 0)
|
| - *pp = p->next;
|
| - return TRUE;
|
| + if (p->sec == sec && p->ifunc == is_ifunc)
|
| + {
|
| + p->count -= 1;
|
| + if (p->count == 0)
|
| + *pp = p->next;
|
| + return TRUE;
|
| + }
|
| + pp = &p->next;
|
| }
|
| - pp = &p->next;
|
| }
|
|
|
| info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"),
|
| @@ -7405,7 +7815,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
|
| if (!NO_OPD_RELOCS
|
| && !info->relocatable
|
| && !dec_dynrel_count (rel->r_info, sec, info,
|
| - NULL, h, sym_sec))
|
| + NULL, h, sym))
|
| goto error_ret;
|
| }
|
| else
|
| @@ -7500,6 +7910,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)
|
| @@ -8012,13 +8425,13 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
|
| /* If we got rid of a DTPMOD/DTPREL reloc pair then
|
| we'll lose one or two dyn relocs. */
|
| if (!dec_dynrel_count (rel->r_info, sec, info,
|
| - NULL, h, sym_sec))
|
| + NULL, h, sym))
|
| return FALSE;
|
|
|
| if (tls_set == (TLS_EXPLICIT | TLS_GD))
|
| {
|
| if (!dec_dynrel_count ((rel + 1)->r_info, sec, info,
|
| - NULL, h, sym_sec))
|
| + NULL, h, sym))
|
| return FALSE;
|
| }
|
| }
|
| @@ -8250,7 +8663,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
|
| . addi ry,rx,addr@toc@l
|
| when addr is within 2G of the toc pointer. This then means
|
| that the word storing "addr" in the toc is no longer needed. */
|
| -
|
| +
|
| if (!ppc64_elf_tdata (ibfd)->has_small_toc_reloc
|
| && toc->output_section->rawsize < (bfd_vma) 1 << 31
|
| && toc->reloc_count != 0)
|
| @@ -8283,7 +8696,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)
|
| @@ -8372,150 +8785,156 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
|
| goto error_ret;
|
|
|
| /* Mark toc entries referenced as used. */
|
| - repeat = 0;
|
| do
|
| - for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
|
| - {
|
| - enum elf_ppc64_reloc_type r_type;
|
| - unsigned long r_symndx;
|
| - asection *sym_sec;
|
| - struct elf_link_hash_entry *h;
|
| - Elf_Internal_Sym *sym;
|
| - bfd_vma val;
|
| - enum {no_check, check_lo, check_ha} insn_check;
|
| -
|
| - r_type = ELF64_R_TYPE (rel->r_info);
|
| - switch (r_type)
|
| - {
|
| - default:
|
| - insn_check = no_check;
|
| - break;
|
| + {
|
| + repeat = 0;
|
| + for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
|
| + {
|
| + enum elf_ppc64_reloc_type r_type;
|
| + unsigned long r_symndx;
|
| + asection *sym_sec;
|
| + struct elf_link_hash_entry *h;
|
| + Elf_Internal_Sym *sym;
|
| + bfd_vma val;
|
| + enum {no_check, check_lo, check_ha} insn_check;
|
|
|
| - case R_PPC64_GOT_TLSLD16_HA:
|
| - case R_PPC64_GOT_TLSGD16_HA:
|
| - case R_PPC64_GOT_TPREL16_HA:
|
| - case R_PPC64_GOT_DTPREL16_HA:
|
| - case R_PPC64_GOT16_HA:
|
| - case R_PPC64_TOC16_HA:
|
| - insn_check = check_ha;
|
| - break;
|
| + r_type = ELF64_R_TYPE (rel->r_info);
|
| + switch (r_type)
|
| + {
|
| + default:
|
| + insn_check = no_check;
|
| + break;
|
|
|
| - case R_PPC64_GOT_TLSLD16_LO:
|
| - case R_PPC64_GOT_TLSGD16_LO:
|
| - case R_PPC64_GOT_TPREL16_LO_DS:
|
| - case R_PPC64_GOT_DTPREL16_LO_DS:
|
| - case R_PPC64_GOT16_LO:
|
| - case R_PPC64_GOT16_LO_DS:
|
| - case R_PPC64_TOC16_LO:
|
| - case R_PPC64_TOC16_LO_DS:
|
| - insn_check = check_lo;
|
| - break;
|
| - }
|
| + case R_PPC64_GOT_TLSLD16_HA:
|
| + case R_PPC64_GOT_TLSGD16_HA:
|
| + case R_PPC64_GOT_TPREL16_HA:
|
| + case R_PPC64_GOT_DTPREL16_HA:
|
| + case R_PPC64_GOT16_HA:
|
| + case R_PPC64_TOC16_HA:
|
| + insn_check = check_ha;
|
| + break;
|
|
|
| - if (insn_check != no_check)
|
| - {
|
| - bfd_vma off = rel->r_offset & ~3;
|
| - unsigned char buf[4];
|
| - unsigned int insn;
|
| + case R_PPC64_GOT_TLSLD16_LO:
|
| + case R_PPC64_GOT_TLSGD16_LO:
|
| + case R_PPC64_GOT_TPREL16_LO_DS:
|
| + case R_PPC64_GOT_DTPREL16_LO_DS:
|
| + case R_PPC64_GOT16_LO:
|
| + case R_PPC64_GOT16_LO_DS:
|
| + case R_PPC64_TOC16_LO:
|
| + case R_PPC64_TOC16_LO_DS:
|
| + insn_check = check_lo;
|
| + break;
|
| + }
|
|
|
| - if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
|
| - {
|
| - free (used);
|
| - goto error_ret;
|
| - }
|
| - insn = bfd_get_32 (ibfd, buf);
|
| - if (insn_check == check_lo
|
| - ? !ok_lo_toc_insn (insn)
|
| - : ((insn & ((0x3f << 26) | 0x1f << 16))
|
| - != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
|
| - {
|
| - char str[12];
|
| -
|
| - ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
|
| - sprintf (str, "%#08x", insn);
|
| - info->callbacks->einfo
|
| - (_("%P: %H: toc optimization is not supported for"
|
| - " %s instruction.\n"),
|
| - ibfd, sec, rel->r_offset & ~3, str);
|
| - }
|
| - }
|
| + if (insn_check != no_check)
|
| + {
|
| + bfd_vma off = rel->r_offset & ~3;
|
| + unsigned char buf[4];
|
| + unsigned int insn;
|
|
|
| - switch (r_type)
|
| - {
|
| - case R_PPC64_TOC16:
|
| - case R_PPC64_TOC16_LO:
|
| - case R_PPC64_TOC16_HI:
|
| - case R_PPC64_TOC16_HA:
|
| - case R_PPC64_TOC16_DS:
|
| - case R_PPC64_TOC16_LO_DS:
|
| - /* In case we're taking addresses of toc entries. */
|
| - case R_PPC64_ADDR64:
|
| - break;
|
| + if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
|
| + {
|
| + free (used);
|
| + goto error_ret;
|
| + }
|
| + insn = bfd_get_32 (ibfd, buf);
|
| + if (insn_check == check_lo
|
| + ? !ok_lo_toc_insn (insn)
|
| + : ((insn & ((0x3f << 26) | 0x1f << 16))
|
| + != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
|
| + {
|
| + char str[12];
|
|
|
| - default:
|
| - continue;
|
| - }
|
| + ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
|
| + sprintf (str, "%#08x", insn);
|
| + info->callbacks->einfo
|
| + (_("%P: %H: toc optimization is not supported for"
|
| + " %s instruction.\n"),
|
| + ibfd, sec, rel->r_offset & ~3, str);
|
| + }
|
| + }
|
|
|
| - r_symndx = ELF64_R_SYM (rel->r_info);
|
| - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
|
| - r_symndx, ibfd))
|
| - {
|
| - free (used);
|
| - goto error_ret;
|
| - }
|
| + switch (r_type)
|
| + {
|
| + case R_PPC64_TOC16:
|
| + case R_PPC64_TOC16_LO:
|
| + case R_PPC64_TOC16_HI:
|
| + case R_PPC64_TOC16_HA:
|
| + case R_PPC64_TOC16_DS:
|
| + case R_PPC64_TOC16_LO_DS:
|
| + /* In case we're taking addresses of toc entries. */
|
| + case R_PPC64_ADDR64:
|
| + break;
|
|
|
| - if (sym_sec != toc)
|
| - continue;
|
| + default:
|
| + continue;
|
| + }
|
|
|
| - if (h != NULL)
|
| - val = h->root.u.def.value;
|
| - else
|
| - val = sym->st_value;
|
| - val += rel->r_addend;
|
| + r_symndx = ELF64_R_SYM (rel->r_info);
|
| + if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
|
| + r_symndx, ibfd))
|
| + {
|
| + free (used);
|
| + goto error_ret;
|
| + }
|
|
|
| - if (val >= toc->size)
|
| - continue;
|
| + if (sym_sec != toc)
|
| + continue;
|
|
|
| - if ((skip[val >> 3] & can_optimize) != 0)
|
| - {
|
| - bfd_vma off;
|
| - unsigned char opc;
|
| + if (h != NULL)
|
| + val = h->root.u.def.value;
|
| + else
|
| + val = sym->st_value;
|
| + val += rel->r_addend;
|
|
|
| - switch (r_type)
|
| - {
|
| - case R_PPC64_TOC16_HA:
|
| - break;
|
| + if (val >= toc->size)
|
| + continue;
|
|
|
| - case R_PPC64_TOC16_LO_DS:
|
| - off = rel->r_offset + (bfd_big_endian (ibfd) ? -2 : 3);
|
| - if (!bfd_get_section_contents (ibfd, sec, &opc, off, 1))
|
| - {
|
| - free (used);
|
| - goto error_ret;
|
| - }
|
| - if ((opc & (0x3f << 2)) == (58u << 2))
|
| + if ((skip[val >> 3] & can_optimize) != 0)
|
| + {
|
| + bfd_vma off;
|
| + unsigned char opc;
|
| +
|
| + switch (r_type)
|
| + {
|
| + case R_PPC64_TOC16_HA:
|
| break;
|
| - /* Fall thru */
|
|
|
| - default:
|
| - /* Wrong sort of reloc, or not a ld. We may
|
| - as well clear ref_from_discarded too. */
|
| - skip[val >> 3] = 0;
|
| - }
|
| - }
|
| + case R_PPC64_TOC16_LO_DS:
|
| + off = rel->r_offset;
|
| + off += (bfd_big_endian (ibfd) ? -2 : 3);
|
| + if (!bfd_get_section_contents (ibfd, sec, &opc,
|
| + off, 1))
|
| + {
|
| + free (used);
|
| + goto error_ret;
|
| + }
|
| + if ((opc & (0x3f << 2)) == (58u << 2))
|
| + break;
|
| + /* Fall thru */
|
|
|
| - /* For the toc section, we only mark as used if
|
| - this entry itself isn't unused. */
|
| - if (sec == toc
|
| - && !used[val >> 3]
|
| - && (used[rel->r_offset >> 3]
|
| - || !(skip[rel->r_offset >> 3] & ref_from_discarded)))
|
| - /* Do all the relocs again, to catch reference
|
| - chains. */
|
| - repeat = 1;
|
| -
|
| - used[val >> 3] = 1;
|
| - }
|
| + default:
|
| + /* Wrong sort of reloc, or not a ld. We may
|
| + as well clear ref_from_discarded too. */
|
| + skip[val >> 3] = 0;
|
| + }
|
| + }
|
| +
|
| + if (sec != toc)
|
| + used[val >> 3] = 1;
|
| + /* For the toc section, we only mark as used if this
|
| + entry itself isn't unused. */
|
| + else if ((used[rel->r_offset >> 3]
|
| + || !(skip[rel->r_offset >> 3] & ref_from_discarded))
|
| + && !used[val >> 3])
|
| + {
|
| + /* Do all the relocs again, to catch reference
|
| + chains. */
|
| + repeat = 1;
|
| + used[val >> 3] = 1;
|
| + }
|
| + }
|
| + }
|
| while (repeat);
|
|
|
| if (elf_section_data (sec)->relocs != relstart)
|
| @@ -8657,7 +9076,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
|
| if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
|
| ppc_howto_init ();
|
| info->callbacks->einfo
|
| - (_("%P: %H: %s relocation references "
|
| + (_("%P: %H: %s references "
|
| "optimized away TOC entry\n"),
|
| ibfd, sec, rel->r_offset,
|
| ppc64_elf_howto_table[r_type]->name);
|
| @@ -8804,19 +9223,18 @@ allocate_got (struct elf_link_hash_entry *h,
|
| got->size += entsize;
|
|
|
| dyn = htab->elf.dynamic_sections_created;
|
| - if ((info->shared
|
| - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
|
| - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
| - || h->root.type != bfd_link_hash_undefweak))
|
| + if (h->type == STT_GNU_IFUNC)
|
| {
|
| - asection *relgot = ppc64_elf_tdata (gent->owner)->relgot;
|
| - relgot->size += rentsize;
|
| + htab->elf.irelplt->size += rentsize;
|
| + htab->got_reli_size += rentsize;
|
| }
|
| - else if (h->type == STT_GNU_IFUNC)
|
| + else if ((info->shared
|
| + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
|
| + && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
| + || h->root.type != bfd_link_hash_undefweak))
|
| {
|
| - asection *relgot = htab->reliplt;
|
| + asection *relgot = ppc64_elf_tdata (gent->owner)->relgot;
|
| relgot->size += rentsize;
|
| - htab->got_reli_size += rentsize;
|
| }
|
| }
|
|
|
| @@ -8874,35 +9292,40 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
| if (!htab->elf.dynamic_sections_created
|
| || h->dynindx == -1)
|
| {
|
| - s = htab->iplt;
|
| + s = htab->elf.iplt;
|
| pent->plt.offset = s->size;
|
| - s->size += PLT_ENTRY_SIZE;
|
| - s = htab->reliplt;
|
| + s->size += PLT_ENTRY_SIZE (htab);
|
| + s = htab->elf.irelplt;
|
| }
|
| else
|
| {
|
| /* If this is the first .plt entry, make room for the special
|
| first entry. */
|
| - s = htab->plt;
|
| + s = htab->elf.splt;
|
| if (s->size == 0)
|
| - s->size += PLT_INITIAL_ENTRY_SIZE;
|
| + s->size += PLT_INITIAL_ENTRY_SIZE (htab);
|
|
|
| pent->plt.offset = s->size;
|
|
|
| /* Make room for this entry. */
|
| - s->size += PLT_ENTRY_SIZE;
|
| + s->size += PLT_ENTRY_SIZE (htab);
|
|
|
| /* Make room for the .glink code. */
|
| s = htab->glink;
|
| if (s->size == 0)
|
| s->size += GLINK_CALL_STUB_SIZE;
|
| - /* We need bigger stubs past index 32767. */
|
| - if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
|
| + if (htab->opd_abi)
|
| + {
|
| + /* We need bigger stubs past index 32767. */
|
| + if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
|
| + s->size += 4;
|
| + s->size += 2*4;
|
| + }
|
| + else
|
| s->size += 4;
|
| - s->size += 2*4;
|
|
|
| /* We also need to make an entry in the .rela.plt section. */
|
| - s = htab->relplt;
|
| + s = htab->elf.srelplt;
|
| }
|
| s->size += sizeof (Elf64_External_Rela);
|
| doneone = TRUE;
|
| @@ -9080,36 +9503,73 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
| for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
| {
|
| asection *sreloc = elf_section_data (p->sec)->sreloc;
|
| - if (!htab->elf.dynamic_sections_created)
|
| - sreloc = htab->reliplt;
|
| + if (eh->elf.type == STT_GNU_IFUNC)
|
| + sreloc = htab->elf.irelplt;
|
| sreloc->size += p->count * sizeof (Elf64_External_Rela);
|
| }
|
|
|
| return TRUE;
|
| }
|
|
|
| -/* Find any dynamic relocs that apply to read-only sections. */
|
| +/* Called via elf_link_hash_traverse from ppc64_elf_size_dynamic_sections
|
| + to set up space for global entry stubs. These are put in glink,
|
| + after the branch table. */
|
|
|
| static bfd_boolean
|
| -readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
| +size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
|
| {
|
| - struct ppc_link_hash_entry *eh;
|
| - struct elf_dyn_relocs *p;
|
| + struct bfd_link_info *info;
|
| + struct ppc_link_hash_table *htab;
|
| + struct plt_entry *pent;
|
| + asection *s;
|
|
|
| - eh = (struct ppc_link_hash_entry *) h;
|
| - for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
| - {
|
| - asection *s = p->sec->output_section;
|
| + if (h->root.type == bfd_link_hash_indirect)
|
| + return TRUE;
|
|
|
| - if (s != NULL && (s->flags & SEC_READONLY) != 0)
|
| - {
|
| - struct bfd_link_info *info = inf;
|
| + if (!h->pointer_equality_needed)
|
| + return TRUE;
|
| +
|
| + if (h->def_regular)
|
| + return TRUE;
|
|
|
| - info->flags |= DF_TEXTREL;
|
| + info = inf;
|
| + htab = ppc_hash_table (info);
|
| + if (htab == NULL)
|
| + return FALSE;
|
|
|
| - /* Not an error, just cut short the traversal. */
|
| - return FALSE;
|
| - }
|
| + s = htab->glink;
|
| + for (pent = h->plt.plist; pent != NULL; pent = pent->next)
|
| + if (pent->plt.offset != (bfd_vma) -1
|
| + && pent->addend == 0)
|
| + {
|
| + /* For ELFv2, if this symbol is not defined in a regular file
|
| + and we are not generating a shared library or pie, then we
|
| + need to define the symbol in the executable on a call stub.
|
| + This is to avoid text relocations. */
|
| + s->size = (s->size + 15) & -16;
|
| + h->root.u.def.section = s;
|
| + h->root.u.def.value = s->size;
|
| + s->size += 16;
|
| + break;
|
| + }
|
| + return TRUE;
|
| +}
|
| +
|
| +/* Set DF_TEXTREL if we find any dynamic relocs that apply to
|
| + read-only sections. */
|
| +
|
| +static bfd_boolean
|
| +maybe_set_textrel (struct elf_link_hash_entry *h, void *info)
|
| +{
|
| + if (h->root.type == bfd_link_hash_indirect)
|
| + return TRUE;
|
| +
|
| + if (readonly_dynrelocs (h))
|
| + {
|
| + ((struct bfd_link_info *) info)->flags |= DF_TEXTREL;
|
| +
|
| + /* Not an error, just cut short the traversal. */
|
| + return FALSE;
|
| }
|
| return TRUE;
|
| }
|
| @@ -9117,7 +9577,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;
|
| @@ -9159,14 +9619,13 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
| unsigned char *lgot_masks;
|
| bfd_size_type locsymcount;
|
| Elf_Internal_Shdr *symtab_hdr;
|
| - asection *srel;
|
|
|
| if (!is_ppc64_elf (ibfd))
|
| continue;
|
|
|
| for (s = ibfd->sections; s != NULL; s = s->next)
|
| {
|
| - struct elf_dyn_relocs *p;
|
| + struct ppc_dyn_relocs *p;
|
|
|
| for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
|
| {
|
| @@ -9180,9 +9639,9 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
| }
|
| else if (p->count != 0)
|
| {
|
| - srel = elf_section_data (p->sec)->sreloc;
|
| - if (!htab->elf.dynamic_sections_created)
|
| - srel = htab->reliplt;
|
| + asection *srel = elf_section_data (p->sec)->sreloc;
|
| + if (p->ifunc)
|
| + srel = htab->elf.irelplt;
|
| srel->size += p->count * sizeof (Elf64_External_Rela);
|
| if ((p->sec->output_section->flags & SEC_READONLY) != 0)
|
| info->flags |= DF_TEXTREL;
|
| @@ -9201,7 +9660,6 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
| end_local_plt = local_plt + locsymcount;
|
| lgot_masks = (unsigned char *) end_local_plt;
|
| s = ppc64_elf_tdata (ibfd)->got;
|
| - srel = ppc64_elf_tdata (ibfd)->relgot;
|
| for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
|
| {
|
| struct got_entry **pent, *ent;
|
| @@ -9217,19 +9675,25 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
| }
|
| else
|
| {
|
| - unsigned int num = 1;
|
| + unsigned int ent_size = 8;
|
| + unsigned int rel_size = sizeof (Elf64_External_Rela);
|
| +
|
| ent->got.offset = s->size;
|
| if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
|
| - num = 2;
|
| - s->size += num * 8;
|
| - if (info->shared)
|
| - srel->size += num * sizeof (Elf64_External_Rela);
|
| - else if ((*lgot_masks & PLT_IFUNC) != 0)
|
| {
|
| - htab->reliplt->size
|
| - += num * sizeof (Elf64_External_Rela);
|
| - htab->got_reli_size
|
| - += num * sizeof (Elf64_External_Rela);
|
| + ent_size *= 2;
|
| + rel_size *= 2;
|
| + }
|
| + s->size += ent_size;
|
| + if ((*lgot_masks & PLT_IFUNC) != 0)
|
| + {
|
| + htab->elf.irelplt->size += rel_size;
|
| + htab->got_reli_size += rel_size;
|
| + }
|
| + else if (info->shared)
|
| + {
|
| + asection *srel = ppc64_elf_tdata (ibfd)->relgot;
|
| + srel->size += rel_size;
|
| }
|
| pent = &ent->next;
|
| }
|
| @@ -9246,11 +9710,11 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
| for (ent = *local_plt; ent != NULL; ent = ent->next)
|
| if (ent->plt.refcount > 0)
|
| {
|
| - s = htab->iplt;
|
| + s = htab->elf.iplt;
|
| ent->plt.offset = s->size;
|
| - s->size += PLT_ENTRY_SIZE;
|
| + s->size += PLT_ENTRY_SIZE (htab);
|
|
|
| - htab->reliplt->size += sizeof (Elf64_External_Rela);
|
| + htab->elf.irelplt->size += sizeof (Elf64_External_Rela);
|
| }
|
| else
|
| ent->plt.offset = (bfd_vma) -1;
|
| @@ -9260,6 +9724,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)
|
| @@ -9307,9 +9777,9 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
| if (s == htab->brlt || s == htab->relbrlt)
|
| /* These haven't been allocated yet; don't strip. */
|
| continue;
|
| - else if (s == htab->got
|
| - || s == htab->plt
|
| - || s == htab->iplt
|
| + else if (s == htab->elf.sgot
|
| + || s == htab->elf.splt
|
| + || s == htab->elf.iplt
|
| || s == htab->glink
|
| || s == htab->dynbss)
|
| {
|
| @@ -9326,7 +9796,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
| {
|
| if (s->size != 0)
|
| {
|
| - if (s != htab->relplt)
|
| + if (s != htab->elf.srelplt)
|
| relocs = TRUE;
|
|
|
| /* We use the reloc_count field as a counter if we need
|
| @@ -9376,7 +9846,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
| continue;
|
|
|
| s = ppc64_elf_tdata (ibfd)->got;
|
| - if (s != NULL && s != htab->got)
|
| + if (s != NULL && s != htab->elf.sgot)
|
| {
|
| if (s->size == 0)
|
| s->flags |= SEC_EXCLUDE;
|
| @@ -9405,6 +9875,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
|
| @@ -9419,7 +9891,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
| return FALSE;
|
| }
|
|
|
| - if (htab->plt != NULL && htab->plt->size != 0)
|
| + if (htab->elf.splt != NULL && htab->elf.splt->size != 0)
|
| {
|
| if (!add_dynamic_entry (DT_PLTGOT, 0)
|
| || !add_dynamic_entry (DT_PLTRELSZ, 0)
|
| @@ -9429,18 +9901,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)
|
| {
|
| @@ -9452,7 +9927,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)
|
| {
|
| @@ -9466,6 +9941,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
|
| @@ -9473,7 +9961,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;
|
| @@ -9542,7 +10031,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;
|
| @@ -9559,9 +10048,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 <glink_entry>
|
| @@ -9581,19 +10070,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)
|
| @@ -9627,12 +10120,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
|
| @@ -9640,12 +10135,13 @@ 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;
|
|
|
| - if (pltindex > 32767)
|
| - glinkoff += (pltindex - 32767) * 4;
|
| + if (pltindex > 32768)
|
| + glinkoff += (pltindex - 32768) * 4;
|
| to = (glinkoff
|
| + htab->glink->output_offset
|
| + htab->glink->output_section->vma);
|
| @@ -9674,44 +10170,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))
|
| + if (plt_load_toc)
|
| {
|
| - r[2].r_offset = r[1].r_offset + 4;
|
| - r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
|
| - r[2].r_addend = r[0].r_addend;
|
| - }
|
| - else
|
| - {
|
| - r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep;
|
| - r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
|
| - r[2].r_addend = r[0].r_addend + 8;
|
| - if (plt_static_chain)
|
| + if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
|
| + {
|
| + r[2].r_offset = r[1].r_offset + 4;
|
| + r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
|
| + r[2].r_addend = r[0].r_addend;
|
| + }
|
| + else
|
| {
|
| - r[3].r_offset = r[2].r_offset + 4;
|
| - r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
|
| - r[3].r_addend = r[0].r_addend + 16;
|
| + r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep;
|
| + r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
|
| + r[2].r_addend = r[0].r_addend + 8;
|
| + if (plt_static_chain)
|
| + {
|
| + r[3].r_offset = r[2].r_offset + 4;
|
| + r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
|
| + r[3].r_addend = r[0].r_addend + 16;
|
| + }
|
| }
|
| }
|
| }
|
| if (ALWAYS_EMIT_R2SAVE
|
| || stub_entry->stub_type == ppc_stub_plt_call_r2save)
|
| - bfd_put_32 (obfd, STD_R2_40R1, p), p += 4;
|
| - bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4;
|
| - bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p), p += 4;
|
| - if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
|
| + bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p), p += 4;
|
| + 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
|
| {
|
| @@ -9721,49 +10224,56 @@ 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;
|
| - bfd_put_32 (obfd, B_DOT + cmp_branch_off, p), p += 4;
|
| + bfd_put_32 (obfd, B_DOT | (cmp_branch_off & 0x3fffffc), p), p += 4;
|
| }
|
| else
|
| bfd_put_32 (obfd, BCTR, p), p += 4;
|
| @@ -9779,11 +10289,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 *
|
| @@ -9801,15 +10309,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;
|
|
|
| @@ -9858,13 +10366,15 @@ 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;
|
|
|
| if (strcmp (opd->name, ".opd") != 0
|
| || opd->reloc_count != 0)
|
| {
|
| - info->callbacks->einfo (_("%P: cannot find opd entry toc for %s\n"),
|
| + info->callbacks->einfo (_("%P: cannot find opd entry toc for `%T'\n"),
|
| stub_entry->h->elf.root.root.string);
|
| bfd_set_error (bfd_error_bad_value);
|
| return 0;
|
| @@ -9910,9 +10420,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
|
| @@ -9929,7 +10441,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)
|
| @@ -9946,8 +10458,9 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
|
|
| if (off + (1 << 25) >= (bfd_vma) (1 << 26))
|
| {
|
| - info->callbacks->einfo (_("%P: long branch stub `%s' offset overflow\n"),
|
| - stub_entry->root.string);
|
| + info->callbacks->einfo
|
| + (_("%P: long branch stub `%s' offset overflow\n"),
|
| + stub_entry->root.string);
|
| htab->stub_error = TRUE;
|
| return FALSE;
|
| }
|
| @@ -10014,6 +10527,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);
|
| @@ -10067,7 +10582,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
| if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
|
| {
|
| info->callbacks->einfo
|
| - (_("%P: linkage table error against `%s'\n"),
|
| + (_("%P: linkage table error against `%T'\n"),
|
| stub_entry->root.string);
|
| bfd_set_error (bfd_error_bad_value);
|
| htab->stub_error = TRUE;
|
| @@ -10100,53 +10615,54 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
| if (PPC_HA (off) != 0)
|
| {
|
| size = 16;
|
| - bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc);
|
| + bfd_put_32 (htab->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
|
| {
|
| bfd_vma r2off = get_r2off (info, stub_entry);
|
|
|
| - if (r2off == 0)
|
| + if (r2off == 0 && htab->opd_abi)
|
| {
|
| htab->stub_error = TRUE;
|
| return FALSE;
|
| }
|
|
|
| - bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
|
| + bfd_put_32 (htab->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
|
| loc += 4;
|
| - size = 20;
|
| + size = 16;
|
| if (PPC_HA (off) != 0)
|
| {
|
| size += 4;
|
| - bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc);
|
| - loc += 4;
|
| - bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc);
|
| + bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc);
|
| loc += 4;
|
| + bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc);
|
| }
|
| else
|
| - {
|
| - bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc);
|
| - loc += 4;
|
| - }
|
| + bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc);
|
|
|
| if (PPC_HA (r2off) != 0)
|
| {
|
| size += 4;
|
| + loc += 4;
|
| bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
|
| + }
|
| + if (PPC_LO (r2off) != 0)
|
| + {
|
| + size += 4;
|
| loc += 4;
|
| + bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
|
| }
|
| - bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
|
| }
|
| loc += 4;
|
| - bfd_put_32 (htab->stub_bfd, MTCTR_R11, loc);
|
| + bfd_put_32 (htab->stub_bfd, MTCTR_R12, loc);
|
| loc += 4;
|
| bfd_put_32 (htab->stub_bfd, BCTR, loc);
|
| break;
|
| @@ -10176,11 +10692,11 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
| if (dest >= (bfd_vma) -2)
|
| abort ();
|
|
|
| - plt = htab->plt;
|
| + plt = htab->elf.splt;
|
| if (!htab->elf.dynamic_sections_created
|
| || stub_entry->h == NULL
|
| || stub_entry->h->elf.dynindx == -1)
|
| - plt = htab->iplt;
|
| + plt = htab->elf.iplt;
|
|
|
| dest += plt->output_offset + plt->output_section->vma;
|
|
|
| @@ -10191,13 +10707,16 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
| bfd_byte *rl;
|
|
|
| rela.r_offset = dest;
|
| - rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
|
| + if (htab->opd_abi)
|
| + rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
|
| + else
|
| + rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
|
| rela.r_addend = (stub_entry->target_value
|
| + stub_entry->target_section->output_offset
|
| + stub_entry->target_section->output_section->vma);
|
|
|
| - rl = (htab->reliplt->contents
|
| - + (htab->reliplt->reloc_count++
|
| + rl = (htab->elf.irelplt->contents
|
| + + (htab->elf.irelplt->reloc_count++
|
| * sizeof (Elf64_External_Rela)));
|
| bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
|
| stub_entry->plt_ent->plt.offset |= 1;
|
| @@ -10210,7 +10729,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
| if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
|
| {
|
| info->callbacks->einfo
|
| - (_("%P: linkage table error against `%s'\n"),
|
| + (_("%P: linkage table error against `%T'\n"),
|
| stub_entry->h != NULL
|
| ? stub_entry->h->elf.root.root.string
|
| : "<local sym>");
|
| @@ -10327,11 +10846,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
| off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
|
| if (off >= (bfd_vma) -2)
|
| abort ();
|
| - plt = htab->plt;
|
| + plt = htab->elf.splt;
|
| if (!htab->elf.dynamic_sections_created
|
| || stub_entry->h == NULL
|
| || stub_entry->h->elf.dynindx == -1)
|
| - plt = htab->iplt;
|
| + plt = htab->elf.iplt;
|
| off += (plt->output_offset
|
| + plt->output_section->vma
|
| - elf_gp (plt->output_section->owner)
|
| @@ -10343,10 +10862,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;
|
| }
|
| }
|
| @@ -10355,6 +10875,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
|
| @@ -10372,7 +10893,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;
|
| @@ -10383,8 +10904,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;
|
|
|
| @@ -10435,12 +10961,14 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
|
| }
|
| else
|
| {
|
| - size = 20;
|
| + size = 16;
|
| if (PPC_HA (off) != 0)
|
| size += 4;
|
|
|
| if (PPC_HA (r2off) != 0)
|
| size += 4;
|
| + if (PPC_LO (r2off) != 0)
|
| + size += 4;
|
| }
|
| }
|
| else if (info->emitrelocations)
|
| @@ -10477,9 +11005,6 @@ ppc64_elf_setup_section_lists
|
| htab->add_stub_section = add_stub_section;
|
| htab->layout_sections_again = layout_sections_again;
|
|
|
| - if (htab->brlt == NULL)
|
| - return 0;
|
| -
|
| /* Find the top input section id. */
|
| for (input_bfd = info->input_bfds, top_id = 3;
|
| input_bfd != NULL;
|
| @@ -10532,8 +11057,7 @@ ppc64_elf_start_multitoc_partition (struct bfd_link_info *info)
|
| {
|
| struct ppc_link_hash_table *htab = ppc_hash_table (info);
|
|
|
| - elf_gp (info->output_bfd) = ppc64_elf_toc (info->output_bfd);
|
| - htab->toc_curr = elf_gp (info->output_bfd);
|
| + htab->toc_curr = ppc64_elf_set_toc (info, info->output_bfd);
|
| htab->toc_bfd = NULL;
|
| htab->toc_first_sec = NULL;
|
| }
|
| @@ -10694,8 +11218,8 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
|
| }
|
|
|
| /* Zap sizes of got sections. */
|
| - htab->reliplt->rawsize = htab->reliplt->size;
|
| - htab->reliplt->size -= htab->got_reli_size;
|
| + htab->elf.irelplt->rawsize = htab->elf.irelplt->size;
|
| + htab->elf.irelplt->size -= htab->got_reli_size;
|
| htab->got_reli_size = 0;
|
|
|
| for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
| @@ -10727,7 +11251,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
|
| unsigned char *lgot_masks;
|
| bfd_size_type locsymcount;
|
| Elf_Internal_Shdr *symtab_hdr;
|
| - asection *s, *srel;
|
| + asection *s;
|
|
|
| if (!is_ppc64_elf (ibfd))
|
| continue;
|
| @@ -10743,26 +11267,31 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
|
| end_local_plt = local_plt + locsymcount;
|
| lgot_masks = (unsigned char *) end_local_plt;
|
| s = ppc64_elf_tdata (ibfd)->got;
|
| - srel = ppc64_elf_tdata (ibfd)->relgot;
|
| for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
|
| {
|
| struct got_entry *ent;
|
|
|
| for (ent = *lgot_ents; ent != NULL; ent = ent->next)
|
| {
|
| - unsigned int num = 1;
|
| + unsigned int ent_size = 8;
|
| + unsigned int rel_size = sizeof (Elf64_External_Rela);
|
| +
|
| ent->got.offset = s->size;
|
| if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
|
| - num = 2;
|
| - s->size += num * 8;
|
| - if (info->shared)
|
| - srel->size += num * sizeof (Elf64_External_Rela);
|
| - else if ((*lgot_masks & PLT_IFUNC) != 0)
|
| {
|
| - htab->reliplt->size
|
| - += num * sizeof (Elf64_External_Rela);
|
| - htab->got_reli_size
|
| - += num * sizeof (Elf64_External_Rela);
|
| + ent_size *= 2;
|
| + rel_size *= 2;
|
| + }
|
| + s->size += ent_size;
|
| + if ((*lgot_masks & PLT_IFUNC) != 0)
|
| + {
|
| + htab->elf.irelplt->size += rel_size;
|
| + htab->got_reli_size += rel_size;
|
| + }
|
| + else if (info->shared)
|
| + {
|
| + asection *srel = ppc64_elf_tdata (ibfd)->relgot;
|
| + srel->size += rel_size;
|
| }
|
| }
|
| }
|
| @@ -10792,7 +11321,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
|
| }
|
| }
|
|
|
| - done_something = htab->reliplt->rawsize != htab->reliplt->size;
|
| + done_something = htab->elf.irelplt->rawsize != htab->elf.irelplt->size;
|
| if (!done_something)
|
| for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
| {
|
| @@ -10980,7 +11509,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;
|
| @@ -11074,42 +11606,25 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
|
|
|
| if (htab->multi_toc_needed)
|
| {
|
| - /* If a code section has a function that uses the TOC then we need
|
| - to use the right TOC (obviously). Also, make sure that .opd gets
|
| - the correct TOC value for R_PPC64_TOC relocs that don't have or
|
| - can't find their function symbol (shouldn't ever happen now).
|
| - Also specially treat .fixup for the linux kernel. .fixup
|
| - contains branches, but only back to the function that hit an
|
| - exception. */
|
| - if (isec->has_toc_reloc
|
| - || (isec->flags & SEC_CODE) == 0
|
| - || strcmp (isec->name, ".fixup") == 0)
|
| + /* Analyse sections that aren't already flagged as needing a
|
| + valid toc pointer. Exclude .fixup for the linux kernel.
|
| + .fixup contains branches, but only back to the function that
|
| + hit an exception. */
|
| + if (!(isec->has_toc_reloc
|
| + || (isec->flags & SEC_CODE) == 0
|
| + || strcmp (isec->name, ".fixup") == 0
|
| + || isec->call_check_done))
|
| {
|
| - if (elf_gp (isec->owner) != 0)
|
| - htab->toc_curr = elf_gp (isec->owner);
|
| - }
|
| - else
|
| - {
|
| - if (!isec->call_check_done
|
| - && toc_adjusting_stub_needed (info, isec) < 0)
|
| + if (toc_adjusting_stub_needed (info, isec) < 0)
|
| return FALSE;
|
| - /* If we make a local call from this section, ie. a branch
|
| - without a following nop, then we have no place to put a
|
| - toc restoring insn. We must use the same toc group as
|
| - the callee.
|
| - Testing makes_toc_func_call actually tests for *any*
|
| - calls to functions that need a good toc pointer. A more
|
| - precise test would be better, as this one will set
|
| - incorrect values for pasted .init/.fini fragments.
|
| - (Fixed later in check_pasted_section.) */
|
| - if (isec->makes_toc_func_call
|
| - && elf_gp (isec->owner) != 0)
|
| - htab->toc_curr = elf_gp (isec->owner);
|
| - }
|
| - }
|
| -
|
| - /* Functions that don't use the TOC can belong in any TOC group.
|
| - Use the last TOC base. */
|
| + }
|
| + /* Make all sections use the TOC assigned for this object file.
|
| + This will be wrong for pasted sections; We fix that in
|
| + check_pasted_section(). */
|
| + if (elf_gp (isec->owner) != 0)
|
| + htab->toc_curr = elf_gp (isec->owner);
|
| + }
|
| +
|
| htab->stub_group[isec->id].toc_off = htab->toc_curr;
|
| return TRUE;
|
| }
|
| @@ -11294,6 +11809,7 @@ maybe_strip_output (struct bfd_link_info *info, asection *isec)
|
| {
|
| if (isec->size == 0
|
| && isec->output_section->size == 0
|
| + && !(isec->output_section->flags & SEC_KEEP)
|
| && !bfd_section_removed_from_list (info->output_bfd,
|
| isec->output_section)
|
| && elf_section_data (isec->output_section)->dynindx == 0)
|
| @@ -11324,9 +11840,13 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
|
|
|
| htab->plt_static_chain = plt_static_chain;
|
| htab->plt_stub_align = plt_stub_align;
|
| - if (plt_thread_safe == -1)
|
| + if (plt_thread_safe == -1 && !info->executable)
|
| + plt_thread_safe = 1;
|
| + if (!htab->opd_abi)
|
| + plt_thread_safe = 0;
|
| + else if (plt_thread_safe == -1)
|
| {
|
| - const char *const thread_starter[] =
|
| + static const char *const thread_starter[] =
|
| {
|
| "pthread_create",
|
| /* libstdc++ */
|
| @@ -11342,7 +11862,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
|
| "GOMP_parallel_loop_dynamic_start",
|
| "GOMP_parallel_loop_guided_start",
|
| "GOMP_parallel_loop_runtime_start",
|
| - "GOMP_parallel_sections_start",
|
| + "GOMP_parallel_sections_start",
|
| };
|
| unsigned i;
|
|
|
| @@ -11430,6 +11950,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;
|
| @@ -11506,12 +12027,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;
|
| @@ -11548,7 +12073,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)
|
| {
|
| @@ -11648,7 +12174,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
|
| }
|
| stub_entry->h = hash;
|
| stub_entry->plt_ent = plt_ent;
|
| - stub_entry->addend = irela->r_addend;
|
| + stub_entry->other = hash ? hash->elf.other : sym->st_other;
|
|
|
| if (stub_entry->h != NULL)
|
| htab->stub_globals += 1;
|
| @@ -11757,7 +12283,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
|
| move, we'll be called again. Provide a value for TOCstart. */
|
|
|
| bfd_vma
|
| -ppc64_elf_toc (bfd *obfd)
|
| +ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
|
| {
|
| asection *s;
|
| bfd_vma TOCstart;
|
| @@ -11808,9 +12334,88 @@ ppc64_elf_toc (bfd *obfd)
|
| if (s != NULL)
|
| TOCstart = s->output_section->vma + s->output_offset;
|
|
|
| + _bfd_set_gp_value (obfd, TOCstart);
|
| +
|
| + if (info != NULL && s != NULL && is_ppc64_elf (obfd))
|
| + {
|
| + struct ppc_link_hash_table *htab = ppc_hash_table (info);
|
| +
|
| + if (htab != NULL
|
| + && htab->elf.hgot != NULL)
|
| + {
|
| + htab->elf.hgot->root.u.def.value = TOC_BASE_OFF;
|
| + htab->elf.hgot->root.u.def.section = s;
|
| + }
|
| + }
|
| 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->elf.splt;
|
| + if (!htab->elf.dynamic_sections_created
|
| + || h->dynindx == -1)
|
| + plt = htab->elf.iplt;
|
| + off = pent->plt.offset + plt->output_offset + plt->output_section->vma;
|
| + off -= h->root.u.def.value + s->output_offset + s->output_section->vma;
|
| +
|
| + if (off + 0x80008000 > 0xffffffff || (off & 3) != 0)
|
| + {
|
| + info->callbacks->einfo
|
| + (_("%P: linkage table error against `%T'\n"),
|
| + h->root.root.string);
|
| + bfd_set_error (bfd_error_bad_value);
|
| + htab->stub_error = TRUE;
|
| + }
|
| +
|
| + 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. */
|
| @@ -11871,7 +12476,9 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
|
| h->non_elf = 0;
|
| }
|
| }
|
| - plt0 = htab->plt->output_section->vma + htab->plt->output_offset - 16;
|
| + plt0 = (htab->elf.splt->output_section->vma
|
| + + htab->elf.splt->output_offset
|
| + - 16);
|
| if (info->emitrelocations)
|
| {
|
| Elf_Internal_Rela *r = get_relocs (htab->glink, 1);
|
| @@ -11886,26 +12493,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)
|
| @@ -11916,26 +12553,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)
|
| @@ -12039,7 +12683,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;
|
| @@ -12089,7 +12733,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))
|
| {
|
| @@ -12249,7 +12892,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| for (; rel < relend; rel++)
|
| {
|
| enum elf_ppc64_reloc_type r_type;
|
| - bfd_vma addend, orig_addend;
|
| + bfd_vma addend;
|
| bfd_reloc_status_type r;
|
| Elf_Internal_Sym *sym;
|
| asection *sec;
|
| @@ -12264,11 +12907,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| bfd_vma relocation;
|
| bfd_boolean unresolved_reloc;
|
| bfd_boolean warned;
|
| + enum { DEST_NORMAL, DEST_OPD, DEST_STUB } reloc_dest;
|
| unsigned int insn;
|
| unsigned int mask;
|
| struct ppc_stub_hash_entry *stub_entry;
|
| bfd_vma max_br_offset;
|
| bfd_vma from;
|
| + const Elf_Internal_Rela orig_rel = *rel;
|
|
|
| r_type = ELF64_R_TYPE (rel->r_info);
|
| r_symndx = ELF64_R_SYM (rel->r_info);
|
| @@ -12288,7 +12933,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| sym_name = NULL;
|
| unresolved_reloc = FALSE;
|
| warned = FALSE;
|
| - orig_addend = rel->r_addend;
|
|
|
| if (r_symndx < symtab_hdr->sh_info)
|
| {
|
| @@ -12322,12 +12966,41 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| }
|
| else
|
| {
|
| + bfd_boolean ignored;
|
| +
|
| RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
|
| r_symndx, symtab_hdr, sym_hashes,
|
| h_elf, sec, relocation,
|
| - unresolved_reloc, warned);
|
| + unresolved_reloc, warned, ignored);
|
| sym_name = h_elf->root.root.string;
|
| sym_type = h_elf->type;
|
| + if (sec != NULL
|
| + && sec->owner == output_bfd
|
| + && strcmp (sec->name, ".opd") == 0)
|
| + {
|
| + /* This is a symbol defined in a linker script. All
|
| + such are defined in output sections, even those
|
| + defined by simple assignment from a symbol defined in
|
| + an input section. Transfer the symbol to an
|
| + appropriate input .opd section, so that a branch to
|
| + this symbol will be mapped to the location specified
|
| + by the opd entry. */
|
| + struct bfd_link_order *lo;
|
| + for (lo = sec->map_head.link_order; lo != NULL; lo = lo->next)
|
| + if (lo->type == bfd_indirect_link_order)
|
| + {
|
| + asection *isec = lo->u.indirect.section;
|
| + if (h_elf->root.u.def.value >= isec->output_offset
|
| + && h_elf->root.u.def.value < (isec->output_offset
|
| + + isec->size))
|
| + {
|
| + h_elf->root.u.def.value -= isec->output_offset;
|
| + h_elf->root.u.def.section = isec;
|
| + sec = isec;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| }
|
| h = (struct ppc_link_hash_entry *) h_elf;
|
|
|
| @@ -12340,6 +13013,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| if (info->relocatable)
|
| continue;
|
|
|
| + if (h != NULL && &h->elf == htab->elf.hgot)
|
| + {
|
| + relocation = (TOCstart
|
| + + htab->stub_group[input_section->id].toc_off);
|
| + sec = bfd_abs_section_ptr;
|
| + unresolved_reloc = FALSE;
|
| + }
|
| +
|
| /* TLS optimizations. Replace instruction sequences and relocs
|
| based on information we collected in tls_optimize. We edit
|
| RELOCS so that --emit-relocs will output something sensible
|
| @@ -12394,8 +13075,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| else
|
| info->callbacks->einfo
|
| (!IS_PPC64_TLS_RELOC (r_type)
|
| - ? _("%P: %H: %s used with TLS symbol %s\n")
|
| - : _("%P: %H: %s used with non-TLS symbol %s\n"),
|
| + ? _("%P: %H: %s used with TLS symbol `%T'\n")
|
| + : _("%P: %H: %s used with non-TLS symbol `%T'\n"),
|
| input_bfd, input_section, rel->r_offset,
|
| ppc64_elf_howto_table[r_type]->name,
|
| sym_name);
|
| @@ -12795,12 +13476,46 @@ 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. */
|
| insn = 0;
|
| max_br_offset = 1 << 25;
|
| addend = rel->r_addend;
|
| + reloc_dest = DEST_NORMAL;
|
| switch (r_type)
|
| {
|
| default:
|
| @@ -12816,7 +13531,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;
|
| @@ -12850,7 +13566,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| && h->oh != NULL
|
| && h->oh->is_func_descriptor)
|
| fdh = ppc_follow_link (h->oh);
|
| - stub_entry = ppc_get_stub_entry (input_section, sec, fdh, rel, htab);
|
| + stub_entry = ppc_get_stub_entry (input_section, sec, fdh, &orig_rel,
|
| + htab);
|
| if (stub_entry != NULL
|
| && (stub_entry->stub_type == ppc_stub_plt_call
|
| || stub_entry->stub_type == ppc_stub_plt_call_r2save
|
| @@ -12859,74 +13576,90 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| {
|
| bfd_boolean can_plt_call = FALSE;
|
|
|
| + /* All of these stubs will modify r2, so there must be a
|
| + branch and link followed by a nop. The nop is
|
| + replaced by an insn to restore r2. */
|
| if (rel->r_offset + 8 <= input_section->size)
|
| {
|
| - unsigned long nop;
|
| - nop = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
|
| - if (nop == NOP
|
| - || nop == CROR_151515 || nop == CROR_313131)
|
| + unsigned long br;
|
| +
|
| + br = bfd_get_32 (input_bfd,
|
| + contents + rel->r_offset);
|
| + if ((br & 1) != 0)
|
| {
|
| - if (h != NULL
|
| - && (h == htab->tls_get_addr_fd
|
| - || h == htab->tls_get_addr)
|
| - && !htab->no_tls_get_addr_opt)
|
| + unsigned long nop;
|
| +
|
| + nop = bfd_get_32 (input_bfd,
|
| + contents + rel->r_offset + 4);
|
| + if (nop == NOP
|
| + || nop == CROR_151515 || nop == CROR_313131)
|
| {
|
| - /* Special stub used, leave nop alone. */
|
| + if (h != NULL
|
| + && (h == htab->tls_get_addr_fd
|
| + || h == htab->tls_get_addr)
|
| + && !htab->no_tls_get_addr_opt)
|
| + {
|
| + /* Special stub used, leave nop alone. */
|
| + }
|
| + else
|
| + bfd_put_32 (input_bfd,
|
| + LD_R2_0R1 + STK_TOC (htab),
|
| + contents + rel->r_offset + 4);
|
| + can_plt_call = TRUE;
|
| }
|
| - else
|
| - bfd_put_32 (input_bfd, LD_R2_40R1,
|
| - contents + rel->r_offset + 4);
|
| - can_plt_call = TRUE;
|
| }
|
| }
|
|
|
| - if (!can_plt_call)
|
| + if (!can_plt_call && h != NULL)
|
| {
|
| - if (stub_entry->stub_type == ppc_stub_plt_call
|
| - || stub_entry->stub_type == ppc_stub_plt_call_r2save)
|
| - {
|
| - /* If this is a plain branch rather than a branch
|
| - and link, don't require a nop. However, don't
|
| - allow tail calls in a shared library as they
|
| - will result in r2 being corrupted. */
|
| - unsigned long br;
|
| - br = bfd_get_32 (input_bfd, contents + rel->r_offset);
|
| - if (info->executable && (br & 1) == 0)
|
| - can_plt_call = TRUE;
|
| - else
|
| - stub_entry = NULL;
|
| - }
|
| - else if (h != NULL
|
| - && strcmp (h->elf.root.root.string,
|
| - ".__libc_start_main") == 0)
|
| + const char *name = h->elf.root.root.string;
|
| +
|
| + if (*name == '.')
|
| + ++name;
|
| +
|
| + if (strncmp (name, "__libc_start_main", 17) == 0
|
| + && (name[17] == 0 || name[17] == '@'))
|
| {
|
| - /* Allow crt1 branch to go via a toc adjusting stub. */
|
| + /* Allow crt1 branch to go via a toc adjusting
|
| + stub. Other calls that never return could do
|
| + the same, if we could detect such. */
|
| can_plt_call = TRUE;
|
| }
|
| - else
|
| + }
|
| +
|
| + if (!can_plt_call)
|
| + {
|
| + /* g++ as of 20130507 emits self-calls without a
|
| + following nop. This is arguably wrong since we
|
| + have conflicting information. On the one hand a
|
| + global symbol and on the other a local call
|
| + sequence, but don't error for this special case.
|
| + It isn't possible to cheaply verify we have
|
| + exactly such a call. Allow all calls to the same
|
| + section. */
|
| + asection *code_sec = sec;
|
| +
|
| + if (get_opd_info (sec) != NULL)
|
| {
|
| - if (strcmp (input_section->output_section->name,
|
| - ".init") == 0
|
| - || strcmp (input_section->output_section->name,
|
| - ".fini") == 0)
|
| - info->callbacks->einfo
|
| - (_("%P: %H: automatic multiple TOCs "
|
| - "not supported using your crt files; "
|
| - "recompile with -mminimal-toc or upgrade gcc\n"),
|
| - input_bfd, input_section, rel->r_offset);
|
| - else
|
| - info->callbacks->einfo
|
| - (_("%P: %H: sibling call optimization to `%s' "
|
| - "does not allow automatic multiple TOCs; "
|
| - "recompile with -mminimal-toc or "
|
| - "-fno-optimize-sibling-calls, "
|
| - "or make `%s' extern\n"),
|
| - input_bfd, input_section, rel->r_offset,
|
| - sym_name,
|
| - sym_name);
|
| - bfd_set_error (bfd_error_bad_value);
|
| - ret = FALSE;
|
| + bfd_vma off = (relocation + addend
|
| + - sec->output_section->vma
|
| + - sec->output_offset);
|
| +
|
| + opd_entry_value (sec, off, &code_sec, NULL, FALSE);
|
| }
|
| + if (code_sec == input_section)
|
| + can_plt_call = TRUE;
|
| + }
|
| +
|
| + if (!can_plt_call)
|
| + {
|
| + info->callbacks->einfo
|
| + (_("%P: %H: call to `%T' lacks nop, can't restore toc; "
|
| + "recompile with -fPIC"),
|
| + input_bfd, input_section, rel->r_offset, sym_name);
|
| +
|
| + bfd_set_error (bfd_error_bad_value);
|
| + ret = FALSE;
|
| }
|
|
|
| if (can_plt_call
|
| @@ -12949,6 +13682,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| {
|
| relocation = dest;
|
| addend = 0;
|
| + reloc_dest = DEST_OPD;
|
| }
|
| }
|
|
|
| @@ -12958,6 +13692,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)
|
| @@ -12976,6 +13714,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| + stub_entry->stub_sec->output_offset
|
| + stub_entry->stub_sec->output_section->vma);
|
| addend = 0;
|
| + reloc_dest = DEST_STUB;
|
|
|
| if ((stub_entry->stub_type == ppc_stub_plt_call
|
| || stub_entry->stub_type == ppc_stub_plt_call_r2save)
|
| @@ -13033,7 +13772,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| {
|
| default:
|
| info->callbacks->einfo
|
| - (_("%P: %B: unknown relocation type %d for symbol %s\n"),
|
| + (_("%P: %B: unknown relocation type %d for `%T'\n"),
|
| input_bfd, (int) r_type, sym_name);
|
|
|
| bfd_set_error (bfd_error_bad_value);
|
| @@ -13110,7 +13849,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
|
| @@ -13118,6 +13857,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| ;
|
| else
|
| {
|
| + BFD_ASSERT (h->elf.dynindx != -1);
|
| indx = h->elf.dynindx;
|
| unresolved_reloc = FALSE;
|
| }
|
| @@ -13131,7 +13871,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| }
|
|
|
| for (; ent != NULL; ent = ent->next)
|
| - if (ent->addend == orig_addend
|
| + if (ent->addend == orig_rel.r_addend
|
| && ent->owner == input_bfd
|
| && ent->tls_type == tls_type)
|
| break;
|
| @@ -13165,15 +13905,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| ifunc = (h != NULL
|
| ? h->elf.type == STT_GNU_IFUNC
|
| : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
|
| - if ((info->shared || indx != 0)
|
| - && (h == NULL
|
| - || (tls_type == (TLS_TLS | TLS_LD)
|
| - && !h->elf.def_dynamic)
|
| - || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
|
| - || h->elf.root.type != bfd_link_hash_undefweak))
|
| + if (ifunc)
|
| + relgot = htab->elf.irelplt;
|
| + else if ((info->shared || indx != 0)
|
| + && (h == NULL
|
| + || (tls_type == (TLS_TLS | TLS_LD)
|
| + && !h->elf.def_dynamic)
|
| + || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
|
| + || h->elf.root.type != bfd_link_hash_undefweak))
|
| relgot = ppc64_elf_tdata (ent->owner)->relgot;
|
| - else if (ifunc)
|
| - relgot = htab->reliplt;
|
| if (relgot != NULL)
|
| {
|
| outrel.r_offset = (got->output_section->vma
|
| @@ -13280,17 +14020,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| symbol. This happens when statically linking PIC code,
|
| or when using -Bsymbolic. Go find a match if there is a
|
| PLT entry. */
|
| - if (htab->plt != NULL)
|
| + if (htab->elf.splt != NULL)
|
| {
|
| struct plt_entry *ent;
|
| for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
|
| - if (ent->addend == orig_addend
|
| - && ent->plt.offset != (bfd_vma) -1)
|
| + if (ent->plt.offset != (bfd_vma) -1
|
| + && ent->addend == orig_rel.r_addend)
|
| {
|
| - relocation = (htab->plt->output_section->vma
|
| - + htab->plt->output_offset
|
| + relocation = (htab->elf.splt->output_section->vma
|
| + + htab->elf.splt->output_offset
|
| + ent->plt.offset);
|
| unresolved_reloc = FALSE;
|
| + break;
|
| }
|
| }
|
| break;
|
| @@ -13350,6 +14091,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:
|
| @@ -13384,6 +14127,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:
|
| @@ -13416,6 +14161,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:
|
| @@ -13487,10 +14234,13 @@ 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)
|
| - outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
|
| + {
|
| + BFD_ASSERT (h->elf.dynindx != -1);
|
| + outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
|
| + }
|
| else
|
| {
|
| /* This symbol is local, or marked to become local,
|
| @@ -13539,8 +14289,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
|
| {
|
| info->callbacks->einfo
|
| - (_("%P: %H: relocation %s for indirect "
|
| - "function %s unsupported\n"),
|
| + (_("%P: %H: %s for indirect "
|
| + "function `%T' unsupported\n"),
|
| input_bfd, input_section, rel->r_offset,
|
| ppc64_elf_howto_table[r_type]->name,
|
| sym_name);
|
| @@ -13584,8 +14334,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| }
|
|
|
| sreloc = elf_section_data (input_section)->sreloc;
|
| - if (!htab->elf.dynamic_sections_created)
|
| - sreloc = htab->reliplt;
|
| + if (h != NULL
|
| + ? h->elf.type == STT_GNU_IFUNC
|
| + : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
|
| + sreloc = htab->elf.irelplt;
|
| if (sreloc == NULL)
|
| abort ();
|
|
|
| @@ -13644,7 +14396,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| /* These ones haven't been implemented yet. */
|
|
|
| info->callbacks->einfo
|
| - (_("%P: %B: relocation %s is not supported for symbol %s\n"),
|
| + (_("%P: %B: %s is not supported for `%T'\n"),
|
| input_bfd,
|
| ppc64_elf_howto_table[r_type]->name, sym_name);
|
|
|
| @@ -13725,21 +14477,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,
|
| @@ -13814,7 +14565,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| rel->r_offset) != (bfd_vma) -1)
|
| {
|
| info->callbacks->einfo
|
| - (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"),
|
| + (_("%P: %H: unresolvable %s against `%T'\n"),
|
| input_bfd, input_section, rel->r_offset,
|
| ppc64_elf_howto_table[(int) r_type]->name,
|
| h->elf.root.root.string);
|
| @@ -13831,8 +14582,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
|
|
| if (r != bfd_reloc_ok)
|
| {
|
| - if (sym_name == NULL)
|
| - sym_name = "(null)";
|
| + char *more_info = NULL;
|
| + const char *reloc_name = ppc64_elf_howto_table[r_type]->name;
|
| +
|
| + if (reloc_dest != DEST_NORMAL)
|
| + {
|
| + more_info = bfd_malloc (strlen (reloc_name) + 8);
|
| + if (more_info != NULL)
|
| + {
|
| + strcpy (more_info, reloc_name);
|
| + strcat (more_info, (reloc_dest == DEST_OPD
|
| + ? " (OPD)" : " (stub)"));
|
| + reloc_name = more_info;
|
| + }
|
| + }
|
| +
|
| if (r == bfd_reloc_overflow)
|
| {
|
| if (warned)
|
| @@ -13851,21 +14615,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| }
|
|
|
| if (!((*info->callbacks->reloc_overflow)
|
| - (info, (h ? &h->elf.root : NULL), sym_name,
|
| - ppc64_elf_howto_table[r_type]->name,
|
| - orig_addend, input_bfd, input_section, rel->r_offset)))
|
| + (info, &h->elf.root, sym_name,
|
| + reloc_name, orig_rel.r_addend,
|
| + input_bfd, input_section, rel->r_offset)))
|
| return FALSE;
|
| }
|
| else
|
| {
|
| info->callbacks->einfo
|
| - (_("%P: %H: %s reloc against `%s': error %d\n"),
|
| + (_("%P: %H: %s against `%T': error %d\n"),
|
| input_bfd, input_section, rel->r_offset,
|
| - ppc64_elf_howto_table[r_type]->name,
|
| - sym_name,
|
| - (int) r);
|
| + reloc_name, sym_name, (int) r);
|
| ret = FALSE;
|
| }
|
| + if (more_info != NULL)
|
| + free (more_info);
|
| }
|
| }
|
|
|
| @@ -13879,8 +14643,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
| bfd_size_type amt;
|
| amt = input_section->reloc_count * sizeof (Elf_Internal_Rela);
|
| rel = bfd_alloc (input_bfd, amt);
|
| - BFD_ASSERT (ppc64_elf_tdata (input_bfd)->opd_relocs == NULL);
|
| - ppc64_elf_tdata (input_bfd)->opd_relocs = rel;
|
| + BFD_ASSERT (ppc64_elf_tdata (input_bfd)->opd.relocs == NULL);
|
| + ppc64_elf_tdata (input_bfd)->opd.relocs = rel;
|
| if (rel == NULL)
|
| return FALSE;
|
| memcpy (rel, relocs, amt);
|
| @@ -13950,30 +14714,57 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
|
| && h->def_regular
|
| && (h->root.type == bfd_link_hash_defined
|
| || h->root.type == bfd_link_hash_defweak));
|
| - rela.r_offset = (htab->iplt->output_section->vma
|
| - + htab->iplt->output_offset
|
| + rela.r_offset = (htab->elf.iplt->output_section->vma
|
| + + htab->elf.iplt->output_offset
|
| + ent->plt.offset);
|
| - rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
|
| + if (htab->opd_abi)
|
| + rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
|
| + else
|
| + rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
|
| rela.r_addend = (h->root.u.def.value
|
| + h->root.u.def.section->output_offset
|
| + h->root.u.def.section->output_section->vma
|
| + ent->addend);
|
| - loc = (htab->reliplt->contents
|
| - + (htab->reliplt->reloc_count++
|
| + loc = (htab->elf.irelplt->contents
|
| + + (htab->elf.irelplt->reloc_count++
|
| * sizeof (Elf64_External_Rela)));
|
| }
|
| else
|
| {
|
| - rela.r_offset = (htab->plt->output_section->vma
|
| - + htab->plt->output_offset
|
| + rela.r_offset = (htab->elf.splt->output_section->vma
|
| + + htab->elf.splt->output_offset
|
| + ent->plt.offset);
|
| rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
|
| rela.r_addend = ent->addend;
|
| - loc = (htab->relplt->contents
|
| - + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
|
| - / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
|
| + loc = (htab->elf.srelplt->contents
|
| + + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
|
| + / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
|
| }
|
| bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
|
| +
|
| + if (!htab->opd_abi)
|
| + {
|
| + if (!h->def_regular)
|
| + {
|
| + /* Mark the symbol as undefined, rather than as
|
| + defined in glink. Leave the value if there were
|
| + any relocations where pointer equality matters
|
| + (this is a clue for the dynamic linker, to make
|
| + function pointer comparisons work between an
|
| + application and shared library), otherwise set it
|
| + to zero. */
|
| + sym->st_shndx = SHN_UNDEF;
|
| + if (!h->pointer_equality_needed)
|
| + sym->st_value = 0;
|
| + else if (!h->ref_regular_nonweak)
|
| + {
|
| + /* This breaks function pointer comparisons, but
|
| + that is better than breaking tests for a NULL
|
| + function pointer. */
|
| + sym->st_value = 0;
|
| + }
|
| + }
|
| + }
|
| }
|
|
|
| if (h->needs_copy)
|
| @@ -14003,9 +14794,15 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
|
| dynamic linker, before writing them out. */
|
|
|
| static enum elf_reloc_type_class
|
| -ppc64_elf_reloc_type_class (const Elf_Internal_Rela *rela)
|
| +ppc64_elf_reloc_type_class (const struct bfd_link_info *info,
|
| + const asection *rel_sec,
|
| + const Elf_Internal_Rela *rela)
|
| {
|
| enum elf_ppc64_reloc_type r_type;
|
| + struct ppc_link_hash_table *htab = ppc_hash_table (info);
|
| +
|
| + if (rel_sec == htab->elf.irelplt)
|
| + return reloc_class_ifunc;
|
|
|
| r_type = ELF64_R_TYPE (rela->r_info);
|
| switch (r_type)
|
| @@ -14042,7 +14839,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
|
| {
|
| Elf64_External_Dyn *dyncon, *dynconend;
|
|
|
| - if (sdyn == NULL || htab->got == NULL)
|
| + if (sdyn == NULL || htab->elf.sgot == NULL)
|
| abort ();
|
|
|
| dyncon = (Elf64_External_Dyn *) sdyn->contents;
|
| @@ -14066,7 +14863,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:
|
| @@ -14076,6 +14873,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)
|
| @@ -14084,23 +14886,23 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
|
| break;
|
|
|
| case DT_PLTGOT:
|
| - s = htab->plt;
|
| + s = htab->elf.splt;
|
| dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
|
| break;
|
|
|
| case DT_JMPREL:
|
| - s = htab->relplt;
|
| + s = htab->elf.srelplt;
|
| dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
|
| break;
|
|
|
| case DT_PLTRELSZ:
|
| - dyn.d_un.d_val = htab->relplt->size;
|
| + dyn.d_un.d_val = htab->elf.srelplt->size;
|
| break;
|
|
|
| case DT_RELASZ:
|
| /* Don't count procedure linkage table relocs in the
|
| overall reloc count. */
|
| - s = htab->relplt;
|
| + s = htab->elf.srelplt;
|
| if (s == NULL)
|
| continue;
|
| dyn.d_un.d_val -= s->size;
|
| @@ -14110,7 +14912,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
|
| /* We may not be using the standard ELF linker script.
|
| If .rela.plt is the first .rela section, we adjust
|
| DT_RELA to not include it. */
|
| - s = htab->relplt;
|
| + s = htab->elf.srelplt;
|
| if (s == NULL)
|
| continue;
|
| if (dyn.d_un.d_ptr != s->output_section->vma + s->output_offset)
|
| @@ -14123,23 +14925,23 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
|
| }
|
| }
|
|
|
| - if (htab->got != NULL && htab->got->size != 0)
|
| + if (htab->elf.sgot != NULL && htab->elf.sgot->size != 0)
|
| {
|
| /* Fill in the first entry in the global offset table.
|
| We use it to hold the link-time TOCbase. */
|
| bfd_put_64 (output_bfd,
|
| elf_gp (output_bfd) + TOC_BASE_OFF,
|
| - htab->got->contents);
|
| + htab->elf.sgot->contents);
|
|
|
| /* Set .got entry size. */
|
| - elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 8;
|
| + elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 8;
|
| }
|
|
|
| - if (htab->plt != NULL && htab->plt->size != 0)
|
| + if (htab->elf.splt != NULL && htab->elf.splt->size != 0)
|
| {
|
| /* Set .plt entry size. */
|
| - elf_section_data (htab->plt->output_section)->this_hdr.sh_entsize
|
| - = PLT_ENTRY_SIZE;
|
| + elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize
|
| + = PLT_ENTRY_SIZE (htab);
|
| }
|
|
|
| /* brlt is SEC_LINKER_CREATED, so we need to write out relocs for
|
|
|