#include "elf/ppc.h"
#include "elf64-ppc.h"
-#define USE_RELA /* we want RELA relocations, not REL. */
-
-
static void ppc_howto_init
PARAMS ((void));
static reloc_howto_type *ppc64_elf_reloc_type_lookup
PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
static void ppc64_elf_info_to_howto
PARAMS ((bfd *abfd, arelent *cache_ptr, Elf64_Internal_Rela *dst));
-static bfd_reloc_status_type ppc64_elf_addr16_ha_reloc
+static bfd_reloc_status_type ppc64_elf_ha_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_brtaken_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_sectoff_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_sectoff_ha_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_toc_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_toc_ha_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_toc64_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static boolean ppc64_elf_set_private_flags
- PARAMS ((bfd *, flagword));
+static bfd_reloc_status_type ppc64_elf_unhandled_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static boolean ppc64_elf_object_p
+ PARAMS ((bfd *));
static boolean ppc64_elf_merge_private_bfd_data
PARAMS ((bfd *, bfd *));
-static boolean ppc64_elf_section_from_shdr
- PARAMS ((bfd *, Elf64_Internal_Shdr *, char *));
-
-
-/* Mask to set RA in memory instructions. */
-#define RA_REGISTER_MASK 0x001f0000
-/* Value to shift register by to insert RA. */
-#define RA_REGISTER_SHIFT 16
/* The name of the dynamic interpreter. This is put in the .interp
section. */
#define CROR_151515 0x4def7b82
#define CROR_313131 0x4ffffb82
-/* .glink entries for the first 32k functions are two instructions. */
+/* .glink entries for the first 32k functions are two instructions. */
#define LI_R0_0 0x38000000 /* li %r0,0 */
#define B_DOT 0x48000000 /* b . */
/* Since .opd is an array of descriptors and each entry will end up
with identical R_PPC64_RELATIVE relocs, there is really no need to
propagate .opd relocs; The dynamic linker should be taught to
- relocate .opd without reloc entries. FIXME: .opd should be trimmed
- of unused values. */
+ relocate .opd without reloc entries. */
#ifndef NO_OPD_RELOCS
#define NO_OPD_RELOCS 0
#endif
\f
+#define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1)
+
/* Relocation HOWTO's. */
static reloc_howto_type *ppc64_elf_howto_table[(int) R_PPC_max];
/* This reloc does nothing. */
HOWTO (R_PPC64_NONE, /* type */
0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC64_NONE", /* name */
false, /* partial_inplace */
"R_PPC64_ADDR24", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0x3fffffc, /* dst_mask */
+ 0x03fffffc, /* dst_mask */
false), /* pcrel_offset */
/* A standard 16 bit relocation. */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- ppc64_elf_addr16_ha_reloc, /* special_function */
+ ppc64_elf_ha_reloc, /* special_function */
"R_PPC64_ADDR16_HA", /* name */
false, /* partial_inplace */
0, /* src_mask */
"R_PPC64_ADDR14", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xfffc, /* dst_mask */
+ 0x0000fffc, /* dst_mask */
false), /* pcrel_offset */
/* An absolute 16 bit branch, for which bit 10 should be set to
false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_brtaken_reloc, /* special_function */
"R_PPC64_ADDR14_BRTAKEN",/* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xfffc, /* dst_mask */
+ 0x0000fffc, /* dst_mask */
false), /* pcrel_offset */
/* An absolute 16 bit branch, for which bit 10 should be set to
false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_brtaken_reloc, /* special_function */
"R_PPC64_ADDR14_BRNTAKEN",/* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xfffc, /* dst_mask */
+ 0x0000fffc, /* dst_mask */
false), /* pcrel_offset */
/* A relative 26 bit branch; the lower two bits must be zero. */
"R_PPC64_REL24", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0x3fffffc, /* dst_mask */
+ 0x03fffffc, /* dst_mask */
true), /* pcrel_offset */
/* A relative 16 bit branch; the lower two bits must be zero. */
"R_PPC64_REL14", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xfffc, /* dst_mask */
+ 0x0000fffc, /* dst_mask */
true), /* pcrel_offset */
/* A relative 16 bit branch. Bit 10 should be set to indicate that
true, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_brtaken_reloc, /* special_function */
"R_PPC64_REL14_BRTAKEN", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xfffc, /* dst_mask */
+ 0x0000fffc, /* dst_mask */
true), /* pcrel_offset */
/* A relative 16 bit branch. Bit 10 should be set to indicate that
true, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_brtaken_reloc, /* special_function */
"R_PPC64_REL14_BRNTAKEN",/* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xfffc, /* dst_mask */
+ 0x0000fffc, /* dst_mask */
true), /* pcrel_offset */
/* Like R_PPC64_ADDR16, but referring to the GOT table entry for the
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_GOT16", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_GOT16_LO", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont,/* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_GOT16_HI", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont,/* complain_on_overflow */
- ppc64_elf_addr16_ha_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_GOT16_HA", /* name */
false, /* partial_inplace */
0, /* src_mask */
run has to have the data at some particular address. */
HOWTO (R_PPC64_COPY, /* type */
0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 0, /* this one is variable size */
+ 0, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_COPY", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_GLOB_DAT", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xffffffffffffffff, /* dst_mask */
+ ONES (64), /* dst_mask */
false), /* pcrel_offset */
/* Created by the link editor. Marks a procedure linkage table
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_JMP_SLOT", /* name */
false, /* partial_inplace */
0, /* src_mask */
"R_PPC64_RELATIVE", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xffffffffffffffff, /* dst_mask */
+ ONES (64), /* dst_mask */
false), /* pcrel_offset */
/* Like R_PPC64_ADDR32, but may be unaligned. */
32, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
- /* FIXME: Verify. Was complain_overflow_bitfield. */
+ /* FIXME: Verify. Was complain_overflow_bitfield. */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC64_REL32", /* name */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLT32", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0, /* dst_mask */
+ 0xffffffff, /* dst_mask */
false), /* pcrel_offset */
/* 32-bit PC relative relocation to the symbol's procedure linkage table.
"R_PPC64_PLTREL32", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0, /* dst_mask */
+ 0xffffffff, /* dst_mask */
true), /* pcrel_offset */
/* Like R_PPC64_ADDR16_LO, but referring to the PLT table entry for
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLT16_LO", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLT16_HI", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- ppc64_elf_addr16_ha_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLT16_HA", /* name */
false, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
false), /* pcrel_offset */
- /* 32-bit section relative relocation. */
- /* FIXME: Verify R_PPC64_SECTOFF. Seems strange with size=2 and
- dst_mask=0. */
+ /* 16-bit section relative relocation. */
HOWTO (R_PPC64_SECTOFF, /* type */
0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- true, /* pc_relative */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_sectoff_reloc, /* special_function */
"R_PPC64_SECTOFF", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0, /* dst_mask */
- true), /* pcrel_offset */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
- /* 16-bit lower half section relative relocation. */
+ /* Like R_PPC64_SECTOFF, but no overflow warning. */
HOWTO (R_PPC64_SECTOFF_LO, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_sectoff_reloc, /* special_function */
"R_PPC64_SECTOFF_LO", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_sectoff_reloc, /* special_function */
"R_PPC64_SECTOFF_HI", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- ppc64_elf_addr16_ha_reloc, /* special_function */
+ ppc64_elf_sectoff_ha_reloc, /* special_function */
"R_PPC64_SECTOFF_HA", /* name */
false, /* partial_inplace */
0, /* src_mask */
false), /* pcrel_offset */
/* Like R_PPC64_REL24 without touching the two least significant
- bits. */
- /* FIXME: Verify R_PPC64_ADDR30. */
+ bits. Should have been named R_PPC64_REL30! */
HOWTO (R_PPC64_ADDR30, /* type */
2, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
"R_PPC64_ADDR64", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xffffffffffffffff, /* dst_mask */
+ ONES (64), /* dst_mask */
false), /* pcrel_offset */
/* The bits 32-47 of an address. */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- ppc64_elf_addr16_ha_reloc, /* special_function */
+ ppc64_elf_ha_reloc, /* special_function */
"R_PPC64_ADDR16_HIGHERA", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- ppc64_elf_addr16_ha_reloc, /* special_function */
+ ppc64_elf_ha_reloc, /* special_function */
"R_PPC64_ADDR16_HIGHESTA", /* name */
false, /* partial_inplace */
0, /* src_mask */
"R_PPC64_UADDR64", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xffffffffffffffff, /* dst_mask */
+ ONES (64), /* dst_mask */
false), /* pcrel_offset */
/* 64-bit relative relocation. */
"R_PPC64_REL64", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xffffffffffffffff, /* dst_mask */
+ ONES (64), /* dst_mask */
true), /* pcrel_offset */
- /* 64-bit relocation to the symbol's procedure linkage table. */
+ /* 64-bit relocation to the symbol's procedure linkage table. */
HOWTO (R_PPC64_PLT64, /* type */
0, /* rightshift */
4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLT64", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0, /* dst_mask */
+ ONES (64), /* dst_mask */
false), /* pcrel_offset */
/* 64-bit PC relative relocation to the symbol's procedure linkage
true, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLTREL64", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0, /* dst_mask */
+ ONES (64), /* dst_mask */
true), /* pcrel_offset */
/* 16 bit TOC-relative relocation. */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_toc_reloc, /* special_function */
"R_PPC64_TOC16", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_toc_reloc, /* special_function */
"R_PPC64_TOC16_LO", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_toc_reloc, /* special_function */
"R_PPC64_TOC16_HI", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- ppc64_elf_addr16_ha_reloc, /* special_function */
+ ppc64_elf_toc_ha_reloc, /* special_function */
"R_PPC64_TOC16_HA", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_toc64_reloc, /* special_function */
"R_PPC64_TOC", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0xffffffffffffffff, /* dst_mask */
+ ONES (64), /* dst_mask */
false), /* pcrel_offset */
/* Like R_PPC64_GOT16, but also informs the link editor that the
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLTGOT16", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLTGOT16_LO", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLTGOT16_HI", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont,/* complain_on_overflow */
- ppc64_elf_addr16_ha_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLTGOT16_HA", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_GOT16_DS", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_GOT16_LO_DS", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLT16_LO_DS", /* name */
false, /* partial_inplace */
0, /* src_mask */
false), /* pcrel_offset */
/* Like R_PPC64_SECTOFF, but for instructions with a DS field. */
- /* FIXME: Verify R_PPC64_SECTOFF. Seems strange with size=2 and
- dst_mask=0. */
HOWTO (R_PPC64_SECTOFF_DS, /* type */
0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- true, /* pc_relative */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_sectoff_reloc, /* special_function */
"R_PPC64_SECTOFF_DS", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0, /* dst_mask */
- true), /* pcrel_offset */
+ 0xfffc, /* dst_mask */
+ false), /* pcrel_offset */
/* Like R_PPC64_SECTOFF_LO, but for instructions with a DS field. */
HOWTO (R_PPC64_SECTOFF_LO_DS, /* type */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_sectoff_reloc, /* special_function */
"R_PPC64_SECTOFF_LO_DS",/* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_toc_reloc, /* special_function */
"R_PPC64_TOC16_DS", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_toc_reloc, /* special_function */
"R_PPC64_TOC16_LO_DS", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLTGOT16_DS", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLTGOT16_LO_DS",/* name */
false, /* partial_inplace */
0, /* src_mask */
break;
case BFD_RELOC_HI16_S_PLTOFF: ppc_reloc = R_PPC64_PLT16_HA;
break;
- case BFD_RELOC_32_BASEREL: ppc_reloc = R_PPC64_SECTOFF;
+ case BFD_RELOC_16_BASEREL: ppc_reloc = R_PPC64_SECTOFF;
break;
case BFD_RELOC_LO16_BASEREL: ppc_reloc = R_PPC64_SECTOFF_LO;
break;
{
unsigned int type;
+ /* Initialize howto table if needed. */
if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
- /* Initialize howto table if needed. */
ppc_howto_init ();
type = ELF64_R_TYPE (dst->r_info);
/* Handle the R_PPC_ADDR16_HA and similar relocs. */
static bfd_reloc_status_type
-ppc64_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section,
- output_bfd, error_message)
- bfd *abfd ATTRIBUTE_UNUSED;
+ppc64_elf_ha_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+
+ /* Adjust the addend for sign extension of the low 16 bits.
+ We won't actually be using the low 16 bits, so trashing them
+ doesn't matter. */
+ reloc_entry->addend += 0x8000;
+ return bfd_reloc_continue;
+}
+
+static bfd_reloc_status_type
+ppc64_elf_brtaken_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message)
+ bfd *abfd;
arelent *reloc_entry;
asymbol *symbol;
- PTR data ATTRIBUTE_UNUSED;
+ PTR data;
asection *input_section;
bfd *output_bfd;
- char **error_message ATTRIBUTE_UNUSED;
+ char **error_message;
{
- bfd_vma relocation;
+ long insn;
+ enum elf_ppc_reloc_type r_type;
+ bfd_size_type octets;
+ /* Disabled until we sort out how ld should choose 'y' vs 'at'. */
+ boolean is_power4 = false;
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+
+ octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+ insn &= ~(0x01 << 21);
+ r_type = (enum elf_ppc_reloc_type) reloc_entry->howto->type;
+ if (r_type == R_PPC64_ADDR14_BRTAKEN
+ || r_type == R_PPC64_REL14_BRTAKEN)
+ insn |= 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */
+
+ if (is_power4)
{
- reloc_entry->address += input_section->output_offset;
- return bfd_reloc_ok;
+ /* Set 'a' bit. This is 0b00010 in BO field for branch
+ on CR(BI) insns (BO == 001at or 011at), and 0b01000
+ for branch on CTR insns (BO == 1a00t or 1a01t). */
+ if ((insn & (0x14 << 21)) == (0x04 << 21))
+ insn |= 0x02 << 21;
+ else if ((insn & (0x14 << 21)) == (0x10 << 21))
+ insn |= 0x08 << 21;
+ else
+ return bfd_reloc_continue;
}
-
- if (reloc_entry->address > input_section->_cooked_size)
- return bfd_reloc_outofrange;
-
- if (bfd_is_com_section (symbol->section))
- relocation = 0;
else
- relocation = symbol->value;
+ {
+ bfd_vma target = 0;
+ bfd_vma from;
- relocation += symbol->section->output_section->vma;
- relocation += symbol->section->output_offset;
- relocation += reloc_entry->addend;
+ if (!bfd_is_com_section (symbol->section))
+ target = symbol->value;
+ target += symbol->section->output_section->vma;
+ target += symbol->section->output_offset;
+ target += reloc_entry->addend;
- reloc_entry->addend += (relocation & 0x8000) << 1;
+ from = (reloc_entry->address
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ /* Invert 'y' bit if not the default. */
+ if ((bfd_signed_vma) (target - from) < 0)
+ insn ^= 0x01 << 21;
+ }
+ bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + octets);
return bfd_reloc_continue;
}
-/* Function to set whether a module needs the -mrelocatable bit set. */
+static bfd_reloc_status_type
+ppc64_elf_sectoff_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+
+ /* Subtract the symbol section base address. */
+ reloc_entry->addend -= symbol->section->output_section->vma;
+ return bfd_reloc_continue;
+}
-static boolean
-ppc64_elf_set_private_flags (abfd, flags)
+static bfd_reloc_status_type
+ppc64_elf_sectoff_ha_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message)
bfd *abfd;
- flagword flags;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
{
- BFD_ASSERT (!elf_flags_init (abfd)
- || elf_elfheader (abfd)->e_flags == flags);
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
- elf_elfheader (abfd)->e_flags = flags;
- elf_flags_init (abfd) = true;
- return true;
+ /* Subtract the symbol section base address. */
+ reloc_entry->addend -= symbol->section->output_section->vma;
+
+ /* Adjust the addend for sign extension of the low 16 bits. */
+ reloc_entry->addend += 0x8000;
+ return bfd_reloc_continue;
}
-/* Merge backend specific data from an object file to the output
- object file when linking. */
-static boolean
-ppc64_elf_merge_private_bfd_data (ibfd, obfd)
- bfd *ibfd;
- bfd *obfd;
+static bfd_reloc_status_type
+ppc64_elf_toc_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
{
- flagword old_flags;
- flagword new_flags;
- boolean error;
+ bfd_vma TOCstart;
- /* Check if we have the same endianess. */
- if (ibfd->xvec->byteorder != obfd->xvec->byteorder
- && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
- {
- const char *msg;
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
- if (bfd_big_endian (ibfd))
- msg = _("%s: compiled for a big endian system and target is little endian");
- else
- msg = _("%s: compiled for a little endian system and target is big endian");
+ TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
+ if (TOCstart == 0)
+ TOCstart = ppc64_elf_toc (input_section->output_section->owner);
- (*_bfd_error_handler) (msg, bfd_archive_filename (ibfd));
+ /* Subtract the TOC base address. */
+ reloc_entry->addend -= TOCstart + TOC_BASE_OFF;
+ return bfd_reloc_continue;
+}
- bfd_set_error (bfd_error_wrong_format);
- return false;
- }
+static bfd_reloc_status_type
+ppc64_elf_toc_ha_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ bfd_vma TOCstart;
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
- || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
- return true;
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
- new_flags = elf_elfheader (ibfd)->e_flags;
- old_flags = elf_elfheader (obfd)->e_flags;
- if (!elf_flags_init (obfd))
- {
- /* First call, no flags set. */
- elf_flags_init (obfd) = true;
- elf_elfheader (obfd)->e_flags = new_flags;
- }
+ TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
+ if (TOCstart == 0)
+ TOCstart = ppc64_elf_toc (input_section->output_section->owner);
- else if (new_flags == old_flags)
- /* Compatible flags are ok. */
- ;
+ /* Subtract the TOC base address. */
+ reloc_entry->addend -= TOCstart + TOC_BASE_OFF;
- else
- {
- /* Incompatible flags. Warn about -mrelocatable mismatch.
- Allow -mrelocatable-lib to be linked with either. */
- error = false;
- if ((new_flags & EF_PPC_RELOCATABLE) != 0
- && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
- {
- error = true;
- (*_bfd_error_handler)
- (_("%s: compiled with -mrelocatable and linked with modules compiled normally"),
- bfd_archive_filename (ibfd));
- }
- else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0
- && (old_flags & EF_PPC_RELOCATABLE) != 0)
- {
- error = true;
- (*_bfd_error_handler)
- (_("%s: compiled normally and linked with modules compiled with -mrelocatable"),
- bfd_archive_filename (ibfd));
- }
+ /* Adjust the addend for sign extension of the low 16 bits. */
+ reloc_entry->addend += 0x8000;
+ return bfd_reloc_continue;
+}
+
+static bfd_reloc_status_type
+ppc64_elf_toc64_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ bfd_vma TOCstart;
+ bfd_size_type octets;
- /* The output is -mrelocatable-lib iff both the input files are. */
- if (! (new_flags & EF_PPC_RELOCATABLE_LIB))
- elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB;
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
- /* The output is -mrelocatable iff it can't be -mrelocatable-lib,
- but each input file is either -mrelocatable or -mrelocatable-lib. */
- if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB)
- && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))
- && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)))
- elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE;
+ TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
+ if (TOCstart == 0)
+ TOCstart = ppc64_elf_toc (input_section->output_section->owner);
- /* Do not warn about eabi vs. V.4 mismatch, just or in the bit
- if any module uses it. */
- elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB);
+ octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets);
+ return bfd_reloc_ok;
+}
- new_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB);
- old_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB);
+static bfd_reloc_status_type
+ppc64_elf_unhandled_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
- /* Warn about any other mismatches. */
- if (new_flags != old_flags)
- {
- error = true;
- (*_bfd_error_handler)
- (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
- bfd_archive_filename (ibfd), (long) new_flags, (long) old_flags);
- }
+ if (error_message != NULL)
+ {
+ static char buf[60];
+ sprintf (buf, "generic linker can't handle %s",
+ reloc_entry->howto->name);
+ *error_message = buf;
+ }
+ return bfd_reloc_dangerous;
+}
- if (error)
+/* Fix bad default arch selected for a 64 bit input bfd when the
+ default is 32 bit. */
+
+static boolean
+ppc64_elf_object_p (abfd)
+ bfd *abfd;
+{
+ if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 32)
+ {
+ Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
+
+ if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS64)
{
- bfd_set_error (bfd_error_bad_value);
- return false;
+ /* Relies on arch after 32 bit default being 64 bit default. */
+ abfd->arch_info = abfd->arch_info->next;
+ BFD_ASSERT (abfd->arch_info->bits_per_word == 64);
}
}
-
return true;
}
-/* Handle a PowerPC specific section when reading an object file. This
- is called when elfcode.h finds a section with an unknown type. */
+/* Merge backend specific data from an object file to the output
+ object file when linking. */
static boolean
-ppc64_elf_section_from_shdr (abfd, hdr, name)
- bfd *abfd;
- Elf64_Internal_Shdr *hdr;
- char *name;
+ppc64_elf_merge_private_bfd_data (ibfd, obfd)
+ bfd *ibfd;
+ bfd *obfd;
{
- asection *newsect;
- flagword flags;
+ /* Check if we have the same endianess. */
+ if (ibfd->xvec->byteorder != obfd->xvec->byteorder
+ && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
+ {
+ const char *msg;
- if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
- return false;
+ if (bfd_big_endian (ibfd))
+ msg = _("%s: compiled for a big endian system and target is little endian");
+ else
+ msg = _("%s: compiled for a little endian system and target is big endian");
- newsect = hdr->bfd_section;
- flags = bfd_get_section_flags (abfd, newsect);
- if (hdr->sh_flags & SHF_EXCLUDE)
- flags |= SEC_EXCLUDE;
+ (*_bfd_error_handler) (msg, bfd_archive_filename (ibfd));
- if (hdr->sh_type == SHT_ORDERED)
- flags |= SEC_SORT_ENTRIES;
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
- bfd_set_section_flags (abfd, newsect, flags);
return true;
}
\f
selects between relative and absolute types. */
#define IS_ABSOLUTE_RELOC(RTYPE) \
- ((RTYPE) != R_PPC64_REL14 \
- && (RTYPE) != R_PPC64_REL14_BRNTAKEN \
- && (RTYPE) != R_PPC64_REL14_BRTAKEN \
- && (RTYPE) != R_PPC64_REL24 \
- && (RTYPE) != R_PPC64_REL32 \
- && (RTYPE) != R_PPC64_REL64)
+ ((RTYPE) != R_PPC64_REL32 \
+ && (RTYPE) != R_PPC64_REL64 \
+ && (RTYPE) != R_PPC64_ADDR30)
/* Section name for stubs is the associated section name plus this
string. */
/* Flag function code and descriptor symbols. */
unsigned int is_func:1;
unsigned int is_func_descriptor:1;
+ unsigned int is_entry:1;
};
/* ppc64 ELF linker hash table. */
} *stub_group;
/* Assorted information used by ppc64_elf_size_stubs. */
- unsigned int bfd_count;
int top_index;
asection **input_list;
- Elf_Internal_Sym **all_local_syms;
/* Short-cuts to get to dynamic linker sections. */
asection *sgot;
select suitable defaults for the stub group size. */
unsigned int has_14bit_branch;
+ /* Set if we detect a reference undefined weak symbol. */
+ unsigned int have_undefweak;
+
/* Incremented every time we size stubs. */
unsigned int stub_iteration;
static boolean ppc64_elf_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static void ppc64_elf_copy_indirect_symbol
- PARAMS ((struct elf_link_hash_entry *, struct elf_link_hash_entry *));
+ PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *,
+ struct elf_link_hash_entry *));
static boolean ppc64_elf_check_relocs
PARAMS ((bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *));
static asection * ppc64_elf_gc_mark_hook
- PARAMS ((bfd *abfd, struct bfd_link_info *info, Elf_Internal_Rela *rel,
- struct elf_link_hash_entry *h, Elf_Internal_Sym *sym));
+ PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
+ struct elf_link_hash_entry *, Elf_Internal_Sym *));
static boolean ppc64_elf_gc_sweep_hook
- PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec,
- const Elf_Internal_Rela *relocs));
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *));
static boolean func_desc_adjust
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean ppc64_elf_func_desc_adjust
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
static void ppc64_elf_hide_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, boolean));
+static boolean edit_opd
+ PARAMS ((bfd *, struct bfd_link_info *));
static boolean allocate_dynrelocs
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean readonly_dynrelocs
PARAMS ((struct bfd_hash_entry *, PTR));
static void group_sections
PARAMS ((struct ppc_link_hash_table *, bfd_size_type, boolean));
-static boolean get_local_syms
- PARAMS ((bfd *, struct ppc_link_hash_table *));
-static boolean ppc64_elf_fake_sections
- PARAMS ((bfd *, Elf64_Internal_Shdr *, asection *));
static boolean ppc64_elf_relocate_section
PARAMS ((bfd *, struct bfd_link_info *info, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *relocs, Elf_Internal_Sym *local_syms,
eh->oh = NULL;
eh->is_func = 0;
eh->is_func_descriptor = 0;
+ eh->is_entry = 0;
}
return entry;
htab->srelbrlt = NULL;
htab->stub_error = 0;
htab->has_14bit_branch = 0;
+ htab->have_undefweak = 0;
htab->stub_iteration = 0;
htab->sym_sec.abfd = NULL;
stub_sec = htab->stub_group[link_sec->id].stub_sec;
if (stub_sec == NULL)
{
+ size_t namelen;
bfd_size_type len;
char *s_name;
- len = strlen (link_sec->name) + sizeof (STUB_SUFFIX);
+ namelen = strlen (link_sec->name);
+ len = namelen + sizeof (STUB_SUFFIX);
s_name = bfd_alloc (htab->stub_bfd, len);
if (s_name == NULL)
return NULL;
- strcpy (s_name, link_sec->name);
- strcpy (s_name + len - sizeof (STUB_SUFFIX), STUB_SUFFIX);
+ memcpy (s_name, link_sec->name, namelen);
+ memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
stub_sec = (*htab->add_stub_section) (s_name, link_sec);
if (stub_sec == NULL)
return NULL;
{
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- htab->srelbrlt = bfd_make_section (dynobj, ".rela.branch_lt");
+ htab->srelbrlt = bfd_make_section_anyway (dynobj, ".rela.branch_lt");
if (!htab->srelbrlt
|| ! bfd_set_section_flags (dynobj, htab->srelbrlt, flags)
|| ! bfd_set_section_alignment (dynobj, htab->srelbrlt, 3))
/* Copy the extra info we tack onto an elf_link_hash_entry. */
static void
-ppc64_elf_copy_indirect_symbol (dir, ind)
+ppc64_elf_copy_indirect_symbol (bed, dir, ind)
+ struct elf_backend_data *bed;
struct elf_link_hash_entry *dir, *ind;
{
struct ppc_link_hash_entry *edir, *eind;
edir->is_func |= eind->is_func;
edir->is_func_descriptor |= eind->is_func_descriptor;
+ edir->is_entry |= eind->is_entry;
- _bfd_elf_link_hash_copy_indirect (dir, ind);
+ _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
}
-/* Look through the relocs for a section during the first phase, and
- calculate needed space in the global offset table, procedure
- linkage table, and dynamic reloc sections. */
+/* Set a flag, used by ppc64_elf_gc_mark_hook, on the entry symbol and
+ symbols undefined on the command-line. */
-static boolean
-ppc64_elf_check_relocs (abfd, info, sec, relocs)
- bfd *abfd;
+boolean
+ppc64_elf_mark_entry_syms (info)
struct bfd_link_info *info;
- asection *sec;
- const Elf_Internal_Rela *relocs;
{
struct ppc_link_hash_table *htab;
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
- const Elf_Internal_Rela *rel;
- const Elf_Internal_Rela *rel_end;
- asection *sreloc;
- boolean is_opd;
+ struct bfd_sym_chain *sym;
+
+ htab = ppc_hash_table (info);
+ for (sym = info->gc_sym_list; sym; sym = sym->next)
+ {
+ struct elf_link_hash_entry *h;
+
+ h = elf_link_hash_lookup (&htab->elf, sym->name, false, false, false);
+ if (h != NULL)
+ ((struct ppc_link_hash_entry *) h)->is_entry = 1;
+ }
+ return true;
+}
+
+/* Look through the relocs for a section during the first phase, and
+ calculate needed space in the global offset table, procedure
+ linkage table, and dynamic reloc sections. */
+
+static boolean
+ppc64_elf_check_relocs (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+ struct ppc_link_hash_table *htab;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ asection *sreloc;
+ asection **opd_sym_map;
if (info->relocateable)
return true;
sym_hashes = elf_sym_hashes (abfd);
sym_hashes_end = (sym_hashes
- + symtab_hdr->sh_size / sizeof (Elf64_External_Sym));
- if (!elf_bad_symtab (abfd))
- sym_hashes_end -= symtab_hdr->sh_info;
+ + symtab_hdr->sh_size / sizeof (Elf64_External_Sym)
+ - symtab_hdr->sh_info);
sreloc = NULL;
- is_opd = strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0;
+ opd_sym_map = NULL;
+ if (strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0)
+ {
+ /* Garbage collection needs some extra help with .opd sections.
+ We don't want to necessarily keep everything referenced by
+ relocs in .opd, as that would keep all functions. Instead,
+ if we reference an .opd symbol (a function descriptor), we
+ want to keep the function code symbol's section. This is
+ easy for global symbols, but for local syms we need to keep
+ information about the associated function section. Later, if
+ edit_opd deletes entries, we'll use this array to adjust
+ local syms in .opd. */
+ union opd_info {
+ asection *func_section;
+ long entry_adjust;
+ };
+ bfd_size_type amt;
+
+ amt = sec->_raw_size * sizeof (union opd_info) / 24;
+ opd_sym_map = (asection **) bfd_zalloc (abfd, amt);
+ if (opd_sym_map == NULL)
+ return false;
+ elf_section_data (sec)->tdata = opd_sym_map;
+ }
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
case R_PPC64_PLT32:
case R_PPC64_PLT64:
/* This symbol requires a procedure linkage table entry. We
- actually build the entry in adjust_dynamic_symbol,
- because this might be a case of linking PIC code without
- linking in any dynamic objects, in which case we don't
- need to generate a procedure linkage table after all. */
+ actually build the entry in adjust_dynamic_symbol,
+ because this might be a case of linking PIC code without
+ linking in any dynamic objects, in which case we don't
+ need to generate a procedure linkage table after all. */
if (h == NULL)
{
/* It does not make sense to have a procedure linkage
- table entry for a local symbol. */
+ table entry for a local symbol. */
bfd_set_error (bfd_error_bad_value);
return false;
}
break;
case R_PPC64_ADDR64:
- if (is_opd
+ if (opd_sym_map != NULL
&& h != NULL
&& h->root.root.string[0] == '.'
&& h->root.root.string[1] != 0)
false, false, false);
if (fdh != NULL)
{
- /* Ensure the function descriptor symbol string is
- part of the code symbol string. We aren't
- changing the name here, just allowing some tricks
- in ppc64_elf_hide_symbol. */
- fdh->root.root.string = h->root.root.string + 1;
((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
((struct ppc_link_hash_entry *) fdh)->oh = h;
((struct ppc_link_hash_entry *) h)->is_func = 1;
((struct ppc_link_hash_entry *) h)->oh = fdh;
}
}
+ if (opd_sym_map != NULL
+ && h == NULL
+ && rel + 1 < rel_end
+ && ((enum elf_ppc_reloc_type) ELF64_R_TYPE ((rel + 1)->r_info)
+ == R_PPC64_TOC))
+ {
+ asection *s;
+
+ s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
+ r_symndx);
+ if (s == NULL)
+ return false;
+ else if (s != sec)
+ opd_sym_map[rel->r_offset / 24] = s;
+ }
/* Fall through. */
case R_PPC64_REL64:
case R_PPC64_UADDR64:
case R_PPC64_TOC:
/* Don't propagate .opd relocs. */
- if (NO_OPD_RELOCS && is_opd)
+ if (NO_OPD_RELOCS && opd_sym_map != NULL)
break;
/* If we are creating a shared library, and this is a reloc
relocation. */
static asection *
-ppc64_elf_gc_mark_hook (abfd, info, rel, h, sym)
- bfd *abfd;
+ppc64_elf_gc_mark_hook (sec, info, rel, h, sym)
+ asection *sec;
struct bfd_link_info *info ATTRIBUTE_UNUSED;
Elf_Internal_Rela *rel;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
{
+ asection *rsec = NULL;
+
if (h != NULL)
{
enum elf_ppc_reloc_type r_type;
+ struct ppc_link_hash_entry *fdh;
r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE (rel->r_info);
switch (r_type)
{
case bfd_link_hash_defined:
case bfd_link_hash_defweak:
- return h->root.u.def.section;
+ fdh = (struct ppc_link_hash_entry *) h;
+
+ /* Function descriptor syms cause the associated
+ function code sym section to be marked. */
+ if (fdh->is_func_descriptor)
+ rsec = fdh->oh->root.u.def.section;
+
+ /* Function entry syms return NULL if they are in .opd
+ and are not ._start (or others undefined on the ld
+ command line). Thus we avoid marking all function
+ sections, as all functions are referenced in .opd. */
+ else if ((fdh->oh != NULL
+ && ((struct ppc_link_hash_entry *) fdh->oh)->is_entry)
+ || elf_section_data (sec)->tdata == NULL)
+ rsec = h->root.u.def.section;
+ break;
case bfd_link_hash_common:
- return h->root.u.c.p->section;
+ rsec = h->root.u.c.p->section;
+ break;
default:
break;
}
else
{
- return bfd_section_from_elf_index (abfd, sym->st_shndx);
+ asection **opd_sym_section;
+
+ rsec = bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+ opd_sym_section = (asection **) elf_section_data (rsec)->tdata;
+ if (opd_sym_section != NULL)
+ rsec = opd_sym_section[sym->st_value / 24];
+ else if (elf_section_data (sec)->tdata != NULL)
+ rsec = NULL;
}
- return NULL;
+ return rsec;
}
/* Update the .got, .plt. and dynamic reloc reference counts for the
if (!((struct ppc_link_hash_entry *) h)->is_func)
return true;
+ if (h->root.type == bfd_link_hash_undefweak
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
+ htab->have_undefweak = true;
+
if (h->plt.refcount > 0
&& h->root.root.string[0] == '.'
&& h->root.root.string[1] != '\0')
{
bfd *abfd;
asymbol *newsym;
+ struct bfd_link_hash_entry *bh;
abfd = h->root.u.undef.abfd;
newsym = bfd_make_empty_symbol (abfd);
if (h->root.type == bfd_link_hash_undefweak)
newsym->flags |= BSF_WEAK;
+ bh = &fdh->root;
if ( !(_bfd_generic_link_add_one_symbol
(info, abfd, newsym->name, newsym->flags,
- newsym->section, newsym->value, NULL, false, false,
- (struct bfd_link_hash_entry **) &fdh)))
+ newsym->section, newsym->value, NULL, false, false, &bh)))
{
return false;
}
+ fdh = (struct elf_link_hash_entry *) bh;
fdh->elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
}
}
((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
((struct ppc_link_hash_entry *) fdh)->oh = h;
- fdh->root.root.string = h->root.root.string + 1;
((struct ppc_link_hash_entry *) h)->oh = fdh;
}
been imported from another library. Function code syms that
are really in the library we must leave global to prevent the
linker dragging in a definition from a static library. */
- force_local = ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
- && info->shared);
+ force_local = (info->shared
+ && ((h->elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) == 0
+ || fdh == NULL
+ || (fdh->elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) == 0
+ || (fdh->elf_link_hash_flags
+ & ELF_LINK_FORCED_LOCAL) != 0));
_bfd_elf_link_hash_hide_symbol (info, h, force_local);
}
}
}
+ elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
+
htab->sfpr->_raw_size = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
+ (MAX_SAVE_FPR + 2 - lowest_restf) * 4);
if (htab->sfpr->_raw_size == 0)
- htab->sfpr->_raw_size = 4;
+ {
+ if (!htab->have_undefweak)
+ {
+ _bfd_strip_section_from_output (info, htab->sfpr);
+ return true;
+ }
+
+ htab->sfpr->_raw_size = 4;
+ }
p = (bfd_byte *) bfd_alloc (htab->elf.dynobj, htab->sfpr->_raw_size);
if (p == NULL)
bfd_put_32 (htab->elf.dynobj, BLR, p);
}
- elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
return true;
}
if (((struct ppc_link_hash_entry *) h)->is_func_descriptor)
{
- const char *name;
struct elf_link_hash_entry *fh = ((struct ppc_link_hash_entry *) h)->oh;
- struct ppc_link_hash_table *htab;
- name = h->root.root.string - 1;
- htab = ppc_hash_table (info);
if (fh == NULL)
- fh = elf_link_hash_lookup (&htab->elf, name, false, false, false);
+ {
+ const char *p, *q;
+ struct ppc_link_hash_table *htab;
+ char save;
+
+ /* We aren't supposed to use alloca in BFD because on
+ systems which do not have alloca the version in libiberty
+ calls xmalloc, which might cause the program to crash
+ when it runs out of memory. This function doesn't have a
+ return status, so there's no way to gracefully return an
+ error. So cheat. We know that string[-1] can be safely
+ dereferenced; It's either a string in an ELF string
+ table, or allocated in an objalloc structure. */
+
+ p = h->root.root.string - 1;
+ save = *p;
+ *(char *) p = '.';
+ htab = ppc_hash_table (info);
+ fh = elf_link_hash_lookup (&htab->elf, p, false, false, false);
+ *(char *) p = save;
+
+ /* Unfortunately, if it so happens that the string we were
+ looking for was allocated immediately before this string,
+ then we overwrote the string terminator. That's the only
+ reason the lookup should fail. */
+ if (fh == NULL)
+ {
+ q = h->root.root.string + strlen (h->root.root.string);
+ while (q >= h->root.root.string && *q == *p)
+ --q, --p;
+ if (q < h->root.root.string && *p == '.')
+ fh = elf_link_hash_lookup (&htab->elf, p, false, false, false);
+ }
+ if (fh != NULL)
+ {
+ ((struct ppc_link_hash_entry *) h)->oh = fh;
+ ((struct ppc_link_hash_entry *) fh)->oh = h;
+ }
+ }
if (fh != NULL)
_bfd_elf_link_hash_hide_symbol (info, fh, force_local);
}
}
+static boolean
+edit_opd (obfd, info)
+ bfd *obfd;
+ struct bfd_link_info *info;
+{
+ bfd *ibfd;
+ unsigned int bfd_indx;
+
+ for (bfd_indx = 0, ibfd = info->input_bfds;
+ ibfd != NULL;
+ ibfd = ibfd->link_next, bfd_indx++)
+ {
+ asection *sec;
+ Elf_Internal_Rela *relstart, *rel, *relend;
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Sym *local_syms;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_vma offset;
+ long *adjust;
+ boolean need_edit;
+
+ sec = bfd_get_section_by_name (ibfd, ".opd");
+ if (sec == NULL)
+ continue;
+
+ adjust = (long *) elf_section_data (sec)->tdata;
+ BFD_ASSERT (adjust != NULL);
+ memset (adjust, 0, (size_t) sec->_raw_size * sizeof (long) / 24);
+
+ if (sec->output_section == bfd_abs_section_ptr)
+ continue;
+
+ /* Look through the section relocs. */
+ if ((sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0)
+ continue;
+
+ local_syms = NULL;
+ symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (ibfd);
+
+ /* Read the relocations. */
+ relstart = _bfd_elf64_link_read_relocs (obfd, sec, (PTR) NULL,
+ (Elf_Internal_Rela *) NULL,
+ info->keep_memory);
+ if (relstart == NULL)
+ return false;
+
+ /* First run through the relocs to check they are sane, and to
+ determine whether we need to edit this opd section. */
+ need_edit = false;
+ offset = 0;
+ relend = relstart + sec->reloc_count;
+ for (rel = relstart; rel < relend; rel++)
+ {
+ enum elf_ppc_reloc_type r_type;
+ unsigned long r_symndx;
+ asection *sym_sec;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+
+ /* .opd contains a regular array of 24 byte entries. We're
+ only interested in the reloc pointing to a function entry
+ point. */
+ r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE (rel->r_info);
+ if (r_type == R_PPC64_TOC)
+ continue;
+
+ if (r_type != R_PPC64_ADDR64)
+ {
+ (*_bfd_error_handler)
+ (_("%s: unexpected reloc type %u in .opd section"),
+ bfd_archive_filename (ibfd), r_type);
+ need_edit = false;
+ break;
+ }
+
+ if (rel + 1 >= relend)
+ continue;
+ r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE ((rel + 1)->r_info);
+ if (r_type != R_PPC64_TOC)
+ continue;
+
+ if (rel->r_offset != offset)
+ {
+ /* If someone messes with .opd alignment then after a
+ "ld -r" we might have padding in the middle of .opd.
+ Also, there's nothing to prevent someone putting
+ something silly in .opd with the assembler. No .opd
+ optimization for them! */
+ (*_bfd_error_handler)
+ (_("%s: .opd is not a regular array of opd entries"),
+ bfd_archive_filename (ibfd));
+ need_edit = false;
+ break;
+ }
+
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ sym_sec = NULL;
+ h = NULL;
+ sym = NULL;
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ sym_sec = h->root.u.def.section;
+ }
+ else
+ {
+ if (local_syms == NULL)
+ {
+ local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (local_syms == NULL)
+ local_syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (local_syms == NULL)
+ goto error_free_rel;
+ }
+ sym = local_syms + r_symndx;
+ if ((sym->st_shndx != SHN_UNDEF
+ && sym->st_shndx < SHN_LORESERVE)
+ || sym->st_shndx > SHN_HIRESERVE)
+ sym_sec = bfd_section_from_elf_index (ibfd, sym->st_shndx);
+ }
+
+ if (sym_sec == NULL || sym_sec->owner == NULL)
+ {
+ (*_bfd_error_handler)
+ (_("%s: undefined sym `%s' in .opd section"),
+ bfd_archive_filename (ibfd),
+ h != NULL ? h->root.root.string : "<local symbol>");
+ need_edit = false;
+ break;
+ }
+
+ /* opd entries are always for functions defined in the
+ current input bfd. If the symbol isn't defined in the
+ input bfd, then we won't be using the function in this
+ bfd; It must be defined in a linkonce section in another
+ bfd, or is weak. It's also possible that we are
+ discarding the function due to a linker script /DISCARD/,
+ which we test for via the output_section. */
+ if (sym_sec->owner != ibfd
+ || sym_sec->output_section == bfd_abs_section_ptr)
+ need_edit = true;
+
+ offset += 24;
+ }
+
+ if (need_edit)
+ {
+ Elf_Internal_Rela *write_rel;
+ bfd_byte *rptr, *wptr;
+ boolean skip;
+
+ /* This seems a waste of time as input .opd sections are all
+ zeros as generated by gcc, but I suppose there's no reason
+ this will always be so. We might start putting something in
+ the third word of .opd entries. */
+ if ((sec->flags & SEC_IN_MEMORY) == 0)
+ {
+ bfd_byte *loc = bfd_alloc (ibfd, sec->_raw_size);
+ if (loc == NULL
+ || !bfd_get_section_contents (ibfd, sec, loc, (bfd_vma) 0,
+ sec->_raw_size))
+ {
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ free (local_syms);
+ error_free_rel:
+ if (elf_section_data (sec)->relocs != relstart)
+ free (relstart);
+ return false;
+ }
+ sec->contents = loc;
+ sec->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS);
+ }
+
+ elf_section_data (sec)->relocs = relstart;
+
+ wptr = sec->contents;
+ rptr = sec->contents;
+ write_rel = relstart;
+ skip = false;
+ offset = 0;
+ for (rel = relstart; rel < relend; rel++)
+ {
+ if (rel->r_offset == offset)
+ {
+ unsigned long r_symndx;
+ asection *sym_sec;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ sym_sec = NULL;
+ h = NULL;
+ sym = NULL;
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ sym_sec = h->root.u.def.section;
+ }
+ else
+ {
+ sym = local_syms + r_symndx;
+ if ((sym->st_shndx != SHN_UNDEF
+ && sym->st_shndx < SHN_LORESERVE)
+ || sym->st_shndx > SHN_HIRESERVE)
+ sym_sec = bfd_section_from_elf_index (ibfd,
+ sym->st_shndx);
+ }
+
+ skip = (sym_sec->owner != ibfd
+ || sym_sec->output_section == bfd_abs_section_ptr);
+ if (skip)
+ {
+ if (h != NULL && sym_sec->owner == ibfd)
+ {
+ /* Arrange for the function descriptor sym
+ to be dropped. */
+ struct elf_link_hash_entry *fdh;
+ struct ppc_link_hash_entry *fh;
+
+ fh = (struct ppc_link_hash_entry *) h;
+ BFD_ASSERT (fh->is_func);
+ fdh = fh->oh;
+ fdh->root.u.def.value = 0;
+ fdh->root.u.def.section = sym_sec;
+ }
+ }
+ else
+ {
+ /* We'll be keeping this opd entry. */
+
+ if (h != NULL)
+ {
+ /* Redefine the function descriptor symbol
+ to this location in the opd section.
+ We've checked above that opd relocs are
+ ordered. */
+ struct elf_link_hash_entry *fdh;
+ struct ppc_link_hash_entry *fh;
+
+ fh = (struct ppc_link_hash_entry *) h;
+ BFD_ASSERT (fh->is_func);
+ fdh = fh->oh;
+ fdh->root.u.def.value = wptr - sec->contents;
+ }
+ else
+ {
+ /* Local syms are a bit tricky. We could
+ tweak them as they can be cached, but
+ we'd need to look through the local syms
+ for the function descriptor sym which we
+ don't have at the moment. So keep an
+ array of adjustments. */
+ adjust[rel->r_offset / 24] = wptr - rptr;
+ }
+
+ if (wptr != rptr)
+ memcpy (wptr, rptr, 24);
+ wptr += 24;
+ }
+ rptr += 24;
+ offset += 24;
+ }
+
+ /* We need to adjust any reloc offsets to point to the
+ new opd entries. While we're at it, we may as well
+ remove redundant relocs. */
+ if (!skip)
+ {
+ rel->r_offset += wptr - rptr;
+ if (write_rel != rel)
+ memcpy (write_rel, rel, sizeof (*rel));
+ ++write_rel;
+ }
+ }
+
+ sec->_cooked_size = wptr - sec->contents;
+ sec->reloc_count = write_rel - relstart;
+ }
+ else if (elf_section_data (sec)->relocs != relstart)
+ free (relstart);
+
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ {
+ if (!info->keep_memory)
+ free (local_syms);
+ else
+ symtab_hdr->contents = (unsigned char *) local_syms;
+ }
+ }
+
+ return true;
+}
+
/* This is the condition under which ppc64_elf_finish_dynamic_symbol
will be called from elflink.h. If elflink.h doesn't call our
finish_dynamic_symbol routine, we'll need to do something about
}
}
+ if (!edit_opd (output_bfd, info))
+ return false;
+
/* Allocate global sym .plt and .got entries, and space for global
sym dynamic relocs. */
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
continue;
}
+ /* .plt is in the bss section. We don't initialise it. */
+ if ((s->flags & SEC_LOAD) == 0)
+ continue;
+
/* Allocate memory for the section contents. We use bfd_zalloc
here in case unused entries are not reclaimed before the
section's contents are written out. This should not happen,
return false;
}
- if (htab->splt->_raw_size != 0)
+ if (htab->splt != NULL && htab->splt->_raw_size != 0)
{
if (!add_dynamic_entry (DT_PLTGOT, 0)
|| !add_dynamic_entry (DT_PLTRELSZ, 0)
break;
case ppc_stub_plt_call:
- /* Build the .glink lazy link call stub. */
- p = htab->sglink->contents + htab->sglink->_cooked_size;
- indx = htab->sglink->reloc_count;
- if (indx < 0x8000)
- {
- bfd_put_32 (htab->sglink->owner, LI_R0_0 | indx, p);
- p += 4;
- }
- else
+ /* Do the best we can for shared libraries built without
+ exporting ".foo" for each "foo". This can happen when symbol
+ versioning scripts strip all bar a subset of symbols. */
+ if (stub_entry->h->oh->root.type != bfd_link_hash_defined
+ && stub_entry->h->oh->root.type != bfd_link_hash_defweak)
{
- bfd_put_32 (htab->sglink->owner, LIS_R0_0 | PPC_HI (indx), p);
- p += 4;
- bfd_put_32 (htab->sglink->owner, ORI_R0_R0_0 | PPC_LO (indx), p);
- p += 4;
+ /* Point the symbol at the stub. There may be multiple stubs,
+ we don't really care; The main thing is to make this sym
+ defined somewhere. */
+ stub_entry->h->oh->root.type = bfd_link_hash_defined;
+ stub_entry->h->oh->root.u.def.section = stub_entry->stub_sec;
+ stub_entry->h->oh->root.u.def.value = stub_entry->stub_offset;
}
- bfd_put_32 (htab->sglink->owner,
- B_DOT | ((htab->sglink->contents - p) & 0x3fffffc), p);
- p += 4;
- htab->sglink->_cooked_size = p - htab->sglink->contents;
- htab->sglink->reloc_count += 1;
/* Now build the stub. */
off = stub_entry->h->elf.plt.offset;
/* Set up various things so that we can make a list of input sections
for each output section included in the link. Returns -1 on error,
- 0 when no stubs will be needed, and 1 on success. */
+ 0 when no stubs will be needed, and 1 on success. */
int
ppc64_elf_setup_section_lists (output_bfd, info)
struct bfd_link_info *info;
{
bfd *input_bfd;
- unsigned int bfd_count;
int top_id, top_index;
asection *section;
asection **input_list, **list;
bfd_size_type amt;
struct ppc_link_hash_table *htab = ppc_hash_table (info);
- if (htab->sbrlt == NULL)
+ if (htab->elf.root.creator->flavour != bfd_target_elf_flavour
+ || htab->sbrlt == NULL)
return 0;
- /* Count the number of input BFDs and find the top input section id. */
- for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
+ /* Find the top input section id. */
+ for (input_bfd = info->input_bfds, top_id = 0;
input_bfd != NULL;
input_bfd = input_bfd->link_next)
{
- bfd_count += 1;
for (section = input_bfd->sections;
section != NULL;
section = section->next)
top_id = section->id;
}
}
- htab->bfd_count = bfd_count;
amt = sizeof (struct map_stub) * (top_id + 1);
htab->stub_group = (struct map_stub *) bfd_zmalloc (amt);
we may insert linker stubs. */
void
-ppc64_elf_next_input_section (output_bfd, info, isec)
- bfd *output_bfd;
+ppc64_elf_next_input_section (info, isec)
struct bfd_link_info *info;
asection *isec;
{
struct ppc_link_hash_table *htab = ppc_hash_table (info);
- if (isec->output_section != NULL
- && isec->output_section->owner == output_bfd
- && isec->output_section->index <= htab->top_index)
+ if (isec->output_section->index <= htab->top_index)
{
asection **list = htab->input_list + isec->output_section->index;
if (*list != bfd_abs_section_ptr)
#undef PREV_SEC
}
-/* Read in all local syms for all input bfds. */
-
-static boolean
-get_local_syms (input_bfd, htab)
- bfd *input_bfd;
- struct ppc_link_hash_table *htab;
-{
- unsigned int bfd_indx;
- Elf_Internal_Sym *local_syms, **all_local_syms;
-
- /* We want to read in symbol extension records only once. To do this
- we need to read in the local symbols in parallel and save them for
- later use; so hold pointers to the local symbols in an array. */
- bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
- all_local_syms = (Elf_Internal_Sym **) bfd_zmalloc (amt);
- htab->all_local_syms = all_local_syms;
- if (all_local_syms == NULL)
- return false;
-
- /* Walk over all the input BFDs, swapping in local symbols.
- If we are creating a shared library, create hash entries for the
- export stubs. */
- for (bfd_indx = 0;
- input_bfd != NULL;
- input_bfd = input_bfd->link_next, bfd_indx++)
- {
- Elf_Internal_Shdr *symtab_hdr;
- Elf_Internal_Shdr *shndx_hdr;
- Elf_Internal_Sym *isym;
- Elf64_External_Sym *ext_syms, *esym, *end_sy;
- Elf_External_Sym_Shndx *shndx_buf, *shndx;
- bfd_size_type sec_size;
-
- /* We'll need the symbol table in a second. */
- symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
- if (symtab_hdr->sh_info == 0)
- continue;
-
- /* We need an array of the local symbols attached to the input bfd.
- Unfortunately, we're going to have to read & swap them in. */
- sec_size = symtab_hdr->sh_info;
- sec_size *= sizeof (Elf_Internal_Sym);
- local_syms = (Elf_Internal_Sym *) bfd_malloc (sec_size);
- if (local_syms == NULL)
- return false;
-
- all_local_syms[bfd_indx] = local_syms;
- sec_size = symtab_hdr->sh_info;
- sec_size *= sizeof (Elf64_External_Sym);
- ext_syms = (Elf64_External_Sym *) bfd_malloc (sec_size);
- if (ext_syms == NULL)
- return false;
-
- if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread ((PTR) ext_syms, sec_size, input_bfd) != sec_size)
- {
- error_ret_free_ext_syms:
- free (ext_syms);
- return false;
- }
-
- shndx_buf = NULL;
- shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
- if (shndx_hdr->sh_size != 0)
- {
- sec_size = symtab_hdr->sh_info;
- sec_size *= sizeof (Elf_External_Sym_Shndx);
- shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (sec_size);
- if (shndx_buf == NULL)
- goto error_ret_free_ext_syms;
-
- if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread ((PTR) shndx_buf, sec_size, input_bfd) != sec_size)
- {
- free (shndx_buf);
- goto error_ret_free_ext_syms;
- }
- }
-
- /* Swap the local symbols in. */
- for (esym = ext_syms, end_sy = esym + symtab_hdr->sh_info,
- isym = local_syms, shndx = shndx_buf;
- esym < end_sy;
- esym++, isym++, shndx = (shndx ? shndx + 1 : NULL))
- bfd_elf64_swap_symbol_in (input_bfd, esym, shndx, isym);
-
- /* Now we can free the external symbols. */
- free (shndx_buf);
- free (ext_syms);
- }
-
- return true;
-}
-
/* Determine and set the size of the stub section for a final link.
The basic idea here is to examine all the relocations looking for
{
bfd_size_type stub_group_size;
boolean stubs_always_before_branch;
- boolean ret = false;
struct ppc_link_hash_table *htab = ppc_hash_table (info);
/* Stash our params away. */
group_sections (htab, stub_group_size, stubs_always_before_branch);
- if (! get_local_syms (info->input_bfds, htab))
- {
- if (htab->all_local_syms)
- goto error_ret_free_local;
- return false;
- }
-
while (1)
{
bfd *input_bfd;
{
Elf_Internal_Shdr *symtab_hdr;
asection *section;
- Elf_Internal_Sym *local_syms;
+ Elf_Internal_Sym *local_syms = NULL;
/* We'll need the symbol table in a second. */
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
if (symtab_hdr->sh_info == 0)
continue;
- local_syms = htab->all_local_syms[bfd_indx];
-
/* Walk over each section attached to the input bfd. */
for (section = input_bfd->sections;
section != NULL;
section = section->next)
{
- Elf_Internal_Shdr *input_rel_hdr;
- Elf64_External_Rela *external_relocs, *erelaend, *erela;
Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
- bfd_size_type amt;
/* If there aren't any relocs, then there's nothing more
to do. */
|| section->output_section->owner != output_bfd)
continue;
- /* Allocate space for the external relocations. */
- amt = section->reloc_count;
- amt *= sizeof (Elf64_External_Rela);
- external_relocs = (Elf64_External_Rela *) bfd_malloc (amt);
- if (external_relocs == NULL)
- {
- goto error_ret_free_local;
- }
-
- /* Likewise for the internal relocations. */
- amt = section->reloc_count;
- amt *= sizeof (Elf_Internal_Rela);
- internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
+ /* Get the relocs. */
+ internal_relocs
+ = _bfd_elf64_link_read_relocs (input_bfd, section, NULL,
+ (Elf_Internal_Rela *) NULL,
+ info->keep_memory);
if (internal_relocs == NULL)
- {
- free (external_relocs);
- goto error_ret_free_local;
- }
-
- /* Read in the external relocs. */
- input_rel_hdr = &elf_section_data (section)->rel_hdr;
- if (bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread ((PTR) external_relocs,
- input_rel_hdr->sh_size,
- input_bfd) != input_rel_hdr->sh_size)
- {
- free (external_relocs);
- error_ret_free_internal:
- free (internal_relocs);
- goto error_ret_free_local;
- }
-
- /* Swap in the relocs. */
- erela = external_relocs;
- erelaend = erela + section->reloc_count;
- irela = internal_relocs;
- for (; erela < erelaend; erela++, irela++)
- bfd_elf64_swap_reloca_in (input_bfd, erela, irela);
-
- /* We're done with the external relocs, free them. */
- free (external_relocs);
+ goto error_ret_free_local;
/* Now examine each relocation. */
irela = internal_relocs;
Elf_Internal_Sym *sym;
Elf_Internal_Shdr *hdr;
+ if (local_syms == NULL)
+ {
+ local_syms
+ = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (local_syms == NULL)
+ local_syms
+ = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (local_syms == NULL)
+ goto error_ret_free_internal;
+ }
sym = local_syms + r_indx;
hdr = elf_elfsections (input_bfd)[sym->st_shndx];
sym_sec = hdr->bfd_section;
if (stub_entry == NULL)
{
free (stub_name);
- goto error_ret_free_local;
+ error_ret_free_internal:
+ if (elf_section_data (section)->relocs == NULL)
+ free (internal_relocs);
+ error_ret_free_local:
+ if (local_syms != NULL
+ && (symtab_hdr->contents
+ != (unsigned char *) local_syms))
+ free (local_syms);
+ return false;
}
stub_entry->target_value = sym_value;
}
/* We're done with the internal relocs, free them. */
- free (internal_relocs);
+ if (elf_section_data (section)->relocs != internal_relocs)
+ free (internal_relocs);
+ }
+
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ {
+ if (!info->keep_memory)
+ free (local_syms);
+ else
+ symtab_hdr->contents = (unsigned char *) local_syms;
}
}
(*htab->layout_sections_again) ();
}
- if (htab->sbrlt->_raw_size == 0)
- {
- _bfd_strip_section_from_output (info, htab->sbrlt);
- if (htab->srelbrlt != NULL)
- _bfd_strip_section_from_output (info, htab->srelbrlt);
- }
-
- ret = true;
+ /* It would be nice to strip .branch_lt from the output if the
+ section is empty, but it's too late. If we strip sections here,
+ the dynamic symbol table is corrupted since the section symbol
+ for the stripped section isn't written. */
- error_ret_free_local:
- while (htab->bfd_count-- > 0)
- if (htab->all_local_syms[htab->bfd_count])
- free (htab->all_local_syms[htab->bfd_count]);
- free (htab->all_local_syms);
-
- return ret;
+ return true;
}
/* Called after we have determined section placement. If sections
- move, we'll be called again. Provide a value for TOCstart, and
- store in the output bfd elf_gp. */
+ move, we'll be called again. Provide a value for TOCstart. */
-boolean
-ppc64_elf_set_toc (obfd, info)
+bfd_vma
+ppc64_elf_toc (obfd)
bfd *obfd;
- struct bfd_link_info *info;
{
- if (!info->relocateable)
- {
- asection *s;
- bfd_vma TOCstart;
+ asection *s;
+ bfd_vma TOCstart;
- /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
- order. The TOC starts where the first of these sections starts. */
- s = bfd_get_section_by_name (obfd, ".got");
- if (s == NULL)
- s = bfd_get_section_by_name (obfd, ".toc");
+ /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
+ order. The TOC starts where the first of these sections starts. */
+ s = bfd_get_section_by_name (obfd, ".got");
+ if (s == NULL)
+ s = bfd_get_section_by_name (obfd, ".toc");
+ if (s == NULL)
+ s = bfd_get_section_by_name (obfd, ".tocbss");
+ if (s == NULL)
+ s = bfd_get_section_by_name (obfd, ".plt");
+ if (s == NULL)
+ {
+ /* This may happen for
+ o references to TOC base (SYM@toc / TOC[tc0]) without a
+ .toc directive
+ o bad linker script
+ o --gc-sections and empty TOC sections
+
+ FIXME: Warn user? */
+
+ /* Look for a likely section. We probably won't even be
+ using TOCstart. */
+ for (s = obfd->sections; s != NULL; s = s->next)
+ if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY))
+ == (SEC_ALLOC | SEC_SMALL_DATA))
+ break;
if (s == NULL)
- s = bfd_get_section_by_name (obfd, ".tocbss");
+ for (s = obfd->sections; s != NULL; s = s->next)
+ if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA))
+ == (SEC_ALLOC | SEC_SMALL_DATA))
+ break;
if (s == NULL)
- s = bfd_get_section_by_name (obfd, ".plt");
+ for (s = obfd->sections; s != NULL; s = s->next)
+ if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
+ break;
if (s == NULL)
- {
- /* This may happen for
- o references to TOC base (SYM@toc / TOC[tc0]) without a
- .toc directive
- o bad linker script
- o --gc-sections and empty TOC sections
-
- FIXME: Warn user? */
-
- /* Look for a likely section. We probably won't even be
- using TOCstart. */
- for (s = obfd->sections; s != NULL; s = s->next)
- if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY))
- == (SEC_ALLOC | SEC_SMALL_DATA))
- break;
- if (s == NULL)
- for (s = obfd->sections; s != NULL; s = s->next)
- if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA))
- == (SEC_ALLOC | SEC_SMALL_DATA))
- break;
- if (s == NULL)
- for (s = obfd->sections; s != NULL; s = s->next)
- if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
- break;
- if (s == NULL)
- for (s = obfd->sections; s != NULL; s = s->next)
- if ((s->flags & SEC_ALLOC) == SEC_ALLOC)
- break;
- }
+ for (s = obfd->sections; s != NULL; s = s->next)
+ if ((s->flags & SEC_ALLOC) == SEC_ALLOC)
+ break;
+ }
- TOCstart = 0;
- if (s != NULL)
- TOCstart = s->output_section->vma + s->output_offset;
+ TOCstart = 0;
+ if (s != NULL)
+ TOCstart = s->output_section->vma + s->output_offset;
- elf_gp (obfd) = TOCstart;
- }
- return true;
+ return TOCstart;
}
/* Build all the stubs associated with the current output file.
if (htab->splt != NULL)
{
+ unsigned int indx;
+
/* Build the .glink plt call stub. */
plt_r2 = (htab->splt->output_offset
+ htab->splt->output_section->vma
- TOC_BASE_OFF);
p = htab->sglink->contents;
p = build_plt_stub (htab->sglink->owner, p, (int) plt_r2, 1);
- while (p - htab->sglink->contents < GLINK_CALL_STUB_SIZE)
+ while (p < htab->sglink->contents + GLINK_CALL_STUB_SIZE)
{
bfd_put_32 (htab->sglink->owner, NOP, p);
p += 4;
}
- htab->sglink->_cooked_size = p - htab->sglink->contents;
- /* Use reloc_count to count entries. */
- htab->sglink->reloc_count = 0;
+ /* Build the .glink lazy link call stubs. */
+ indx = 0;
+ while (p < htab->sglink->contents + htab->sglink->_raw_size)
+ {
+ if (indx < 0x8000)
+ {
+ bfd_put_32 (htab->sglink->owner, LI_R0_0 | indx, p);
+ p += 4;
+ }
+ else
+ {
+ bfd_put_32 (htab->sglink->owner, LIS_R0_0 | PPC_HI (indx), p);
+ p += 4;
+ bfd_put_32 (htab->sglink->owner, ORI_R0_R0_0 | PPC_LO (indx), p);
+ p += 4;
+ }
+ bfd_put_32 (htab->sglink->owner,
+ B_DOT | ((htab->sglink->contents - p) & 0x3fffffc), p);
+ indx++;
+ p += 4;
+ }
+ htab->sglink->_cooked_size = p - htab->sglink->contents;
}
if (htab->sbrlt->_raw_size != 0)
/* Build the stubs as directed by the stub hash table. */
bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
- htab->sglink->reloc_count = 0;
for (stub_sec = htab->stub_bfd->sections;
stub_sec != NULL;
return !htab->stub_error;
}
-/* Set up any other section flags and such that may be necessary. */
-
-static boolean
-ppc64_elf_fake_sections (abfd, shdr, asect)
- bfd *abfd ATTRIBUTE_UNUSED;
- Elf64_Internal_Shdr *shdr;
- asection *asect;
-{
- if ((asect->flags & SEC_EXCLUDE) != 0)
- shdr->sh_flags |= SHF_EXCLUDE;
-
- if ((asect->flags & SEC_SORT_ENTRIES) != 0)
- shdr->sh_type = SHT_ORDERED;
-
- return true;
-}
-
/* The RELOCATE_SECTION function is called by the ELF backend linker
to handle the relocations for a section.
/* Disabled until we sort out how ld should choose 'y' vs 'at'. */
boolean is_power4 = false;
+ if (info->relocateable)
+ return true;
+
/* Initialize howto table if needed. */
if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
ppc_howto_init ();
TOCstart = elf_gp (output_bfd);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
- is_opd = strcmp (bfd_get_section_name (abfd, input_section), ".opd") == 0;
+ is_opd = elf_section_data (input_section)->tdata != NULL;
rel = relocs;
relend = relocs + input_section->reloc_count;
unsigned long r_symndx;
bfd_vma relocation;
boolean unresolved_reloc;
+ boolean warned;
long insn;
struct ppc_stub_hash_entry *stub_entry;
bfd_vma max_br_offset;
r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE (rel->r_info);
r_symndx = ELF64_R_SYM (rel->r_info);
-
- if (info->relocateable)
- {
- /* This is a relocatable link. We don't have to change
- anything, unless the reloc is against a section symbol,
- in which case we have to adjust according to where the
- section symbol winds up in the output section. */
- if (r_symndx < symtab_hdr->sh_info)
- {
- sym = local_syms + r_symndx;
- if ((unsigned) ELF_ST_TYPE (sym->st_info) == STT_SECTION)
- {
- sec = local_sections[r_symndx];
- rel->r_addend += sec->output_offset + sym->st_value;
- }
- }
- continue;
- }
-
- /* This is a final link. */
-
offset = rel->r_offset;
addend = rel->r_addend;
r = bfd_reloc_other;
h = (struct elf_link_hash_entry *) 0;
sym_name = (const char *) 0;
unresolved_reloc = false;
+ warned = false;
if (r_type == R_PPC64_TOC)
{
sym_name = "<local symbol>";
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+ /* rel may have changed, update our copy of addend. */
+ addend = rel->r_addend;
+
+ if (elf_section_data (sec) != NULL)
+ {
+ long *opd_sym_adjust;
+
+ opd_sym_adjust = (long *) elf_section_data (sec)->tdata;
+ if (opd_sym_adjust != NULL && sym->st_value % 24 == 0)
+ relocation += opd_sym_adjust[sym->st_value / 24];
+ }
}
else
{
|| info->no_undefined
|| ELF_ST_VISIBILITY (h->other)))))
return false;
+ warned = true;
}
}
/* Branch taken prediction relocations. */
case R_PPC64_ADDR14_BRTAKEN:
case R_PPC64_REL14_BRTAKEN:
- insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */
- /* Fall thru. */
+ insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */
+ /* Fall thru. */
/* Branch not taken prediction relocations. */
case R_PPC64_ADDR14_BRNTAKEN:
}
else
{
+ from = (offset
+ + input_section->output_offset
+ + input_section->output_section->vma);
+
/* Invert 'y' bit if not the default. */
- if ((bfd_signed_vma) (relocation - offset) < 0)
+ if ((bfd_signed_vma) (relocation + addend - from) < 0)
insn ^= 0x01 << 21;
}
blr. We can thus call a weak function without first
checking whether the function is defined. We have a
blr at the end of .sfpr. */
+ BFD_ASSERT (htab->sfpr->_raw_size != 0);
relocation = (htab->sfpr->_raw_size - 4
+ htab->sfpr->output_offset
+ htab->sfpr->output_section->vma);
from = (offset
+ input_section->output_offset
+ input_section->output_section->vma);
+
/* But let's not be silly about it. If the blr isn't in
reach, just go to the next instruction. */
- if (relocation - from + (1 << 25) >= (1 << 26))
+ if (relocation - from + (1 << 25) >= (1 << 26)
+ || htab->sfpr->_raw_size == 0)
relocation = from + 4;
}
break;
relocate = true;
if (r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
{
+ if (is_opd && h != NULL)
+ {
+ /* Lie about opd entries. This case occurs
+ when building shared libraries and we
+ reference a function in another shared
+ lib. The same thing happens for a weak
+ definition in an application that's
+ overridden by a strong definition in a
+ shared lib. (I believe this is a generic
+ bug in binutils handling of weak syms.)
+ In these cases we won't use the opd
+ entry in this lib. */
+ unresolved_reloc = false;
+ }
outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
}
else
break;
}
- /* FIXME: Why do we allow debugging sections to escape this error?
- More importantly, why do we not emit dynamic relocs above in
- debugging sections (which are ! SEC_ALLOC)? If we had
- emitted the dynamic reloc, we could remove the fudge here. */
+ /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
+ because such sections are not SEC_ALLOC and thus ld.so will
+ not process them. */
if (unresolved_reloc
- && !(info->shared
- && (input_section->flags & SEC_DEBUGGING) != 0
+ && !((input_section->flags & SEC_DEBUGGING) != 0
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
- (*_bfd_error_handler)
- (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
- bfd_archive_filename (input_bfd),
- bfd_get_section_name (input_bfd, input_section),
- (long) rel->r_offset,
- h->root.root.string);
+ {
+ (*_bfd_error_handler)
+ (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
+ bfd_archive_filename (input_bfd),
+ bfd_get_section_name (input_bfd, input_section),
+ (long) rel->r_offset,
+ h->root.root.string);
+ ret = false;
+ }
r = _bfd_final_link_relocate (ppc64_elf_howto_table[(int) r_type],
input_bfd,
relocation,
addend);
- if (r == bfd_reloc_ok)
- ;
- else if (r == bfd_reloc_overflow)
+ if (r != bfd_reloc_ok)
{
const char *name;
name = bfd_section_name (input_bfd, sec);
}
- if (! ((*info->callbacks->reloc_overflow)
- (info, name, ppc64_elf_howto_table[(int) r_type]->name,
- (bfd_vma) 0, input_bfd, input_section, offset)))
- return false;
+ if (r == bfd_reloc_overflow)
+ {
+ if (warned)
+ continue;
+ if (!((*info->callbacks->reloc_overflow)
+ (info, name, ppc64_elf_howto_table[(int) r_type]->name,
+ rel->r_addend, input_bfd, input_section, offset)))
+ return false;
+ }
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%s(%s+0x%lx): reloc against `%s': error %d"),
+ bfd_archive_filename (input_bfd),
+ bfd_get_section_name (input_bfd, input_section),
+ (long) rel->r_offset, name, (int) r);
+ ret = false;
+ }
}
- else
- ret = false;
}
return ret;
Elf64_External_Rela *loc;
/* This symbol has an entry in the procedure linkage table. Set
- it up. */
+ it up. */
if (htab->splt == NULL
|| htab->srelplt == NULL
Elf64_External_Rela *loc;
/* This symbol has an entry in the global offset table. Set it
- up. */
+ up. */
if (htab->sgot == NULL || htab->srelgot == NULL)
abort ();
#define elf_backend_plt_header_size PLT_INITIAL_ENTRY_SIZE
#define elf_backend_can_gc_sections 1
#define elf_backend_can_refcount 1
+#define elf_backend_rela_normal 1
#define bfd_elf64_bfd_reloc_type_lookup ppc64_elf_reloc_type_lookup
-#define bfd_elf64_bfd_set_private_flags ppc64_elf_set_private_flags
#define bfd_elf64_bfd_merge_private_bfd_data ppc64_elf_merge_private_bfd_data
#define bfd_elf64_bfd_link_hash_table_create ppc64_elf_link_hash_table_create
#define bfd_elf64_bfd_link_hash_table_free ppc64_elf_link_hash_table_free
-#define elf_backend_section_from_shdr ppc64_elf_section_from_shdr
+#define elf_backend_object_p ppc64_elf_object_p
#define elf_backend_create_dynamic_sections ppc64_elf_create_dynamic_sections
#define elf_backend_copy_indirect_symbol ppc64_elf_copy_indirect_symbol
#define elf_backend_check_relocs ppc64_elf_check_relocs
#define elf_backend_hide_symbol ppc64_elf_hide_symbol
#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_fake_sections ppc64_elf_fake_sections
#define elf_backend_relocate_section ppc64_elf_relocate_section
#define elf_backend_finish_dynamic_symbol ppc64_elf_finish_dynamic_symbol
#define elf_backend_reloc_type_class ppc64_elf_reloc_type_class