/* PowerPC-specific support for 32-bit ELF
- Copyright (C) 1994-2017 Free Software Foundation, Inc.
+ Copyright (C) 1994-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
/* For new-style .glink and .plt. */
#define GLINK_PLTRESOLVE 16*4
-#define GLINK_ENTRY_SIZE 4*4
-#define TLS_GET_ADDR_GLINK_SIZE 12*4
+#define GLINK_ENTRY_SIZE(htab, h) \
+ ((4*4 \
+ + (h != NULL \
+ && h == htab->tls_get_addr \
+ && !htab->params->no_tls_get_addr_opt ? 8*4 : 0) \
+ + (1u << htab->params->plt_stub_align) - 1) \
+ & -(1u << htab->params->plt_stub_align))
/* VxWorks uses its own plt layout, filled in by the static linker. */
static const bfd_vma ppc_elf_vxworks_plt_entry
[VXWORKS_PLT_ENTRY_SIZE / 4] =
{
- 0x3d800000, /* lis r12,0 */
- 0x818c0000, /* lwz r12,0(r12) */
- 0x7d8903a6, /* mtctr r12 */
- 0x4e800420, /* bctr */
- 0x39600000, /* li r11,0 */
- 0x48000000, /* b 14 <.PLT0resolve+0x4> */
- 0x60000000, /* nop */
- 0x60000000, /* nop */
+ 0x3d800000, /* lis r12,0 */
+ 0x818c0000, /* lwz r12,0(r12) */
+ 0x7d8903a6, /* mtctr r12 */
+ 0x4e800420, /* bctr */
+ 0x39600000, /* li r11,0 */
+ 0x48000000, /* b 14 <.PLT0resolve+0x4> */
+ 0x60000000, /* nop */
+ 0x60000000, /* nop */
};
static const bfd_vma ppc_elf_vxworks_pic_plt_entry
[VXWORKS_PLT_ENTRY_SIZE / 4] =
static const bfd_vma ppc_elf_vxworks_plt0_entry
[VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] =
{
- 0x3d800000, /* lis r12,0 */
- 0x398c0000, /* addi r12,r12,0 */
- 0x800c0008, /* lwz r0,8(r12) */
- 0x7c0903a6, /* mtctr r0 */
- 0x818c0004, /* lwz r12,4(r12) */
- 0x4e800420, /* bctr */
- 0x60000000, /* nop */
- 0x60000000, /* nop */
+ 0x3d800000, /* lis r12,0 */
+ 0x398c0000, /* addi r12,r12,0 */
+ 0x800c0008, /* lwz r0,8(r12) */
+ 0x7c0903a6, /* mtctr r0 */
+ 0x818c0004, /* lwz r12,4(r12) */
+ 0x4e800420, /* bctr */
+ 0x60000000, /* nop */
+ 0x60000000, /* nop */
};
static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
[VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] =
{
0x819e0008, /* lwz r12,8(r30) */
- 0x7d8903a6, /* mtctr r12 */
+ 0x7d8903a6, /* mtctr r12 */
0x819e0004, /* lwz r12,4(r30) */
- 0x4e800420, /* bctr */
- 0x60000000, /* nop */
- 0x60000000, /* nop */
- 0x60000000, /* nop */
- 0x60000000, /* nop */
+ 0x4e800420, /* bctr */
+ 0x60000000, /* nop */
+ 0x60000000, /* nop */
+ 0x60000000, /* nop */
+ 0x60000000, /* nop */
};
/* For executables, we have some additional relocations in
#define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3
/* The number of relocations in the PLTResolve slot. */
#define VXWORKS_PLTRESOLVE_RELOCS 2
-/* The number of relocations in the PLTResolve slot when when creating
+/* The number of relocations in the PLTResolve slot when creating
a shared library. */
#define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0
+ (SYM)->root.u.def.section->output_offset \
+ (SYM)->root.u.def.value)
\f
+/* Relocation HOWTO's. */
+/* Like other ELF RELA targets that don't apply multiple
+ field-altering relocations to the same localation, src_mask is
+ always zero and pcrel_offset is the same as pc_relative.
+ PowerPC can always use a zero bitpos, even when the field is not at
+ the LSB. For example, a REL24 could use rightshift=2, bisize=24
+ and bitpos=2 which matches the ABI description, or as we do here,
+ rightshift=0, bitsize=26 and bitpos=0. */
+#define HOW(type, size, bitsize, mask, rightshift, pc_relative, \
+ complain, special_func) \
+ HOWTO (type, rightshift, size, bitsize, pc_relative, 0, \
+ complain_overflow_ ## complain, special_func, \
+ #type, FALSE, 0, mask, pc_relative)
+
static reloc_howto_type *ppc_elf_howto_table[R_PPC_max];
static reloc_howto_type ppc_elf_howto_raw[] = {
/* This reloc does nothing. */
- HOWTO (R_PPC_NONE, /* type */
- 0, /* rightshift */
- 3, /* size (0 = byte, 1 = short, 2 = long) */
- 0, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_NONE", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_NONE, 3, 0, 0, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
/* A standard 32 bit relocation. */
- HOWTO (R_PPC_ADDR32, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_ADDR32", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_ADDR32, 2, 32, 0xffffffff, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
/* An absolute 26 bit branch; the lower two bits must be zero.
FIXME: we don't check that, we just clear them. */
- HOWTO (R_PPC_ADDR24, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 26, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_ADDR24", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x3fffffc, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_ADDR24, 2, 26, 0x3fffffc, 0, FALSE, signed,
+ bfd_elf_generic_reloc),
/* A standard 16 bit relocation. */
- HOWTO (R_PPC_ADDR16, /* type */
- 0, /* rightshift */
- 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 */
- "R_PPC_ADDR16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_ADDR16, 1, 16, 0xffff, 0, FALSE, bitfield,
+ bfd_elf_generic_reloc),
/* A 16 bit relocation without overflow. */
- HOWTO (R_PPC_ADDR16_LO, /* type */
- 0, /* 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_PPC_ADDR16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_ADDR16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
/* The high order 16 bits of an address. */
- HOWTO (R_PPC_ADDR16_HI, /* 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_PPC_ADDR16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_ADDR16_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ bfd_elf_generic_reloc),
/* The high order 16 bits of an address, plus 1 if the contents of
the low 16 bits, treated as a signed number, is negative. */
- HOWTO (R_PPC_ADDR16_HA, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_addr16_ha_reloc, /* special_function */
- "R_PPC_ADDR16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_ADDR16_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_addr16_ha_reloc),
/* An absolute 16 bit branch; the lower two bits must be zero.
FIXME: we don't check that, we just clear them. */
- HOWTO (R_PPC_ADDR14, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_ADDR14", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xfffc, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_ADDR14, 2, 16, 0xfffc, 0, FALSE, signed,
+ bfd_elf_generic_reloc),
/* An absolute 16 bit branch, for which bit 10 should be set to
indicate that the branch is expected to be taken. The lower two
bits must be zero. */
- HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_ADDR14_BRTAKEN",/* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xfffc, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_ADDR14_BRTAKEN, 2, 16, 0xfffc, 0, FALSE, signed,
+ bfd_elf_generic_reloc),
/* An absolute 16 bit branch, for which bit 10 should be set to
indicate that the branch is not expected to be taken. The lower
two bits must be zero. */
- HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_ADDR14_BRNTAKEN",/* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xfffc, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_ADDR14_BRNTAKEN, 2, 16, 0xfffc, 0, FALSE, signed,
+ bfd_elf_generic_reloc),
/* A relative 26 bit branch; the lower two bits must be zero. */
- HOWTO (R_PPC_REL24, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 26, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_REL24", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x3fffffc, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_REL24, 2, 26, 0x3fffffc, 0, TRUE, signed,
+ bfd_elf_generic_reloc),
/* A relative 16 bit branch; the lower two bits must be zero. */
- HOWTO (R_PPC_REL14, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_REL14", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xfffc, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_REL14, 2, 16, 0xfffc, 0, TRUE, signed,
+ bfd_elf_generic_reloc),
/* A relative 16 bit branch. Bit 10 should be set to indicate that
the branch is expected to be taken. The lower two bits must be
zero. */
- HOWTO (R_PPC_REL14_BRTAKEN, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_REL14_BRTAKEN", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xfffc, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_REL14_BRTAKEN, 2, 16, 0xfffc, 0, TRUE, signed,
+ bfd_elf_generic_reloc),
/* A relative 16 bit branch. Bit 10 should be set to indicate that
the branch is not expected to be taken. The lower two bits must
be zero. */
- HOWTO (R_PPC_REL14_BRNTAKEN, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_REL14_BRNTAKEN",/* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xfffc, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_REL14_BRNTAKEN, 2, 16, 0xfffc, 0, TRUE, signed,
+ bfd_elf_generic_reloc),
/* Like R_PPC_ADDR16, but referring to the GOT table entry for the
symbol. */
- HOWTO (R_PPC_GOT16, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for
the symbol. */
- HOWTO (R_PPC_GOT16_LO, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for
the symbol. */
- HOWTO (R_PPC_GOT16_HI, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT16_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for
the symbol. */
- HOWTO (R_PPC_GOT16_HA, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT16_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like R_PPC_REL24, but referring to the procedure linkage table
entry for the symbol. */
- HOWTO (R_PPC_PLTREL24, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 26, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_PLTREL24", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x3fffffc, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_PLTREL24, 2, 26, 0x3fffffc, 0, TRUE, signed,
+ ppc_elf_unhandled_reloc),
/* This is used only by the dynamic linker. The symbol should exist
both in the object being run and in some shared library. The
dynamic linker copies the data addressed by the symbol from the
shared library into the object, because the object being
run has to have the data at some particular address. */
- HOWTO (R_PPC_COPY, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_COPY", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_COPY, 2, 32, 0, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like R_PPC_ADDR32, but used when setting global offset table
entries. */
- HOWTO (R_PPC_GLOB_DAT, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GLOB_DAT", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GLOB_DAT, 2, 32, 0xffffffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Marks a procedure linkage table entry for a symbol. */
- HOWTO (R_PPC_JMP_SLOT, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_JMP_SLOT", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_JMP_SLOT, 2, 32, 0, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Used only by the dynamic linker. When the object is run, this
longword is set to the load address of the object, plus the
addend. */
- HOWTO (R_PPC_RELATIVE, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_RELATIVE", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_RELATIVE, 2, 32, 0xffffffff, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
/* Like R_PPC_REL24, but uses the value of the symbol within the
object rather than the final value. Normally used for
_GLOBAL_OFFSET_TABLE_. */
- HOWTO (R_PPC_LOCAL24PC, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 26, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_LOCAL24PC", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x3fffffc, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_LOCAL24PC, 2, 26, 0x3fffffc, 0, TRUE, signed,
+ bfd_elf_generic_reloc),
/* Like R_PPC_ADDR32, but may be unaligned. */
- HOWTO (R_PPC_UADDR32, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_UADDR32", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_UADDR32, 2, 32, 0xffffffff, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
/* Like R_PPC_ADDR16, but may be unaligned. */
- HOWTO (R_PPC_UADDR16, /* type */
- 0, /* rightshift */
- 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 */
- "R_PPC_UADDR16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_UADDR16, 1, 16, 0xffff, 0, FALSE, bitfield,
+ bfd_elf_generic_reloc),
/* 32-bit PC relative */
- HOWTO (R_PPC_REL32, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_REL32", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_REL32, 2, 32, 0xffffffff, 0, TRUE, dont,
+ bfd_elf_generic_reloc),
/* 32-bit relocation to the symbol's procedure linkage table.
FIXME: not supported. */
- HOWTO (R_PPC_PLT32, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_PLT32", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_PLT32, 2, 32, 0, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* 32-bit PC relative relocation to the symbol's procedure linkage table.
FIXME: not supported. */
- HOWTO (R_PPC_PLTREL32, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_PLTREL32", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_PLTREL32, 2, 32, 0, 0, TRUE, dont,
+ ppc_elf_unhandled_reloc),
/* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for
the symbol. */
- HOWTO (R_PPC_PLT16_LO, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_PLT16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_PLT16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for
the symbol. */
- HOWTO (R_PPC_PLT16_HI, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_PLT16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_PLT16_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for
the symbol. */
- HOWTO (R_PPC_PLT16_HA, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_PLT16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_PLT16_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* A sign-extended 16 bit value relative to _SDA_BASE_, for use with
small data items. */
- HOWTO (R_PPC_SDAREL16, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_SDAREL16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_SDAREL16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* 16-bit section relative relocation. */
- HOWTO (R_PPC_SECTOFF, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_SECTOFF", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_SECTOFF, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* 16-bit lower half section relative relocation. */
- HOWTO (R_PPC_SECTOFF_LO, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_SECTOFF_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_SECTOFF_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* 16-bit upper half section relative relocation. */
- HOWTO (R_PPC_SECTOFF_HI, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_SECTOFF_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_SECTOFF_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* 16-bit upper half adjusted section relative relocation. */
- HOWTO (R_PPC_SECTOFF_HA, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_SECTOFF_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_SECTOFF_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Marker relocs for TLS. */
- HOWTO (R_PPC_TLS,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_TLS", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
-
- HOWTO (R_PPC_TLSGD,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_TLSGD", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
-
- HOWTO (R_PPC_TLSLD,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_TLSLD", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_TLS, 2, 32, 0, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
+
+ HOW (R_PPC_TLSGD, 2, 32, 0, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
+
+ HOW (R_PPC_TLSLD, 2, 32, 0, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
+
+ /* Marker relocs on inline plt call instructions. */
+ HOW (R_PPC_PLTSEQ, 2, 32, 0, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
+
+ HOW (R_PPC_PLTCALL, 2, 32, 0, 0, FALSE, dont,
+ bfd_elf_generic_reloc),
/* Computes the load module index of the load module that contains the
definition of its TLS sym. */
- HOWTO (R_PPC_DTPMOD32,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_DTPMOD32", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_DTPMOD32, 2, 32, 0xffffffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Computes a dtv-relative displacement, the difference between the value
of sym+add and the base address of the thread-local storage block that
contains the definition of sym, minus 0x8000. */
- HOWTO (R_PPC_DTPREL32,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_DTPREL32", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_DTPREL32, 2, 32, 0xffffffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* A 16 bit dtprel reloc. */
- HOWTO (R_PPC_DTPREL16,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_DTPREL16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_DTPREL16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* Like DTPREL16, but no overflow. */
- HOWTO (R_PPC_DTPREL16_LO,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_DTPREL16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_DTPREL16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like DTPREL16_LO, but next higher group of 16 bits. */
- HOWTO (R_PPC_DTPREL16_HI,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_DTPREL16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_DTPREL16_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like DTPREL16_HI, but adjust for low 16 bits. */
- HOWTO (R_PPC_DTPREL16_HA,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_DTPREL16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_DTPREL16_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Computes a tp-relative displacement, the difference between the value of
sym+add and the value of the thread pointer (r13). */
- HOWTO (R_PPC_TPREL32,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_TPREL32", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_TPREL32, 2, 32, 0xffffffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* A 16 bit tprel reloc. */
- HOWTO (R_PPC_TPREL16,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_TPREL16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_TPREL16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* Like TPREL16, but no overflow. */
- HOWTO (R_PPC_TPREL16_LO,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_TPREL16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_TPREL16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like TPREL16_LO, but next higher group of 16 bits. */
- HOWTO (R_PPC_TPREL16_HI,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_TPREL16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_TPREL16_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like TPREL16_HI, but adjust for low 16 bits. */
- HOWTO (R_PPC_TPREL16_HA,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_TPREL16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_TPREL16_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Allocates two contiguous entries in the GOT to hold a tls_index structure,
with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset
to the first entry. */
- HOWTO (R_PPC_GOT_TLSGD16,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TLSGD16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TLSGD16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* Like GOT_TLSGD16, but no overflow. */
- HOWTO (R_PPC_GOT_TLSGD16_LO,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TLSGD16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TLSGD16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like GOT_TLSGD16_LO, but next higher group of 16 bits. */
- HOWTO (R_PPC_GOT_TLSGD16_HI,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TLSGD16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TLSGD16_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like GOT_TLSGD16_HI, but adjust for low 16 bits. */
- HOWTO (R_PPC_GOT_TLSGD16_HA,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TLSGD16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TLSGD16_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Allocates two contiguous entries in the GOT to hold a tls_index structure,
with values (sym+add)@dtpmod and zero, and computes the offset to the
first entry. */
- HOWTO (R_PPC_GOT_TLSLD16,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TLSLD16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TLSLD16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* Like GOT_TLSLD16, but no overflow. */
- HOWTO (R_PPC_GOT_TLSLD16_LO,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TLSLD16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TLSLD16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like GOT_TLSLD16_LO, but next higher group of 16 bits. */
- HOWTO (R_PPC_GOT_TLSLD16_HI,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TLSLD16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TLSLD16_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like GOT_TLSLD16_HI, but adjust for low 16 bits. */
- HOWTO (R_PPC_GOT_TLSLD16_HA,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TLSLD16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TLSLD16_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes
the offset to the entry. */
- HOWTO (R_PPC_GOT_DTPREL16,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_DTPREL16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_DTPREL16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* Like GOT_DTPREL16, but no overflow. */
- HOWTO (R_PPC_GOT_DTPREL16_LO,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_DTPREL16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_DTPREL16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like GOT_DTPREL16_LO, but next higher group of 16 bits. */
- HOWTO (R_PPC_GOT_DTPREL16_HI,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_DTPREL16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_DTPREL16_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like GOT_DTPREL16_HI, but adjust for low 16 bits. */
- HOWTO (R_PPC_GOT_DTPREL16_HA,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_DTPREL16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_DTPREL16_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the
offset to the entry. */
- HOWTO (R_PPC_GOT_TPREL16,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TPREL16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TPREL16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* Like GOT_TPREL16, but no overflow. */
- HOWTO (R_PPC_GOT_TPREL16_LO,
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TPREL16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TPREL16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like GOT_TPREL16_LO, but next higher group of 16 bits. */
- HOWTO (R_PPC_GOT_TPREL16_HI,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TPREL16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TPREL16_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Like GOT_TPREL16_HI, but adjust for low 16 bits. */
- HOWTO (R_PPC_GOT_TPREL16_HA,
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_GOT_TPREL16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GOT_TPREL16_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* The remaining relocs are from the Embedded ELF ABI, and are not
in the SVR4 ELF ABI. */
/* 32 bit value resulting from the addend minus the symbol. */
- HOWTO (R_PPC_EMB_NADDR32, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_EMB_NADDR32", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_EMB_NADDR32, 2, 32, 0xffffffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* 16 bit value resulting from the addend minus the symbol. */
- HOWTO (R_PPC_EMB_NADDR16, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_EMB_NADDR16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_EMB_NADDR16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* 16 bit value resulting from the addend minus the symbol. */
- HOWTO (R_PPC_EMB_NADDR16_LO, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont,/* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_EMB_ADDR16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_EMB_NADDR16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* The high order 16 bits of the addend minus the symbol. */
- HOWTO (R_PPC_EMB_NADDR16_HI, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_EMB_NADDR16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_EMB_NADDR16_HI, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* The high order 16 bits of the result of the addend minus the address,
plus 1 if the contents of the low 16 bits, treated as a signed number,
is negative. */
- HOWTO (R_PPC_EMB_NADDR16_HA, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_EMB_NADDR16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_EMB_NADDR16_HA, 1, 16, 0xffff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* 16 bit value resulting from allocating a 4 byte word to hold an
address in the .sdata section, and returning the offset from
_SDA_BASE_ for that relocation. */
- HOWTO (R_PPC_EMB_SDAI16, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_EMB_SDAI16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_EMB_SDAI16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* 16 bit value resulting from allocating a 4 byte word to hold an
address in the .sdata2 section, and returning the offset from
_SDA2_BASE_ for that relocation. */
- HOWTO (R_PPC_EMB_SDA2I16, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_EMB_SDA2I16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_EMB_SDA2I16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with
small data items. */
- HOWTO (R_PPC_EMB_SDA2REL, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_EMB_SDA2REL", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_EMB_SDA2REL, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit
signed offset from the appropriate base, and filling in the register
field with the appropriate register (0, 2, or 13). */
- HOWTO (R_PPC_EMB_SDA21, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_EMB_SDA21", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_EMB_SDA21, 2, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* Relocation not handled: R_PPC_EMB_MRKREF */
/* Relocation not handled: R_PPC_EMB_RELSEC16 */
/* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling
in the 16 bit signed offset from the appropriate base, and filling in the
register field with the appropriate register (0, 2, or 13). */
- HOWTO (R_PPC_EMB_RELSDA, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_EMB_RELSDA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_EMB_RELSDA, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* A relative 8 bit branch. */
- HOWTO (R_PPC_VLE_REL8, /* type */
- 1, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 8, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_REL8", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xff, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_VLE_REL8, 1, 8, 0xff, 1, TRUE, signed,
+ bfd_elf_generic_reloc),
/* A relative 15 bit branch. */
- HOWTO (R_PPC_VLE_REL15, /* type */
- 1, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 15, /* bitsize */
- TRUE, /* pc_relative */
- 1, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_REL15", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xfffe, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_VLE_REL15, 2, 16, 0xfffe, 0, TRUE, signed,
+ bfd_elf_generic_reloc),
/* A relative 24 bit branch. */
- HOWTO (R_PPC_VLE_REL24, /* type */
- 1, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 24, /* bitsize */
- TRUE, /* pc_relative */
- 1, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_REL24", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1fffffe, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_VLE_REL24, 2, 25, 0x1fffffe, 0, TRUE, signed,
+ bfd_elf_generic_reloc),
/* The 16 LSBS in split16a format. */
- HOWTO (R_PPC_VLE_LO16A, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_LO16A", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f07ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_LO16A, 2, 16, 0x1f07ff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* The 16 LSBS in split16d format. */
- HOWTO (R_PPC_VLE_LO16D, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_LO16D", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f007ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_LO16D, 2, 16, 0x3e007ff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Bits 16-31 split16a format. */
- HOWTO (R_PPC_VLE_HI16A, /* type */
- 16, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_HI16A", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f07ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_HI16A, 2, 16, 0x1f07ff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Bits 16-31 split16d format. */
- HOWTO (R_PPC_VLE_HI16D, /* type */
- 16, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_HI16D", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f007ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_HI16D, 2, 16, 0x3e007ff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Bits 16-31 (High Adjusted) in split16a format. */
- HOWTO (R_PPC_VLE_HA16A, /* type */
- 16, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_HA16A", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f07ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_HA16A, 2, 16, 0x1f07ff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Bits 16-31 (High Adjusted) in split16d format. */
- HOWTO (R_PPC_VLE_HA16D, /* type */
- 16, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_HA16D", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f007ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_HA16D, 2, 16, 0x3e007ff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* This reloc is like R_PPC_EMB_SDA21 but only applies to e_add16i
instructions. If the register base is 0 then the linker changes
the e_add16i to an e_li instruction. */
- HOWTO (R_PPC_VLE_SDA21, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_SDA21", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_SDA21, 2, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
/* Like R_PPC_VLE_SDA21 but ignore overflow. */
- HOWTO (R_PPC_VLE_SDA21_LO, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_SDA21_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_SDA21_LO, 2, 16, 0xffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* The 16 LSBS relative to _SDA_BASE_ in split16a format. */
- HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_LO16A", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f07ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_SDAREL_LO16A, 2, 16, 0x1f07ff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* The 16 LSBS relative to _SDA_BASE_ in split16d format. */
- HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_LO16D", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f007ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_SDAREL_LO16D, 2, 16, 0x3e007ff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Bits 16-31 relative to _SDA_BASE_ in split16a format. */
- HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */
- 16, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_HI16A", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f07ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_SDAREL_HI16A, 2, 16, 0x1f07ff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Bits 16-31 relative to _SDA_BASE_ in split16d format. */
- HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */
- 16, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_HI16D", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f007ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_SDAREL_HI16D, 2, 16, 0x3e007ff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */
- HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */
- 16, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_HA16A", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f07ff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_SDAREL_HA16A, 2, 16, 0x1f07ff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */
- HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */
- 16, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_HA16D", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1f007ff, /* dst_mask */
- FALSE), /* pcrel_offset */
-
- HOWTO (R_PPC_IRELATIVE, /* type */
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_IRELATIVE", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_VLE_SDAREL_HA16D, 2, 16, 0x3e007ff, 16, FALSE, dont,
+ ppc_elf_unhandled_reloc),
+
+ /* e_li split20 format. */
+ HOW (R_PPC_VLE_ADDR20, 2, 20, 0x1f7fff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
+
+ HOW (R_PPC_IRELATIVE, 2, 32, 0xffffffff, 0, FALSE, dont,
+ ppc_elf_unhandled_reloc),
/* A 16 bit relative relocation. */
- HOWTO (R_PPC_REL16, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_REL16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_REL16, 1, 16, 0xffff, 0, TRUE, signed,
+ bfd_elf_generic_reloc),
/* A 16 bit relative relocation without overflow. */
- HOWTO (R_PPC_REL16_LO, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont,/* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_REL16_LO", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_REL16_LO, 1, 16, 0xffff, 0, TRUE, dont,
+ bfd_elf_generic_reloc),
/* The high order 16 bits of a relative address. */
- HOWTO (R_PPC_REL16_HI, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_REL16_HI", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_REL16_HI, 1, 16, 0xffff, 16, TRUE, dont,
+ bfd_elf_generic_reloc),
/* The high order 16 bits of a relative address, plus 1 if the contents of
the low 16 bits, treated as a signed number, is negative. */
- HOWTO (R_PPC_REL16_HA, /* type */
- 16, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_addr16_ha_reloc, /* special_function */
- "R_PPC_REL16_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_REL16_HA, 1, 16, 0xffff, 16, TRUE, dont,
+ ppc_elf_addr16_ha_reloc),
/* Like R_PPC_REL16_HA but for split field in addpcis. */
- HOWTO (R_PPC_REL16DX_HA, /* type */
- 16, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_addr16_ha_reloc, /* special_function */
- "R_PPC_REL16DX_HA", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0x1fffc1, /* dst_mask */
- TRUE), /* pcrel_offset */
+ HOW (R_PPC_REL16DX_HA, 2, 16, 0x1fffc1, 16, TRUE, signed,
+ ppc_elf_addr16_ha_reloc),
+
+ /* A split-field reloc for addpcis, non-relative (gas internal use only). */
+ HOW (R_PPC_16DX_HA, 2, 16, 0x1fffc1, 16, FALSE, signed,
+ ppc_elf_addr16_ha_reloc),
/* GNU extension to record C++ vtable hierarchy. */
- HOWTO (R_PPC_GNU_VTINHERIT, /* type */
- 0, /* rightshift */
- 0, /* size (0 = byte, 1 = short, 2 = long) */
- 0, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- NULL, /* special_function */
- "R_PPC_GNU_VTINHERIT", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GNU_VTINHERIT, 0, 0, 0, 0, FALSE, dont,
+ NULL),
/* GNU extension to record C++ vtable member usage. */
- HOWTO (R_PPC_GNU_VTENTRY, /* type */
- 0, /* rightshift */
- 0, /* size (0 = byte, 1 = short, 2 = long) */
- 0, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- NULL, /* special_function */
- "R_PPC_GNU_VTENTRY", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_GNU_VTENTRY, 0, 0, 0, 0, FALSE, dont,
+ NULL),
/* Phony reloc to handle AIX style TOC entries. */
- HOWTO (R_PPC_TOC16, /* type */
- 0, /* rightshift */
- 1, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
- FALSE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- ppc_elf_unhandled_reloc, /* special_function */
- "R_PPC_TOC16", /* name */
- FALSE, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- FALSE), /* pcrel_offset */
+ HOW (R_PPC_TOC16, 1, 16, 0xffff, 0, FALSE, signed,
+ ppc_elf_unhandled_reloc),
};
-
-/* External 32-bit PPC structure for PRPSINFO. This structure is
- ABI-defined, thus we choose to use char arrays here in order to
- avoid dealing with different types in different architectures.
-
- The PPC 32-bit structure uses int for `pr_uid' and `pr_gid' while
- most non-PPC architectures use `short int'.
-
- This structure will ultimately be written in the corefile's note
- section, as the PRPSINFO. */
-
-struct elf_external_ppc_linux_prpsinfo32
- {
- char pr_state; /* Numeric process state. */
- char pr_sname; /* Char for pr_state. */
- char pr_zomb; /* Zombie. */
- char pr_nice; /* Nice val. */
- char pr_flag[4]; /* Flags. */
- char pr_uid[4];
- char pr_gid[4];
- char pr_pid[4];
- char pr_ppid[4];
- char pr_pgrp[4];
- char pr_sid[4];
- char pr_fname[16]; /* Filename of executable. */
- char pr_psargs[80]; /* Initial part of arg list. */
- };
-
-/* Helper function to copy an elf_internal_linux_prpsinfo in host
- endian to an elf_external_ppc_linux_prpsinfo32 in target endian. */
-
-static inline void
-swap_ppc_linux_prpsinfo32_out (bfd *obfd,
- const struct elf_internal_linux_prpsinfo *from,
- struct elf_external_ppc_linux_prpsinfo32 *to)
-{
- bfd_put_8 (obfd, from->pr_state, &to->pr_state);
- bfd_put_8 (obfd, from->pr_sname, &to->pr_sname);
- bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb);
- bfd_put_8 (obfd, from->pr_nice, &to->pr_nice);
- bfd_put_32 (obfd, from->pr_flag, to->pr_flag);
- bfd_put_32 (obfd, from->pr_uid, to->pr_uid);
- bfd_put_32 (obfd, from->pr_gid, to->pr_gid);
- bfd_put_32 (obfd, from->pr_pid, to->pr_pid);
- bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid);
- bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp);
- bfd_put_32 (obfd, from->pr_sid, to->pr_sid);
- strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname));
- strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs));
-}
\f
/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */
case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break;
case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break;
case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break;
+ case BFD_RELOC_PPC_16DX_HA: r = R_PPC_16DX_HA; break;
case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC_REL16DX_HA; break;
case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break;
case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break;
/* Set the howto pointer for a PowerPC ELF reloc. */
-static void
-ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
+static bfd_boolean
+ppc_elf_info_to_howto (bfd *abfd,
arelent *cache_ptr,
Elf_Internal_Rela *dst)
{
if (r_type >= R_PPC_max)
{
/* xgettext:c-format */
- _bfd_error_handler (_("%B: unrecognised PPC reloc number: %d"),
+ _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
abfd, r_type);
bfd_set_error (bfd_error_bad_value);
- r_type = R_PPC_NONE;
+ return FALSE;
}
+
cache_ptr->howto = ppc_elf_howto_table[r_type];
/* Just because the above assert didn't trigger doesn't mean that
ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation. */
- if (!cache_ptr->howto)
+ if (cache_ptr->howto == NULL)
{
/* xgettext:c-format */
- _bfd_error_handler (_("%B: invalid relocation type %d"),
+ _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
abfd, r_type);
bfd_set_error (bfd_error_bad_value);
- cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
+ return FALSE;
}
+
+ return TRUE;
}
/* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs. */
static bfd_reloc_status_type
-ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+ppc_elf_addr16_ha_reloc (bfd *abfd,
arelent *reloc_entry,
asymbol *symbol,
- void *data ATTRIBUTE_UNUSED,
+ void *data,
asection *input_section,
bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
if (mach == 0)
{
s = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
- if (s != NULL && bfd_malloc_and_get_section (abfd, s, &contents))
+ if (s != NULL
+ && s->size >= 24
+ && bfd_malloc_and_get_section (abfd, s, &contents))
{
unsigned int apuinfo_size = bfd_get_32 (abfd, contents + 4);
unsigned int i;
return TRUE;
}
-char *
-elfcore_write_ppc_linux_prpsinfo32
- (bfd *abfd,
- char *buf,
- int *bufsiz,
- const struct elf_internal_linux_prpsinfo *prpsinfo)
-{
- struct elf_external_ppc_linux_prpsinfo32 data;
-
- swap_ppc_linux_prpsinfo32_out (abfd, prpsinfo, &data);
- return elfcore_write_note (abfd, buf, bufsiz,
- "CORE", NT_PRPSINFO, &data, sizeof (data));
-}
-
static char *
ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...)
{
case NT_PRPSINFO:
{
- char data[128];
+ char data[128] ATTRIBUTE_NONSTRING;
va_list ap;
va_start (ap, note_type);
memset (data, 0, sizeof (data));
strncpy (data + 32, va_arg (ap, const char *), 16);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+ DIAGNOSTIC_PUSH;
+ /* GCC 8.0 and 8.1 warn about 80 equals destination size with
+ -Wstringop-truncation:
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
+ */
+ DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
+#endif
strncpy (data + 48, va_arg (ap, const char *), 80);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+ DIAGNOSTIC_POP;
+#endif
va_end (ap);
return elfcore_write_note (abfd, buf, bufsiz,
"CORE", note_type, data, sizeof (data));
amt += (m->count - j - 1) * sizeof (asection *);
n = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
if (n == NULL)
- return FALSE;
+ return FALSE;
n->p_type = PT_LOAD;
n->count = m->count - j;
/* This is what we want for new plt/got. */
static struct bfd_elf_special_section ppc_alt_plt =
- { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC };
+ { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC };
static const struct bfd_elf_special_section *
-ppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+ppc_elf_get_sec_type_attr (bfd *abfd, asection *sec)
{
const struct bfd_elf_special_section *ssect;
continue;
/* xgettext:c-format */
- error_message = _("corrupt %s section in %B");
+ error_message = _("corrupt %s section in %pB");
length = asec->size;
if (length < 20)
goto fail;
|| (bfd_bread (buffer, length, ibfd) != length))
{
/* xgettext:c-format */
- error_message = _("unable to read in %s section from %B");
+ error_message = _("unable to read in %s section from %pB");
goto fail;
}
{
ibfd = abfd;
/* xgettext:c-format */
- error_message = _("warning: unable to set size of %s section in %B");
+ error_message = _("warning: unable to set size of %s section in %pB");
}
}
free (buffer);
if (error_message)
- _bfd_error_handler (error_message, ibfd, APUINFO_SECTION_NAME);
+ _bfd_error_handler (error_message, APUINFO_SECTION_NAME, ibfd);
}
/* Prevent the output section from accumulating the input sections'
/* Finally we can generate the output section. */
static void
-ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
+ppc_final_write_processing (bfd *abfd)
{
bfd_byte *buffer;
asection *asec;
if (buffer == NULL)
{
_bfd_error_handler
- (_("failed to allocate space for new APUinfo section."));
+ (_("failed to allocate space for new APUinfo section"));
return;
}
}
if (length != asec->size)
- _bfd_error_handler (_("failed to compute new APUinfo section."));
+ _bfd_error_handler (_("failed to compute new APUinfo section"));
if (! bfd_set_section_contents (abfd, asec, buffer, (file_ptr) 0, length))
- _bfd_error_handler (_("failed to install new APUinfo section."));
+ _bfd_error_handler (_("failed to install new APUinfo section"));
free (buffer);
apuinfo_list_finish ();
}
+
+static bfd_boolean
+ppc_elf_final_write_processing (bfd *abfd)
+{
+ ppc_final_write_processing (abfd);
+ return _bfd_elf_final_write_processing (abfd);
+}
\f
static bfd_boolean
is_nonpic_glink_stub (bfd *abfd, asection *glink, bfd_vma off)
{
- bfd_byte buf[GLINK_ENTRY_SIZE];
+ bfd_byte buf[4 * 4];
- if (!bfd_get_section_contents (abfd, glink, buf, off, GLINK_ENTRY_SIZE))
+ if (!bfd_get_section_contents (abfd, glink, buf, off, sizeof buf))
return FALSE;
return ((bfd_get_32 (abfd, buf + 0) & 0xffff0000) == LIS_11
asection *plt, *relplt, *dynamic, *glink;
bfd_vma glink_vma = 0;
bfd_vma resolv_vma = 0;
- bfd_vma stub_vma;
+ bfd_vma stub_off;
asymbol *s;
arelent *p;
- long count, i;
+ long count, i, stub_delta;
size_t size;
char *names;
bfd_byte buf[4];
/* If the stubs are those for -shared/-pie then we might have
multiple stubs for each plt entry. If that is the case then
there is no way to associate stubs with their plt entries short
- of figuring out the GOT pointer value used in the stub. */
- if (!is_nonpic_glink_stub (abfd, glink,
- glink_vma - GLINK_ENTRY_SIZE - glink->vma))
+ of figuring out the GOT pointer value used in the stub.
+ The offsets tested here need to cover all possible values of
+ GLINK_ENTRY_SIZE for other than __tls_get_addr_opt. */
+ stub_off = glink_vma - glink->vma;
+ for (stub_delta = 16; stub_delta <= 32; stub_delta += 8)
+ if (is_nonpic_glink_stub (abfd, glink, stub_off - stub_delta))
+ break;
+ if (stub_delta > 32)
return 0;
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
if (s == NULL)
return -1;
- stub_vma = glink_vma;
+ stub_off = glink_vma - glink->vma;
names = (char *) (s + count + 1 + (resolv_vma != 0));
p = relplt->relocation + count - 1;
for (i = 0; i < count; i++)
{
size_t len;
+ stub_off -= stub_delta;
+ if (strcmp ((*p->sym_ptr_ptr)->name, "__tls_get_addr_opt") == 0)
+ stub_off -= 32;
*s = **p->sym_ptr_ptr;
/* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since
we are defining a symbol, ensure one of them is set. */
s->flags |= BSF_GLOBAL;
s->flags |= BSF_SYNTHETIC;
s->section = glink;
- stub_vma -= 16;
- if (strcmp ((*p->sym_ptr_ptr)->name, "__tls_get_addr_opt") == 0)
- stub_vma -= 32;
- s->value = stub_vma - glink->vma;
+ s->value = stub_off;
s->name = names;
s->udata.p = NULL;
len = strlen ((*p->sym_ptr_ptr)->name);
bfd_vma glink_offset;
};
-/* Of those relocs that might be copied as dynamic relocs, this function
- selects those that must be copied when linking a shared library,
- even when the symbol is local. */
+/* Of those relocs that might be copied as dynamic relocs, this
+ function selects those that must be copied when linking a shared
+ library or PIE, even when the symbol is local. */
static int
must_be_dyn_reloc (struct bfd_link_info *info,
switch (r_type)
{
default:
+ /* Only relative relocs can be resolved when the object load
+ address isn't fixed. DTPREL32 is excluded because the
+ dynamic linker needs to differentiate global dynamic from
+ local dynamic __tls_index pairs when PPC_OPT_TLS is set. */
return 1;
case R_PPC_REL24:
case R_PPC_TPREL16_LO:
case R_PPC_TPREL16_HI:
case R_PPC_TPREL16_HA:
- return !bfd_link_executable (info);
+ /* These relocations are relative but in a shared library the
+ linker doesn't know the thread pointer base. */
+ return bfd_link_dll (info);
}
}
/* Track dynamic relocs copied for this symbol. */
struct elf_dyn_relocs *dyn_relocs;
- /* Contexts in which symbol is used in the GOT (or TOC).
- TLS_GD .. TLS_TLS bits are or'd into the mask as the
- corresponding relocs are encountered during check_relocs.
- tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to
- indicate the corresponding GOT entry type is not needed. */
-#define TLS_GD 1 /* GD reloc. */
-#define TLS_LD 2 /* LD reloc. */
-#define TLS_TPREL 4 /* TPREL reloc, => IE. */
-#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */
-#define TLS_TLS 16 /* Any TLS reloc. */
-#define TLS_TPRELGD 32 /* TPREL reloc resulting from GD->IE. */
-#define PLT_IFUNC 64 /* STT_GNU_IFUNC. */
- char tls_mask;
+ /* Contexts in which symbol is used in the GOT.
+ Bits are or'd into the mask as the corresponding relocs are
+ encountered during check_relocs, with TLS_TLS being set when any
+ of the other TLS bits are set. tls_optimize clears bits when
+ optimizing to indicate the corresponding GOT entry type is not
+ needed. If set, TLS_TLS is never cleared. tls_optimize may also
+ set TLS_GDIE when a GD reloc turns into an IE one.
+ These flags are also kept for local symbols. */
+#define TLS_TLS 1 /* Any TLS reloc. */
+#define TLS_GD 2 /* GD reloc. */
+#define TLS_LD 4 /* LD reloc. */
+#define TLS_TPREL 8 /* TPREL reloc, => IE. */
+#define TLS_DTPREL 16 /* DTPREL reloc, => LD. */
+#define TLS_MARK 32 /* __tls_get_addr call marked. */
+#define TLS_GDIE 64 /* GOT TPREL reloc resulting from GD->IE. */
+ unsigned char tls_mask;
+
+ /* The above field is also used to mark function symbols. In which
+ case TLS_TLS will be 0. */
+#define PLT_IFUNC 2 /* STT_GNU_IFUNC. */
+#define PLT_KEEP 4 /* inline plt call requires plt entry. */
+#define NON_GOT 256 /* local symbol plt, not stored. */
/* Nonzero if we have seen a small data relocation referring to this
symbol. */
elf_linker_section_t sdata[2];
asection *sbss;
asection *glink_eh_frame;
+ asection *pltlocal;
+ asection *relpltlocal;
/* The (unloaded but important) .rela.plt.unloaded on VxWorks. */
asection *srelplt2;
/* True if the target system is VxWorks. */
unsigned int is_vxworks:1;
+ /* Whether there exist local gnu indirect function resolvers,
+ referenced by dynamic relocations. */
+ unsigned int local_ifunc_resolver:1;
+ unsigned int maybe_local_ifunc_resolver:1;
+
+ /* Set if tls optimization is enabled. */
+ unsigned int do_tls_opt:1;
+
+ /* Set if inline plt calls should be converted to direct calls. */
+ unsigned int can_convert_all_inline_plt:1;
+
/* The size of PLT entries. */
int plt_entry_size;
/* The distance between adjacent PLT slots. */
/* Nonzero if this section has a call to __tls_get_addr. */
#define has_tls_get_addr_call sec_flg1
+ /* Flag set when PLTCALL relocs are detected. */
+#define has_pltcall sec_flg2
+
/* Get the PPC ELF linker hash table from a link_info structure. */
#define ppc_elf_hash_table(p) \
{
struct ppc_elf_link_hash_table *ret;
static struct ppc_elf_params default_params
- = { PLT_OLD, 0, 1, 0, 0, 12, 0, 0, 0 };
+ = { PLT_OLD, 0, 0, 1, 0, 0, 12, 0, 0, 0 };
ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
if (ret == NULL)
struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
asection *s;
flagword flags;
+ int p2align;
flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY | SEC_HAS_CONTENTS
| SEC_IN_MEMORY | SEC_LINKER_CREATED);
s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags);
htab->glink = s;
+ p2align = htab->params->ppc476_workaround ? 6 : 4;
+ if (p2align < htab->params->plt_stub_align)
+ p2align = htab->params->plt_stub_align;
if (s == NULL
- || !bfd_set_section_alignment (abfd, s,
- htab->params->ppc476_workaround ? 6 : 4))
+ || !bfd_set_section_alignment (abfd, s, p2align))
return FALSE;
if (!info->no_ld_generated_unwind_info)
|| ! bfd_set_section_alignment (abfd, s, 2))
return FALSE;
+ /* Local plt entries. */
+ flags = (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->pltlocal = bfd_make_section_anyway_with_flags (abfd, ".branch_lt",
+ flags);
+ if (htab->pltlocal == NULL
+ || ! bfd_set_section_alignment (abfd, htab->pltlocal, 2))
+ return FALSE;
+
+ if (bfd_link_pic (info))
+ {
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->relpltlocal
+ = bfd_make_section_anyway_with_flags (abfd, ".rela.branch_lt", flags);
+ if (htab->relpltlocal == NULL
+ || ! bfd_set_section_alignment (abfd, htab->relpltlocal, 2))
+ return FALSE;
+ }
+
if (!ppc_elf_create_linker_section (abfd, info, 0,
&htab->sdata[0]))
return FALSE;
edir->tls_mask |= eind->tls_mask;
edir->has_sda_refs |= eind->has_sda_refs;
- /* If called to transfer flags for a weakdef during processing
- of elf_adjust_dynamic_symbol, don't copy non_got_ref.
- We clear it ourselves for ELIMINATE_COPY_RELOCS. */
- if (!(ELIMINATE_COPY_RELOCS
- && eind->elf.root.type != bfd_link_hash_indirect
- && edir->elf.dynamic_adjusted))
- edir->elf.non_got_ref |= eind->elf.non_got_ref;
-
if (edir->elf.versioned != versioned_hidden)
edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
edir->elf.ref_regular |= eind->elf.ref_regular;
edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
+ edir->elf.non_got_ref |= eind->elf.non_got_ref;
edir->elf.needs_plt |= eind->elf.needs_plt;
edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed;
+ /* If we were called to copy over info for a weak sym, that's all. */
+ if (eind->elf.root.type != bfd_link_hash_indirect)
+ return;
+
if (eind->dyn_relocs != NULL)
{
if (edir->dyn_relocs != NULL)
eind->dyn_relocs = NULL;
}
- /* 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
- code in ppc_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. */
- if (eind->elf.root.type != bfd_link_hash_indirect)
- return;
-
/* Copy over the GOT refcount entries that we may have already seen to
the symbol which just became indirect. */
edir->elf.got.refcount += eind->elf.got.refcount;
*valp = sym->st_size;
}
- if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
- && (abfd->flags & DYNAMIC) == 0
- && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
- elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
-
return TRUE;
}
\f
{
bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd);
struct plt_entry **local_plt;
- char *local_got_tls_masks;
+ unsigned char *local_got_tls_masks;
if (local_got_refcounts == NULL)
{
}
local_plt = (struct plt_entry **) (local_got_refcounts + symtab_hdr->sh_info);
- local_got_tls_masks = (char *) (local_plt + symtab_hdr->sh_info);
- local_got_tls_masks[r_symndx] |= tls_type;
- if (tls_type != PLT_IFUNC)
+ local_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info);
+ local_got_tls_masks[r_symndx] |= tls_type & 0xff;
+ if ((tls_type & NON_GOT) == 0)
local_got_refcounts[r_symndx] += 1;
return local_plt + r_symndx;
}
|| r_type == R_PPC_VLE_REL24);
}
+/* Relocs on inline plt call sequence insns prior to the call. */
+
+static bfd_boolean
+is_plt_seq_reloc (enum elf_ppc_reloc_type r_type)
+{
+ return (r_type == R_PPC_PLT16_HA
+ || r_type == R_PPC_PLT16_HI
+ || r_type == R_PPC_PLT16_LO
+ || r_type == R_PPC_PLTSEQ);
+}
+
static void
bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: relocation %s cannot be used when making a shared object"),
+ (_("%pB: relocation %s cannot be used when making a shared object"),
abfd,
ppc_elf_howto_table[r_type]->name);
bfd_set_error (bfd_error_bad_value);
return TRUE;
#ifdef DEBUG
- _bfd_error_handler ("ppc_elf_check_relocs called for section %A in %B",
+ _bfd_error_handler ("ppc_elf_check_relocs called for section %pA in %pB",
sec, abfd);
#endif
struct elf_link_hash_entry *h;
int tls_type;
struct plt_entry **ifunc;
+ struct plt_entry **pltent;
+ bfd_vma addend;
r_symndx = ELF32_R_SYM (rel->r_info);
if (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;
-
- /* PR15323, ref flags aren't set for references in the same
- object. */
- h->root.non_ir_ref = 1;
}
/* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
{
/* Set PLT_IFUNC flag for this sym, no GOT entry yet. */
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
- PLT_IFUNC);
+ NON_GOT | PLT_IFUNC);
if (ifunc == NULL)
return FALSE;
In a non-pie executable even when there are
no plt calls. */
if (!bfd_link_pic (info)
- || is_branch_reloc (r_type))
+ || is_branch_reloc (r_type)
+ || r_type == R_PPC_PLT16_LO
+ || r_type == R_PPC_PLT16_HI
+ || r_type == R_PPC_PLT16_HA)
{
- bfd_vma addend = 0;
+ addend = 0;
if (r_type == R_PPC_PLTREL24)
- {
- ppc_elf_tdata (abfd)->makes_plt_call = 1;
- if (bfd_link_pic (info))
- addend = rel->r_addend;
- }
+ ppc_elf_tdata (abfd)->makes_plt_call = 1;
+ if (bfd_link_pic (info)
+ && (r_type == R_PPC_PLTREL24
+ || r_type == R_PPC_PLT16_LO
+ || r_type == R_PPC_PLT16_HI
+ || r_type == R_PPC_PLT16_HA))
+ addend = rel->r_addend;
if (!update_plt_info (abfd, ifunc, got2, addend))
return FALSE;
}
case R_PPC_TLSLD:
/* These special tls relocs tie a call to __tls_get_addr with
its parameter symbol. */
+ if (h != NULL)
+ ppc_elf_hash_entry (h)->tls_mask |= TLS_TLS | TLS_MARK;
+ else
+ if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
+ NON_GOT | TLS_TLS | TLS_MARK))
+ return FALSE;
+ break;
+
+ case R_PPC_PLTSEQ:
break;
case R_PPC_GOT_TLSLD16:
case R_PPC_GOT_TPREL16_LO:
case R_PPC_GOT_TPREL16_HI:
case R_PPC_GOT_TPREL16_HA:
- if (bfd_link_pic (info))
+ if (bfd_link_dll (info))
info->flags |= DF_STATIC_TLS;
tls_type = TLS_TLS | TLS_TPREL;
goto dogottls;
case R_PPC_VLE_HI16D:
case R_PPC_VLE_HA16A:
case R_PPC_VLE_HA16D:
+ case R_PPC_VLE_ADDR20:
break;
case R_PPC_EMB_SDA2REL:
case R_PPC_PLTREL24:
if (h == NULL)
break;
- /* Fall through */
+ ppc_elf_tdata (abfd)->makes_plt_call = 1;
+ goto pltentry;
+
+ case R_PPC_PLTCALL:
+ sec->has_pltcall = 1;
+ /* Fall through. */
+
case R_PPC_PLT32:
case R_PPC_PLTREL32:
case R_PPC_PLT16_LO:
case R_PPC_PLT16_HI:
case R_PPC_PLT16_HA:
+ pltentry:
#ifdef DEBUG
fprintf (stderr, "Reloc requires a PLT entry\n");
#endif
/* This symbol requires a procedure linkage table entry. */
if (h == NULL)
{
- if (ifunc == NULL)
- {
- /* It does not make sense to have a procedure linkage
- table entry for a non-ifunc local symbol. */
- info->callbacks->einfo
- /* xgettext:c-format */
- (_("%P: %H: %s reloc against local symbol\n"),
- abfd, sec, rel->r_offset,
- ppc_elf_howto_table[r_type]->name);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
+ pltent = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+ NON_GOT | PLT_KEEP);
+ if (pltent == NULL)
+ return FALSE;
}
else
{
- bfd_vma addend = 0;
-
- if (r_type == R_PPC_PLTREL24)
- {
- ppc_elf_tdata (abfd)->makes_plt_call = 1;
- if (bfd_link_pic (info))
- addend = rel->r_addend;
- }
+ if (r_type != R_PPC_PLTREL24)
+ ppc_elf_hash_entry (h)->tls_mask |= PLT_KEEP;
h->needs_plt = 1;
- if (!update_plt_info (abfd, &h->plt.plist, got2, addend))
- return FALSE;
+ pltent = &h->plt.plist;
}
+ addend = 0;
+ if (bfd_link_pic (info)
+ && (r_type == R_PPC_PLTREL24
+ || r_type == R_PPC_PLT16_LO
+ || r_type == R_PPC_PLT16_HI
+ || r_type == R_PPC_PLT16_HA))
+ addend = rel->r_addend;
+ if (!update_plt_info (abfd, pltent, got2, addend))
+ return FALSE;
break;
/* The following relocations don't need to propagate the
case R_PPC_RELAX:
case R_PPC_RELAX_PLT:
case R_PPC_RELAX_PLTREL24:
+ case R_PPC_16DX_HA:
break;
/* These should only appear in dynamic objects. */
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_PPC_GNU_VTENTRY:
- BFD_ASSERT (h != NULL);
- if (h != NULL
- && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
return FALSE;
break;
- /* We shouldn't really be seeing these. */
+ /* We shouldn't really be seeing TPREL32. */
case R_PPC_TPREL32:
case R_PPC_TPREL16:
case R_PPC_TPREL16_LO:
case R_PPC_TPREL16_HI:
case R_PPC_TPREL16_HA:
- if (bfd_link_pic (info))
+ if (bfd_link_dll (info))
info->flags |= DF_STATIC_TLS;
goto dodyn;
\f
/* Warn for conflicting Tag_GNU_Power_ABI_FP attributes between IBFD
and OBFD, and merge non-conflicting ones. */
-void
+bfd_boolean
_bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
{
bfd *obfd = info->output_bfd;
obj_attribute *in_attr, *in_attrs;
obj_attribute *out_attr, *out_attrs;
+ bfd_boolean ret = TRUE;
in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
{
int in_fp = in_attr->i & 3;
int out_fp = out_attr->i & 3;
+ static bfd *last_fp, *last_ld;
if (in_fp == 0)
;
else if (out_fp == 0)
{
- out_attr->type = 1;
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
out_attr->i ^= in_fp;
+ last_fp = ibfd;
}
else if (out_fp != 2 && in_fp == 2)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses hard float, %pB uses soft float"),
+ last_fp, ibfd);
+ ret = FALSE;
+ }
else if (out_fp == 2 && in_fp != 2)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses hard float, %pB uses soft float"),
+ ibfd, last_fp);
+ ret = FALSE;
+ }
else if (out_fp == 1 && in_fp == 3)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses double-precision hard float, "
- "%B uses single-precision hard float"), obfd, ibfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses double-precision hard float, "
+ "%pB uses single-precision hard float"), last_fp, ibfd);
+ ret = FALSE;
+ }
else if (out_fp == 3 && in_fp == 1)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses double-precision hard float, "
- "%B uses single-precision hard float"), ibfd, obfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses double-precision hard float, "
+ "%pB uses single-precision hard float"), ibfd, last_fp);
+ ret = FALSE;
+ }
in_fp = in_attr->i & 0xc;
out_fp = out_attr->i & 0xc;
;
else if (out_fp == 0)
{
- out_attr->type = 1;
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
out_attr->i ^= in_fp;
+ last_ld = ibfd;
}
else if (out_fp != 2 * 4 && in_fp == 2 * 4)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses 64-bit long double, "
- "%B uses 128-bit long double"), ibfd, obfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses 64-bit long double, "
+ "%pB uses 128-bit long double"), ibfd, last_ld);
+ ret = FALSE;
+ }
else if (in_fp != 2 * 4 && out_fp == 2 * 4)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses 64-bit long double, "
- "%B uses 128-bit long double"), obfd, ibfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses 64-bit long double, "
+ "%pB uses 128-bit long double"), last_ld, ibfd);
+ ret = FALSE;
+ }
else if (out_fp == 1 * 4 && in_fp == 3 * 4)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses IBM long double, "
- "%B uses IEEE long double"), ibfd, obfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses IBM long double, "
+ "%pB uses IEEE long double"), last_ld, ibfd);
+ ret = FALSE;
+ }
else if (out_fp == 3 * 4 && in_fp == 1 * 4)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses IBM long double, "
- "%B uses IEEE long double"), obfd, ibfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses IBM long double, "
+ "%pB uses IEEE long double"), ibfd, last_ld);
+ ret = FALSE;
+ }
+ }
+
+ if (!ret)
+ {
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+ bfd_set_error (bfd_error_bad_value);
}
+ return ret;
}
/* Merge object attributes from IBFD into OBFD. Warn if
bfd *obfd;
obj_attribute *in_attr, *in_attrs;
obj_attribute *out_attr, *out_attrs;
+ bfd_boolean ret;
- _bfd_elf_ppc_merge_fp_attributes (ibfd, info);
+ if (!_bfd_elf_ppc_merge_fp_attributes (ibfd, info))
+ return FALSE;
obfd = info->output_bfd;
in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
merge non-conflicting ones. */
in_attr = &in_attrs[Tag_GNU_Power_ABI_Vector];
out_attr = &out_attrs[Tag_GNU_Power_ABI_Vector];
+ ret = TRUE;
if (in_attr->i != out_attr->i)
{
int in_vec = in_attr->i & 3;
int out_vec = out_attr->i & 3;
+ static bfd *last_vec;
if (in_vec == 0)
;
else if (out_vec == 0)
{
- out_attr->type = 1;
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
out_attr->i = in_vec;
+ last_vec = ibfd;
}
/* For now, allow generic to transition to AltiVec or SPE
without a warning. If GCC marked files with their stack
;
else if (out_vec == 1)
{
- out_attr->type = 1;
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
out_attr->i = in_vec;
+ last_vec = ibfd;
}
else if (out_vec < in_vec)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"),
- obfd, ibfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses AltiVec vector ABI, %pB uses SPE vector ABI"),
+ last_vec, ibfd);
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+ ret = FALSE;
+ }
else if (out_vec > in_vec)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"),
- ibfd, obfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses AltiVec vector ABI, %pB uses SPE vector ABI"),
+ ibfd, last_vec);
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+ ret = FALSE;
+ }
}
/* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes
{
int in_struct = in_attr->i & 3;
int out_struct = out_attr->i & 3;
+ static bfd *last_struct;
if (in_struct == 0 || in_struct == 3)
;
else if (out_struct == 0)
{
- out_attr->type = 1;
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
out_attr->i = in_struct;
+ last_struct = ibfd;
}
else if (out_struct < in_struct)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses r3/r4 for small structure returns, "
- "%B uses memory"), obfd, ibfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses r3/r4 for small structure returns, "
+ "%pB uses memory"), last_struct, ibfd);
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+ ret = FALSE;
+ }
else if (out_struct > in_struct)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("Warning: %B uses r3/r4 for small structure returns, "
- "%B uses memory"), ibfd, obfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB uses r3/r4 for small structure returns, "
+ "%pB uses memory"), ibfd, last_struct);
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+ ret = FALSE;
+ }
+ }
+ if (!ret)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
}
/* Merge Tag_compatibility attributes and any common GNU ones. */
- _bfd_elf_merge_object_attributes (ibfd, info);
-
- return TRUE;
+ return _bfd_elf_merge_object_attributes (ibfd, info);
}
/* Merge backend specific data from an object file to the output
{
error = TRUE;
_bfd_error_handler
- (_("%B: compiled with -mrelocatable and linked with "
+ (_("%pB: compiled with -mrelocatable and linked with "
"modules compiled normally"), ibfd);
}
else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0
{
error = TRUE;
_bfd_error_handler
- (_("%B: compiled normally and linked with "
+ (_("%pB: compiled normally and linked with "
"modules compiled with -mrelocatable"), ibfd);
}
error = TRUE;
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: uses different e_flags (0x%lx) fields "
- "than previous modules (0x%lx)"),
- ibfd, (long) new_flags, (long) old_flags);
+ (_("%pB: uses different e_flags (%#x) fields "
+ "than previous modules (%#x)"),
+ ibfd, new_flags, old_flags);
}
if (error)
split16_format_type split16_format,
bfd_boolean fixup)
{
- unsigned int insn, opcode, top5;
+ unsigned int insn, opcode;
insn = bfd_get_32 (input_bfd, loc);
- opcode = insn & 0xf300f800;
+ opcode = insn & E_OPCODE_MASK;
if (opcode == E_OR2I_INSN
|| opcode == E_AND2I_DOT_INSN
|| opcode == E_OR2IS_INSN
else
_bfd_error_handler
/* xgettext:c-format */
- (_("%B(%A+0x%lx): expected 16A style relocation on 0x%08x insn"),
+ (_("%pB(%pA+0x%lx): expected 16A style relocation on 0x%08x insn"),
input_bfd, input_section, offset, opcode);
}
}
else
_bfd_error_handler
/* xgettext:c-format */
- (_("%B(%A+0x%lx): expected 16D style relocation on 0x%08x insn"),
+ (_("%pB(%pA+0x%lx): expected 16D style relocation on 0x%08x insn"),
input_bfd, input_section, offset, opcode);
}
}
- top5 = value & 0xf800;
- top5 = top5 << (split16_format == split16a_type ? 5 : 9);
- insn &= (split16_format == split16a_type ? ~0x1f07ff : ~0x1f007ff);
- insn |= top5;
+ if (split16_format == split16a_type)
+ {
+ insn &= ~((0xf800 << 5) | 0x7ff);
+ insn |= (value & 0xf800) << 5;
+ if ((insn & E_LI_MASK) == E_LI_INSN)
+ {
+ /* Hack for e_li. Extend sign. */
+ insn &= ~(0xf0000 >> 5);
+ insn |= (-(value & 0x8000) & 0xf0000) >> 5;
+ }
+ }
+ else
+ {
+ insn &= ~((0xf800 << 10) | 0x7ff);
+ insn |= (value & 0xf800) << 10;
+ }
insn |= value & 0x7ff;
bfd_put_32 (input_bfd, insn, loc);
}
+
+static void
+ppc_elf_vle_split20 (bfd *output_bfd, bfd_byte *loc, bfd_vma value)
+{
+ unsigned int insn;
+
+ insn = bfd_get_32 (output_bfd, loc);
+ /* We have an li20 field, bits 17..20, 11..15, 21..31. */
+ /* Top 4 bits of value to 17..20. */
+ insn |= (value & 0xf0000) >> 5;
+ /* Next 5 bits of the value to 11..15. */
+ insn |= (value & 0xf800) << 5;
+ /* And the final 11 bits of the value to bits 21 to 31. */
+ insn |= value & 0x7ff;
+ bfd_put_32 (output_bfd, insn, loc);
+}
+
\f
/* Choose which PLT scheme to use, and set .plt flags appropriately.
Returns -1 on error, 0 for old PLT, 1 for new PLT. */
|| h->needs_plt)
&& h->ref_regular
&& !(SYMBOL_CALLS_LOCAL (info, h)
- || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
- && h->root.type == bfd_link_hash_undefweak)))
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
{
/* Profiling of shared libs (and pies) is not supported with
secure plt, because ppc32 does profiling before a
if (htab->plt_type == PLT_OLD && htab->params->plt_style == PLT_NEW)
{
if (htab->old_bfd != NULL)
- info->callbacks->einfo (_("%P: bss-plt forced due to %B\n"),
- htab->old_bfd);
+ _bfd_error_handler (_("bss-plt forced due to %pB"), htab->old_bfd);
else
- info->callbacks->einfo (_("%P: bss-plt forced by profiling\n"));
+ _bfd_error_handler (_("bss-plt forced by profiling"));
}
BFD_ASSERT (htab->plt_type != PLT_VXWORKS);
return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
}
-/* Update the got, plt and dynamic reloc reference counts for the
- section being removed. */
-
static bfd_boolean
-ppc_elf_gc_sweep_hook (bfd *abfd,
- struct bfd_link_info *info,
- asection *sec,
- const Elf_Internal_Rela *relocs)
+get_sym_h (struct elf_link_hash_entry **hp,
+ Elf_Internal_Sym **symp,
+ asection **symsecp,
+ unsigned char **tls_maskp,
+ Elf_Internal_Sym **locsymsp,
+ unsigned long r_symndx,
+ bfd *ibfd)
{
- struct ppc_elf_link_hash_table *htab;
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
- bfd_signed_vma *local_got_refcounts;
- const Elf_Internal_Rela *rel, *relend;
- asection *got2;
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
- if (bfd_link_relocatable (info))
- return TRUE;
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+ struct elf_link_hash_entry *h;
- if ((sec->flags & SEC_ALLOC) == 0)
- return TRUE;
+ 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;
- elf_section_data (sec)->local_dynrel = NULL;
+ if (hp != NULL)
+ *hp = h;
- htab = ppc_elf_hash_table (info);
- symtab_hdr = &elf_symtab_hdr (abfd);
- sym_hashes = elf_sym_hashes (abfd);
- local_got_refcounts = elf_local_got_refcounts (abfd);
- got2 = bfd_get_section_by_name (abfd, ".got2");
+ if (symp != NULL)
+ *symp = NULL;
+
+ if (symsecp != NULL)
+ {
+ asection *symsec = NULL;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ symsec = h->root.u.def.section;
+ *symsecp = symsec;
+ }
- relend = relocs + sec->reloc_count;
- for (rel = relocs; rel < relend; rel++)
+ if (tls_maskp != NULL)
+ *tls_maskp = &ppc_elf_hash_entry (h)->tls_mask;
+ }
+ else
{
- unsigned long r_symndx;
- enum elf_ppc_reloc_type r_type;
- struct elf_link_hash_entry *h = NULL;
+ Elf_Internal_Sym *sym;
+ Elf_Internal_Sym *locsyms = *locsymsp;
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
+ if (locsyms == NULL)
{
- struct elf_dyn_relocs **pp, *p;
- struct ppc_elf_link_hash_entry *eh;
+ locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (locsyms == NULL)
+ locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
+ symtab_hdr->sh_info,
+ 0, NULL, NULL, NULL);
+ if (locsyms == NULL)
+ return FALSE;
+ *locsymsp = locsyms;
+ }
+ sym = locsyms + r_symndx;
- 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;
- eh = (struct ppc_elf_link_hash_entry *) h;
+ if (hp != NULL)
+ *hp = NULL;
- for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
- if (p->sec == sec)
- {
- /* Everything must go for SEC. */
- *pp = p->next;
- break;
- }
- }
+ if (symp != NULL)
+ *symp = sym;
- r_type = ELF32_R_TYPE (rel->r_info);
- if (!htab->is_vxworks
- && h == NULL
- && local_got_refcounts != NULL
- && (!bfd_link_pic (info)
- || is_branch_reloc (r_type)))
+ if (symsecp != NULL)
+ *symsecp = bfd_section_from_elf_index (ibfd, sym->st_shndx);
+
+ if (tls_maskp != NULL)
{
- struct plt_entry **local_plt = (struct plt_entry **)
- (local_got_refcounts + symtab_hdr->sh_info);
- char *local_got_tls_masks = (char *)
- (local_plt + symtab_hdr->sh_info);
- if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
- {
- struct plt_entry **ifunc = local_plt + r_symndx;
- bfd_vma addend = 0;
- struct plt_entry *ent;
+ bfd_signed_vma *local_got;
+ unsigned char *tls_mask;
- if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
- addend = rel->r_addend;
- ent = find_plt_ent (ifunc, got2, addend);
- if (ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
- continue;
+ tls_mask = NULL;
+ local_got = elf_local_got_refcounts (ibfd);
+ if (local_got != NULL)
+ {
+ struct plt_entry **local_plt = (struct plt_entry **)
+ (local_got + symtab_hdr->sh_info);
+ unsigned char *lgot_masks = (unsigned char *)
+ (local_plt + symtab_hdr->sh_info);
+ tls_mask = &lgot_masks[r_symndx];
}
+ *tls_maskp = tls_mask;
}
+ }
+ return TRUE;
+}
+\f
+/* Analyze inline PLT call relocations to see whether calls to locally
+ defined functions can be converted to direct calls. */
- switch (r_type)
- {
- case R_PPC_GOT_TLSLD16:
- case R_PPC_GOT_TLSLD16_LO:
- case R_PPC_GOT_TLSLD16_HI:
- case R_PPC_GOT_TLSLD16_HA:
- case R_PPC_GOT_TLSGD16:
- case R_PPC_GOT_TLSGD16_LO:
- case R_PPC_GOT_TLSGD16_HI:
- case R_PPC_GOT_TLSGD16_HA:
- case R_PPC_GOT_TPREL16:
- case R_PPC_GOT_TPREL16_LO:
- case R_PPC_GOT_TPREL16_HI:
- case R_PPC_GOT_TPREL16_HA:
- case R_PPC_GOT_DTPREL16:
- case R_PPC_GOT_DTPREL16_LO:
- case R_PPC_GOT_DTPREL16_HI:
- case R_PPC_GOT_DTPREL16_HA:
- case R_PPC_GOT16:
- case R_PPC_GOT16_LO:
- case R_PPC_GOT16_HI:
- case R_PPC_GOT16_HA:
- if (h != NULL)
- {
- if (h->got.refcount > 0)
- h->got.refcount--;
- if (!bfd_link_pic (info))
- {
- struct plt_entry *ent;
+bfd_boolean
+ppc_elf_inline_plt (struct bfd_link_info *info)
+{
+ struct ppc_elf_link_hash_table *htab;
+ bfd *ibfd;
+ asection *sec;
+ bfd_vma low_vma, high_vma, limit;
- ent = find_plt_ent (&h->plt.plist, NULL, 0);
- if (ent != NULL && ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
- }
- }
- else if (local_got_refcounts != NULL)
- {
- if (local_got_refcounts[r_symndx] > 0)
- local_got_refcounts[r_symndx]--;
- }
- break;
+ htab = ppc_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
- case R_PPC_REL24:
- case R_PPC_REL14:
- case R_PPC_REL14_BRTAKEN:
- case R_PPC_REL14_BRNTAKEN:
- case R_PPC_REL32:
- if (h == NULL || h == htab->elf.hgot)
- break;
- /* Fall through. */
+ /* A bl insn can reach -0x2000000 to 0x1fffffc. The limit is
+ reduced somewhat to cater for possible stubs that might be added
+ between the call and its destination. */
+ limit = 0x1e00000;
+ low_vma = -1;
+ high_vma = 0;
+ for (sec = info->output_bfd->sections; sec != NULL; sec = sec->next)
+ if ((sec->flags & (SEC_ALLOC | SEC_CODE)) == (SEC_ALLOC | SEC_CODE))
+ {
+ if (low_vma > sec->vma)
+ low_vma = sec->vma;
+ if (high_vma < sec->vma + sec->size)
+ high_vma = sec->vma + sec->size;
+ }
- case R_PPC_ADDR32:
- case R_PPC_ADDR24:
- case R_PPC_ADDR16:
- case R_PPC_ADDR16_LO:
- case R_PPC_ADDR16_HI:
- case R_PPC_ADDR16_HA:
- case R_PPC_ADDR14:
- case R_PPC_ADDR14_BRTAKEN:
- case R_PPC_ADDR14_BRNTAKEN:
- case R_PPC_UADDR32:
- case R_PPC_UADDR16:
- if (bfd_link_pic (info))
- break;
- /* Fall through. */
+ /* If a "bl" can reach anywhere in local code sections, then we can
+ convert all inline PLT sequences to direct calls when the symbol
+ is local. */
+ if (high_vma - low_vma < limit)
+ {
+ htab->can_convert_all_inline_plt = 1;
+ return TRUE;
+ }
- case R_PPC_PLT32:
- case R_PPC_PLTREL24:
- case R_PPC_PLTREL32:
- case R_PPC_PLT16_LO:
- case R_PPC_PLT16_HI:
- case R_PPC_PLT16_HA:
- if (h != NULL)
- {
- bfd_vma addend = 0;
- struct plt_entry *ent;
+ /* Otherwise, go looking through relocs for cases where a direct
+ call won't reach. Mark the symbol on any such reloc to disable
+ the optimization and keep the PLT entry as it seems likely that
+ this will be better than creating trampolines. Note that this
+ will disable the optimization for all inline PLT calls to a
+ particular symbol, not just those that won't reach. The
+ difficulty in doing a more precise optimization is that the
+ linker needs to make a decision depending on whether a
+ particular R_PPC_PLTCALL insn can be turned into a direct
+ call, for each of the R_PPC_PLTSEQ and R_PPC_PLT16* insns in
+ the sequence, and there is nothing that ties those relocs
+ together except their symbol. */
- if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
- addend = rel->r_addend;
- ent = find_plt_ent (&h->plt.plist, got2, addend);
- if (ent != NULL && ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
- }
- break;
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Sym *local_syms;
- default:
- break;
+ if (!is_ppc_elf (ibfd))
+ continue;
+
+ local_syms = NULL;
+ symtab_hdr = &elf_symtab_hdr (ibfd);
+
+ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+ if (sec->has_pltcall
+ && !bfd_is_abs_section (sec->output_section))
+ {
+ Elf_Internal_Rela *relstart, *rel, *relend;
+
+ /* Read the relocations. */
+ relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+ info->keep_memory);
+ if (relstart == NULL)
+ return FALSE;
+
+ relend = relstart + sec->reloc_count;
+ for (rel = relstart; rel < relend; )
+ {
+ enum elf_ppc_reloc_type r_type;
+ unsigned long r_symndx;
+ asection *sym_sec;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+ unsigned char *tls_maskp;
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+ if (r_type != R_PPC_PLTCALL)
+ continue;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (!get_sym_h (&h, &sym, &sym_sec, &tls_maskp, &local_syms,
+ r_symndx, ibfd))
+ {
+ if (elf_section_data (sec)->relocs != relstart)
+ free (relstart);
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ free (local_syms);
+ return FALSE;
+ }
+
+ if (sym_sec != NULL && sym_sec->output_section != NULL)
+ {
+ bfd_vma from, to;
+ if (h != NULL)
+ to = h->root.u.def.value;
+ else
+ to = sym->st_value;
+ to += (rel->r_addend
+ + sym_sec->output_offset
+ + sym_sec->output_section->vma);
+ from = (rel->r_offset
+ + sec->output_offset
+ + sec->output_section->vma);
+ if (to - from + limit < 2 * limit)
+ *tls_maskp &= ~PLT_KEEP;
+ }
+ }
+ 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;
}
-\f
+
/* Set plt output section type, htab->tls_get_addr, and call the
generic ELF tls_setup function. */
&& (tga->type == STT_FUNC
|| tga->needs_plt)
&& !(SYMBOL_CALLS_LOCAL (info, tga)
- || (ELF_ST_VISIBILITY (tga->other) != STV_DEFAULT
- && tga->root.type == bfd_link_hash_undefweak)))
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga)))
{
struct plt_entry *ent;
for (ent = tga->plt.plist; ent != NULL; ent = ent->next)
for (pass = 0; pass < 2; ++pass)
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
- Elf_Internal_Sym *locsyms = NULL;
Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
asection *got2 = bfd_get_section_by_name (ibfd, ".got2");
enum elf_ppc_reloc_type r_type;
unsigned long r_symndx;
struct elf_link_hash_entry *h = NULL;
- char *tls_mask;
- char tls_set, tls_clear;
+ unsigned char *tls_mask;
+ unsigned char tls_set, tls_clear;
bfd_boolean is_local;
bfd_signed_vma *got_count;
tls_set = 0;
else
/* GD -> IE */
- tls_set = TLS_TLS | TLS_TPRELGD;
+ tls_set = TLS_TLS | TLS_GDIE;
tls_clear = TLS_GD;
break;
case R_PPC_TLSGD:
case R_PPC_TLSLD:
+ if (rel + 1 < relend
+ && is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info)))
+ {
+ if (pass != 0
+ && ELF32_R_TYPE (rel[1].r_info) != R_PPC_PLTSEQ)
+ {
+ r_type = ELF32_R_TYPE (rel[1].r_info);
+ r_symndx = ELF32_R_SYM (rel[1].r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ struct elf_link_hash_entry **sym_hashes;
+
+ sym_hashes = elf_sym_hashes (ibfd);
+ 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 != NULL)
+ {
+ struct plt_entry *ent = NULL;
+ bfd_vma addend = 0;
+
+ if (bfd_link_pic (info))
+ addend = rel->r_addend;
+ ent = find_plt_ent (&h->plt.plist,
+ got2, addend);
+ if (ent != NULL
+ && ent->plt.refcount > 0)
+ ent->plt.refcount -= 1;
+ }
+ }
+ }
+ continue;
+ }
expecting_tls_get_addr = 2;
tls_set = 0;
tls_clear = 0;
if (pass == 0)
{
if (!expecting_tls_get_addr
- || (expecting_tls_get_addr == 1
- && !sec->has_tls_get_addr_call))
+ || !sec->has_tls_get_addr_call)
continue;
if (rel + 1 < relend
return TRUE;
}
- if (expecting_tls_get_addr)
- {
- struct plt_entry *ent;
- bfd_vma addend = 0;
-
- if (bfd_link_pic (info)
- && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
- addend = rel[1].r_addend;
- ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
- got2, addend);
- if (ent != NULL && ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
-
- if (expecting_tls_get_addr == 2)
- continue;
- }
-
if (h != NULL)
{
tls_mask = &ppc_elf_hash_entry (h)->tls_mask;
{
bfd_signed_vma *lgot_refs;
struct plt_entry **local_plt;
- char *lgot_masks;
+ unsigned char *lgot_masks;
- if (locsyms == NULL)
- {
- locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
- if (locsyms == NULL)
- locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
- symtab_hdr->sh_info,
- 0, NULL, NULL, NULL);
- if (locsyms == NULL)
- {
- if (elf_section_data (sec)->relocs != relstart)
- free (relstart);
- return FALSE;
- }
- }
lgot_refs = elf_local_got_refcounts (ibfd);
if (lgot_refs == NULL)
abort ();
local_plt = (struct plt_entry **)
(lgot_refs + symtab_hdr->sh_info);
- lgot_masks = (char *) (local_plt + symtab_hdr->sh_info);
+ lgot_masks = (unsigned char *)
+ (local_plt + symtab_hdr->sh_info);
tls_mask = &lgot_masks[r_symndx];
got_count = &lgot_refs[r_symndx];
}
+ /* If we don't have old-style __tls_get_addr calls
+ without TLSGD/TLSLD marker relocs, and we haven't
+ found a new-style __tls_get_addr call with a
+ marker for this symbol, then we either have a
+ broken object file or an -mlongcall style
+ indirect call to __tls_get_addr without a marker.
+ Disable optimization in this case. */
+ if ((tls_clear & (TLS_GD | TLS_LD)) != 0
+ && !sec->has_tls_get_addr_call
+ && ((*tls_mask & (TLS_TLS | TLS_MARK))
+ != (TLS_TLS | TLS_MARK)))
+ continue;
+
+ if (expecting_tls_get_addr)
+ {
+ struct plt_entry *ent;
+ bfd_vma addend = 0;
+
+ if (bfd_link_pic (info)
+ && (ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24
+ || ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTCALL))
+ addend = rel[1].r_addend;
+ ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
+ got2, addend);
+ if (ent != NULL && ent->plt.refcount > 0)
+ ent->plt.refcount -= 1;
+
+ if (expecting_tls_get_addr == 2)
+ continue;
+ }
+
if (tls_set == 0)
{
/* We managed to get rid of a got entry. */
if (elf_section_data (sec)->relocs != relstart)
free (relstart);
}
-
- if (locsyms != NULL
- && (symtab_hdr->contents != (unsigned char *) locsyms))
- {
- if (!info->keep_memory)
- free (locsyms);
- else
- symtab_hdr->contents = (unsigned char *) locsyms;
- }
}
+ htab->do_tls_opt = 1;
return TRUE;
}
\f
-/* Return true if we have dynamic relocs that apply to read-only sections. */
+/* Find dynamic relocs for H that apply to read-only sections. */
-static bfd_boolean
+static asection *
readonly_dynrelocs (struct elf_link_hash_entry *h)
{
struct elf_dyn_relocs *p;
{
asection *s = p->sec->output_section;
- if (s != NULL
- && ((s->flags & (SEC_READONLY | SEC_ALLOC))
- == (SEC_READONLY | SEC_ALLOC)))
- return TRUE;
+ if (s != NULL && (s->flags & SEC_READONLY) != 0)
+ return p->sec;
}
+ return NULL;
+}
+
+/* Return true if we have dynamic relocs against H or any of its weak
+ aliases, that apply to read-only sections. Cannot be used after
+ size_dynamic_sections. */
+
+static bfd_boolean
+alias_readonly_dynrelocs (struct elf_link_hash_entry *h)
+{
+ struct ppc_elf_link_hash_entry *eh = ppc_elf_hash_entry (h);
+ do
+ {
+ if (readonly_dynrelocs (&eh->elf))
+ return TRUE;
+ eh = ppc_elf_hash_entry (eh->elf.u.alias);
+ } while (eh != NULL && &eh->elf != h);
+
+ return FALSE;
+}
+
+/* Return whether H has pc-relative dynamic relocs. */
+
+static bfd_boolean
+pc_dynrelocs (struct elf_link_hash_entry *h)
+{
+ struct elf_dyn_relocs *p;
+
+ for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
+ if (p->pc_count != 0)
+ return TRUE;
return FALSE;
}
BFD_ASSERT (htab->elf.dynobj != NULL
&& (h->needs_plt
|| h->type == STT_GNU_IFUNC
- || h->u.weakdef != NULL
+ || h->is_weakalias
|| (h->def_dynamic
&& h->ref_regular
&& !h->def_regular)));
|| h->type == STT_GNU_IFUNC
|| h->needs_plt)
{
+ bfd_boolean local = (SYMBOL_CALLS_LOCAL (info, h)
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+ /* Discard dyn_relocs when non-pic if we've decided that a
+ function symbol is local. */
+ if (!bfd_link_pic (info) && local)
+ ppc_elf_hash_entry (h)->dyn_relocs = NULL;
+
/* Clear procedure linkage table information for any symbol that
won't need a .plt entry. */
struct plt_entry *ent;
break;
if (ent == NULL
|| (h->type != STT_GNU_IFUNC
- && (SYMBOL_CALLS_LOCAL (info, h)
- || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
- && h->root.type == bfd_link_hash_undefweak))))
+ && local
+ && (htab->can_convert_all_inline_plt
+ || (ppc_elf_hash_entry (h)->tls_mask
+ & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)))
{
/* A PLT entry is not required/allowed when:
resolution of the symbol to be set at load time rather
than link time. */
if ((h->pointer_equality_needed
- || (!h->ref_regular_nonweak && h->non_got_ref))
+ || (h->non_got_ref
+ && !h->ref_regular_nonweak
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
&& !htab->is_vxworks
&& !ppc_elf_hash_entry (h)->has_sda_refs
&& !readonly_dynrelocs (h))
{
h->pointer_equality_needed = 0;
- /* After adjust_dynamic_symbol, non_got_ref set in the
- non-pic case means that dyn_relocs for this symbol
- should be discarded. */
- h->non_got_ref = 0;
+ /* If we haven't seen a branch reloc and the symbol
+ isn't an ifunc then we don't need a plt entry. */
+ if (!h->needs_plt && h->type != STT_GNU_IFUNC)
+ h->plt.plist = NULL;
}
+ else if (!bfd_link_pic (info))
+ /* We are going to be defining the function symbol on the
+ plt stub, so no dyn_relocs needed when non-pic. */
+ ppc_elf_hash_entry (h)->dyn_relocs = NULL;
}
h->protected_def = 0;
+ /* Function symbols can't have copy relocs. */
return TRUE;
}
else
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
- if (h->u.weakdef != NULL)
- {
- BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
- || h->u.weakdef->root.type == bfd_link_hash_defweak);
- h->root.u.def.section = h->u.weakdef->root.u.def.section;
- h->root.u.def.value = h->u.weakdef->root.u.def.value;
- if (ELIMINATE_COPY_RELOCS)
- h->non_got_ref = h->u.weakdef->non_got_ref;
+ if (h->is_weakalias)
+ {
+ struct elf_link_hash_entry *def = weakdef (h);
+ BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+ h->root.u.def.section = def->root.u.def.section;
+ h->root.u.def.value = def->root.u.def.value;
+ if (def->root.u.def.section == htab->elf.sdynbss
+ || def->root.u.def.section == htab->elf.sdynrelro
+ || def->root.u.def.section == htab->dynsbss)
+ ppc_elf_hash_entry (h)->dyn_relocs = NULL;
return TRUE;
}
&& htab->params->pic_fixup == 0
&& info->disable_target_specific_optimizations <= 1)
htab->params->pic_fixup = 1;
- h->non_got_ref = 0;
return TRUE;
}
/* If -z nocopyreloc was given, we won't generate them either. */
if (info->nocopyreloc)
- {
- h->non_got_ref = 0;
- return TRUE;
- }
+ return TRUE;
- /* If we didn't find any dynamic relocs in read-only sections, then
+ /* If we don't find any dynamic relocs in read-only sections, then
we'll be keeping the dynamic relocs and avoiding the copy reloc.
We can't do this if there are any small data relocations. This
doesn't work on VxWorks, where we can not have dynamic
&& !ppc_elf_hash_entry (h)->has_sda_refs
&& !htab->is_vxworks
&& !h->def_regular
- && !readonly_dynrelocs (h))
- {
- h->non_got_ref = 0;
- return TRUE;
- }
+ && !alias_readonly_dynrelocs (h))
+ return TRUE;
/* We must allocate the symbol in our .dynbss section, which will
become part of the .bss section of the executable. There will be
Of course, if the symbol is referenced using SDAREL relocs, we
must instead allocate it in .sbss. */
-
if (ppc_elf_hash_entry (h)->has_sda_refs)
s = htab->dynsbss;
else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
s = htab->elf.sdynbss;
BFD_ASSERT (s != NULL);
- /* We must generate a R_PPC_COPY reloc to tell the dynamic linker to
- copy the initial value out of the dynamic object and into the
- runtime process image. We need to remember the offset into the
- .rela.bss section we are going to use. */
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
{
asection *srel;
+ /* We must generate a R_PPC_COPY reloc to tell the dynamic
+ linker to copy the initial value out of the dynamic object
+ and into the runtime process image. */
if (ppc_elf_hash_entry (h)->has_sda_refs)
srel = htab->relsbss;
else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
h->needs_copy = 1;
}
+ /* We no longer want dyn_relocs. */
+ ppc_elf_hash_entry (h)->dyn_relocs = NULL;
return _bfd_elf_adjust_dynamic_copy (info, h, s);
}
\f
return where;
}
-/* If H is undefined weak, make it dynamic if that makes sense. */
+/* Calculate size of GOT entries for symbol given its TLS_MASK.
+ TLS_LD is excluded because those go in a special GOT slot. */
+
+static inline unsigned int
+got_entries_needed (int tls_mask)
+{
+ unsigned int need;
+ if ((tls_mask & TLS_TLS) == 0)
+ need = 4;
+ else
+ {
+ need = 0;
+ if ((tls_mask & TLS_GD) != 0)
+ need += 8;
+ if ((tls_mask & (TLS_TPREL | TLS_GDIE)) != 0)
+ need += 4;
+ if ((tls_mask & TLS_DTPREL) != 0)
+ need += 4;
+ }
+ return need;
+}
+
+/* Calculate size of relocs needed for symbol given its TLS_MASK and
+ NEEDed GOT entries. KNOWN says a TPREL offset can be calculated at
+ link time. */
+
+static inline unsigned int
+got_relocs_needed (int tls_mask, unsigned int need, bfd_boolean known)
+{
+ /* All the entries we allocated need relocs.
+ Except IE in executable with a local symbol. We could also omit
+ the DTPREL reloc on the second word of a GD entry under the same
+ condition as that for IE, but ld.so needs to differentiate
+ LD and GD entries. */
+ if (known && (tls_mask & TLS_TLS) != 0
+ && (tls_mask & (TLS_TPREL | TLS_GDIE)) != 0)
+ need -= 4;
+ return need * sizeof (Elf32_External_Rela) / 4;
+}
+
+/* If H is undefined, make it dynamic if that makes sense. */
static bfd_boolean
-ensure_undefweak_dynamic (struct bfd_link_info *info,
- struct elf_link_hash_entry *h)
+ensure_undef_dynamic (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
{
struct elf_link_hash_table *htab = elf_hash_table (info);
if (htab->dynamic_sections_created
- && h->root.type == bfd_link_hash_undefweak
+ && ((info->dynamic_undefined_weak != 0
+ && h->root.type == bfd_link_hash_undefweak)
+ || h->root.type == bfd_link_hash_undefined)
&& h->dynindx == -1
&& !h->forced_local
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
{
unsigned int need;
- /* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- if (!ensure_undefweak_dynamic (info, &eh->elf))
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (!ensure_undef_dynamic (info, &eh->elf))
return FALSE;
need = 0;
- if ((eh->tls_mask & TLS_TLS) != 0)
+ if ((eh->tls_mask & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD))
{
- if ((eh->tls_mask & TLS_LD) != 0)
- {
- if (!eh->elf.def_dynamic)
- /* We'll just use htab->tlsld_got.offset. This should
- always be the case. It's a little odd if we have
- a local dynamic reloc against a non-local symbol. */
- htab->tlsld_got.refcount += 1;
- else
- need += 8;
- }
- if ((eh->tls_mask & TLS_GD) != 0)
+ if (!eh->elf.def_dynamic)
+ /* We'll just use htab->tlsld_got.offset. This should
+ always be the case. It's a little odd if we have
+ a local dynamic reloc against a non-local symbol. */
+ htab->tlsld_got.refcount += 1;
+ else
need += 8;
- if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
- need += 4;
- if ((eh->tls_mask & TLS_DTPREL) != 0)
- need += 4;
}
- else
- need += 4;
+ need += got_entries_needed (eh->tls_mask);
if (need == 0)
eh->elf.got.offset = (bfd_vma) -1;
else
|| (htab->elf.dynamic_sections_created
&& eh->elf.dynindx != -1
&& !SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
- && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
- || eh->elf.root.type != bfd_link_hash_undefweak))
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &eh->elf))
{
- asection *rsec = htab->elf.srelgot;
+ asection *rsec;
+ bfd_boolean tprel_known = (bfd_link_executable (info)
+ && SYMBOL_REFERENCES_LOCAL (info,
+ &eh->elf));
+ need = got_relocs_needed (eh->tls_mask, need, tprel_known);
+ if ((eh->tls_mask & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD)
+ && eh->elf.def_dynamic)
+ need -= sizeof (Elf32_External_Rela);
+ rsec = htab->elf.srelgot;
if (eh->elf.type == STT_GNU_IFUNC)
rsec = htab->elf.irelplt;
- /* All the entries we allocated need relocs.
- Except LD only needs one. */
- if ((eh->tls_mask & TLS_LD) != 0
- && eh->elf.def_dynamic)
- need -= 4;
- rsec->size += need * (sizeof (Elf32_External_Rela) / 4);
+ rsec->size += need;
}
}
}
else
eh->elf.got.offset = (bfd_vma) -1;
+ /* If no dynamic sections we can't have dynamic relocs, except for
+ IFUNCs which are handled even in static executables. */
if (!htab->elf.dynamic_sections_created
&& h->type != STT_GNU_IFUNC)
eh->dyn_relocs = NULL;
+ /* Discard relocs on undefined symbols that must be local. */
+ else if (h->root.type == bfd_link_hash_undefined
+ && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ eh->dyn_relocs = NULL;
+
+ /* Also discard relocs on undefined weak syms with non-default
+ visibility, or when dynamic_undefined_weak says so. */
+ else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ eh->dyn_relocs = NULL;
+
if (eh->dyn_relocs == NULL)
;
}
}
- /* Discard relocs on undefined symbols that must be local. */
- if (eh->dyn_relocs != NULL
- && h->root.type == bfd_link_hash_undefined
- && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
- || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
- eh->dyn_relocs = NULL;
-
- /* Also discard relocs on undefined weak syms with non-default
- visibility. */
- if (eh->dyn_relocs != NULL
- && h->root.type == bfd_link_hash_undefweak)
+ if (eh->dyn_relocs != NULL)
{
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
- eh->dyn_relocs = NULL;
-
- /* Make sure undefined weak symbols are output as a dynamic
- symbol in PIEs. */
- else if (!ensure_undefweak_dynamic (info, h))
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (!ensure_undef_dynamic (info, h))
return FALSE;
}
}
/* For the non-pic case, discard space for relocs against
symbols which turn out to need copy relocs or are not
dynamic. */
- if (!h->non_got_ref
+ if (h->dynamic_adjusted
&& !h->def_regular
+ && !ELF_COMMON_DEF_P (h)
&& !(h->protected_def
&& eh->has_addr16_ha
&& eh->has_addr16_lo
&& htab->params->pic_fixup > 0))
{
- /* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- if (!ensure_undefweak_dynamic (info, h))
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (!ensure_undef_dynamic (info, h))
return FALSE;
if (h->dynindx == -1)
sreloc->size += p->count * sizeof (Elf32_External_Rela);
}
- /* Handle PLT relocs. Done last, after dynindx has settled. */
+ /* Handle PLT relocs. Done last, after dynindx has settled.
+ We might need a PLT entry when the symbol
+ a) is dynamic, or
+ b) is an ifunc, or
+ c) has plt16 relocs and has been processed by adjust_dynamic_symbol, or
+ d) has plt16 relocs and we are linking statically. */
dyn = htab->elf.dynamic_sections_created && h->dynindx != -1;
- if (dyn || h->type == STT_GNU_IFUNC)
+ if (dyn
+ || h->type == STT_GNU_IFUNC
+ || (h->needs_plt && h->dynamic_adjusted)
+ || (h->needs_plt
+ && h->def_regular
+ && !htab->elf.dynamic_sections_created
+ && !htab->can_convert_all_inline_plt
+ && (ppc_elf_hash_entry (h)->tls_mask
+ & (TLS_TLS | PLT_KEEP)) == PLT_KEEP))
{
struct plt_entry *ent;
bfd_boolean doneone = FALSE;
- bfd_vma plt_offset = 0, glink_offset = 0;
+ bfd_vma plt_offset = 0, glink_offset = (bfd_vma) -1;
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0)
asection *s = htab->elf.splt;
if (!dyn)
- s = htab->elf.iplt;
+ {
+ if (h->type == STT_GNU_IFUNC)
+ s = htab->elf.iplt;
+ else
+ s = htab->pltlocal;
+ }
if (htab->plt_type == PLT_NEW || !dyn)
{
}
ent->plt.offset = plt_offset;
- s = htab->glink;
- if (!doneone || bfd_link_pic (info))
- {
- glink_offset = s->size;
- s->size += GLINK_ENTRY_SIZE;
- if (h == htab->tls_get_addr
- && !htab->params->no_tls_get_addr_opt)
- s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
- }
- if (!doneone
- && !bfd_link_pic (info)
- && h->def_dynamic
- && !h->def_regular)
+ if (s == htab->pltlocal)
+ ent->glink_offset = glink_offset;
+ else
{
- h->root.u.def.section = s;
- h->root.u.def.value = glink_offset;
- }
- ent->glink_offset = glink_offset;
+ s = htab->glink;
+ if (!doneone || bfd_link_pic (info))
+ {
+ glink_offset = s->size;
+ s->size += GLINK_ENTRY_SIZE (htab, h);
+ }
+ if (!doneone
+ && !bfd_link_pic (info)
+ && h->def_dynamic
+ && !h->def_regular)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = glink_offset;
+ }
+ ent->glink_offset = glink_offset;
- if (htab->params->emit_stub_syms
- && !add_stub_sym (ent, h, info))
- return FALSE;
+ if (htab->params->emit_stub_syms
+ && !add_stub_sym (ent, h, info))
+ return FALSE;
+ }
}
else
{
if (!doneone)
{
if (!dyn)
- htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
+ {
+ if (h->type == STT_GNU_IFUNC)
+ {
+ s = htab->elf.irelplt;
+ s->size += sizeof (Elf32_External_Rela);
+ }
+ else if (bfd_link_pic (info))
+ {
+ s = htab->relpltlocal;
+ s->size += sizeof (Elf32_External_Rela);
+ }
+ }
else
{
htab->elf.srelplt->size += sizeof (Elf32_External_Rela);
read-only sections. */
static bfd_boolean
-maybe_set_textrel (struct elf_link_hash_entry *h, void *info)
+maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
{
+ asection *sec;
+
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
- if (readonly_dynrelocs (h))
+ sec = readonly_dynrelocs (h);
+ if (sec != NULL)
{
- ((struct bfd_link_info *) info)->flags |= DF_TEXTREL;
+ struct bfd_link_info *info = (struct bfd_link_info *) info_p;
+
+ info->flags |= DF_TEXTREL;
+ info->callbacks->minfo
+ (_("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"),
+ sec->owner, h->root.root.string, sec);
/* Not an error, just cut short the traversal. */
return FALSE;
if ((p->sec->output_section->flags
& (SEC_READONLY | SEC_ALLOC))
== (SEC_READONLY | SEC_ALLOC))
- info->flags |= DF_TEXTREL;
+ {
+ info->flags |= DF_TEXTREL;
+ info->callbacks->minfo (_("%pB: dynamic relocation in read-only section `%pA'\n"),
+ p->sec->owner, p->sec);
+ }
}
}
}
for (; local_got < end_local_got; ++local_got, ++lgot_masks)
if (*local_got > 0)
{
- unsigned int need = 0;
- if ((*lgot_masks & TLS_TLS) != 0)
- {
- if ((*lgot_masks & TLS_GD) != 0)
- need += 8;
- if ((*lgot_masks & TLS_LD) != 0)
- htab->tlsld_got.refcount += 1;
- if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0)
- need += 4;
- if ((*lgot_masks & TLS_DTPREL) != 0)
- need += 4;
- }
- else
- need += 4;
+ unsigned int need;
+ if ((*lgot_masks & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD))
+ htab->tlsld_got.refcount += 1;
+ need = got_entries_needed (*lgot_masks);
if (need == 0)
*local_got = (bfd_vma) -1;
else
*local_got = allocate_got (htab, need);
if (bfd_link_pic (info))
{
- asection *srel = htab->elf.srelgot;
- if ((*lgot_masks & PLT_IFUNC) != 0)
+ asection *srel;
+ bfd_boolean tprel_known = bfd_link_executable (info);
+
+ need = got_relocs_needed (*lgot_masks, need, tprel_known);
+ srel = htab->elf.srelgot;
+ if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
srel = htab->elf.irelplt;
- srel->size += need * (sizeof (Elf32_External_Rela) / 4);
+ srel->size += need;
}
}
}
continue;
/* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */
- for (; local_plt < end_local_plt; ++local_plt)
+ lgot_masks = (char *) end_local_plt;
+ for (; local_plt < end_local_plt; ++local_plt, ++lgot_masks)
{
struct plt_entry *ent;
bfd_boolean doneone = FALSE;
- bfd_vma plt_offset = 0, glink_offset = 0;
+ bfd_vma plt_offset = 0, glink_offset = (bfd_vma) -1;
for (ent = *local_plt; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0)
{
- s = htab->elf.iplt;
+ if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+ s = htab->elf.iplt;
+ else if (htab->can_convert_all_inline_plt
+ || (*lgot_masks & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)
+ {
+ ent->plt.offset = (bfd_vma) -1;
+ continue;
+ }
+ else
+ s = htab->pltlocal;
if (!doneone)
{
}
ent->plt.offset = plt_offset;
- s = htab->glink;
- if (!doneone || bfd_link_pic (info))
+ if (s != htab->pltlocal && (!doneone || bfd_link_pic (info)))
{
+ s = htab->glink;
glink_offset = s->size;
- s->size += GLINK_ENTRY_SIZE;
+ s->size += GLINK_ENTRY_SIZE (htab, NULL);
}
ent->glink_offset = glink_offset;
if (!doneone)
{
- htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
+ if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+ {
+ s = htab->elf.irelplt;
+ s->size += sizeof (Elf32_External_Rela);
+ }
+ else if (bfd_link_pic (info))
+ {
+ s = htab->relpltlocal;
+ s->size += sizeof (Elf32_External_Rela);
+ }
doneone = TRUE;
}
}
&& htab->elf.dynamic_sections_created)
{
htab->glink_pltresolve = htab->glink->size;
- /* Space for the branch table. ??? We don't need entries for
- non-dynamic symbols in this table. This case can arise with
- static ifuncs or forced local ifuncs. */
- htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
+ /* Space for the branch table. */
+ htab->glink->size
+ += htab->elf.srelplt->size / (sizeof (Elf32_External_Rela) / 4) - 4;
/* Pad out to align the start of PLTresolve. */
htab->glink->size += -htab->glink->size & (htab->params->ppc476_workaround
? 63 : 15);
comment below. */
}
else if (s == htab->elf.iplt
+ || s == htab->pltlocal
|| s == htab->glink
|| s == htab->glink_eh_frame
|| s == htab->elf.sgotplt
bfd_byte *hit_addr;
unsigned long t0;
struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *isym;
struct plt_entry **plist;
unsigned char sym_type;
case R_PPC_REL24:
case R_PPC_LOCAL24PC:
case R_PPC_PLTREL24:
+ case R_PPC_PLTCALL:
max_branch_offset = 1 << 25;
break;
}
/* Get the value of the symbol referred to by the reloc. */
- h = NULL;
- if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
- {
- /* A local symbol. */
- Elf_Internal_Sym *isym;
+ if (!get_sym_h (&h, &isym, &tsec, NULL, &isymbuf,
+ ELF32_R_SYM (irel->r_info), abfd))
+ goto error_return;
- /* Read this BFD's local symbols. */
- if (isymbuf == NULL)
- {
- isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
- if (isymbuf == NULL)
- isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
- symtab_hdr->sh_info, 0,
- NULL, NULL, NULL);
- if (isymbuf == 0)
- goto error_return;
- }
- isym = isymbuf + ELF32_R_SYM (irel->r_info);
- if (isym->st_shndx == SHN_UNDEF)
- tsec = bfd_und_section_ptr;
+ if (isym != NULL)
+ {
+ if (tsec != NULL)
+ ;
else if (isym->st_shndx == SHN_ABS)
tsec = bfd_abs_section_ptr;
- else if (isym->st_shndx == SHN_COMMON)
- tsec = bfd_com_section_ptr;
else
- tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+ continue;
toff = isym->st_value;
sym_type = ELF_ST_TYPE (isym->st_info);
}
else
{
- /* Global symbol handling. */
- unsigned long indx;
-
- indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
- h = elf_sym_hashes (abfd)[indx];
-
- 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)
- {
- tsec = h->root.u.def.section;
- toff = h->root.u.def.value;
- }
+ if (tsec != NULL)
+ toff = h->root.u.def.value;
else if (h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak)
{
+ unsigned long indx;
+
+ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
tsec = bfd_und_section_ptr;
toff = bfd_link_relocatable (link_info) ? indx : 0;
}
if (tsec == isec)
continue;
+ /* toff is used for the symbol index when the symbol is
+ undefined and we're doing a relocatable link, so we can't
+ support addends. It would be possible to do so by
+ putting the addend in one_branch_fixup but addends on
+ branches are rare so it hardly seems worth supporting. */
+ if (bfd_link_relocatable (link_info)
+ && tsec == bfd_und_section_ptr
+ && r_type != R_PPC_PLTREL24
+ && irel->r_addend != 0)
+ continue;
+
/* There probably isn't any reason to handle symbols in
SEC_MERGE sections; SEC_MERGE doesn't seem a likely
attribute for a code section, and we are only looking at
a section symbol should not include the addend; Such an
access is presumed to be an offset from "sym"; The
location of interest is just "sym". */
- if (sym_type == STT_SECTION)
+ if (sym_type == STT_SECTION
+ && r_type != R_PPC_PLTREL24)
toff += irel->r_addend;
toff
elf_section_data (tsec)->sec_info,
toff);
- if (sym_type != STT_SECTION)
+ if (sym_type != STT_SECTION
+ && r_type != R_PPC_PLTREL24)
toff += irel->r_addend;
}
/* PLTREL24 addends are special. */
roff = irel->r_offset;
+ /* Avoid creating a lot of unnecessary fixups when
+ relocatable if the output section size is such that a
+ fixup can be created at final link.
+ The max_branch_offset adjustment allows for some number
+ of other fixups being needed at final link. */
+ if (bfd_link_relocatable (link_info)
+ && (isec->output_section->rawsize - (isec->output_offset + roff)
+ < max_branch_offset - (max_branch_offset >> 4)))
+ continue;
+
/* If the branch is in range, no need to do anything. */
if (tsec != bfd_und_section_ptr
&& (!bfd_link_relocatable (link_info)
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
static void
-write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
+write_glink_stub (struct elf_link_hash_entry *h, struct plt_entry *ent,
+ asection *plt_sec, unsigned char *p,
struct bfd_link_info *info)
{
struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
bfd *output_bfd = info->output_bfd;
bfd_vma plt;
+ unsigned char *end = p + GLINK_ENTRY_SIZE (htab, h);
+
+ if (h != NULL
+ && h == htab->tls_get_addr
+ && !htab->params->no_tls_get_addr_opt)
+ {
+ bfd_put_32 (output_bfd, LWZ_11_3, p);
+ p += 4;
+ bfd_put_32 (output_bfd, LWZ_12_3 + 4, p);
+ p += 4;
+ bfd_put_32 (output_bfd, MR_0_3, p);
+ p += 4;
+ bfd_put_32 (output_bfd, CMPWI_11_0, p);
+ p += 4;
+ bfd_put_32 (output_bfd, ADD_3_12_2, p);
+ p += 4;
+ bfd_put_32 (output_bfd, BEQLR, p);
+ p += 4;
+ bfd_put_32 (output_bfd, MR_3_0, p);
+ p += 4;
+ bfd_put_32 (output_bfd, NOP, p);
+ p += 4;
+ }
plt = ((ent->plt.offset & ~1)
+ plt_sec->output_section->vma
plt -= got;
if (plt + 0x8000 < 0x10000)
- {
- bfd_put_32 (output_bfd, LWZ_11_30 + PPC_LO (plt), p);
- p += 4;
- bfd_put_32 (output_bfd, MTCTR_11, p);
- p += 4;
- bfd_put_32 (output_bfd, BCTR, p);
- p += 4;
- bfd_put_32 (output_bfd, htab->params->ppc476_workaround ? BA : NOP, p);
- p += 4;
- }
+ bfd_put_32 (output_bfd, LWZ_11_30 + PPC_LO (plt), p);
else
{
bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (plt), p);
p += 4;
bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
- p += 4;
- bfd_put_32 (output_bfd, MTCTR_11, p);
- p += 4;
- bfd_put_32 (output_bfd, BCTR, p);
- p += 4;
}
}
else
bfd_put_32 (output_bfd, LIS_11 + PPC_HA (plt), p);
p += 4;
bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
- p += 4;
- bfd_put_32 (output_bfd, MTCTR_11, p);
- p += 4;
- bfd_put_32 (output_bfd, BCTR, p);
+ }
+ p += 4;
+ bfd_put_32 (output_bfd, MTCTR_11, p);
+ p += 4;
+ bfd_put_32 (output_bfd, BCTR, p);
+ p += 4;
+ while (p < end)
+ {
+ bfd_put_32 (output_bfd, htab->params->ppc476_workaround ? BA : NOP, p);
p += 4;
}
}
struct ppc_elf_relax_info *relax_info = NULL;
#ifdef DEBUG
- _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
+ _bfd_error_handler ("ppc_elf_relocate_section called for %pB section %pA, "
"%ld relocations%s",
input_bfd, input_section,
(long) input_section->reloc_count,
(bfd_link_relocatable (info)) ? " (relocatable)" : "");
#endif
+ if (!is_ppc_elf (input_bfd))
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
got2 = bfd_get_section_by_name (input_bfd, ".got2");
/* Initialize howto table if not already done. */
unsigned long r_symndx;
bfd_vma relocation;
bfd_vma branch_bit, from;
- bfd_boolean unresolved_reloc;
+ bfd_boolean unresolved_reloc, save_unresolved_reloc;
bfd_boolean warned;
unsigned int tls_type, tls_mask, tls_gd;
- struct plt_entry **ifunc;
+ struct plt_entry **ifunc, **plt_list;
struct reloc_howto_struct alt_howto;
again:
howto = ppc_elf_howto_table[r_type];
_bfd_clear_contents (howto, input_bfd, input_section,
- contents + rel->r_offset);
+ contents, rel->r_offset);
wrel->r_offset = rel->r_offset;
wrel->r_info = 0;
wrel->r_addend = 0;
/* For ld -r, remove relocations in debug sections against
- sections defined in discarded sections. Not done for
+ symbols defined in discarded sections. Not done for
non-debug to preserve relocs in .eh_frame which the
eh_frame editing code expects to be present. */
if (bfd_link_relocatable (info)
case R_PPC_GOT_TLSGD16_HI:
case R_PPC_GOT_TLSGD16_HA:
- tls_gd = TLS_TPRELGD;
+ tls_gd = TLS_GDIE;
if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
goto tls_gdld_hi;
break;
case R_PPC_GOT_TLSGD16:
case R_PPC_GOT_TLSGD16_LO:
- tls_gd = TLS_TPRELGD;
+ tls_gd = TLS_GDIE;
if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
goto tls_ldgd_opt;
break;
break;
case R_PPC_TLSGD:
- if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
+ && rel + 1 < relend)
{
unsigned int insn2;
bfd_vma offset = rel->r_offset;
- if ((tls_mask & TLS_TPRELGD) != 0)
+ if (is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info)))
+ {
+ bfd_put_32 (input_bfd, NOP, contents + offset);
+ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
+ break;
+ }
+
+ if ((tls_mask & TLS_GDIE) != 0)
{
/* IE */
r_type = R_PPC_NONE;
break;
case R_PPC_TLSLD:
- if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
+ && rel + 1 < relend)
{
unsigned int insn2;
+ if (is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info)))
+ {
+ bfd_put_32 (input_bfd, NOP, contents + rel->r_offset);
+ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
+ break;
+ }
+
for (r_symndx = 0;
r_symndx < symtab_hdr->sh_info;
r_symndx++)
case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_REL14_BRNTAKEN:
{
- bfd_vma insn;
+ unsigned int insn;
insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
insn &= ~BRANCH_PREDICT_BIT;
insn ^= BRANCH_PREDICT_BIT;
bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
- break;
}
+ break;
+
+ case R_PPC_PLT16_HA:
+ {
+ unsigned int insn;
+
+ insn = bfd_get_32 (input_bfd,
+ contents + rel->r_offset - d_offset);
+ if ((insn & (0x3f << 26)) == 15u << 26
+ && (insn & (0x1f << 16)) != 0)
+ {
+ if (!bfd_link_pic (info))
+ {
+ /* Convert addis to lis. */
+ insn &= ~(0x1f << 16);
+ bfd_put_32 (input_bfd, insn,
+ contents + rel->r_offset - d_offset);
+ }
+ }
+ else if (bfd_link_pic (info))
+ info->callbacks->einfo
+ (_("%P: %H: error: %s with unexpected instruction %x\n"),
+ input_bfd, input_section, rel->r_offset,
+ "R_PPC_PLT16_HA", insn);
+ }
+ break;
}
if (ELIMINATE_COPY_RELOCS
off = (p - contents) - (rel->r_offset - d_offset);
if (off > 0x1fffffc || (off & 3) != 0)
info->callbacks->einfo
- (_("%P: %H: fixup branch overflow\n"),
+ (_("%H: fixup branch overflow\n"),
input_bfd, input_section, rel->r_offset);
bfd_put_32 (input_bfd, B | off,
wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA);
wrel->r_addend = got_addr;
insn &= ~0xffff;
- insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff;
+ insn |= ((unsigned int) (got_addr + 0x8000) >> 16) & 0xffff;
bfd_put_32 (input_bfd, insn, p);
/* Convert lis to lwz, loading address from GOT. */
r_type = R_PPC_GOT16_LO;
}
else
- info->callbacks->einfo
+ _bfd_error_handler
/* xgettext:c-format */
- (_("%P: %H: error: %s with unexpected instruction %x\n"),
- input_bfd, input_section, rel->r_offset,
+ (_("%pB(%pA+%#" PRIx64 "): error: "
+ "%s with unexpected instruction %#x"),
+ input_bfd, input_section, (uint64_t) rel->r_offset,
"R_PPC_ADDR16_HA", insn);
}
else if (r_type == R_PPC_ADDR16_LO)
rel->r_info = ELF32_R_INFO (0, r_type);
}
else
- info->callbacks->einfo
+ _bfd_error_handler
/* xgettext:c-format */
- (_("%P: %H: error: %s with unexpected instruction %x\n"),
- input_bfd, input_section, rel->r_offset,
+ (_("%pB(%pA+%#" PRIx64 "): error: "
+ "%s with unexpected instruction %#x"),
+ input_bfd, input_section, (uint64_t) rel->r_offset,
"R_PPC_ADDR16_LO", insn);
}
}
ent = NULL;
if (ifunc != NULL
&& (!bfd_link_pic (info)
- || is_branch_reloc (r_type)))
+ || is_branch_reloc (r_type)
+ || r_type == R_PPC_PLT16_LO
+ || r_type == R_PPC_PLT16_HI
+ || r_type == R_PPC_PLT16_HA))
{
addend = 0;
- if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
+ if (bfd_link_pic (info)
+ && (r_type == R_PPC_PLTREL24
+ || r_type == R_PPC_PLT16_LO
+ || r_type == R_PPC_PLT16_HI
+ || r_type == R_PPC_PLT16_HA))
addend = rel->r_addend;
ent = find_plt_ent (ifunc, got2, addend);
}
into .got2). */
info->callbacks->einfo
/* xgettext:c-format */
- (_("%X%P: %H: unsupported bss-plt -fPIC ifunc %s\n"),
+ (_("%X%H: unsupported bss-plt -fPIC ifunc %s\n"),
input_bfd, input_section, rel->r_offset, sym_name);
}
- if (h == NULL && (ent->plt.offset & 1) == 0)
- {
- Elf_Internal_Rela rela;
- bfd_byte *loc;
-
- rela.r_offset = (htab->elf.iplt->output_section->vma
- + htab->elf.iplt->output_offset
- + ent->plt.offset);
- rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
- rela.r_addend = relocation;
- loc = htab->elf.irelplt->contents;
- loc += (htab->elf.irelplt->reloc_count++
- * sizeof (Elf32_External_Rela));
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
-
- ent->plt.offset |= 1;
- }
- if (h == NULL && (ent->glink_offset & 1) == 0)
- {
- unsigned char *p = ((unsigned char *) htab->glink->contents
- + ent->glink_offset);
- write_glink_stub (ent, htab->elf.iplt, p, info);
- ent->glink_offset |= 1;
- }
unresolved_reloc = FALSE;
if (htab->plt_type == PLT_NEW
}
addend = rel->r_addend;
- tls_type = 0;
+ save_unresolved_reloc = unresolved_reloc;
howto = NULL;
if (r_type < R_PPC_max)
howto = ppc_elf_howto_table[r_type];
+
switch (r_type)
{
default:
- info->callbacks->einfo
- /* xgettext:c-format */
- (_("%P: %B: unknown relocation type %d for symbol %s\n"),
- input_bfd, (int) r_type, sym_name);
+ break;
+
+ case R_PPC_TPREL16_HA:
+ if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ unsigned int insn = bfd_get_32 (input_bfd, p);
+ if ((insn & ((0x3f << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
+ /* xgettext:c-format */
+ info->callbacks->minfo
+ (_("%H: warning: %s unexpected insn %#x.\n"),
+ input_bfd, input_section, rel->r_offset, howto->name, insn);
+ else
+ bfd_put_32 (input_bfd, NOP, p);
+ }
+ break;
+
+ case R_PPC_TPREL16_LO:
+ if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ unsigned int insn = bfd_get_32 (input_bfd, p);
+ insn &= ~(0x1f << 16);
+ insn |= 2 << 16;
+ bfd_put_32 (input_bfd, insn, p);
+ }
+ break;
+ }
+
+ tls_type = 0;
+ switch (r_type)
+ {
+ default:
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: %s unsupported"),
+ input_bfd, howto->name);
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1
|| SYMBOL_REFERENCES_LOCAL (info, h)
- || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
- && h->root.type == bfd_link_hash_undefweak))
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
/* 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
off &= ~1;
else
{
- unsigned int tls_m = (tls_mask
- & (TLS_LD | TLS_GD | TLS_DTPREL
- | TLS_TPREL | TLS_TPRELGD));
+ unsigned int tls_m = ((tls_mask & TLS_TLS) != 0
+ ? tls_mask & (TLS_LD | TLS_GD | TLS_DTPREL
+ | TLS_TPREL | TLS_GDIE)
+ : 0);
if (offp == &htab->tlsld_got.offset)
tls_m = TLS_LD;
tls_ty = TLS_TLS | TLS_DTPREL;
tls_m &= ~TLS_DTPREL;
}
- else if ((tls_m & (TLS_TPREL | TLS_TPRELGD)) != 0)
+ else if ((tls_m & (TLS_TPREL | TLS_GDIE)) != 0)
{
tls_ty = TLS_TLS | TLS_TPREL;
tls_m = 0;
if (indx != 0
|| (bfd_link_pic (info)
&& (h == NULL
- || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak
- || offp == &htab->tlsld_got.offset)))
+ || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)
+ || offp == &htab->tlsld_got.offset)
+ && !(tls_ty == (TLS_TLS | TLS_TPREL)
+ && bfd_link_executable (info)
+ && SYMBOL_REFERENCES_LOCAL (info, h))))
{
asection *rsec = htab->elf.srelgot;
bfd_byte * loc;
if (ifunc != NULL)
- rsec = htab->elf.irelplt;
+ {
+ rsec = htab->elf.irelplt;
+ if (indx == 0)
+ htab->local_ifunc_resolver = 1;
+ else if (is_static_defined (h))
+ htab->maybe_local_ifunc_resolver = 1;
+ }
outrel.r_offset = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off);
else
{
bfd_vma value = relocation;
- int tlsopt = (htab->plt_type == PLT_NEW
- && !htab->params->no_tls_get_addr_opt
- && htab->tls_get_addr != NULL
- && htab->tls_get_addr->plt.plist != NULL);
if (tls_ty != 0)
{
value = 0;
else
value -= htab->elf.tls_sec->vma + DTP_OFFSET;
- if ((tls_ty & TLS_TPREL)
- || (tlsopt && !(tls_ty & TLS_DTPREL)))
+ if (tls_ty & TLS_TPREL)
value += DTP_OFFSET - TP_OFFSET;
}
{
bfd_put_32 (input_bfd, value,
htab->elf.sgot->contents + off + 4);
- value = !tlsopt;
+ value = 1;
}
}
bfd_put_32 (input_bfd, value,
if (addend != 0)
info->callbacks->einfo
/* xgettext:c-format */
- (_("%P: %H: non-zero addend on %s reloc against `%s'\n"),
+ (_("%H: non-zero addend on %s reloc against `%s'\n"),
input_bfd, input_section, rel->r_offset,
howto->name,
sym_name);
-fPIC code, so the linker won't know whether r30 is
_GLOBAL_OFFSET_TABLE_ or pointing into a .got2 section. */
/* xgettext:c-format */
- info->callbacks->einfo (_("%X%P: %H: @local call to ifunc %s\n"),
+ info->callbacks->einfo (_("%X%H: @local call to ifunc %s\n"),
input_bfd, input_section, rel->r_offset,
h->root.root.string);
}
if (htab->elf.tls_sec != NULL)
addend -= htab->elf.tls_sec->vma + TP_OFFSET;
/* The TPREL16 relocs shouldn't really be used in shared
- libs as they will result in DT_TEXTREL being set, but
- support them anyway. */
+ libs or with non-local symbols as that will result in
+ DT_TEXTREL being set, but support them anyway. */
goto dodyn;
case R_PPC_TPREL32:
|| is_vxworks_tls)
break;
- if ((bfd_link_pic (info)
- && !(h != NULL
- && ((h->root.type == bfd_link_hash_undefined
- && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
- || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
- || (h->root.type == bfd_link_hash_undefweak
- && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)))
- && (must_be_dyn_reloc (info, r_type)
- || !SYMBOL_CALLS_LOCAL (info, h)))
- || (ELIMINATE_COPY_RELOCS
- && !bfd_link_pic (info)
- && h != NULL
- && h->dynindx != -1
- && !h->non_got_ref
- && !h->def_regular
- && !(h->protected_def
- && ppc_elf_hash_entry (h)->has_addr16_ha
- && ppc_elf_hash_entry (h)->has_addr16_lo
- && htab->params->pic_fixup > 0)))
+ if (bfd_link_pic (info)
+ ? ((h == NULL
+ || ppc_elf_hash_entry (h)->dyn_relocs != NULL)
+ && ((h != NULL && pc_dynrelocs (h))
+ || must_be_dyn_reloc (info, r_type)))
+ : (h != NULL
+ && ppc_elf_hash_entry (h)->dyn_relocs != NULL))
{
int skip;
bfd_byte *loc;
asection *sreloc;
+ long indx = 0;
+
#ifdef DEBUG
fprintf (stderr, "ppc_elf_relocate_section needs to "
"create relocation for %s\n",
/* When generating a shared object, these relocations
are copied into the output file to be resolved at run
time. */
- sreloc = elf_section_data (input_section)->sreloc;
- if (ifunc)
- sreloc = htab->elf.irelplt;
- if (sreloc == NULL)
- return FALSE;
-
skip = 0;
outrel.r_offset = _bfd_elf_section_offset (output_bfd, info,
input_section,
outrel.r_offset += (input_section->output_section->vma
+ input_section->output_offset);
+ /* Optimize unaligned reloc use. */
+ if ((r_type == R_PPC_ADDR32 && (outrel.r_offset & 3) != 0)
+ || (r_type == R_PPC_UADDR32 && (outrel.r_offset & 3) == 0))
+ r_type ^= R_PPC_ADDR32 ^ R_PPC_UADDR32;
+ if ((r_type == R_PPC_ADDR16 && (outrel.r_offset & 1) != 0)
+ || (r_type == R_PPC_UADDR16 && (outrel.r_offset & 1) == 0))
+ r_type ^= R_PPC_ADDR16 ^ R_PPC_UADDR16;
+
if (skip)
memset (&outrel, 0, sizeof outrel);
- else if ((h != NULL
- && (h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak))
- || !SYMBOL_REFERENCES_LOCAL (info, h))
+ else if (!SYMBOL_REFERENCES_LOCAL (info, h))
{
- BFD_ASSERT (h->dynindx != -1);
+ indx = h->dynindx;
+ BFD_ASSERT (indx != -1);
unresolved_reloc = FALSE;
- outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+ outrel.r_info = ELF32_R_INFO (indx, r_type);
outrel.r_addend = rel->r_addend;
}
else
if (r_type != R_PPC_ADDR32)
{
- long indx = 0;
-
if (ifunc != NULL)
{
/* If we get here when building a static
indirection function to resolve the reloc. */
info->callbacks->einfo
/* xgettext:c-format */
- (_("%P: %H: relocation %s for indirect "
+ (_("%H: relocation %s for indirect "
"function %s unsupported\n"),
input_bfd, input_section, rel->r_offset,
howto->name,
but ld.so expects buggy relocs.
FIXME: Why not always use a zero index? */
osec = sec->output_section;
- indx = elf_section_data (osec)->dynindx;
- if (indx == 0)
+ if ((osec->flags & SEC_THREAD_LOCAL) != 0)
+ {
+ osec = htab->elf.tls_sec;
+ indx = 0;
+ }
+ else
{
- osec = htab->elf.text_index_section;
indx = elf_section_data (osec)->dynindx;
+ if (indx == 0)
+ {
+ osec = htab->elf.text_index_section;
+ indx = elf_section_data (osec)->dynindx;
+ }
+ BFD_ASSERT (indx != 0);
}
- BFD_ASSERT (indx != 0);
-#ifdef DEBUG
- if (indx == 0)
- printf ("indx=%ld section=%s flags=%08x name=%s\n",
- indx, osec->name, osec->flags,
- h->root.root.string);
-#endif
+
+ /* ld.so doesn't expect buggy TLS relocs.
+ Don't leave the symbol value in the
+ addend for them. */
+ if (IS_PPC_TLS_RELOC (r_type))
+ outrel.r_addend -= osec->vma;
}
outrel.r_info = ELF32_R_INFO (indx, r_type);
outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
}
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (ifunc)
+ {
+ sreloc = htab->elf.irelplt;
+ if (indx == 0)
+ htab->local_ifunc_resolver = 1;
+ else if (is_static_defined (h))
+ htab->maybe_local_ifunc_resolver = 1;
+ }
+ if (sreloc == NULL)
+ return FALSE;
+
loc = sreloc->contents;
loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
break;
}
}
- else if (r_type == R_PPC_DTPMOD32
- && htab->plt_type == PLT_NEW
- && !htab->params->no_tls_get_addr_opt
- && htab->tls_get_addr != NULL
- && htab->tls_get_addr->plt.plist != NULL)
- {
- /* Set up for __tls_get_addr_opt stub when this entry
- does not have dynamic relocs. */
- relocation = 0;
- /* Set up the next word for local dynamic. If it turns
- out to be global dynamic, the reloc will overwrite
- this value. */
- if (rel->r_offset + 8 <= input_section->size)
- bfd_put_32 (input_bfd, DTP_OFFSET - TP_OFFSET,
- contents + rel->r_offset + 4);
- }
- else if (r_type == R_PPC_DTPREL32
- && htab->plt_type == PLT_NEW
- && !htab->params->no_tls_get_addr_opt
- && htab->tls_get_addr != NULL
- && htab->tls_get_addr->plt.plist != NULL
- && rel > relocs
- && rel[-1].r_info == ELF32_R_INFO (r_symndx, R_PPC_DTPMOD32)
- && rel[-1].r_offset + 4 == rel->r_offset)
- {
- /* __tls_get_addr_opt stub value. */
- addend += DTP_OFFSET - TP_OFFSET;
- }
break;
case R_PPC_RELAX_PLT:
addend = 0;
break;
+ case R_PPC_PLTSEQ:
+ case R_PPC_PLTCALL:
+ case R_PPC_PLT16_LO:
+ case R_PPC_PLT16_HI:
+ case R_PPC_PLT16_HA:
+ plt_list = NULL;
+ if (h != NULL)
+ plt_list = &h->plt.plist;
+ else if (ifunc != NULL)
+ plt_list = ifunc;
+ else if (local_got_offsets != NULL)
+ {
+ struct plt_entry **local_plt;
+ local_plt = (struct plt_entry **) (local_got_offsets
+ + symtab_hdr->sh_info);
+ plt_list = local_plt + r_symndx;
+ }
+ unresolved_reloc = TRUE;
+ if (plt_list != NULL)
+ {
+ struct plt_entry *ent;
+
+ ent = find_plt_ent (plt_list, got2,
+ bfd_link_pic (info) ? addend : 0);
+ if (ent != NULL && ent->plt.offset != (bfd_vma) -1)
+ {
+ asection *plt;
+
+ unresolved_reloc = FALSE;
+ plt = htab->elf.splt;
+ if (!htab->elf.dynamic_sections_created
+ || h == NULL
+ || h->dynindx == -1)
+ {
+ if (ifunc != NULL)
+ plt = htab->elf.iplt;
+ else
+ plt = htab->pltlocal;
+ }
+ relocation = (plt->output_section->vma
+ + plt->output_offset
+ + ent->plt.offset);
+ if (bfd_link_pic (info))
+ {
+ bfd_vma got = 0;
+
+ if (ent->addend >= 32768)
+ got = (ent->addend
+ + ent->sec->output_section->vma
+ + ent->sec->output_offset);
+ else
+ got = SYM_VAL (htab->elf.hgot);
+ relocation -= got;
+ }
+ }
+ }
+ addend = 0;
+ break;
+
/* Relocate against _SDA_BASE_. */
case R_PPC_SDAREL16:
{
if (!(strcmp (name, ".sdata") == 0
|| strcmp (name, ".sbss") == 0))
{
- info->callbacks->einfo
+ _bfd_error_handler
/* xgettext:c-format */
- (_("%P: %B: the target (%s) of a %s relocation is "
- "in the wrong output section (%s)\n"),
+ (_("%pB: the target (%s) of a %s relocation is "
+ "in the wrong output section (%s)"),
input_bfd,
sym_name,
howto->name,
if (!(strcmp (name, ".sdata2") == 0
|| strcmp (name, ".sbss2") == 0))
{
- info->callbacks->einfo
+ _bfd_error_handler
/* xgettext:c-format */
- (_("%P: %B: the target (%s) of a %s relocation is "
- "in the wrong output section (%s)\n"),
+ (_("%pB: the target (%s) of a %s relocation is "
+ "in the wrong output section (%s)"),
input_bfd,
sym_name,
howto->name,
}
else
{
- info->callbacks->einfo
+ _bfd_error_handler
/* xgettext:c-format */
- (_("%P: %B: the target (%s) of a %s relocation is "
- "in the wrong output section (%s)\n"),
+ (_("%pB: the target (%s) of a %s relocation is "
+ "in the wrong output section (%s)"),
input_bfd,
sym_name,
howto->name,
addend -= SYM_VAL (sda);
}
+ if (r_type == R_PPC_EMB_RELSDA)
+ break;
+
+ /* The PowerPC Embedded Application Binary Interface
+ version 1.0 insanely chose to specify R_PPC_EMB_SDA21
+ operating on a 24-bit field at r_offset. GNU as and
+ GNU ld have always assumed R_PPC_EMB_SDA21 operates on
+ a 32-bit bit insn at r_offset. Cope with object file
+ producers that possibly comply with the EABI in
+ generating an odd r_offset for big-endian objects. */
+ if (r_type == R_PPC_EMB_SDA21)
+ rel->r_offset &= ~1;
+
insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
if (reg == 0
&& (r_type == R_PPC_VLE_SDA21
goto overflow;
goto copy_reloc;
}
- else if (r_type == R_PPC_EMB_SDA21
- || r_type == R_PPC_VLE_SDA21
- || r_type == R_PPC_VLE_SDA21_LO)
- {
- /* Fill in register field. */
- insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
- }
+ /* Fill in register field. */
+ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
}
break;
{
bfd_vma value;
const char *name;
- //int reg;
struct elf_link_hash_entry *sda = NULL;
if (sec == NULL || sec->output_section == NULL)
name = bfd_get_section_name (output_bfd, sec->output_section);
if (strcmp (name, ".sdata") == 0
|| strcmp (name, ".sbss") == 0)
- {
- //reg = 13;
- sda = htab->sdata[0].sym;
- }
+ sda = htab->sdata[0].sym;
else if (strcmp (name, ".sdata2") == 0
- || strcmp (name, ".sbss2") == 0)
- {
- //reg = 2;
- sda = htab->sdata[1].sym;
- }
+ || strcmp (name, ".sbss2") == 0)
+ sda = htab->sdata[1].sym;
else
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: the target (%s) of a %s relocation is "
+ (_("%pB: the target (%s) of a %s relocation is "
"in the wrong output section (%s)"),
input_bfd,
sym_name,
goto copy_reloc;
}
- if (sda != NULL)
+ if (sda == NULL || !is_static_defined (sda))
{
- if (!is_static_defined (sda))
- {
- unresolved_reloc = TRUE;
- break;
- }
+ unresolved_reloc = TRUE;
+ break;
}
-
- value = (sda->root.u.def.section->output_section->vma
- + sda->root.u.def.section->output_offset
- + addend);
+ value = relocation + addend - SYM_VAL (sda);
if (r_type == R_PPC_VLE_SDAREL_LO16A)
ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
}
goto copy_reloc;
+ case R_PPC_VLE_ADDR20:
+ ppc_elf_vle_split20 (output_bfd, contents + rel->r_offset, relocation);
+ continue;
+
/* Relocate against the beginning of the section. */
case R_PPC_SECTOFF:
case R_PPC_SECTOFF_LO:
case R_PPC_IRELATIVE:
case R_PPC_PLT32:
case R_PPC_PLTREL32:
- case R_PPC_PLT16_LO:
- case R_PPC_PLT16_HI:
- case R_PPC_PLT16_HA:
case R_PPC_ADDR30:
case R_PPC_EMB_RELSEC16:
case R_PPC_EMB_RELST_LO:
case R_PPC_EMB_RELST_HI:
case R_PPC_EMB_RELST_HA:
case R_PPC_EMB_BIT_FLD:
- info->callbacks->einfo
- /* xgettext:c-format */
- (_("%P: %B: relocation %s is not yet supported for symbol %s\n"),
- input_bfd,
- howto->name,
- sym_name);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: %s unsupported"),
+ input_bfd, howto->name);
bfd_set_error (bfd_error_invalid_operation);
ret = FALSE;
goto copy_reloc;
}
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case R_PPC_PLTCALL:
+ if (unresolved_reloc)
+ {
+ bfd_byte *p = contents + rel->r_offset;
+ unsigned int insn = bfd_get_32 (input_bfd, p);
+ insn &= 1;
+ bfd_put_32 (input_bfd, B | insn, p);
+ unresolved_reloc = save_unresolved_reloc;
+ r_type = R_PPC_REL24;
+ howto = ppc_elf_howto_table[r_type];
+ }
+ else if (htab->plt_type != PLT_NEW)
+ info->callbacks->einfo
+ (_("%X%P: %H: %s relocation unsupported for bss-plt\n"),
+ input_bfd, input_section, rel->r_offset,
+ howto->name);
+ break;
+
+ case R_PPC_PLTSEQ:
+ case R_PPC_PLT16_HA:
+ case R_PPC_PLT16_LO:
+ if (unresolved_reloc)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ bfd_put_32 (input_bfd, NOP, p);
+ unresolved_reloc = FALSE;
+ r_type = R_PPC_NONE;
+ howto = ppc_elf_howto_table[r_type];
+ }
+ else if (htab->plt_type != PLT_NEW)
+ info->callbacks->einfo
+ (_("%X%P: %H: %s relocation unsupported for bss-plt\n"),
+ input_bfd, input_section, rel->r_offset,
+ howto->name);
+ break;
+ }
+
/* Do any further special processing. */
switch (r_type)
{
relocation ^= lobit;
info->callbacks->einfo
/* xgettext:c-format */
- (_("%P: %H: error: %s against `%s' not a multiple of %u\n"),
+ (_("%H: error: %s against `%s' not a multiple of %u\n"),
input_bfd, input_section, rel->r_offset,
howto->name, sym_name, mask + 1);
bfd_set_error (bfd_error_bad_value);
{
info->callbacks->einfo
/* xgettext:c-format */
- (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"),
+ (_("%H: unresolvable %s relocation against symbol `%s'\n"),
input_bfd, input_section, rel->r_offset,
howto->name,
sym_name);
{
info->callbacks->einfo
/* xgettext:c-format */
- (_("%P: %H: %s reloc against `%s': error %d\n"),
+ (_("%H: %s reloc against `%s': error %d\n"),
input_bfd, input_section, rel->r_offset,
howto->name, sym_name, (int) r);
ret = FALSE;
. new_page: new_page:
. */
insn = bfd_get_32 (input_bfd, contents + offset);
- if ((insn & (0x3f << 26)) == (18u << 26) /* b,bl,ba,bla */
- || ((insn & (0x3f << 26)) == (16u << 26) /* bc,bcl,bca,bcla*/
- && (insn & (0x14 << 21)) == (0x14 << 21)) /* with BO=0x14 */
+ if ((insn & (0x3f << 26)) == (18u << 26) /* b,bl,ba,bla */
+ || ((insn & (0x3f << 26)) == (16u << 26) /* bc,bcl,bca,bcla*/
+ && (insn & (0x14 << 21)) == (0x14 << 21)) /* with BO=0x14 */
|| ((insn & (0x3f << 26)) == (19u << 26)
&& (insn & (0x3ff << 1)) == (16u << 1) /* bclr,bclrl */
- && (insn & (0x14 << 21)) == (0x14 << 21)))/* with BO=0x14 */
+ && (insn & (0x14 << 21)) == (0x14 << 21)))/* with BO=0x14 */
continue;
patch_addr = (start_addr + input_section->size
return ret;
}
\f
-/* Finish up dynamic symbol handling. We set the contents of various
- dynamic sections here. */
+/* Write out the PLT relocs and entries for H. */
static bfd_boolean
-ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
- struct bfd_link_info *info,
- struct elf_link_hash_entry *h,
- Elf_Internal_Sym *sym)
+write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
{
- struct ppc_elf_link_hash_table *htab;
+ struct bfd_link_info *info = (struct bfd_link_info *) inf;
+ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
struct plt_entry *ent;
bfd_boolean doneone;
-#ifdef DEBUG
- fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
- h->root.root.string);
-#endif
-
- htab = ppc_elf_hash_table (info);
- BFD_ASSERT (htab->elf.dynobj != NULL);
-
doneone = FALSE;
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1)
Elf_Internal_Rela rela;
bfd_byte *loc;
bfd_vma reloc_index;
+ asection *plt = htab->elf.splt;
+ asection *relplt = htab->elf.srelplt;
if (htab->plt_type == PLT_NEW
|| !htab->elf.dynamic_sections_created
/* Fill in the .plt on VxWorks. */
if (bfd_link_pic (info))
{
- bfd_put_32 (output_bfd,
+ bfd_put_32 (info->output_bfd,
plt_entry[0] | PPC_HA (got_offset),
- htab->elf.splt->contents + ent->plt.offset + 0);
- bfd_put_32 (output_bfd,
+ plt->contents + ent->plt.offset + 0);
+ bfd_put_32 (info->output_bfd,
plt_entry[1] | PPC_LO (got_offset),
- htab->elf.splt->contents + ent->plt.offset + 4);
+ plt->contents + ent->plt.offset + 4);
}
else
{
bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot);
- bfd_put_32 (output_bfd,
+ bfd_put_32 (info->output_bfd,
plt_entry[0] | PPC_HA (got_loc),
- htab->elf.splt->contents + ent->plt.offset + 0);
- bfd_put_32 (output_bfd,
+ plt->contents + ent->plt.offset + 0);
+ bfd_put_32 (info->output_bfd,
plt_entry[1] | PPC_LO (got_loc),
- htab->elf.splt->contents + ent->plt.offset + 4);
+ plt->contents + ent->plt.offset + 4);
}
- bfd_put_32 (output_bfd, plt_entry[2],
- htab->elf.splt->contents + ent->plt.offset + 8);
- bfd_put_32 (output_bfd, plt_entry[3],
- htab->elf.splt->contents + ent->plt.offset + 12);
+ bfd_put_32 (info->output_bfd, plt_entry[2],
+ plt->contents + ent->plt.offset + 8);
+ bfd_put_32 (info->output_bfd, plt_entry[3],
+ plt->contents + ent->plt.offset + 12);
/* This instruction is an immediate load. The value loaded is
the byte offset of the R_PPC_JMP_SLOT relocation from the
low-order 16 bits of the load instruction. */
/* NOTE: It appears that this is now an index rather than a
prescaled offset. */
- bfd_put_32 (output_bfd,
+ bfd_put_32 (info->output_bfd,
plt_entry[4] | reloc_index,
- htab->elf.splt->contents + ent->plt.offset + 16);
+ plt->contents + ent->plt.offset + 16);
/* This instruction is a PC-relative branch whose target is
the start of the PLT section. The address of this branch
instruction is 20 bytes beyond the start of this PLT entry.
The address is encoded in bits 6-29, inclusive. The value
stored is right-shifted by two bits, permitting a 26-bit
offset. */
- bfd_put_32 (output_bfd,
+ bfd_put_32 (info->output_bfd,
(plt_entry[5]
| (-(ent->plt.offset + 20) & 0x03fffffc)),
- htab->elf.splt->contents + ent->plt.offset + 20);
- bfd_put_32 (output_bfd, plt_entry[6],
- htab->elf.splt->contents + ent->plt.offset + 24);
- bfd_put_32 (output_bfd, plt_entry[7],
- htab->elf.splt->contents + ent->plt.offset + 28);
+ plt->contents + ent->plt.offset + 20);
+ bfd_put_32 (info->output_bfd, plt_entry[6],
+ plt->contents + ent->plt.offset + 24);
+ bfd_put_32 (info->output_bfd, plt_entry[7],
+ plt->contents + ent->plt.offset + 28);
/* Fill in the GOT entry corresponding to this PLT slot with
the address immediately after the "bctr" instruction
in this PLT entry. */
- bfd_put_32 (output_bfd, (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
- + ent->plt.offset + 16),
+ bfd_put_32 (info->output_bfd, (plt->output_section->vma
+ + plt->output_offset
+ + ent->plt.offset + 16),
htab->elf.sgotplt->contents + got_offset);
if (!bfd_link_pic (info))
* sizeof (Elf32_External_Rela));
/* Provide the @ha relocation for the first instruction. */
- rela.r_offset = (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
+ rela.r_offset = (plt->output_section->vma
+ + plt->output_offset
+ ent->plt.offset + 2);
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_HA);
rela.r_addend = got_offset;
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
loc += sizeof (Elf32_External_Rela);
/* Provide the @l relocation for the second instruction. */
- rela.r_offset = (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
+ rela.r_offset = (plt->output_section->vma
+ + plt->output_offset
+ ent->plt.offset + 6);
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_LO);
rela.r_addend = got_offset;
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
loc += sizeof (Elf32_External_Rela);
/* Provide a relocation for the GOT entry corresponding to this
rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
R_PPC_ADDR32);
rela.r_addend = ent->plt.offset + 16;
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
}
/* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT.
rela.r_offset = (htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset
+ got_offset);
-
+ rela.r_addend = 0;
}
else
{
- asection *splt = htab->elf.splt;
+ rela.r_addend = 0;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
- splt = htab->elf.iplt;
+ {
+ if (h->type == STT_GNU_IFUNC)
+ {
+ plt = htab->elf.iplt;
+ relplt = htab->elf.irelplt;
+ }
+ else
+ {
+ plt = htab->pltlocal;
+ relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+ }
+ if (h->def_regular
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak))
+ rela.r_addend = SYM_VAL (h);
+ }
- rela.r_offset = (splt->output_section->vma
- + splt->output_offset
- + ent->plt.offset);
- if (htab->plt_type == PLT_OLD
- || !htab->elf.dynamic_sections_created
- || h->dynindx == -1)
+ if (relplt == NULL)
{
- /* We don't need to fill in the .plt. The ppc dynamic
- linker will fill it in. */
+ loc = plt->contents + ent->plt.offset;
+ bfd_put_32 (info->output_bfd, rela.r_addend, loc);
}
else
{
- bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
- + htab->glink->output_section->vma
- + htab->glink->output_offset);
- bfd_put_32 (output_bfd, val,
- splt->contents + ent->plt.offset);
- }
- }
+ rela.r_offset = (plt->output_section->vma
+ + plt->output_offset
+ + ent->plt.offset);
- /* Fill in the entry in the .rela.plt section. */
- rela.r_addend = 0;
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
- {
- BFD_ASSERT (h->type == STT_GNU_IFUNC
- && h->def_regular
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak));
- rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
- rela.r_addend = SYM_VAL (h);
+ if (htab->plt_type == PLT_OLD
+ || !htab->elf.dynamic_sections_created
+ || h->dynindx == -1)
+ {
+ /* We don't need to fill in the .plt. The ppc dynamic
+ linker will fill it in. */
+ }
+ else
+ {
+ bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
+ + htab->glink->output_section->vma
+ + htab->glink->output_offset);
+ bfd_put_32 (info->output_bfd, val,
+ plt->contents + ent->plt.offset);
+ }
+ }
}
- else
- rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
-
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
- loc = (htab->elf.irelplt->contents
- + (htab->elf.irelplt->reloc_count++
- * sizeof (Elf32_External_Rela)));
- else
- loc = (htab->elf.srelplt->contents
- + reloc_index * sizeof (Elf32_External_Rela));
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
- if (!h->def_regular)
+ if (relplt != NULL)
{
- /* Mark the symbol as undefined, rather than as
- defined in the .plt section. 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)
+ /* Fill in the entry in the .rela.plt section. */
+ if (!htab->elf.dynamic_sections_created
+ || h->dynindx == -1)
{
- /* This breaks function pointer comparisons, but
- that is better than breaking tests for a NULL
- function pointer. */
- sym->st_value = 0;
+ if (h->type == STT_GNU_IFUNC)
+ rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+ else
+ rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+ loc = relplt->contents + (relplt->reloc_count++
+ * sizeof (Elf32_External_Rela));
+ htab->local_ifunc_resolver = 1;
}
- }
- else if (h->type == STT_GNU_IFUNC
- && !bfd_link_pic (info))
- {
- /* Set the value of ifunc symbols in a non-pie
- executable to the glink entry. This is to avoid
- text relocations. We can't do this for ifunc in
- allocate_dynrelocs, as we do for normal dynamic
- function symbols with plt entries, because we need
- to keep the original value around for the ifunc
- relocation. */
- sym->st_shndx = (_bfd_elf_section_from_bfd_section
- (output_bfd, htab->glink->output_section));
- sym->st_value = (ent->glink_offset
- + htab->glink->output_offset
- + htab->glink->output_section->vma);
+ else
+ {
+ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
+ loc = relplt->contents + (reloc_index
+ * sizeof (Elf32_External_Rela));
+ if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+ htab->maybe_local_ifunc_resolver = 1;
+ }
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
}
doneone = TRUE;
}
|| h->dynindx == -1)
{
unsigned char *p;
- asection *splt = htab->elf.splt;
+ asection *plt = htab->elf.splt;
+
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
- splt = htab->elf.iplt;
-
- p = (unsigned char *) htab->glink->contents + ent->glink_offset;
-
- if (h == htab->tls_get_addr && !htab->params->no_tls_get_addr_opt)
{
- bfd_put_32 (output_bfd, LWZ_11_3, p);
- p += 4;
- bfd_put_32 (output_bfd, LWZ_12_3 + 4, p);
- p += 4;
- bfd_put_32 (output_bfd, MR_0_3, p);
- p += 4;
- bfd_put_32 (output_bfd, CMPWI_11_0, p);
- p += 4;
- bfd_put_32 (output_bfd, ADD_3_12_2, p);
- p += 4;
- bfd_put_32 (output_bfd, BEQLR, p);
- p += 4;
- bfd_put_32 (output_bfd, MR_3_0, p);
- p += 4;
- bfd_put_32 (output_bfd, NOP, p);
- p += 4;
+ if (h->type == STT_GNU_IFUNC)
+ plt = htab->elf.iplt;
+ else
+ break;
}
- write_glink_stub (ent, splt, p, info);
+ p = (unsigned char *) htab->glink->contents + ent->glink_offset;
+ write_glink_stub (h, ent, plt, p, info);
if (!bfd_link_pic (info))
/* We only need one non-PIC glink stub. */
else
break;
}
+ return TRUE;
+}
+
+/* Finish up PLT handling. */
+
+bfd_boolean
+ppc_finish_symbols (struct bfd_link_info *info)
+{
+ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+ bfd *ibfd;
+
+ if (!htab)
+ return TRUE;
+
+ elf_link_hash_traverse (&htab->elf, write_global_sym_plt, info);
+
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+ {
+ bfd_vma *local_got, *end_local_got;
+ struct plt_entry **local_plt, **lplt, **end_local_plt;
+ Elf_Internal_Shdr *symtab_hdr;
+ bfd_size_type locsymcount;
+ Elf_Internal_Sym *local_syms = NULL;
+ struct plt_entry *ent;
+
+ if (!is_ppc_elf (ibfd))
+ continue;
+
+ local_got = elf_local_got_offsets (ibfd);
+ if (!local_got)
+ continue;
+
+ symtab_hdr = &elf_symtab_hdr (ibfd);
+ locsymcount = symtab_hdr->sh_info;
+ end_local_got = local_got + locsymcount;
+ local_plt = (struct plt_entry **) end_local_got;
+ end_local_plt = local_plt + locsymcount;
+ for (lplt = local_plt; lplt < end_local_plt; ++lplt)
+ for (ent = *lplt; ent != NULL; ent = ent->next)
+ {
+ if (ent->plt.offset != (bfd_vma) -1)
+ {
+ Elf_Internal_Sym *sym;
+ asection *sym_sec;
+ asection *plt, *relplt;
+ bfd_byte *loc;
+ bfd_vma val;
+ Elf_Internal_Rela rela;
+ unsigned char *p;
+
+ if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
+ lplt - local_plt, ibfd))
+ {
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ free (local_syms);
+ return FALSE;
+ }
+
+ val = sym->st_value;
+ if (sym_sec != NULL && sym_sec->output_section != NULL)
+ val += sym_sec->output_offset + sym_sec->output_section->vma;
+
+ if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+ {
+ htab->local_ifunc_resolver = 1;
+ plt = htab->elf.iplt;
+ relplt = htab->elf.irelplt;
+ rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+ }
+ else
+ {
+ plt = htab->pltlocal;
+ if (bfd_link_pic (info))
+ {
+ relplt = htab->relpltlocal;
+ rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+ }
+ else
+ {
+ loc = plt->contents + ent->plt.offset;
+ bfd_put_32 (info->output_bfd, val, loc);
+ continue;
+ }
+ }
+
+ rela.r_offset = (ent->plt.offset
+ + plt->output_offset
+ + plt->output_section->vma);
+ rela.r_addend = val;
+ loc = relplt->contents + (relplt->reloc_count++
+ * sizeof (Elf32_External_Rela));
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
+
+ p = (unsigned char *) htab->glink->contents + ent->glink_offset;
+ write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
+ }
+ }
+
+ 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;
+}
+
+/* Finish up dynamic symbol handling. We set the contents of various
+ dynamic sections here. */
+
+static bfd_boolean
+ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
+ struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
+{
+ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+ struct plt_entry *ent;
+
+#ifdef DEBUG
+ fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
+ h->root.root.string);
+#endif
+
+ if (!h->def_regular
+ || (h->type == STT_GNU_IFUNC && !bfd_link_pic (info)))
+ for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+ if (ent->plt.offset != (bfd_vma) -1)
+ {
+ if (!h->def_regular)
+ {
+ /* Mark the symbol as undefined, rather than as
+ defined in the .plt section. 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;
+ }
+ }
+ else
+ {
+ /* Set the value of ifunc symbols in a non-pie
+ executable to the glink entry. This is to avoid
+ text relocations. We can't do this for ifunc in
+ allocate_dynrelocs, as we do for normal dynamic
+ function symbols with plt entries, because we need
+ to keep the original value around for the ifunc
+ relocation. */
+ sym->st_shndx
+ = (_bfd_elf_section_from_bfd_section
+ (info->output_bfd, htab->glink->output_section));
+ sym->st_value = (ent->glink_offset
+ + htab->glink->output_offset
+ + htab->glink->output_section->vma);
+ }
+ break;
+ }
if (h->needs_copy)
{
if (ppc_elf_hash_entry (h)->has_sda_refs)
s = htab->relsbss;
- else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+ else if (h->root.u.def.section == htab->elf.sdynrelro)
s = htab->elf.sreldynrelro;
else
s = htab->elf.srelbss;
struct bfd_link_info *info)
{
asection *sdyn;
- asection *splt;
struct ppc_elf_link_hash_table *htab;
bfd_vma got;
bfd *dynobj;
htab = ppc_elf_hash_table (info);
dynobj = htab->elf.dynobj;
sdyn = bfd_get_linker_section (dynobj, ".dynamic");
- if (htab->is_vxworks)
- splt = htab->elf.splt;
- else
- splt = NULL;
got = 0;
if (htab->elf.hgot != NULL)
dyn.d_un.d_ptr = got;
break;
+ case DT_TEXTREL:
+ if (htab->local_ifunc_resolver)
+ info->callbacks->einfo
+ (_("%X%P: text relocations and GNU indirect "
+ "functions will result in a segfault at runtime\n"));
+ else if (htab->maybe_local_ifunc_resolver)
+ info->callbacks->einfo
+ (_("%P: warning: text relocations and GNU indirect "
+ "functions may result in a segfault at runtime\n"));
+ continue;
+
default:
if (htab->is_vxworks
&& elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
}
}
- if (htab->elf.sgot != NULL)
+ if (htab->elf.sgot != NULL
+ && htab->elf.sgot->output_section != bfd_abs_section_ptr)
{
if (htab->elf.hgot->root.u.def.section == htab->elf.sgot
|| htab->elf.hgot->root.u.def.section == htab->elf.sgotplt)
else
{
/* xgettext:c-format */
- info->callbacks->einfo (_("%P: %s not defined in linker created %s\n"),
- htab->elf.hgot->root.root.string,
- (htab->elf.sgotplt != NULL
- ? htab->elf.sgotplt->name
- : htab->elf.sgot->name));
+ _bfd_error_handler (_("%s not defined in linker created %pA"),
+ htab->elf.hgot->root.root.string,
+ (htab->elf.sgotplt != NULL
+ ? htab->elf.sgotplt : htab->elf.sgot));
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
}
}
/* Fill in the first entry in the VxWorks procedure linkage table. */
- if (splt && splt->size > 0)
+ if (htab->is_vxworks
+ && htab->elf.splt != NULL
+ && htab->elf.splt->size != 0
+ && htab->elf.splt->output_section != bfd_abs_section_ptr)
{
+ asection *splt = htab->elf.splt;
/* Use the right PLT. */
const bfd_vma *plt_entry = (bfd_link_pic (info)
? ppc_elf_vxworks_pic_plt0_entry
unsigned char *p;
unsigned char *endp;
bfd_vma res0;
- unsigned int i;
/*
* PIC glink code is the following:
* 1: addi 11,11,(1b-res_0)@l
* mflr 12
* mtlr 0
- * sub 11,11,12 # r11 = index * 4
+ * sub 11,11,12 # r11 = index * 4
* addis 12,12,(got+4-1b)@ha
- * lwz 0,(got+4-1b)@l(12) # got[1] address of dl_runtime_resolve
- * lwz 12,(got+8-1b)@l(12) # got[2] contains the map address
+ * lwz 0,(got+4-1b)@l(12) # got[1] address of dl_runtime_resolve
+ * lwz 12,(got+8-1b)@l(12) # got[2] contains the map address
* mtctr 0
* add 0,11,11
- * add 11,0,11 # r11 = index * 12 = reloc offset.
+ * add 11,0,11 # r11 = index * 12 = reloc offset.
* bctr
- */
- static const unsigned int pic_plt_resolve[] =
- {
- ADDIS_11_11,
- MFLR_0,
- BCL_20_31,
- ADDI_11_11,
- MFLR_12,
- MTLR_0,
- SUB_11_11_12,
- ADDIS_12_12,
- LWZ_0_12,
- LWZ_12_12,
- MTCTR_0,
- ADD_0_11_11,
- ADD_11_0_11,
- BCTR,
- NOP,
- NOP
- };
-
- /*
+ *
* Non-PIC glink code is a little simpler.
*
* # ith PLT code stub.
* PLTresolve:
* lis 12,(got+4)@ha
* addis 11,11,(-res_0)@ha
- * lwz 0,(got+4)@l(12) # got[1] address of dl_runtime_resolve
- * addi 11,11,(-res_0)@l # r11 = index * 4
+ * lwz 0,(got+4)@l(12) # got[1] address of dl_runtime_resolve
+ * addi 11,11,(-res_0)@l # r11 = index * 4
* mtctr 0
* add 0,11,11
- * lwz 12,(got+8)@l(12) # got[2] contains the map address
- * add 11,0,11 # r11 = index * 12 = reloc offset.
+ * lwz 12,(got+8)@l(12) # got[2] contains the map address
+ * add 11,0,11 # r11 = index * 12 = reloc offset.
* bctr
*/
- static const unsigned int plt_resolve[] =
- {
- LIS_12,
- ADDIS_11_11,
- LWZ_0_12,
- ADDI_11_11,
- MTCTR_0,
- ADD_0_11_11,
- LWZ_12_12,
- ADD_11_0_11,
- BCTR,
- NOP,
- NOP,
- NOP,
- NOP,
- NOP,
- NOP,
- NOP
- };
-
- if (ARRAY_SIZE (pic_plt_resolve) != GLINK_PLTRESOLVE / 4)
- abort ();
- if (ARRAY_SIZE (plt_resolve) != GLINK_PLTRESOLVE / 4)
- abort ();
/* Build the branch table, one for each plt entry (less one),
and perhaps some padding. */
}
/* Last comes the PLTresolve stub. */
+ endp = p + GLINK_PLTRESOLVE;
if (bfd_link_pic (info))
{
bfd_vma bcl;
- for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++)
- {
- unsigned int insn = pic_plt_resolve[i];
-
- if (htab->params->ppc476_workaround && insn == NOP)
- insn = BA + 0;
- bfd_put_32 (output_bfd, insn, p);
- p += 4;
- }
- p -= 4 * ARRAY_SIZE (pic_plt_resolve);
-
bcl = (htab->glink->size - GLINK_PLTRESOLVE + 3*4
+ htab->glink->output_section->vma
+ htab->glink->output_offset);
- bfd_put_32 (output_bfd,
- ADDIS_11_11 + PPC_HA (bcl - res0), p + 0*4);
- bfd_put_32 (output_bfd,
- ADDI_11_11 + PPC_LO (bcl - res0), p + 3*4);
- bfd_put_32 (output_bfd,
- ADDIS_12_12 + PPC_HA (got + 4 - bcl), p + 7*4);
+ bfd_put_32 (output_bfd, ADDIS_11_11 + PPC_HA (bcl - res0), p);
+ p += 4;
+ bfd_put_32 (output_bfd, MFLR_0, p);
+ p += 4;
+ bfd_put_32 (output_bfd, BCL_20_31, p);
+ p += 4;
+ bfd_put_32 (output_bfd, ADDI_11_11 + PPC_LO (bcl - res0), p);
+ p += 4;
+ bfd_put_32 (output_bfd, MFLR_12, p);
+ p += 4;
+ bfd_put_32 (output_bfd, MTLR_0, p);
+ p += 4;
+ bfd_put_32 (output_bfd, SUB_11_11_12, p);
+ p += 4;
+ bfd_put_32 (output_bfd, ADDIS_12_12 + PPC_HA (got + 4 - bcl), p);
+ p += 4;
if (PPC_HA (got + 4 - bcl) == PPC_HA (got + 8 - bcl))
{
- bfd_put_32 (output_bfd,
- LWZ_0_12 + PPC_LO (got + 4 - bcl), p + 8*4);
- bfd_put_32 (output_bfd,
- LWZ_12_12 + PPC_LO (got + 8 - bcl), p + 9*4);
+ bfd_put_32 (output_bfd, LWZ_0_12 + PPC_LO (got + 4 - bcl), p);
+ p += 4;
+ bfd_put_32 (output_bfd, LWZ_12_12 + PPC_LO (got + 8 - bcl), p);
+ p += 4;
}
else
{
- bfd_put_32 (output_bfd,
- LWZU_0_12 + PPC_LO (got + 4 - bcl), p + 8*4);
- bfd_put_32 (output_bfd,
- LWZ_12_12 + 4, p + 9*4);
+ bfd_put_32 (output_bfd, LWZU_0_12 + PPC_LO (got + 4 - bcl), p);
+ p += 4;
+ bfd_put_32 (output_bfd, LWZ_12_12 + 4, p);
+ p += 4;
}
+ bfd_put_32 (output_bfd, MTCTR_0, p);
+ p += 4;
+ bfd_put_32 (output_bfd, ADD_0_11_11, p);
}
else
{
- for (i = 0; i < ARRAY_SIZE (plt_resolve); i++)
- {
- unsigned int insn = plt_resolve[i];
-
- if (htab->params->ppc476_workaround && insn == NOP)
- insn = BA + 0;
- bfd_put_32 (output_bfd, insn, p);
- p += 4;
- }
- p -= 4 * ARRAY_SIZE (plt_resolve);
-
- bfd_put_32 (output_bfd,
- LIS_12 + PPC_HA (got + 4), p + 0*4);
- bfd_put_32 (output_bfd,
- ADDIS_11_11 + PPC_HA (-res0), p + 1*4);
- bfd_put_32 (output_bfd,
- ADDI_11_11 + PPC_LO (-res0), p + 3*4);
+ bfd_put_32 (output_bfd, LIS_12 + PPC_HA (got + 4), p);
+ p += 4;
+ bfd_put_32 (output_bfd, ADDIS_11_11 + PPC_HA (-res0), p);
+ p += 4;
if (PPC_HA (got + 4) == PPC_HA (got + 8))
- {
- bfd_put_32 (output_bfd,
- LWZ_0_12 + PPC_LO (got + 4), p + 2*4);
- bfd_put_32 (output_bfd,
- LWZ_12_12 + PPC_LO (got + 8), p + 6*4);
- }
+ bfd_put_32 (output_bfd, LWZ_0_12 + PPC_LO (got + 4), p);
else
- {
- bfd_put_32 (output_bfd,
- LWZU_0_12 + PPC_LO (got + 4), p + 2*4);
- bfd_put_32 (output_bfd,
- LWZ_12_12 + 4, p + 6*4);
- }
+ bfd_put_32 (output_bfd, LWZU_0_12 + PPC_LO (got + 4), p);
+ p += 4;
+ bfd_put_32 (output_bfd, ADDI_11_11 + PPC_LO (-res0), p);
+ p += 4;
+ bfd_put_32 (output_bfd, MTCTR_0, p);
+ p += 4;
+ bfd_put_32 (output_bfd, ADD_0_11_11, p);
+ p += 4;
+ if (PPC_HA (got + 4) == PPC_HA (got + 8))
+ bfd_put_32 (output_bfd, LWZ_12_12 + PPC_LO (got + 8), p);
+ else
+ bfd_put_32 (output_bfd, LWZ_12_12 + 4, p);
+ }
+ p += 4;
+ bfd_put_32 (output_bfd, ADD_11_0_11, p);
+ p += 4;
+ bfd_put_32 (output_bfd, BCTR, p);
+ p += 4;
+ while (p < endp)
+ {
+ bfd_put_32 (output_bfd,
+ htab->params->ppc476_workaround ? BA : NOP, p);
+ p += 4;
}
+ BFD_ASSERT (p == endp);
}
if (htab->glink_eh_frame != NULL
#define ELF_ARCH bfd_arch_powerpc
#define ELF_TARGET_ID PPC32_ELF_DATA
#define ELF_MACHINE_CODE EM_PPC
-#ifdef __QNXTARGET__
-#define ELF_MAXPAGESIZE 0x1000
-#define ELF_COMMONPAGESIZE 0x1000
-#else
#define ELF_MAXPAGESIZE 0x10000
-#define ELF_COMMONPAGESIZE 0x10000
-#endif
-#define ELF_MINPAGESIZE 0x1000
+#define ELF_COMMONPAGESIZE 0x1000
+#define ELF_RELROPAGESIZE ELF_MAXPAGESIZE
#define elf_info_to_howto ppc_elf_info_to_howto
#ifdef EM_CYGNUS_POWERPC
#define elf_backend_object_p ppc_elf_object_p
#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook
-#define elf_backend_gc_sweep_hook ppc_elf_gc_sweep_hook
#define elf_backend_section_from_shdr ppc_elf_section_from_shdr
#define elf_backend_relocate_section ppc_elf_relocate_section
#define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections
#define elf_backend_check_relocs ppc_elf_check_relocs
+#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible
#define elf_backend_copy_indirect_symbol ppc_elf_copy_indirect_symbol
#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol
#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook
#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections
#define elf_backend_fake_sections ppc_elf_fake_sections
#define elf_backend_additional_program_headers ppc_elf_additional_program_headers
-#define elf_backend_modify_segment_map ppc_elf_modify_segment_map
+#define elf_backend_modify_segment_map ppc_elf_modify_segment_map
#define elf_backend_grok_prstatus ppc_elf_grok_prstatus
#define elf_backend_grok_psinfo ppc_elf_grok_psinfo
#define elf_backend_write_core_note ppc_elf_write_core_note
/* VxWorks uses the elf default section flags for .plt. */
static const struct bfd_elf_special_section *
-ppc_elf_vxworks_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+ppc_elf_vxworks_get_sec_type_attr (bfd *abfd, asection *sec)
{
if (sec->name == NULL)
return NULL;
if (ret)
{
struct ppc_elf_link_hash_table *htab
- = (struct ppc_elf_link_hash_table *)ret;
+ = (struct ppc_elf_link_hash_table *)ret;
htab->is_vxworks = 1;
htab->plt_type = PLT_VXWORKS;
htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE;
ppc_elf_vxworks_add_symbol_hook (bfd *abfd,
struct bfd_link_info *info,
Elf_Internal_Sym *sym,
- const char **namep ATTRIBUTE_UNUSED,
- flagword *flagsp ATTRIBUTE_UNUSED,
+ const char **namep,
+ flagword *flagsp,
asection **secp,
bfd_vma *valp)
{
- if (!elf_vxworks_add_symbol_hook(abfd, info, sym,namep, flagsp, secp,
- valp))
+ if (!elf_vxworks_add_symbol_hook (abfd, info, sym, namep, flagsp, secp,
+ valp))
return FALSE;
- return ppc_elf_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, valp);
+ return ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp);
}
-static void
-ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
+static bfd_boolean
+ppc_elf_vxworks_final_write_processing (bfd *abfd)
{
- ppc_elf_final_write_processing(abfd, linker);
- elf_vxworks_final_write_processing(abfd, linker);
+ ppc_final_write_processing (abfd);
+ return elf_vxworks_final_write_processing (abfd);
}
/* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so