From a0835439a7ea0c7a8bb58e87cce0e84b7a441316 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sun, 28 Feb 2016 16:38:47 +0000 Subject: Add some missing files as patch doesn't like the copied and changed files that were in the original patches --- .../recipes/patches/binutils/missing-files.p | 13021 +++++++++++++++++++ 1 file changed, 13021 insertions(+) create mode 100644 ppc-amigaos/recipes/patches/binutils/missing-files.p diff --git a/ppc-amigaos/recipes/patches/binutils/missing-files.p b/ppc-amigaos/recipes/patches/binutils/missing-files.p new file mode 100644 index 0000000..be93e0f --- /dev/null +++ b/ppc-amigaos/recipes/patches/binutils/missing-files.p @@ -0,0 +1,13021 @@ +--- /dev/null 2015-09-06 08:42:34.091999986 +0100 ++++ bfd/elf32-amigaos.c 2016-01-03 01:46:50.503001072 +0000 +@@ -0,0 +1,9972 @@ ++/* PowerPC-specific support for 32-bit ELF ++ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, ++ 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 ++ Free Software Foundation, Inc. ++ Written by Ian Lance Taylor, Cygnus Support. ++ ++ This file is part of BFD, the Binary File Descriptor library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the ++ Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, ++ Boston, MA 02110-1301, USA. */ ++ ++ ++/* This file is based on a preliminary PowerPC ELF ABI. The ++ information may not match the final PowerPC ELF ABI. It includes ++ suggestions from the in-progress Embedded PowerPC ABI, and that ++ information may also not match. */ ++ ++#include "sysdep.h" ++#include ++#include "bfd.h" ++#include "bfdlink.h" ++#include "libbfd.h" ++#include "elf-bfd.h" ++#include "elf/ppc.h" ++#include "elf/amigaos.h" ++#include "elf32-ppc.h" ++#include "elf-vxworks.h" ++#include "dwarf2.h" ++ ++#undef DEBUG ++ ++typedef enum split16_format_type ++{ ++ split16a_type = 0, ++ split16d_type ++} ++split16_format_type; ++ ++/* RELA relocations are used here. */ ++#define USE_RELA ++#define USE_REL 0 ++ ++static bfd_reloc_status_type ppc_elf_addr16_ha_reloc ++ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); ++static bfd_reloc_status_type ppc_elf_unhandled_reloc ++ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); ++static void ppc_elf_vle_split16 ++ (bfd *, bfd_byte *, bfd_vma, bfd_vma, split16_format_type); ++ ++int ppc_elf_amigaos_select_plt_layout (bfd *, struct bfd_link_info *, ++ enum ppc_elf_plt_type, int); ++ ++bfd_boolean ppc_elf_amigaos_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr); ++bfd_boolean ppc_elf_amigaos_modify_segment_map (bfd *abfd, ++ struct bfd_link_info *info ATTRIBUTE_UNUSED); ++asection *ppc_elf_amigaos_tls_setup (bfd *obfd, struct bfd_link_info *info, ++ int no_tls_get_addr_opt); ++bfd_boolean ppc_elf_amigaos_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *info); ++unsigned int _bfd_elf_amigaos_ppc_at_tls_transform (unsigned int insn, unsigned int reg); ++unsigned int _bfd_elf_amigaos_ppc_at_tprel_transform (unsigned int insn, unsigned int reg); ++ ++/* Branch prediction bit for branch taken relocs. */ ++#define BRANCH_PREDICT_BIT 0x200000 ++/* Mask to set RA in memory instructions. */ ++#define RA_REGISTER_MASK 0x001f0000 ++/* Value to shift register by to insert RA. */ ++#define RA_REGISTER_SHIFT 16 ++ ++/* The name of the dynamic interpreter. This is put in the .interp ++ section. */ ++#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" ++ ++/* For old-style PLT. */ ++/* The number of single-slot PLT entries (the rest use two slots). */ ++#define PLT_NUM_SINGLE_ENTRIES 8192 ++ ++/* 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 ++ ++/* VxWorks uses its own plt layout, filled in by the static linker. */ ++ ++/* The standard VxWorks PLT entry. */ ++#define VXWORKS_PLT_ENTRY_SIZE 32 ++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 */ ++ }; ++static const bfd_vma ppc_elf_vxworks_pic_plt_entry ++ [VXWORKS_PLT_ENTRY_SIZE / 4] = ++ { ++ 0x3d9e0000, /* addis r12,r30,0 */ ++ 0x818c0000, /* lwz r12,0(r12) */ ++ 0x7d8903a6, /* mtctr r12 */ ++ 0x4e800420, /* bctr */ ++ 0x39600000, /* li r11,0 */ ++ 0x48000000, /* b 14 <.PLT0resolve+0x4> 14: R_PPC_REL24 .PLTresolve */ ++ 0x60000000, /* nop */ ++ 0x60000000, /* nop */ ++ }; ++ ++/* The initial VxWorks PLT entry. */ ++#define VXWORKS_PLT_INITIAL_ENTRY_SIZE 32 ++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 */ ++ }; ++static const bfd_vma ppc_elf_vxworks_pic_plt0_entry ++ [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] = ++ { ++ 0x819e0008, /* lwz r12,8(r30) */ ++ 0x7d8903a6, /* mtctr r12 */ ++ 0x819e0004, /* lwz r12,4(r30) */ ++ 0x4e800420, /* bctr */ ++ 0x60000000, /* nop */ ++ 0x60000000, /* nop */ ++ 0x60000000, /* nop */ ++ 0x60000000, /* nop */ ++ }; ++ ++/* For executables, we have some additional relocations in ++ .rela.plt.unloaded, for the kernel loader. */ ++ ++/* The number of non-JMP_SLOT relocations per PLT0 slot. */ ++#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 ++ a shared library. */ ++#define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0 ++ ++/* Some instructions. */ ++#define ADDIS_11_11 0x3d6b0000 ++#define ADDIS_11_30 0x3d7e0000 ++#define ADDIS_12_12 0x3d8c0000 ++#define ADDI_11_11 0x396b0000 ++#define ADD_0_11_11 0x7c0b5a14 ++#define ADD_3_12_2 0x7c6c1214 ++#define ADD_11_0_11 0x7d605a14 ++#define B 0x48000000 ++#define BCL_20_31 0x429f0005 ++#define BCTR 0x4e800420 ++#define BEQLR 0x4d820020 ++#define CMPWI_11_0 0x2c0b0000 ++#define LIS_11 0x3d600000 ++#define LIS_12 0x3d800000 ++#define LWZU_0_12 0x840c0000 ++#define LWZ_0_12 0x800c0000 ++#define LWZ_11_3 0x81630000 ++#define LWZ_11_11 0x816b0000 ++#define LWZ_11_30 0x817e0000 ++#define LWZ_12_3 0x81830000 ++#define LWZ_12_12 0x818c0000 ++#define MR_0_3 0x7c601b78 ++#define MR_3_0 0x7c030378 ++#define MFLR_0 0x7c0802a6 ++#define MFLR_12 0x7d8802a6 ++#define MTCTR_0 0x7c0903a6 ++#define MTCTR_11 0x7d6903a6 ++#define MTLR_0 0x7c0803a6 ++#define NOP 0x60000000 ++#define SUB_11_11_12 0x7d6c5850 ++ ++/* Offset of tp and dtp pointers from start of TLS block. */ ++#define TP_OFFSET 0x7000 ++#define DTP_OFFSET 0x8000 ++ ++/* The value of a defined global symbol. */ ++#define SYM_VAL(SYM) \ ++ ((SYM)->root.u.def.section->output_section->vma \ ++ + (SYM)->root.u.def.section->output_offset \ ++ + (SYM)->root.u.def.value) ++ ++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 */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* 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 */ ++ ++ /* 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_bitfield, /* 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 */ ++ ++ /* 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_bitfield, /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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_bitfield, /* 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 */ ++ ++ /* 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_bitfield, /* 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 */ ++ ++ /* 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_bitfield, /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_GOT16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL24", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_COPY", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GLOB_DAT", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_JMP_SLOT", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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_bitfield, /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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_bitfield, /* 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 */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_PLT16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SDAREL16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_ADDR16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_addr16_ha_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDAI16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2I16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2REL", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA21", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Relocation not handled: R_PPC_EMB_MRKREF */ ++ /* Relocation not handled: R_PPC_EMB_RELSEC16 */ ++ /* Relocation not handled: R_PPC_EMB_RELST_LO */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HI */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HA */ ++ /* Relocation not handled: R_PPC_EMB_BIT_FLD */ ++ ++ ++ /* A standard 32 bit base relative relocation. */ ++ HOWTO (R_PPC_AMIGAOS_BREL, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_AMIGAOS_BREL", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A 16 bit base relative relocation without overflow. */ ++ HOWTO (R_PPC_AMIGAOS_BREL_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_AMIGAOS_BREL_LO",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of a base relative address. */ ++ HOWTO (R_PPC_AMIGAOS_BREL_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_AMIGAOS_BREL_HI",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of a base relative address, plus 1 if the contents ++ of the low 16 bits, treated as a signed number, is negative. */ ++ HOWTO (R_PPC_AMIGAOS_BREL_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_AMIGAOS_BREL_HA",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_RELSDA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ 0xfe, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* 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 */ ++ ++ /* The 16 LSBS in split16a format. */ ++ HOWTO (R_PPC_VLE_LO16A, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_LO16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The 16 LSBS in split16d format. */ ++ HOWTO (R_PPC_VLE_LO16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_LO16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 split16a format. */ ++ HOWTO (R_PPC_VLE_HI16A, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_HI16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 split16d format. */ ++ HOWTO (R_PPC_VLE_HI16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_HI16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 (High Adjusted) in split16a format. */ ++ HOWTO (R_PPC_VLE_HA16A, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_HA16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 (High Adjusted) in split16d format. */ ++ HOWTO (R_PPC_VLE_HA16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_HA16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_VLE_SDA21, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDA21", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_VLE_SDA21_LO, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDA21_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_LO16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The 16 LSBS relative to _SDA_BASE_ in split16d format. */ ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_LO16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 relative to _SDA_BASE_ in split16a format. */ ++ HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_HI16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 relative to _SDA_BASE_ in split16d format. */ ++ HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_HI16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */ ++ HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_HA16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */ ++ HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_HA16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* 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_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_IRELATIVE", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 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_bitfield, /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ ++ /* 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 */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_TOC16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++}; ++ ++/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ ++ ++static void ++ppc_elf_howto_init (void) ++{ ++ unsigned int i, type; ++ ++ for (i = 0; ++ i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); ++ i++) ++ { ++ type = ppc_elf_howto_raw[i].type; ++ if (type >= (sizeof (ppc_elf_howto_table) ++ / sizeof (ppc_elf_howto_table[0]))) ++ abort (); ++ ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i]; ++ } ++} ++ ++static reloc_howto_type * ++ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, ++ bfd_reloc_code_real_type code) ++{ ++ enum elf_ppc_reloc_type r; ++ ++ /* Initialize howto table if not already done. */ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ ppc_elf_howto_init (); ++ ++ switch (code) ++ { ++ default: ++ return NULL; ++ ++ case BFD_RELOC_NONE: r = R_PPC_NONE; break; ++ case BFD_RELOC_32: r = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC_BA26: r = R_PPC_ADDR24; break; ++ case BFD_RELOC_PPC64_ADDR16_DS: ++ case BFD_RELOC_16: r = R_PPC_ADDR16; break; ++ case BFD_RELOC_PPC64_ADDR16_LO_DS: ++ case BFD_RELOC_LO16: r = R_PPC_ADDR16_LO; break; ++ case BFD_RELOC_HI16: r = R_PPC_ADDR16_HI; break; ++ case BFD_RELOC_HI16_S: r = R_PPC_ADDR16_HA; break; ++ case BFD_RELOC_PPC_BA16: r = R_PPC_ADDR14; break; ++ case BFD_RELOC_PPC_BA16_BRTAKEN: r = R_PPC_ADDR14_BRTAKEN; break; ++ case BFD_RELOC_PPC_BA16_BRNTAKEN: r = R_PPC_ADDR14_BRNTAKEN; break; ++ case BFD_RELOC_PPC_B26: r = R_PPC_REL24; break; ++ case BFD_RELOC_PPC_B16: r = R_PPC_REL14; break; ++ case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC_REL14_BRTAKEN; break; ++ case BFD_RELOC_PPC_B16_BRNTAKEN: r = R_PPC_REL14_BRNTAKEN; break; ++ case BFD_RELOC_PPC64_GOT16_DS: ++ case BFD_RELOC_16_GOTOFF: r = R_PPC_GOT16; break; ++ case BFD_RELOC_PPC64_GOT16_LO_DS: ++ case BFD_RELOC_LO16_GOTOFF: r = R_PPC_GOT16_LO; break; ++ case BFD_RELOC_HI16_GOTOFF: r = R_PPC_GOT16_HI; break; ++ case BFD_RELOC_HI16_S_GOTOFF: r = R_PPC_GOT16_HA; break; ++ case BFD_RELOC_24_PLT_PCREL: r = R_PPC_PLTREL24; break; ++ case BFD_RELOC_PPC_COPY: r = R_PPC_COPY; break; ++ case BFD_RELOC_PPC_GLOB_DAT: r = R_PPC_GLOB_DAT; break; ++ case BFD_RELOC_PPC_LOCAL24PC: r = R_PPC_LOCAL24PC; break; ++ case BFD_RELOC_32_PCREL: r = R_PPC_REL32; break; ++ case BFD_RELOC_32_PLTOFF: r = R_PPC_PLT32; break; ++ case BFD_RELOC_32_PLT_PCREL: r = R_PPC_PLTREL32; break; ++ case BFD_RELOC_PPC64_PLT16_LO_DS: ++ case BFD_RELOC_LO16_PLTOFF: r = R_PPC_PLT16_LO; break; ++ case BFD_RELOC_HI16_PLTOFF: r = R_PPC_PLT16_HI; break; ++ case BFD_RELOC_HI16_S_PLTOFF: r = R_PPC_PLT16_HA; break; ++ case BFD_RELOC_GPREL16: r = R_PPC_SDAREL16; break; ++ case BFD_RELOC_PPC64_SECTOFF_DS: ++ case BFD_RELOC_16_BASEREL: r = R_PPC_SECTOFF; break; ++ case BFD_RELOC_PPC64_SECTOFF_LO_DS: ++ case BFD_RELOC_LO16_BASEREL: r = R_PPC_SECTOFF_LO; break; ++ case BFD_RELOC_HI16_BASEREL: r = R_PPC_SECTOFF_HI; break; ++ case BFD_RELOC_HI16_S_BASEREL: r = R_PPC_SECTOFF_HA; break; ++ case BFD_RELOC_CTOR: r = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC64_TOC16_DS: ++ case BFD_RELOC_PPC_TOC16: r = R_PPC_TOC16; break; ++ case BFD_RELOC_PPC_TLS: r = R_PPC_TLS; break; ++ case BFD_RELOC_PPC_TLSGD: r = R_PPC_TLSGD; break; ++ case BFD_RELOC_PPC_TLSLD: r = R_PPC_TLSLD; break; ++ case BFD_RELOC_PPC_DTPMOD: r = R_PPC_DTPMOD32; break; ++ case BFD_RELOC_PPC64_TPREL16_DS: ++ case BFD_RELOC_PPC_TPREL16: r = R_PPC_TPREL16; break; ++ case BFD_RELOC_PPC64_TPREL16_LO_DS: ++ case BFD_RELOC_PPC_TPREL16_LO: r = R_PPC_TPREL16_LO; break; ++ case BFD_RELOC_PPC_TPREL16_HI: r = R_PPC_TPREL16_HI; break; ++ case BFD_RELOC_PPC_TPREL16_HA: r = R_PPC_TPREL16_HA; break; ++ case BFD_RELOC_PPC_TPREL: r = R_PPC_TPREL32; break; ++ case BFD_RELOC_PPC64_DTPREL16_DS: ++ case BFD_RELOC_PPC_DTPREL16: r = R_PPC_DTPREL16; break; ++ case BFD_RELOC_PPC64_DTPREL16_LO_DS: ++ case BFD_RELOC_PPC_DTPREL16_LO: r = R_PPC_DTPREL16_LO; break; ++ case BFD_RELOC_PPC_DTPREL16_HI: r = R_PPC_DTPREL16_HI; break; ++ case BFD_RELOC_PPC_DTPREL16_HA: r = R_PPC_DTPREL16_HA; break; ++ case BFD_RELOC_PPC_DTPREL: r = R_PPC_DTPREL32; break; ++ case BFD_RELOC_PPC_GOT_TLSGD16: r = R_PPC_GOT_TLSGD16; break; ++ case BFD_RELOC_PPC_GOT_TLSGD16_LO: r = R_PPC_GOT_TLSGD16_LO; break; ++ case BFD_RELOC_PPC_GOT_TLSGD16_HI: r = R_PPC_GOT_TLSGD16_HI; break; ++ case BFD_RELOC_PPC_GOT_TLSGD16_HA: r = R_PPC_GOT_TLSGD16_HA; break; ++ case BFD_RELOC_PPC_GOT_TLSLD16: r = R_PPC_GOT_TLSLD16; break; ++ case BFD_RELOC_PPC_GOT_TLSLD16_LO: r = R_PPC_GOT_TLSLD16_LO; break; ++ case BFD_RELOC_PPC_GOT_TLSLD16_HI: r = R_PPC_GOT_TLSLD16_HI; break; ++ case BFD_RELOC_PPC_GOT_TLSLD16_HA: r = R_PPC_GOT_TLSLD16_HA; break; ++ case BFD_RELOC_PPC_GOT_TPREL16: r = R_PPC_GOT_TPREL16; break; ++ case BFD_RELOC_PPC_GOT_TPREL16_LO: r = R_PPC_GOT_TPREL16_LO; break; ++ case BFD_RELOC_PPC_GOT_TPREL16_HI: r = R_PPC_GOT_TPREL16_HI; break; ++ case BFD_RELOC_PPC_GOT_TPREL16_HA: r = R_PPC_GOT_TPREL16_HA; break; ++ case BFD_RELOC_PPC_GOT_DTPREL16: r = R_PPC_GOT_DTPREL16; break; ++ case BFD_RELOC_PPC_GOT_DTPREL16_LO: r = R_PPC_GOT_DTPREL16_LO; break; ++ case BFD_RELOC_PPC_GOT_DTPREL16_HI: r = R_PPC_GOT_DTPREL16_HI; break; ++ case BFD_RELOC_PPC_GOT_DTPREL16_HA: r = R_PPC_GOT_DTPREL16_HA; break; ++ case BFD_RELOC_PPC_EMB_NADDR32: r = R_PPC_EMB_NADDR32; break; ++ case BFD_RELOC_PPC_EMB_NADDR16: r = R_PPC_EMB_NADDR16; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_LO: r = R_PPC_EMB_NADDR16_LO; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HI: r = R_PPC_EMB_NADDR16_HI; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HA: r = R_PPC_EMB_NADDR16_HA; break; ++ case BFD_RELOC_PPC_EMB_SDAI16: r = R_PPC_EMB_SDAI16; break; ++ case BFD_RELOC_PPC_EMB_SDA2I16: r = R_PPC_EMB_SDA2I16; break; ++ case BFD_RELOC_PPC_EMB_SDA2REL: r = R_PPC_EMB_SDA2REL; break; ++ case BFD_RELOC_PPC_EMB_SDA21: r = R_PPC_EMB_SDA21; break; ++ case BFD_RELOC_PPC_EMB_MRKREF: r = R_PPC_EMB_MRKREF; break; ++ case BFD_RELOC_PPC_EMB_RELSEC16: r = R_PPC_EMB_RELSEC16; break; ++ case BFD_RELOC_PPC_EMB_RELST_LO: r = R_PPC_EMB_RELST_LO; break; ++ case BFD_RELOC_PPC_EMB_RELST_HI: r = R_PPC_EMB_RELST_HI; break; ++ case BFD_RELOC_PPC_EMB_RELST_HA: r = R_PPC_EMB_RELST_HA; break; ++ case BFD_RELOC_PPC_EMB_BIT_FLD: r = R_PPC_EMB_BIT_FLD; break; ++ case BFD_RELOC_PPC_EMB_RELSDA: r = R_PPC_EMB_RELSDA; break; ++ case BFD_RELOC_PPC_VLE_REL8: r = R_PPC_VLE_REL8; break; ++ case BFD_RELOC_PPC_VLE_REL15: r = R_PPC_VLE_REL15; break; ++ case BFD_RELOC_PPC_VLE_REL24: r = R_PPC_VLE_REL24; break; ++ case BFD_RELOC_PPC_VLE_LO16A: r = R_PPC_VLE_LO16A; break; ++ case BFD_RELOC_PPC_VLE_LO16D: r = R_PPC_VLE_LO16D; break; ++ case BFD_RELOC_PPC_VLE_HI16A: r = R_PPC_VLE_HI16A; break; ++ case BFD_RELOC_PPC_VLE_HI16D: r = R_PPC_VLE_HI16D; break; ++ case BFD_RELOC_PPC_VLE_HA16A: r = R_PPC_VLE_HA16A; break; ++ case BFD_RELOC_PPC_VLE_HA16D: r = R_PPC_VLE_HA16D; break; ++ case BFD_RELOC_PPC_VLE_SDA21: r = R_PPC_VLE_SDA21; break; ++ case BFD_RELOC_PPC_VLE_SDA21_LO: r = R_PPC_VLE_SDA21_LO; break; ++ case BFD_RELOC_PPC_VLE_SDAREL_LO16A: ++ r = R_PPC_VLE_SDAREL_LO16A; ++ break; ++ case BFD_RELOC_PPC_VLE_SDAREL_LO16D: ++ r = R_PPC_VLE_SDAREL_LO16D; ++ break; ++ case BFD_RELOC_PPC_VLE_SDAREL_HI16A: ++ r = R_PPC_VLE_SDAREL_HI16A; ++ break; ++ case BFD_RELOC_PPC_VLE_SDAREL_HI16D: ++ r = R_PPC_VLE_SDAREL_HI16D; ++ break; ++ case BFD_RELOC_PPC_VLE_SDAREL_HA16A: ++ r = R_PPC_VLE_SDAREL_HA16A; ++ break; ++ case BFD_RELOC_PPC_VLE_SDAREL_HA16D: ++ r = R_PPC_VLE_SDAREL_HA16D; ++ break; ++ case BFD_RELOC_16_PCREL: r = R_PPC_REL16; break; ++ 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_AMIGAOS_BREL: r = R_PPC_AMIGAOS_BREL; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL_LO: r = R_PPC_AMIGAOS_BREL_LO; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL_HI: r = R_PPC_AMIGAOS_BREL_HI; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL_HA: r = R_PPC_AMIGAOS_BREL_HA; break; ++ case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break; ++ case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break; ++ } ++ ++ return ppc_elf_howto_table[r]; ++}; ++ ++static reloc_howto_type * ++ppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, ++ const char *r_name) ++{ ++ unsigned int i; ++ ++ for (i = 0; ++ i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); ++ i++) ++ if (ppc_elf_howto_raw[i].name != NULL ++ && strcasecmp (ppc_elf_howto_raw[i].name, r_name) == 0) ++ return &ppc_elf_howto_raw[i]; ++ ++ return NULL; ++} ++ ++/* Set the howto pointer for a PowerPC ELF reloc. */ ++ ++static void ++ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, ++ arelent *cache_ptr, ++ Elf_Internal_Rela *dst) ++{ ++ /* Initialize howto table if not already done. */ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ ppc_elf_howto_init (); ++ ++ BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); ++ cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; ++ ++ /* 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) ++ { ++ (*_bfd_error_handler) (_("%B: invalid relocation type %d"), ++ abfd, ELF32_R_TYPE (dst->r_info)); ++ bfd_set_error (bfd_error_bad_value); ++ ++ cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE]; ++ } ++} ++ ++/* 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, ++ arelent *reloc_entry, ++ asymbol *symbol, ++ void *data ATTRIBUTE_UNUSED, ++ asection *input_section, ++ bfd *output_bfd, ++ char **error_message ATTRIBUTE_UNUSED) ++{ ++ bfd_vma relocation; ++ ++ if (output_bfd != NULL) ++ { ++ reloc_entry->address += input_section->output_offset; ++ return bfd_reloc_ok; ++ } ++ ++ if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) ++ return bfd_reloc_outofrange; ++ ++ if (bfd_is_com_section (symbol->section)) ++ relocation = 0; ++ else ++ relocation = symbol->value; ++ ++ relocation += symbol->section->output_section->vma; ++ relocation += symbol->section->output_offset; ++ relocation += reloc_entry->addend; ++ if (reloc_entry->howto->pc_relative) ++ relocation -= reloc_entry->address; ++ ++ reloc_entry->addend += (relocation & 0x8000) << 1; ++ ++ return bfd_reloc_continue; ++} ++ ++static bfd_reloc_status_type ++ppc_elf_unhandled_reloc (bfd *abfd, ++ arelent *reloc_entry, ++ asymbol *symbol, ++ void *data, ++ asection *input_section, ++ bfd *output_bfd, ++ char **error_message) ++{ ++ /* If this is a relocatable link (output_bfd test tells us), just ++ call the generic function. Any adjustment will be done at final ++ link time. */ ++ if (output_bfd != NULL) ++ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, ++ input_section, output_bfd, error_message); ++ ++ if (error_message != NULL) ++ { ++ static char buf[60]; ++ sprintf (buf, _("generic linker can't handle %s"), ++ reloc_entry->howto->name); ++ *error_message = buf; ++ } ++ return bfd_reloc_dangerous; ++} ++ ++/* Sections created by the linker. */ ++ ++typedef struct elf_linker_section ++{ ++ /* Pointer to the bfd section. */ ++ asection *section; ++ /* Section name. */ ++ const char *name; ++ /* Associated bss section name. */ ++ const char *bss_name; ++ /* Associated symbol name. */ ++ const char *sym_name; ++ /* Associated symbol. */ ++ struct elf_link_hash_entry *sym; ++} elf_linker_section_t; ++ ++/* Linked list of allocated pointer entries. This hangs off of the ++ symbol lists, and provides allows us to return different pointers, ++ based on different addend's. */ ++ ++typedef struct elf_linker_section_pointers ++{ ++ /* next allocated pointer for this symbol */ ++ struct elf_linker_section_pointers *next; ++ /* offset of pointer from beginning of section */ ++ bfd_vma offset; ++ /* addend used */ ++ bfd_vma addend; ++ /* which linker section this is */ ++ elf_linker_section_t *lsect; ++} elf_linker_section_pointers_t; ++ ++struct ppc_elf_obj_tdata ++{ ++ struct elf_obj_tdata elf; ++ ++ /* A mapping from local symbols to offsets into the various linker ++ sections added. This is index by the symbol index. */ ++ elf_linker_section_pointers_t **linker_section_pointers; ++ ++ /* Flags used to auto-detect plt type. */ ++ unsigned int makes_plt_call : 1; ++ unsigned int has_rel16 : 1; ++}; ++ ++#define ppc_elf_tdata(bfd) \ ++ ((struct ppc_elf_obj_tdata *) (bfd)->tdata.any) ++ ++#define elf_local_ptr_offsets(bfd) \ ++ (ppc_elf_tdata (bfd)->linker_section_pointers) ++ ++#define is_ppc_elf(bfd) \ ++ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ ++ && elf_object_id (bfd) == PPC32_ELF_DATA) ++ ++/* Override the generic function because we store some extras. */ ++ ++static bfd_boolean ++ppc_elf_mkobject (bfd *abfd) ++{ ++ return bfd_elf_allocate_object (abfd, sizeof (struct ppc_elf_obj_tdata), ++ PPC32_ELF_DATA); ++} ++ ++/* Fix bad default arch selected for a 32 bit input bfd when the ++ default is 64 bit. */ ++ ++static bfd_boolean ++ppc_elf_object_p (bfd *abfd) ++{ ++ if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64) ++ { ++ Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); ++ ++ if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32) ++ { ++ /* Relies on arch after 64 bit default being 32 bit default. */ ++ abfd->arch_info = abfd->arch_info->next; ++ BFD_ASSERT (abfd->arch_info->bits_per_word == 32); ++ } ++ } ++ return TRUE; ++} ++ ++/* Function to set whether a module needs the -mrelocatable bit set. */ ++ ++static bfd_boolean ++ppc_elf_set_private_flags (bfd *abfd, flagword flags) ++{ ++ BFD_ASSERT (!elf_flags_init (abfd) ++ || elf_elfheader (abfd)->e_flags == flags); ++ ++ elf_elfheader (abfd)->e_flags = flags; ++ elf_flags_init (abfd) = TRUE; ++ return TRUE; ++} ++ ++/* Support for core dump NOTE sections. */ ++ ++static bfd_boolean ++ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) ++{ ++ int offset; ++ unsigned int size; ++ ++ switch (note->descsz) ++ { ++ default: ++ return FALSE; ++ ++ case 268: /* Linux/PPC. */ ++ /* pr_cursig */ ++ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); ++ ++ /* pr_pid */ ++ elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); ++ ++ /* pr_reg */ ++ offset = 72; ++ size = 192; ++ ++ break; ++ } ++ ++ /* Make a ".reg/999" section. */ ++ return _bfd_elfcore_make_pseudosection (abfd, ".reg", ++ size, note->descpos + offset); ++} ++ ++static bfd_boolean ++ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) ++{ ++ switch (note->descsz) ++ { ++ default: ++ return FALSE; ++ ++ case 128: /* Linux/PPC elf_prpsinfo. */ ++ elf_tdata (abfd)->core_pid ++ = bfd_get_32 (abfd, note->descdata + 16); ++ elf_tdata (abfd)->core_program ++ = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); ++ elf_tdata (abfd)->core_command ++ = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); ++ } ++ ++ /* Note that for some reason, a spurious space is tacked ++ onto the end of the args in some (at least one anyway) ++ implementations, so strip it off if it exists. */ ++ ++ { ++ char *command = elf_tdata (abfd)->core_command; ++ int n = strlen (command); ++ ++ if (0 < n && command[n - 1] == ' ') ++ command[n - 1] = '\0'; ++ } ++ ++ return TRUE; ++} ++ ++static char * ++ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...) ++{ ++ switch (note_type) ++ { ++ default: ++ return NULL; ++ ++ case NT_PRPSINFO: ++ { ++ char data[128]; ++ va_list ap; ++ ++ va_start (ap, note_type); ++ memset (data, 0, sizeof (data)); ++ strncpy (data + 32, va_arg (ap, const char *), 16); ++ strncpy (data + 48, va_arg (ap, const char *), 80); ++ va_end (ap); ++ return elfcore_write_note (abfd, buf, bufsiz, ++ "CORE", note_type, data, sizeof (data)); ++ } ++ ++ case NT_PRSTATUS: ++ { ++ char data[268]; ++ va_list ap; ++ long pid; ++ int cursig; ++ const void *greg; ++ ++ va_start (ap, note_type); ++ memset (data, 0, 72); ++ pid = va_arg (ap, long); ++ bfd_put_32 (abfd, pid, data + 24); ++ cursig = va_arg (ap, int); ++ bfd_put_16 (abfd, cursig, data + 12); ++ greg = va_arg (ap, const void *); ++ memcpy (data + 72, greg, 192); ++ memset (data + 264, 0, 4); ++ va_end (ap); ++ return elfcore_write_note (abfd, buf, bufsiz, ++ "CORE", note_type, data, sizeof (data)); ++ } ++ } ++} ++ ++static flagword ++ppc_elf_lookup_section_flags (char *flag_name) ++{ ++ ++ if (!strcmp (flag_name, "SHF_PPC_VLE")) ++ return SHF_PPC_VLE; ++ ++ return 0; ++} ++ ++/* Add the VLE flag if required. */ ++ ++bfd_boolean ++ppc_elf_amigaos_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr) ++{ ++ if (bfd_get_mach (abfd) == bfd_mach_ppc_vle ++ && (shdr->sh_flags & SHF_EXECINSTR) != 0) ++ shdr->sh_flags |= SHF_PPC_VLE; ++ ++ return TRUE; ++} ++ ++/* Return address for Ith PLT stub in section PLT, for relocation REL ++ or (bfd_vma) -1 if it should not be included. */ ++ ++static bfd_vma ++ppc_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED, ++ const asection *plt ATTRIBUTE_UNUSED, ++ const arelent *rel) ++{ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_plt_sym_cal (0x%08x)\n", (unsigned int)rel->address); ++#endif ++ return rel->address; ++} ++ ++/* Handle a PowerPC specific section when reading an object file. This ++ is called when bfd_section_from_shdr finds a section with an unknown ++ type. */ ++ ++static bfd_boolean ++ppc_elf_section_from_shdr (bfd *abfd, ++ Elf_Internal_Shdr *hdr, ++ const char *name, ++ int shindex) ++{ ++ asection *newsect; ++ flagword flags; ++ ++ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) ++ return FALSE; ++ ++ newsect = hdr->bfd_section; ++ flags = bfd_get_section_flags (abfd, newsect); ++ if (hdr->sh_flags & SHF_EXCLUDE) ++ flags |= SEC_EXCLUDE; ++ ++ if (hdr->sh_type == SHT_ORDERED) ++ flags |= SEC_SORT_ENTRIES; ++ ++ bfd_set_section_flags (abfd, newsect, flags); ++ return TRUE; ++} ++ ++/* Set up any other section flags and such that may be necessary. */ ++ ++static bfd_boolean ++ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, ++ Elf_Internal_Shdr *shdr, ++ asection *asect) ++{ ++ if ((asect->flags & SEC_SORT_ENTRIES) != 0) ++ shdr->sh_type = SHT_ORDERED; ++ ++ return TRUE; ++} ++ ++/* If we have .sbss2 or .PPC.EMB.sbss0 output sections, we ++ need to bump up the number of section headers. */ ++ ++static int ++ppc_elf_additional_program_headers (bfd *abfd, ++ struct bfd_link_info *info ATTRIBUTE_UNUSED) ++{ ++ asection *s; ++// int ret = 0; ++ int ret = 1; ++ ++ s = bfd_get_section_by_name (abfd, ".sbss2"); ++ if (s != NULL && (s->flags & SEC_ALLOC) != 0) ++ ++ret; ++ ++ s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0"); ++ if (s != NULL && (s->flags & SEC_ALLOC) != 0) ++ ++ret; ++ ++ return ret; ++} ++ ++/* Modify the segment map for VLE executables. */ ++ ++bfd_boolean ++ppc_elf_amigaos_modify_segment_map (bfd *abfd, ++ struct bfd_link_info *info ATTRIBUTE_UNUSED) ++{ ++ struct elf_segment_map *m, *n; ++ bfd_size_type amt; ++ unsigned int j, k; ++ bfd_boolean sect0_vle, sectj_vle; ++ ++ /* At this point in the link, output sections have already been sorted by ++ LMA and assigned to segments. All that is left to do is to ensure ++ there is no mixing of VLE & non-VLE sections in a text segment. ++ If we find that case, we split the segment. ++ We maintain the original output section order. */ ++ ++ for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) ++ { ++ if (m->count == 0) ++ continue; ++ ++ sect0_vle = (elf_section_flags (m->sections[0]) & SHF_PPC_VLE) != 0; ++ for (j = 1; j < m->count; ++j) ++ { ++ sectj_vle = (elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0; ++ ++ if (sectj_vle != sect0_vle) ++ break; ++ } ++ if (j >= m->count) ++ continue; ++ ++ /* sections 0..j-1 stay in this (current) segment, ++ the remainder are put in a new segment. ++ The scan resumes with the new segment. */ ++ ++ /* Fix the new segment. */ ++ amt = sizeof (struct elf_segment_map); ++ amt += (m->count - j - 1) * sizeof (asection *); ++ n = (struct elf_segment_map *) bfd_zalloc (abfd, amt); ++ if (n == NULL) ++ return FALSE; ++ ++ n->p_type = PT_LOAD; ++ n->p_flags = PF_X | PF_R; ++ if (sectj_vle) ++ n->p_flags |= PF_PPC_VLE; ++ n->count = m->count - j; ++ for (k = 0; k < n->count; ++k) ++ { ++ n->sections[k] = m->sections[j+k]; ++ m->sections[j+k] = NULL; ++ } ++ n->next = m->next; ++ m->next = n; ++ ++ /* Fix the current segment */ ++ m->count = j; ++ } ++ ++ return TRUE; ++} ++ ++/* Add extra PPC sections -- Note, for now, make .sbss2 and ++ .PPC.EMB.sbss0 a normal section, and not a bss section so ++ that the linker doesn't crater when trying to make more than ++ 2 sections. */ ++ ++static const struct bfd_elf_special_section ppc_elf_special_sections[] = ++{ ++ { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR }, ++ { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, ++ { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC }, ++ { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, ++ { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC }, ++ { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC }, ++ { STRING_COMMA_LEN (".PPC.EMB.apuinfo"), 0, SHT_NOTE, 0 }, ++ { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC }, ++ { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC }, ++ { NULL, 0, 0, 0, 0 } ++}; ++ ++/* 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 }; ++ ++static const struct bfd_elf_special_section * ++ppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) ++{ ++ const struct bfd_elf_special_section *ssect; ++ ++ /* See if this is one of the special sections. */ ++ if (sec->name == NULL) ++ return NULL; ++ ++ ssect = _bfd_elf_get_special_section (sec->name, ppc_elf_special_sections, ++ sec->use_rela_p); ++ if (ssect != NULL) ++ { ++ if (ssect == ppc_elf_special_sections && (sec->flags & SEC_LOAD) != 0) ++ ssect = &ppc_alt_plt; ++ return ssect; ++ } ++ ++ return _bfd_elf_get_sec_type_attr (abfd, sec); ++} ++ ++/* Very simple linked list structure for recording apuinfo values. */ ++typedef struct apuinfo_list ++{ ++ struct apuinfo_list *next; ++ unsigned long value; ++} ++apuinfo_list; ++ ++static apuinfo_list *head; ++static bfd_boolean apuinfo_set; ++ ++static void ++apuinfo_list_init (void) ++{ ++ head = NULL; ++ apuinfo_set = FALSE; ++} ++ ++static void ++apuinfo_list_add (unsigned long value) ++{ ++ apuinfo_list *entry = head; ++ ++ while (entry != NULL) ++ { ++ if (entry->value == value) ++ return; ++ entry = entry->next; ++ } ++ ++ entry = bfd_malloc (sizeof (* entry)); ++ if (entry == NULL) ++ return; ++ ++ entry->value = value; ++ entry->next = head; ++ head = entry; ++} ++ ++static unsigned ++apuinfo_list_length (void) ++{ ++ apuinfo_list *entry; ++ unsigned long count; ++ ++ for (entry = head, count = 0; ++ entry; ++ entry = entry->next) ++ ++ count; ++ ++ return count; ++} ++ ++static inline unsigned long ++apuinfo_list_element (unsigned long number) ++{ ++ apuinfo_list * entry; ++ ++ for (entry = head; ++ entry && number --; ++ entry = entry->next) ++ ; ++ ++ return entry ? entry->value : 0; ++} ++ ++static void ++apuinfo_list_finish (void) ++{ ++ apuinfo_list *entry; ++ ++ for (entry = head; entry;) ++ { ++ apuinfo_list *next = entry->next; ++ free (entry); ++ entry = next; ++ } ++ ++ head = NULL; ++} ++ ++#define APUINFO_SECTION_NAME ".PPC.EMB.apuinfo" ++#define APUINFO_LABEL "APUinfo" ++ ++/* Scan the input BFDs and create a linked list of ++ the APUinfo values that will need to be emitted. */ ++ ++static void ++ppc_elf_amigaos_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info) ++{ ++ bfd *ibfd; ++ asection *asec; ++ char *buffer = NULL; ++ bfd_size_type largest_input_size = 0; ++ unsigned i; ++ unsigned long length; ++ const char *error_message = NULL; ++ ++ if (link_info == NULL) ++ return; ++ ++ apuinfo_list_init (); ++ ++ /* Read in the input sections contents. */ ++ for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next) ++ { ++ unsigned long datum; ++ ++ asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME); ++ if (asec == NULL) ++ continue; ++ ++ error_message = _("corrupt %s section in %B"); ++ length = asec->size; ++ if (length < 20) ++ goto fail; ++ ++ apuinfo_set = TRUE; ++ if (largest_input_size < asec->size) ++ { ++ if (buffer) ++ free (buffer); ++ largest_input_size = asec->size; ++ buffer = bfd_malloc (largest_input_size); ++ if (!buffer) ++ return; ++ } ++ ++ if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0 ++ || (bfd_bread (buffer, length, ibfd) != length)) ++ { ++ error_message = _("unable to read in %s section from %B"); ++ goto fail; ++ } ++ ++ /* Verify the contents of the header. Note - we have to ++ extract the values this way in order to allow for a ++ host whose endian-ness is different from the target. */ ++ datum = bfd_get_32 (ibfd, buffer); ++ if (datum != sizeof APUINFO_LABEL) ++ goto fail; ++ ++ datum = bfd_get_32 (ibfd, buffer + 8); ++ if (datum != 0x2) ++ goto fail; ++ ++ if (strcmp (buffer + 12, APUINFO_LABEL) != 0) ++ goto fail; ++ ++ /* Get the number of bytes used for apuinfo entries. */ ++ datum = bfd_get_32 (ibfd, buffer + 4); ++ if (datum + 20 != length) ++ goto fail; ++ ++ /* Scan the apuinfo section, building a list of apuinfo numbers. */ ++ for (i = 0; i < datum; i += 4) ++ apuinfo_list_add (bfd_get_32 (ibfd, buffer + 20 + i)); ++ } ++ ++ error_message = NULL; ++ ++ if (apuinfo_set) ++ { ++ /* Compute the size of the output section. */ ++ unsigned num_entries = apuinfo_list_length (); ++ ++ /* Set the output section size, if it exists. */ ++ asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); ++ ++ if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4)) ++ { ++ ibfd = abfd; ++ error_message = _("warning: unable to set size of %s section in %B"); ++ } ++ } ++ ++ fail: ++ if (buffer) ++ free (buffer); ++ ++ if (error_message) ++ (*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME); ++} ++ ++/* Prevent the output section from accumulating the input sections' ++ contents. We have already stored this in our linked list structure. */ ++ ++static bfd_boolean ++ppc_elf_amigaos_write_section (bfd *abfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *link_info ATTRIBUTE_UNUSED, ++ asection *asec, ++ bfd_byte *contents ATTRIBUTE_UNUSED) ++{ ++ return apuinfo_set && strcmp (asec->name, APUINFO_SECTION_NAME) == 0; ++} ++ ++/* Finally we can generate the output section. */ ++ ++static void ++ppc_elf_amigaos_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) ++{ ++ bfd_byte *buffer; ++ asection *asec; ++ unsigned i; ++ unsigned num_entries; ++ bfd_size_type length; ++ ++ asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); ++ if (asec == NULL) ++ return; ++ ++ if (!apuinfo_set) ++ return; ++ ++ length = asec->size; ++ if (length < 20) ++ return; ++ ++ buffer = bfd_malloc (length); ++ if (buffer == NULL) ++ { ++ (*_bfd_error_handler) ++ (_("failed to allocate space for new APUinfo section.")); ++ return; ++ } ++ ++ /* Create the apuinfo header. */ ++ num_entries = apuinfo_list_length (); ++ bfd_put_32 (abfd, sizeof APUINFO_LABEL, buffer); ++ bfd_put_32 (abfd, num_entries * 4, buffer + 4); ++ bfd_put_32 (abfd, 0x2, buffer + 8); ++ strcpy ((char *) buffer + 12, APUINFO_LABEL); ++ ++ length = 20; ++ for (i = 0; i < num_entries; i++) ++ { ++ bfd_put_32 (abfd, apuinfo_list_element (i), buffer + length); ++ length += 4; ++ } ++ ++ if (length != asec->size) ++ (*_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.")); ++ ++ free (buffer); ++ ++ apuinfo_list_finish (); ++} ++ ++static bfd_boolean ++is_nonpic_glink_stub (bfd *abfd, asection *glink, bfd_vma off) ++{ ++ bfd_byte buf[GLINK_ENTRY_SIZE]; ++ ++ if (!bfd_get_section_contents (abfd, glink, buf, off, GLINK_ENTRY_SIZE)) ++ return FALSE; ++ ++ return ((bfd_get_32 (abfd, buf + 0) & 0xffff0000) == LIS_11 ++ && (bfd_get_32 (abfd, buf + 4) & 0xffff0000) == LWZ_11_11 ++ && bfd_get_32 (abfd, buf + 8) == MTCTR_11 ++ && bfd_get_32 (abfd, buf + 12) == BCTR); ++} ++ ++static bfd_boolean ++section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr) ++{ ++ bfd_vma vma = *(bfd_vma *) ptr; ++ return ((section->flags & SEC_ALLOC) != 0 ++ && section->vma <= vma ++ && vma < section->vma + section->size); ++} ++ ++static long ++ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, ++ long dynsymcount, asymbol **dynsyms, ++ asymbol **ret) ++{ ++ bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); ++ asection *plt, *relplt, *dynamic, *glink; ++ bfd_vma glink_vma = 0; ++ bfd_vma resolv_vma = 0; ++ bfd_vma stub_vma; ++ asymbol *s; ++ arelent *p; ++ long count, i; ++ size_t size; ++ char *names; ++ bfd_byte buf[4]; ++ ++ *ret = NULL; ++ ++ if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) ++ return 0; ++ ++ if (dynsymcount <= 0) ++ return 0; ++ ++ relplt = bfd_get_section_by_name (abfd, ".rela.plt"); ++ if (relplt == NULL) ++ return 0; ++ ++ plt = bfd_get_section_by_name (abfd, ".plt"); ++ if (plt == NULL) ++ return 0; ++ ++ /* Call common code to handle old-style executable PLTs. */ ++ if (elf_section_flags (plt) & SHF_EXECINSTR) ++ return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms, ++ dynsymcount, dynsyms, ret); ++ ++ /* If this object was prelinked, the prelinker stored the address ++ of .glink at got[1]. If it wasn't prelinked, got[1] will be zero. */ ++ dynamic = bfd_get_section_by_name (abfd, ".dynamic"); ++ if (dynamic != NULL) ++ { ++ bfd_byte *dynbuf, *extdyn, *extdynend; ++ size_t extdynsize; ++ void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); ++ ++ if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf)) ++ return -1; ++ ++ extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; ++ swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; ++ ++ extdyn = dynbuf; ++ extdynend = extdyn + dynamic->size; ++ for (; extdyn < extdynend; extdyn += extdynsize) ++ { ++ Elf_Internal_Dyn dyn; ++ (*swap_dyn_in) (abfd, extdyn, &dyn); ++ ++ if (dyn.d_tag == DT_NULL) ++ break; ++ ++ if (dyn.d_tag == DT_PPC_GOT) ++ { ++ unsigned int g_o_t = dyn.d_un.d_val; ++ asection *got = bfd_get_section_by_name (abfd, ".got"); ++ if (got != NULL ++ && bfd_get_section_contents (abfd, got, buf, ++ g_o_t - got->vma + 4, 4)) ++ glink_vma = bfd_get_32 (abfd, buf); ++ break; ++ } ++ } ++ free (dynbuf); ++ } ++ ++ /* Otherwise we read the first plt entry. */ ++ if (glink_vma == 0) ++ { ++ if (bfd_get_section_contents (abfd, plt, buf, 0, 4)) ++ glink_vma = bfd_get_32 (abfd, buf); ++ } ++ ++ if (glink_vma == 0) ++ return 0; ++ ++ /* The .glink section usually does not survive the final ++ link; search for the section (usually .text) where the ++ glink stubs now reside. */ ++ glink = bfd_sections_find_if (abfd, section_covers_vma, &glink_vma); ++ if (glink == NULL) ++ return 0; ++ ++ /* Determine glink PLT resolver by reading the relative branch ++ from the first glink stub. */ ++ if (bfd_get_section_contents (abfd, glink, buf, ++ glink_vma - glink->vma, 4)) ++ { ++ unsigned int insn = bfd_get_32 (abfd, buf); ++ ++ /* The first glink stub may either branch to the resolver ... */ ++ insn ^= B; ++ if ((insn & ~0x3fffffc) == 0) ++ resolv_vma = glink_vma + (insn ^ 0x2000000) - 0x2000000; ++ ++ /* ... or fall through a bunch of NOPs. */ ++ else if ((insn ^ B ^ NOP) == 0) ++ for (i = 4; ++ bfd_get_section_contents (abfd, glink, buf, ++ glink_vma - glink->vma + i, 4); ++ i += 4) ++ if (bfd_get_32 (abfd, buf) != NOP) ++ { ++ resolv_vma = glink_vma + i; ++ break; ++ } ++ } ++ ++ count = relplt->size / sizeof (Elf32_External_Rela); ++ stub_vma = glink_vma - (bfd_vma) count * 16; ++ /* 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)) ++ return 0; ++ ++ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; ++ if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) ++ return -1; ++ ++ size = count * sizeof (asymbol); ++ p = relplt->relocation; ++ for (i = 0; i < count; i++, p++) ++ { ++ size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); ++ if (p->addend != 0) ++ size += sizeof ("+0x") - 1 + 8; ++ } ++ ++ size += sizeof (asymbol) + sizeof ("__glink"); ++ ++ if (resolv_vma) ++ size += sizeof (asymbol) + sizeof ("__glink_PLTresolve"); ++ ++ s = *ret = bfd_malloc (size); ++ if (s == NULL) ++ return -1; ++ ++ names = (char *) (s + count + 1 + (resolv_vma != 0)); ++ p = relplt->relocation; ++ for (i = 0; i < count; i++, p++) ++ { ++ size_t len; ++ ++ *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. */ ++ if ((s->flags & BSF_LOCAL) == 0) ++ s->flags |= BSF_GLOBAL; ++ s->flags |= BSF_SYNTHETIC; ++ s->section = glink; ++ s->value = stub_vma - glink->vma; ++ s->name = names; ++ s->udata.p = NULL; ++ len = strlen ((*p->sym_ptr_ptr)->name); ++ memcpy (names, (*p->sym_ptr_ptr)->name, len); ++ names += len; ++ if (p->addend != 0) ++ { ++ memcpy (names, "+0x", sizeof ("+0x") - 1); ++ names += sizeof ("+0x") - 1; ++ bfd_sprintf_vma (abfd, names, p->addend); ++ names += strlen (names); ++ } ++ memcpy (names, "@plt", sizeof ("@plt")); ++ names += sizeof ("@plt"); ++ ++s; ++ stub_vma += 16; ++ } ++ ++ /* Add a symbol at the start of the glink branch table. */ ++ memset (s, 0, sizeof *s); ++ s->the_bfd = abfd; ++ s->flags = BSF_GLOBAL | BSF_SYNTHETIC; ++ s->section = glink; ++ s->value = glink_vma - glink->vma; ++ s->name = names; ++ memcpy (names, "__glink", sizeof ("__glink")); ++ names += sizeof ("__glink"); ++ s++; ++ count++; ++ ++ if (resolv_vma) ++ { ++ /* Add a symbol for the glink PLT resolver. */ ++ memset (s, 0, sizeof *s); ++ s->the_bfd = abfd; ++ s->flags = BSF_GLOBAL | BSF_SYNTHETIC; ++ s->section = glink; ++ s->value = resolv_vma - glink->vma; ++ s->name = names; ++ memcpy (names, "__glink_PLTresolve", sizeof ("__glink_PLTresolve")); ++ names += sizeof ("__glink_PLTresolve"); ++ s++; ++ count++; ++ } ++ ++ return count; ++} ++ ++/* The following functions are specific to the ELF linker, while ++ functions above are used generally. They appear in this file more ++ or less in the order in which they are called. eg. ++ ppc_elf_check_relocs is called early in the link process, ++ ppc_elf_finish_dynamic_sections is one of the last functions ++ called. */ ++ ++/* Track PLT entries needed for a given symbol. We might need more ++ than one glink entry per symbol when generating a pic binary. */ ++struct plt_entry ++{ ++ struct plt_entry *next; ++ ++ /* -fPIC uses multiple GOT sections, one per file, called ".got2". ++ This field stores the offset into .got2 used to initialise the ++ GOT pointer reg. It will always be at least 32768. (Current ++ gcc always uses an offset of 32768, but ld -r will pack .got2 ++ sections together resulting in larger offsets). */ ++ bfd_vma addend; ++ ++ /* The .got2 section. */ ++ asection *sec; ++ ++ /* PLT refcount or offset. */ ++ union ++ { ++ bfd_signed_vma refcount; ++ bfd_vma offset; ++ } plt; ++ ++ /* .glink stub offset. */ ++ 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. */ ++ ++static int ++must_be_dyn_reloc (struct bfd_link_info *info, ++ enum elf_ppc_reloc_type r_type) ++{ ++ switch (r_type) ++ { ++ default: ++ return 1; ++ ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ case R_PPC_REL32: ++ return 0; ++ ++ case R_PPC_TPREL32: ++ case R_PPC_TPREL16: ++ case R_PPC_TPREL16_LO: ++ case R_PPC_TPREL16_HI: ++ case R_PPC_TPREL16_HA: ++ return !info->executable; ++ } ++} ++ ++/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid ++ copying dynamic variables from a shared lib into an app's dynbss ++ section, and instead use a dynamic relocation to point into the ++ shared lib. */ ++#define ELIMINATE_COPY_RELOCS 1 ++ ++/* PPC ELF linker hash entry. */ ++ ++struct ppc_elf_link_hash_entry ++{ ++ struct elf_link_hash_entry elf; ++ ++ /* If this symbol is used in the linker created sections, the processor ++ specific backend uses this field to map the field into the offset ++ from the beginning of the section. */ ++ elf_linker_section_pointers_t *linker_section_pointer; ++ ++ /* 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; ++ ++ /* Nonzero if we have seen a small data relocation referring to this ++ symbol. */ ++ unsigned char has_sda_refs; ++}; ++ ++#define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent)) ++ ++/* PPC ELF linker hash table. */ ++ ++struct ppc_elf_link_hash_table ++{ ++ struct elf_link_hash_table elf; ++ ++ /* Short-cuts to get to dynamic linker sections. */ ++ asection *got; ++ asection *relgot; ++ asection *glink; ++ asection *plt; ++ asection *relplt; ++ asection *iplt; ++ asection *reliplt; ++ asection *dynbss; ++ asection *relbss; ++ asection *dynsbss; ++ asection *relsbss; ++ elf_linker_section_t sdata[2]; ++ asection *sbss; ++ asection *glink_eh_frame; ++ ++ /* The (unloaded but important) .rela.plt.unloaded on VxWorks. */ ++ asection *srelplt2; ++ ++ /* The .got.plt section (VxWorks only)*/ ++ asection *sgotplt; ++ ++ /* Shortcut to __tls_get_addr. */ ++ struct elf_link_hash_entry *tls_get_addr; ++ ++ /* The bfd that forced an old-style PLT. */ ++ bfd *old_bfd; ++ ++ /* TLS local dynamic got entry handling. */ ++ union { ++ bfd_signed_vma refcount; ++ bfd_vma offset; ++ } tlsld_got; ++ ++ /* Offset of branch table to PltResolve function in glink. */ ++ bfd_vma glink_pltresolve; ++ ++ /* Size of reserved GOT entries. */ ++ unsigned int got_header_size; ++ /* Non-zero if allocating the header left a gap. */ ++ unsigned int got_gap; ++ ++ /* The type of PLT we have chosen to use. */ ++ enum ppc_elf_plt_type plt_type; ++ ++ /* Set if we should emit symbols for stubs. */ ++ unsigned int emit_stub_syms:1; ++ ++ /* Set if __tls_get_addr optimization should not be done. */ ++ unsigned int no_tls_get_addr_opt:1; ++ ++ /* True if the target system is VxWorks. */ ++ unsigned int is_vxworks:1; ++ ++ /* The size of PLT entries. */ ++ int plt_entry_size; ++ /* The distance between adjacent PLT slots. */ ++ int plt_slot_size; ++ /* The size of the first PLT entry. */ ++ int plt_initial_entry_size; ++ ++ /* Small local sym cache. */ ++ struct sym_cache sym_cache; ++}; ++ ++/* Rename some of the generic section flags to better document how they ++ are used for ppc32. The flags are only valid for ppc32 elf objects. */ ++ ++/* Nonzero if this section has TLS related relocations. */ ++#define has_tls_reloc sec_flg0 ++ ++/* Nonzero if this section has a call to __tls_get_addr. */ ++#define has_tls_get_addr_call sec_flg1 ++ ++/* Get the PPC ELF linker hash table from a link_info structure. */ ++ ++#define ppc_elf_hash_table(p) \ ++ (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ ++ == PPC32_ELF_DATA ? ((struct ppc_elf_link_hash_table *) ((p)->hash)) : NULL) ++ ++/* Create an entry in a PPC ELF linker hash table. */ ++ ++static struct bfd_hash_entry * ++ppc_elf_link_hash_newfunc (struct bfd_hash_entry *entry, ++ struct bfd_hash_table *table, ++ const char *string) ++{ ++ /* Allocate the structure if it has not already been allocated by a ++ subclass. */ ++ if (entry == NULL) ++ { ++ entry = bfd_hash_allocate (table, ++ sizeof (struct ppc_elf_link_hash_entry)); ++ if (entry == NULL) ++ return entry; ++ } ++ ++ /* Call the allocation method of the superclass. */ ++ entry = _bfd_elf_link_hash_newfunc (entry, table, string); ++ if (entry != NULL) ++ { ++ ppc_elf_hash_entry (entry)->linker_section_pointer = NULL; ++ ppc_elf_hash_entry (entry)->dyn_relocs = NULL; ++ ppc_elf_hash_entry (entry)->tls_mask = 0; ++ ppc_elf_hash_entry (entry)->has_sda_refs = 0; ++ } ++ ++ return entry; ++} ++ ++/* Create a PPC ELF linker hash table. */ ++ ++static struct bfd_link_hash_table * ++ppc_elf_link_hash_table_create (bfd *abfd) ++{ ++ struct ppc_elf_link_hash_table *ret; ++ ++ ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table)); ++ if (ret == NULL) ++ return NULL; ++ ++ if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, ++ ppc_elf_link_hash_newfunc, ++ sizeof (struct ppc_elf_link_hash_entry), ++ PPC32_ELF_DATA)) ++ { ++ free (ret); ++ return NULL; ++ } ++ ++ ret->elf.init_plt_refcount.refcount = 0; ++ ret->elf.init_plt_refcount.glist = NULL; ++ ret->elf.init_plt_offset.offset = 0; ++ ret->elf.init_plt_offset.glist = NULL; ++ ++ ret->sdata[0].name = ".sdata"; ++ ret->sdata[0].sym_name = "_SDA_BASE_"; ++ ret->sdata[0].bss_name = ".sbss"; ++ ++ ret->sdata[1].name = ".sdata2"; ++ ret->sdata[1].sym_name = "_SDA2_BASE_"; ++ ret->sdata[1].bss_name = ".sbss2"; ++ ++ ret->plt_entry_size = 12; ++ ret->plt_slot_size = 8; ++ ret->plt_initial_entry_size = 72; ++ ++ return &ret->elf.root; ++} ++ ++/* Create .got and the related sections. */ ++ ++static bfd_boolean ++ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ asection *s; ++ flagword flags; ++ ++ if (!_bfd_elf_create_got_section (abfd, info)) ++ return FALSE; ++ ++ htab = ppc_elf_hash_table (info); ++ htab->got = s = bfd_get_linker_section (abfd, ".got"); ++ if (s == NULL) ++ abort (); ++ ++ if (htab->is_vxworks) ++ { ++ htab->sgotplt = bfd_get_linker_section (abfd, ".got.plt"); ++ if (!htab->sgotplt) ++ abort (); ++ } ++ else ++ { ++ /* The powerpc .got has a blrl instruction in it. Mark it ++ executable. */ ++ flags = (SEC_ALLOC | SEC_LOAD | /*SEC_CODE |*/ SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ if (!bfd_set_section_flags (abfd, s, flags)) ++ return FALSE; ++ } ++ ++ htab->relgot = bfd_get_linker_section (abfd, ".rela.got"); ++ if (!htab->relgot) ++ abort (); ++ ++ return TRUE; ++} ++ ++static bfd_boolean ++ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info) ++{ ++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); ++ asection *s; ++ flagword flags; ++ ++ 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; ++ if (s == NULL ++ || !bfd_set_section_alignment (abfd, s, 4)) ++ return FALSE; ++ ++ if (!info->no_ld_generated_unwind_info) ++ { ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ s = bfd_make_section_anyway_with_flags (abfd, ".eh_frame", flags); ++ htab->glink_eh_frame = s; ++ if (s == NULL ++ || !bfd_set_section_alignment (abfd, s, 2)) ++ return FALSE; ++ } ++ ++ flags = SEC_ALLOC | SEC_LINKER_CREATED; ++ s = bfd_make_section_anyway_with_flags (abfd, ".iplt", flags); ++ htab->iplt = s; ++ if (s == NULL ++ || !bfd_set_section_alignment (abfd, s, 4)) ++ return FALSE; ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ s = bfd_make_section_anyway_with_flags (abfd, ".rela.iplt", flags); ++ htab->reliplt = s; ++ if (s == NULL ++ || ! bfd_set_section_alignment (abfd, s, 2)) ++ return FALSE; ++ return TRUE; ++} ++ ++/* We have to create .dynsbss and .rela.sbss here so that they get mapped ++ to output sections (just like _bfd_elf_create_dynamic_sections has ++ to create .dynbss and .rela.bss). */ ++ ++static bfd_boolean ++ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ asection *s; ++ flagword flags; ++ ++ htab = ppc_elf_hash_table (info); ++ ++ if (htab->got == NULL ++ && !ppc_elf_create_got (abfd, info)) ++ return FALSE; ++ ++ if (!_bfd_elf_create_dynamic_sections (abfd, info)) ++ return FALSE; ++ ++ if (htab->glink == NULL ++ && !ppc_elf_create_glink (abfd, info)) ++ return FALSE; ++ ++ htab->dynbss = bfd_get_linker_section (abfd, ".dynbss"); ++ s = bfd_make_section_anyway_with_flags (abfd, ".dynsbss", ++ SEC_ALLOC | SEC_LINKER_CREATED); ++ htab->dynsbss = s; ++ if (s == NULL) ++ return FALSE; ++ ++ if (! info->shared) ++ { ++ htab->relbss = bfd_get_linker_section (abfd, ".rela.bss"); ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ s = bfd_make_section_anyway_with_flags (abfd, ".rela.sbss", flags); ++ htab->relsbss = s; ++ if (s == NULL ++ || ! bfd_set_section_alignment (abfd, s, 2)) ++ return FALSE; ++ } ++ ++ if (htab->is_vxworks ++ && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2)) ++ return FALSE; ++ ++ htab->relplt = bfd_get_linker_section (abfd, ".rela.plt"); ++ htab->plt = s = bfd_get_linker_section (abfd, ".plt"); ++ if (s == NULL) ++ abort (); ++ ++ flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED | SEC_READONLY; ++ if (htab->plt_type == PLT_VXWORKS) ++ /* The VxWorks PLT is a loaded section with contents. */ ++ flags |= SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY; ++ return bfd_set_section_flags (abfd, s, flags); ++} ++ ++/* Copy the extra info we tack onto an elf_link_hash_entry. */ ++ ++static void ++ppc_elf_copy_indirect_symbol (struct bfd_link_info *info, ++ struct elf_link_hash_entry *dir, ++ struct elf_link_hash_entry *ind) ++{ ++ struct ppc_elf_link_hash_entry *edir, *eind; ++ ++ edir = (struct ppc_elf_link_hash_entry *) dir; ++ eind = (struct ppc_elf_link_hash_entry *) ind; ++ ++ 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; ++ ++ 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.needs_plt |= eind->elf.needs_plt; ++ edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed; ++ ++ if (eind->dyn_relocs != NULL) ++ { ++ if (edir->dyn_relocs != NULL) ++ { ++ struct elf_dyn_relocs **pp; ++ struct elf_dyn_relocs *p; ++ ++ /* Add reloc counts against the indirect sym to the direct sym ++ list. Merge any entries against the same section. */ ++ for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) ++ { ++ struct elf_dyn_relocs *q; ++ ++ for (q = edir->dyn_relocs; q != NULL; q = q->next) ++ if (q->sec == p->sec) ++ { ++ q->pc_count += p->pc_count; ++ q->count += p->count; ++ *pp = p->next; ++ break; ++ } ++ if (q == NULL) ++ pp = &p->next; ++ } ++ *pp = edir->dyn_relocs; ++ } ++ ++ edir->dyn_relocs = eind->dyn_relocs; ++ 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; ++ eind->elf.got.refcount = 0; ++ ++ /* And plt entries. */ ++ if (eind->elf.plt.plist != NULL) ++ { ++ if (edir->elf.plt.plist != NULL) ++ { ++ struct plt_entry **entp; ++ struct plt_entry *ent; ++ ++ for (entp = &eind->elf.plt.plist; (ent = *entp) != NULL; ) ++ { ++ struct plt_entry *dent; ++ ++ for (dent = edir->elf.plt.plist; dent != NULL; dent = dent->next) ++ if (dent->sec == ent->sec && dent->addend == ent->addend) ++ { ++ dent->plt.refcount += ent->plt.refcount; ++ *entp = ent->next; ++ break; ++ } ++ if (dent == NULL) ++ entp = &ent->next; ++ } ++ *entp = edir->elf.plt.plist; ++ } ++ ++ edir->elf.plt.plist = eind->elf.plt.plist; ++ eind->elf.plt.plist = NULL; ++ } ++ ++ if (eind->elf.dynindx != -1) ++ { ++ if (edir->elf.dynindx != -1) ++ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, ++ edir->elf.dynstr_index); ++ edir->elf.dynindx = eind->elf.dynindx; ++ edir->elf.dynstr_index = eind->elf.dynstr_index; ++ eind->elf.dynindx = -1; ++ eind->elf.dynstr_index = 0; ++ } ++} ++ ++/* Hook called by the linker routine which adds symbols from an object ++ file. We use it to put .comm items in .sbss, and not .bss. */ ++ ++static bfd_boolean ++ppc_elf_add_symbol_hook (bfd *abfd, ++ struct bfd_link_info *info, ++ Elf_Internal_Sym *sym, ++ const char **namep ATTRIBUTE_UNUSED, ++ flagword *flagsp ATTRIBUTE_UNUSED, ++ asection **secp, ++ bfd_vma *valp) ++{ ++ if (sym->st_shndx == SHN_COMMON ++ && !info->relocatable ++ && is_ppc_elf (info->output_bfd) ++ && sym->st_size <= elf_gp_size (abfd)) ++ { ++ /* Common symbols less than or equal to -G nn bytes are automatically ++ put into .sbss. */ ++ struct ppc_elf_link_hash_table *htab; ++ ++ htab = ppc_elf_hash_table (info); ++ if (htab->sbss == NULL) ++ { ++ flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED; ++ ++ if (!htab->elf.dynobj) ++ htab->elf.dynobj = abfd; ++ ++ htab->sbss = bfd_make_section_anyway_with_flags (htab->elf.dynobj, ++ ".sbss", ++ flags); ++ if (htab->sbss == NULL) ++ return FALSE; ++ } ++ ++ *secp = htab->sbss; ++ *valp = sym->st_size; ++ } ++ ++ if ((abfd->flags & DYNAMIC) == 0 ++ && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC ++ || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)) ++ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; ++ ++ return TRUE; ++} ++ ++static bfd_boolean ++create_sdata_sym (struct bfd_link_info *info, elf_linker_section_t *lsect) ++{ ++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); ++ ++ lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name, ++ TRUE, FALSE, TRUE); ++ if (lsect->sym == NULL) ++ return FALSE; ++ if (lsect->sym->root.type == bfd_link_hash_new) ++ lsect->sym->non_elf = 0; ++ lsect->sym->ref_regular = 1; ++ _bfd_elf_link_hash_hide_symbol (info, lsect->sym, TRUE); ++ return TRUE; ++} ++ ++/* Create a special linker section. */ ++ ++static bfd_boolean ++ppc_elf_create_linker_section (bfd *abfd, ++ struct bfd_link_info *info, ++ flagword flags, ++ elf_linker_section_t *lsect) ++{ ++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); ++ asection *s; ++ ++ flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED); ++ ++ /* Record the first bfd that needs the special sections. */ ++ if (!htab->elf.dynobj) ++ htab->elf.dynobj = abfd; ++ ++ s = bfd_make_section_anyway_with_flags (htab->elf.dynobj, ++ lsect->name, ++ flags); ++ if (s == NULL ++ || !bfd_set_section_alignment (htab->elf.dynobj, s, 2)) ++ return FALSE; ++ lsect->section = s; ++ ++ return create_sdata_sym (info, lsect); ++} ++ ++/* Find a linker generated pointer with a given addend and type. */ ++ ++static elf_linker_section_pointers_t * ++elf_find_pointer_linker_section ++ (elf_linker_section_pointers_t *linker_pointers, ++ bfd_vma addend, ++ elf_linker_section_t *lsect) ++{ ++ for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next) ++ if (lsect == linker_pointers->lsect && addend == linker_pointers->addend) ++ return linker_pointers; ++ ++ return NULL; ++} ++ ++/* Allocate a pointer to live in a linker created section. */ ++ ++static bfd_boolean ++elf_create_pointer_linker_section (bfd *abfd, ++ elf_linker_section_t *lsect, ++ struct elf_link_hash_entry *h, ++ const Elf_Internal_Rela *rel) ++{ ++ elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL; ++ elf_linker_section_pointers_t *linker_section_ptr; ++ unsigned long r_symndx = ELF32_R_SYM (rel->r_info); ++ bfd_size_type amt; ++ ++ BFD_ASSERT (lsect != NULL); ++ ++ /* Is this a global symbol? */ ++ if (h != NULL) ++ { ++ struct ppc_elf_link_hash_entry *eh; ++ ++ /* Has this symbol already been allocated? If so, our work is done. */ ++ eh = (struct ppc_elf_link_hash_entry *) h; ++ if (elf_find_pointer_linker_section (eh->linker_section_pointer, ++ rel->r_addend, ++ lsect)) ++ return TRUE; ++ ++ ptr_linker_section_ptr = &eh->linker_section_pointer; ++ } ++ else ++ { ++ BFD_ASSERT (is_ppc_elf (abfd)); ++ ++ /* Allocation of a pointer to a local symbol. */ ++ elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd); ++ ++ /* Allocate a table to hold the local symbols if first time. */ ++ if (!ptr) ++ { ++ unsigned int num_symbols = elf_symtab_hdr (abfd).sh_info; ++ ++ amt = num_symbols; ++ amt *= sizeof (elf_linker_section_pointers_t *); ++ ptr = bfd_zalloc (abfd, amt); ++ ++ if (!ptr) ++ return FALSE; ++ ++ elf_local_ptr_offsets (abfd) = ptr; ++ } ++ ++ /* Has this symbol already been allocated? If so, our work is done. */ ++ if (elf_find_pointer_linker_section (ptr[r_symndx], ++ rel->r_addend, ++ lsect)) ++ return TRUE; ++ ++ ptr_linker_section_ptr = &ptr[r_symndx]; ++ } ++ ++ /* Allocate space for a pointer in the linker section, and allocate ++ a new pointer record from internal memory. */ ++ BFD_ASSERT (ptr_linker_section_ptr != NULL); ++ amt = sizeof (elf_linker_section_pointers_t); ++ linker_section_ptr = bfd_alloc (abfd, amt); ++ ++ if (!linker_section_ptr) ++ return FALSE; ++ ++ linker_section_ptr->next = *ptr_linker_section_ptr; ++ linker_section_ptr->addend = rel->r_addend; ++ linker_section_ptr->lsect = lsect; ++ *ptr_linker_section_ptr = linker_section_ptr; ++ ++ linker_section_ptr->offset = lsect->section->size; ++ lsect->section->size += 4; ++ ++#ifdef DEBUG ++ fprintf (stderr, ++ "Create pointer in linker section %s, offset = %ld, section size = %ld\n", ++ lsect->name, (long) linker_section_ptr->offset, ++ (long) lsect->section->size); ++#endif ++ ++ return TRUE; ++} ++ ++static struct plt_entry ** ++update_local_sym_info (bfd *abfd, ++ Elf_Internal_Shdr *symtab_hdr, ++ unsigned long r_symndx, ++ int tls_type) ++{ ++ bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd); ++ struct plt_entry **local_plt; ++ char *local_got_tls_masks; ++ ++ if (local_got_refcounts == NULL) ++ { ++ bfd_size_type size = symtab_hdr->sh_info; ++ ++ size *= (sizeof (*local_got_refcounts) ++ + sizeof (*local_plt) ++ + sizeof (*local_got_tls_masks)); ++ local_got_refcounts = bfd_zalloc (abfd, size); ++ if (local_got_refcounts == NULL) ++ return NULL; ++ elf_local_got_refcounts (abfd) = local_got_refcounts; ++ } ++ ++ 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_refcounts[r_symndx] += 1; ++ return local_plt + r_symndx; ++} ++ ++static bfd_boolean ++update_plt_info (bfd *abfd, struct plt_entry **plist, ++ asection *sec, bfd_vma addend) ++{ ++ struct plt_entry *ent; ++ ++ if (addend < 32768) ++ sec = NULL; ++ for (ent = *plist; ent != NULL; ent = ent->next) ++ if (ent->sec == sec && ent->addend == addend) ++ break; ++ if (ent == NULL) ++ { ++ bfd_size_type amt = sizeof (*ent); ++ ent = bfd_alloc (abfd, amt); ++ if (ent == NULL) ++ return FALSE; ++ ent->next = *plist; ++ ent->sec = sec; ++ ent->addend = addend; ++ ent->plt.refcount = 0; ++ *plist = ent; ++ } ++ ent->plt.refcount += 1; ++ return TRUE; ++} ++ ++static struct plt_entry * ++find_plt_ent (struct plt_entry **plist, asection *sec, bfd_vma addend) ++{ ++ struct plt_entry *ent; ++ ++ if (addend < 32768) ++ sec = NULL; ++ for (ent = *plist; ent != NULL; ent = ent->next) ++ if (ent->sec == sec && ent->addend == addend) ++ break; ++ return ent; ++} ++ ++static bfd_boolean ++is_branch_reloc (enum elf_ppc_reloc_type r_type) ++{ ++ return (r_type == R_PPC_PLTREL24 ++ || r_type == R_PPC_LOCAL24PC ++ || r_type == R_PPC_REL24 ++ || r_type == R_PPC_REL14 ++ || r_type == R_PPC_REL14_BRTAKEN ++ || r_type == R_PPC_REL14_BRNTAKEN ++ || r_type == R_PPC_ADDR24 ++ || r_type == R_PPC_ADDR14 ++ || r_type == R_PPC_ADDR14_BRTAKEN ++ || r_type == R_PPC_ADDR14_BRNTAKEN); ++} ++ ++static void ++bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type) ++{ ++ (*_bfd_error_handler) ++ (_("%B: 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); ++} ++ ++/* Look through the relocs for a section during the first phase, and ++ allocate space in the global offset table or procedure linkage ++ table. */ ++ ++static bfd_boolean ++ppc_elf_check_relocs (bfd *abfd, ++ struct bfd_link_info *info, ++ asection *sec, ++ const Elf_Internal_Rela *relocs) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes; ++ const Elf_Internal_Rela *rel; ++ const Elf_Internal_Rela *rel_end; ++ asection *got2, *sreloc; ++ struct elf_link_hash_entry *tga; ++ ++ if (info->relocatable) ++ return TRUE; ++ ++ /* Don't do anything special with non-loaded, non-alloced sections. ++ In particular, any relocs in such sections should not affect GOT ++ and PLT reference counting (ie. we don't allow them to create GOT ++ or PLT entries), there's no possibility or desire to optimize TLS ++ relocs, and there's not much point in propagating relocs to shared ++ libs that the dynamic linker won't relocate. */ ++ if ((sec->flags & SEC_ALLOC) == 0) ++ return TRUE; ++ ++#ifdef DEBUG ++ _bfd_error_handler ("ppc_elf_check_relocs called for section %A in %B", ++ sec, abfd); ++#endif ++ ++ BFD_ASSERT (is_ppc_elf (abfd)); ++ ++ /* Initialize howto table if not already done. */ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ ppc_elf_howto_init (); ++ ++ htab = ppc_elf_hash_table (info); ++ if (htab->glink == NULL) ++ { ++ if (htab->elf.dynobj == NULL) ++ htab->elf.dynobj = abfd; ++ if (!ppc_elf_create_glink (htab->elf.dynobj, info)) ++ return FALSE; ++ } ++ tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", ++ FALSE, FALSE, TRUE); ++ symtab_hdr = &elf_symtab_hdr (abfd); ++ sym_hashes = elf_sym_hashes (abfd); ++ got2 = bfd_get_section_by_name (abfd, ".got2"); ++ sreloc = NULL; ++ ++ rel_end = relocs + sec->reloc_count; ++ for (rel = relocs; rel < rel_end; rel++) ++ { ++ unsigned long r_symndx; ++ enum elf_ppc_reloc_type r_type; ++ struct elf_link_hash_entry *h; ++ int tls_type; ++ ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx < symtab_hdr->sh_info) ++ h = NULL; ++ else ++ { ++ 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 a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. ++ This shows up in particular in an R_PPC_ADDR32 in the eabi ++ startup code. */ ++ if (h != NULL ++ && htab->got == NULL ++ && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) ++ { ++ if (htab->elf.dynobj == NULL) ++ htab->elf.dynobj = abfd; ++ if (!ppc_elf_create_got (htab->elf.dynobj, info)) ++ return FALSE; ++ BFD_ASSERT (h == htab->elf.hgot); ++ } ++ ++ tls_type = 0; ++ r_type = ELF32_R_TYPE (rel->r_info); ++ if (h == NULL && !htab->is_vxworks) ++ { ++ Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache, ++ abfd, r_symndx); ++ if (isym == NULL) ++ return FALSE; ++ ++ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC ++ && (!info->shared ++ || is_branch_reloc (r_type))) ++ { ++ struct plt_entry **ifunc; ++ bfd_vma addend; ++ ++ ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, ++ PLT_IFUNC); ++ if (ifunc == NULL) ++ return FALSE; ++ ++ /* STT_GNU_IFUNC symbols must have a PLT entry; ++ In a non-pie executable even when there are ++ no plt calls. */ ++ addend = 0; ++ if (r_type == R_PPC_PLTREL24) ++ { ++ ppc_elf_tdata (abfd)->makes_plt_call = 1; ++ if (info->shared) ++ addend = rel->r_addend; ++ } ++ if (!update_plt_info (abfd, ifunc, got2, addend)) ++ return FALSE; ++ } ++ } ++ ++ if (!htab->is_vxworks ++ && is_branch_reloc (r_type) ++ && h != NULL ++ && h == tga) ++ { ++ if (rel != relocs ++ && (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD ++ || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD)) ++ /* We have a new-style __tls_get_addr call with a marker ++ reloc. */ ++ ; ++ else ++ /* Mark this section as having an old-style call. */ ++ sec->has_tls_get_addr_call = 1; ++ } ++ ++ switch (r_type) ++ { ++ case R_PPC_TLSGD: ++ case R_PPC_TLSLD: ++ /* These special tls relocs tie a call to __tls_get_addr with ++ its parameter symbol. */ ++ break; ++ ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ case R_PPC_GOT_TLSLD16_HI: ++ case R_PPC_GOT_TLSLD16_HA: ++ tls_type = TLS_TLS | TLS_LD; ++ goto dogottls; ++ ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ case R_PPC_GOT_TLSGD16_HI: ++ case R_PPC_GOT_TLSGD16_HA: ++ tls_type = TLS_TLS | TLS_GD; ++ goto dogottls; ++ ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ case R_PPC_GOT_TPREL16_HI: ++ case R_PPC_GOT_TPREL16_HA: ++ if (!info->executable) ++ info->flags |= DF_STATIC_TLS; ++ tls_type = TLS_TLS | TLS_TPREL; ++ goto dogottls; ++ ++ case R_PPC_GOT_DTPREL16: ++ case R_PPC_GOT_DTPREL16_LO: ++ case R_PPC_GOT_DTPREL16_HI: ++ case R_PPC_GOT_DTPREL16_HA: ++ tls_type = TLS_TLS | TLS_DTPREL; ++ dogottls: ++ sec->has_tls_reloc = 1; ++ /* Fall thru */ ++ ++ /* GOT16 relocations */ ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ /* This symbol requires a global offset table entry. */ ++ if (htab->got == NULL) ++ { ++ if (htab->elf.dynobj == NULL) ++ htab->elf.dynobj = abfd; ++ if (!ppc_elf_create_got (htab->elf.dynobj, info)) ++ return FALSE; ++ } ++ if (h != NULL) ++ { ++ h->got.refcount += 1; ++ ppc_elf_hash_entry (h)->tls_mask |= tls_type; ++ } ++ else ++ /* This is a global offset table entry for a local symbol. */ ++ if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, tls_type)) ++ return FALSE; ++ ++ /* We may also need a plt entry if the symbol turns out to be ++ an ifunc. */ ++ if (h != NULL && !info->shared) ++ { ++ if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) ++ return FALSE; ++ } ++ break; ++ ++ /* Indirect .sdata relocation. */ ++ case R_PPC_EMB_SDAI16: ++ if (info->shared) ++ { ++ bad_shared_reloc (abfd, r_type); ++ return FALSE; ++ } ++ if (htab->sdata[0].section == NULL ++ && !ppc_elf_create_linker_section (abfd, info, 0, ++ &htab->sdata[0])) ++ return FALSE; ++ if (!elf_create_pointer_linker_section (abfd, &htab->sdata[0], ++ h, rel)) ++ return FALSE; ++ if (h != NULL) ++ { ++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE; ++ h->non_got_ref = TRUE; ++ } ++ break; ++ ++ /* Indirect .sdata2 relocation. */ ++ case R_PPC_EMB_SDA2I16: ++ if (info->shared) ++ { ++ bad_shared_reloc (abfd, r_type); ++ return FALSE; ++ } ++ if (htab->sdata[1].section == NULL ++ && !ppc_elf_create_linker_section (abfd, info, SEC_READONLY, ++ &htab->sdata[1])) ++ return FALSE; ++ if (!elf_create_pointer_linker_section (abfd, &htab->sdata[1], ++ h, rel)) ++ return FALSE; ++ if (h != NULL) ++ { ++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE; ++ h->non_got_ref = TRUE; ++ } ++ break; ++ ++ case R_PPC_VLE_SDAREL_LO16A: ++ case R_PPC_VLE_SDAREL_LO16D: ++ case R_PPC_VLE_SDAREL_HI16A: ++ case R_PPC_VLE_SDAREL_HI16D: ++ case R_PPC_VLE_SDAREL_HA16A: ++ case R_PPC_VLE_SDAREL_HA16D: ++ case R_PPC_SDAREL16: ++ if (htab->sdata[0].sym == NULL ++ && !create_sdata_sym (info, &htab->sdata[0])) ++ return FALSE; ++ ++ if (htab->sdata[1].sym == NULL ++ && !create_sdata_sym (info, &htab->sdata[1])) ++ return FALSE; ++ ++ if (h != NULL) ++ { ++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE; ++ h->non_got_ref = TRUE; ++ } ++ break; ++ ++ case R_PPC_VLE_REL8: ++ case R_PPC_VLE_REL15: ++ case R_PPC_VLE_REL24: ++ case R_PPC_VLE_LO16A: ++ case R_PPC_VLE_LO16D: ++ case R_PPC_VLE_HI16A: ++ case R_PPC_VLE_HI16D: ++ case R_PPC_VLE_HA16A: ++ case R_PPC_VLE_HA16D: ++ break; ++ ++ case R_PPC_EMB_SDA2REL: ++ if (info->shared) ++ { ++ bad_shared_reloc (abfd, r_type); ++ return FALSE; ++ } ++ if (htab->sdata[1].sym == NULL ++ && !create_sdata_sym (info, &htab->sdata[1])) ++ return FALSE; ++ if (h != NULL) ++ { ++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE; ++ h->non_got_ref = TRUE; ++ } ++ break; ++ ++ case R_PPC_VLE_SDA21_LO: ++ case R_PPC_VLE_SDA21: ++ case R_PPC_EMB_SDA21: ++ case R_PPC_EMB_RELSDA: ++ if (info->shared) ++ { ++ bad_shared_reloc (abfd, r_type); ++ return FALSE; ++ } ++ if (htab->sdata[0].sym == NULL ++ && !create_sdata_sym (info, &htab->sdata[0])) ++ return FALSE; ++ if (htab->sdata[1].sym == NULL ++ && !create_sdata_sym (info, &htab->sdata[1])) ++ return FALSE; ++ if (h != NULL) ++ { ++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE; ++ h->non_got_ref = TRUE; ++ } ++ break; ++ ++ case R_PPC_EMB_NADDR32: ++ case R_PPC_EMB_NADDR16: ++ case R_PPC_EMB_NADDR16_LO: ++ case R_PPC_EMB_NADDR16_HI: ++ case R_PPC_EMB_NADDR16_HA: ++ if (info->shared) ++ { ++ bad_shared_reloc (abfd, r_type); ++ return FALSE; ++ } ++ if (h != NULL) ++ h->non_got_ref = TRUE; ++ break; ++ ++ case R_PPC_PLTREL24: ++ if (h == NULL) ++ break; ++ /* 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: ++#ifdef DEBUG ++ fprintf (stderr, "Reloc requires a PLT entry\n"); ++#endif ++ /* This symbol requires a procedure linkage table entry. We ++ actually build the entry in finish_dynamic_symbol, ++ because this might be a case of linking PIC code without ++ linking in any dynamic objects, in which case we don't ++ need to generate a procedure linkage table after all. */ ++ ++ if (h == NULL) ++ { ++ /* It does not make sense to have a procedure linkage ++ table entry for a local symbol. */ ++ info->callbacks->einfo (_("%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; ++ } ++ else ++ { ++ bfd_vma addend = 0; ++ ++ if (r_type == R_PPC_PLTREL24) ++ { ++ ppc_elf_tdata (abfd)->makes_plt_call = 1; ++ if (info->shared) ++ addend = rel->r_addend; ++ } ++ h->needs_plt = 1; ++ if (!update_plt_info (abfd, &h->plt.plist, got2, addend)) ++ return FALSE; ++ } ++ break; ++ ++ /* The following relocations don't need to propagate the ++ relocation if linking a shared object since they are ++ section relative. */ ++ case R_PPC_SECTOFF: ++ case R_PPC_SECTOFF_LO: ++ case R_PPC_SECTOFF_HI: ++ case R_PPC_SECTOFF_HA: ++ case R_PPC_DTPREL16: ++ case R_PPC_DTPREL16_LO: ++ case R_PPC_DTPREL16_HI: ++ case R_PPC_DTPREL16_HA: ++ case R_PPC_TOC16: ++ break; ++ ++ case R_PPC_REL16: ++ case R_PPC_REL16_LO: ++ case R_PPC_REL16_HI: ++ case R_PPC_REL16_HA: ++ ppc_elf_tdata (abfd)->has_rel16 = 1; ++ break; ++ ++ /* These are just markers. */ ++ case R_PPC_TLS: ++ case R_PPC_EMB_MRKREF: ++ case R_PPC_NONE: ++ case R_PPC_max: ++ case R_PPC_RELAX: ++ case R_PPC_RELAX_PLT: ++ case R_PPC_RELAX_PLTREL24: ++ break; ++ ++ /* These should only appear in dynamic objects. */ ++ case R_PPC_COPY: ++ case R_PPC_GLOB_DAT: ++ case R_PPC_JMP_SLOT: ++ case R_PPC_RELATIVE: ++ case R_PPC_IRELATIVE: ++ break; ++ ++ /* These aren't handled yet. We'll report an error later. */ ++ 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: ++ break; ++ ++ /* These don't work with a GOT */ ++ case R_PPC_AMIGAOS_BREL: ++ case R_PPC_AMIGAOS_BREL_HI: ++ case R_PPC_AMIGAOS_BREL_LO: ++ case R_PPC_AMIGAOS_BREL_HA: ++ break; ++ ++ /* This refers only to functions defined in the shared library. */ ++ case R_PPC_LOCAL24PC: ++ if (h != NULL && h == htab->elf.hgot && htab->plt_type == PLT_UNSET) ++ { ++ htab->plt_type = PLT_OLD; ++ htab->old_bfd = abfd; ++ } ++ break; ++ ++ /* This relocation describes the C++ object vtable hierarchy. ++ Reconstruct it for later use during GC. */ ++ case R_PPC_GNU_VTINHERIT: ++ if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) ++ return FALSE; ++ break; ++ ++ /* 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)) ++ return FALSE; ++ break; ++ ++ /* We shouldn't really be seeing these. */ ++ case R_PPC_TPREL32: ++ case R_PPC_TPREL16: ++ case R_PPC_TPREL16_LO: ++ case R_PPC_TPREL16_HI: ++ case R_PPC_TPREL16_HA: ++ if (!info->executable) ++ info->flags |= DF_STATIC_TLS; ++ goto dodyn; ++ ++ /* Nor these. */ ++ case R_PPC_DTPMOD32: ++ case R_PPC_DTPREL32: ++ goto dodyn; ++ ++ case R_PPC_REL32: ++ if (h == NULL ++ && got2 != NULL ++ && (sec->flags & SEC_CODE) != 0 ++ && info->shared ++ && htab->plt_type == PLT_UNSET) ++ { ++ /* Old -fPIC gcc code has .long LCTOC1-LCFx just before ++ the start of a function, which assembles to a REL32 ++ reference to .got2. If we detect one of these, then ++ force the old PLT layout because the linker cannot ++ reliably deduce the GOT pointer value needed for ++ PLT call stubs. */ ++ asection *s; ++ Elf_Internal_Sym *isym; ++ ++ isym = bfd_sym_from_r_symndx (&htab->sym_cache, ++ abfd, r_symndx); ++ if (isym == NULL) ++ return FALSE; ++ ++ s = bfd_section_from_elf_index (abfd, isym->st_shndx); ++ if (s == got2) ++ { ++ htab->plt_type = PLT_OLD; ++ htab->old_bfd = abfd; ++ } ++ } ++ if (h == NULL || h == htab->elf.hgot) ++ break; ++ /* fall through */ ++ ++ case R_PPC_ADDR32: ++ case R_PPC_ADDR16: ++ case R_PPC_ADDR16_LO: ++ case R_PPC_ADDR16_HI: ++ case R_PPC_ADDR16_HA: ++ case R_PPC_UADDR32: ++ case R_PPC_UADDR16: ++ if (h != NULL && !info->shared) ++ { ++ /* We may need a plt entry if the symbol turns out to be ++ a function defined in a dynamic object. */ ++ if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) ++ return FALSE; ++ ++ /* We may need a copy reloc too. */ ++ h->non_got_ref = 1; ++ h->pointer_equality_needed = 1; ++ } ++ goto dodyn; ++ ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ if (h == NULL) ++ break; ++ if (h == htab->elf.hgot) ++ { ++ if (htab->plt_type == PLT_UNSET) ++ { ++ htab->plt_type = PLT_OLD; ++ htab->old_bfd = abfd; ++ } ++ break; ++ } ++ /* fall through */ ++ ++ case R_PPC_ADDR24: ++ case R_PPC_ADDR14: ++ case R_PPC_ADDR14_BRTAKEN: ++ case R_PPC_ADDR14_BRNTAKEN: ++ if (h != NULL && !info->shared) ++ { ++ /* We may need a plt entry if the symbol turns out to be ++ a function defined in a dynamic object. */ ++ h->needs_plt = 1; ++ if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) ++ return FALSE; ++ break; ++ } ++ ++ dodyn: ++ /* If we are creating a shared library, and this is a reloc ++ against a global symbol, or a non PC relative reloc ++ against a local symbol, then we need to copy the reloc ++ into the shared library. However, if we are linking with ++ -Bsymbolic, we do not need to copy a reloc against a ++ global symbol which is defined in an object we are ++ including in the link (i.e., DEF_REGULAR is set). At ++ this point we have not seen all the input files, so it is ++ possible that DEF_REGULAR is not set now but will be set ++ later (it is never cleared). In case of a weak definition, ++ DEF_REGULAR may be cleared later by a strong definition in ++ a shared library. We account for that possibility below by ++ storing information in the dyn_relocs field of the hash ++ table entry. A similar situation occurs when creating ++ shared libraries and symbol visibility changes render the ++ symbol local. ++ ++ If on the other hand, we are creating an executable, we ++ may need to keep relocations for symbols satisfied by a ++ dynamic library if we manage to avoid copy relocs for the ++ symbol. */ ++ if ((info->shared ++ && (must_be_dyn_reloc (info, r_type) ++ || (h != NULL ++ && (! info->symbolic ++ || h->root.type == bfd_link_hash_defweak ++ || !h->def_regular)))) ++ || (ELIMINATE_COPY_RELOCS ++ && !info->shared ++ && h != NULL ++ && (h->root.type == bfd_link_hash_defweak ++ || !h->def_regular))) ++ { ++ struct elf_dyn_relocs *p; ++ struct elf_dyn_relocs **rel_head; ++ ++#ifdef DEBUG ++ fprintf (stderr, ++ "ppc_elf_check_relocs needs to " ++ "create relocation for %s\n", ++ (h && h->root.root.string ++ ? h->root.root.string : "")); ++#endif ++ if (sreloc == NULL) ++ { ++ if (htab->elf.dynobj == NULL) ++ htab->elf.dynobj = abfd; ++ ++ sreloc = _bfd_elf_make_dynamic_reloc_section ++ (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE); ++ ++ if (sreloc == NULL) ++ return FALSE; ++ } ++ ++ /* If this is a global symbol, we count the number of ++ relocations we need for this symbol. */ ++ if (h != NULL) ++ { ++ rel_head = &ppc_elf_hash_entry (h)->dyn_relocs; ++ } ++ else ++ { ++ /* Track dynamic relocs needed for local syms too. ++ We really need local syms available to do this ++ easily. Oh well. */ ++ asection *s; ++ void *vpp; ++ Elf_Internal_Sym *isym; ++ ++ isym = bfd_sym_from_r_symndx (&htab->sym_cache, ++ abfd, r_symndx); ++ if (isym == NULL) ++ return FALSE; ++ ++ s = bfd_section_from_elf_index (abfd, isym->st_shndx); ++ if (s == NULL) ++ s = sec; ++ ++ vpp = &elf_section_data (s)->local_dynrel; ++ rel_head = (struct elf_dyn_relocs **) vpp; ++ } ++ ++ p = *rel_head; ++ if (p == NULL || p->sec != sec) ++ { ++ p = bfd_alloc (htab->elf.dynobj, sizeof *p); ++ if (p == NULL) ++ return FALSE; ++ p->next = *rel_head; ++ *rel_head = p; ++ p->sec = sec; ++ p->count = 0; ++ p->pc_count = 0; ++ } ++ ++ p->count += 1; ++ if (!must_be_dyn_reloc (info, r_type)) ++ p->pc_count += 1; ++ } ++ ++ break; ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++/* Merge object attributes from IBFD into OBFD. Raise an error if ++ there are conflicting attributes. */ ++static bfd_boolean ++ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) ++{ ++ obj_attribute *in_attr, *in_attrs; ++ obj_attribute *out_attr, *out_attrs; ++ ++ if (!elf_known_obj_attributes_proc (obfd)[0].i) ++ { ++ /* This is the first object. Copy the attributes. */ ++ _bfd_elf_copy_obj_attributes (ibfd, obfd); ++ ++ /* Use the Tag_null value to indicate the attributes have been ++ initialized. */ ++ elf_known_obj_attributes_proc (obfd)[0].i = 1; ++ ++ return TRUE; ++ } ++ ++ in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; ++ out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; ++ ++ /* Check for conflicting Tag_GNU_Power_ABI_FP attributes and merge ++ non-conflicting ones. */ ++ in_attr = &in_attrs[Tag_GNU_Power_ABI_FP]; ++ out_attr = &out_attrs[Tag_GNU_Power_ABI_FP]; ++ if (in_attr->i != out_attr->i) ++ { ++ out_attr->type = 1; ++ if (out_attr->i == 0) ++ out_attr->i = in_attr->i; ++ else if (in_attr->i == 0) ++ ; ++ else if (out_attr->i == 1 && in_attr->i == 2) ++ _bfd_error_handler ++ (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd); ++ else if (out_attr->i == 1 && in_attr->i == 3) ++ _bfd_error_handler ++ (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"), ++ obfd, ibfd); ++ else if (out_attr->i == 3 && in_attr->i == 1) ++ _bfd_error_handler ++ (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"), ++ ibfd, obfd); ++ else if (out_attr->i == 3 && in_attr->i == 2) ++ _bfd_error_handler ++ (_("Warning: %B uses soft float, %B uses single-precision hard float"), ++ ibfd, obfd); ++ else if (out_attr->i == 2 && (in_attr->i == 1 || in_attr->i == 3)) ++ _bfd_error_handler ++ (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd); ++ else if (in_attr->i > 3) ++ _bfd_error_handler ++ (_("Warning: %B uses unknown floating point ABI %d"), ibfd, ++ in_attr->i); ++ else ++ _bfd_error_handler ++ (_("Warning: %B uses unknown floating point ABI %d"), obfd, ++ out_attr->i); ++ } ++ ++ /* Check for conflicting Tag_GNU_Power_ABI_Vector attributes and ++ merge non-conflicting ones. */ ++ in_attr = &in_attrs[Tag_GNU_Power_ABI_Vector]; ++ out_attr = &out_attrs[Tag_GNU_Power_ABI_Vector]; ++ if (in_attr->i != out_attr->i) ++ { ++ const char *in_abi = NULL, *out_abi = NULL; ++ ++ switch (in_attr->i) ++ { ++ case 1: in_abi = "generic"; break; ++ case 2: in_abi = "AltiVec"; break; ++ case 3: in_abi = "SPE"; break; ++ } ++ ++ switch (out_attr->i) ++ { ++ case 1: out_abi = "generic"; break; ++ case 2: out_abi = "AltiVec"; break; ++ case 3: out_abi = "SPE"; break; ++ } ++ ++ out_attr->type = 1; ++ if (out_attr->i == 0) ++ out_attr->i = in_attr->i; ++ else if (in_attr->i == 0) ++ ; ++ /* For now, allow generic to transition to AltiVec or SPE ++ without a warning. If GCC marked files with their stack ++ alignment and used don't-care markings for files which are ++ not affected by the vector ABI, we could warn about this ++ case too. */ ++ else if (out_attr->i == 1) ++ out_attr->i = in_attr->i; ++ else if (in_attr->i == 1) ++ ; ++ else if (in_abi == NULL) ++ _bfd_error_handler ++ (_("Warning: %B uses unknown vector ABI %d"), ibfd, ++ in_attr->i); ++ else if (out_abi == NULL) ++ _bfd_error_handler ++ (_("Warning: %B uses unknown vector ABI %d"), obfd, ++ in_attr->i); ++ else ++ _bfd_error_handler ++ (_("Warning: %B uses vector ABI \"%s\", %B uses \"%s\""), ++ ibfd, obfd, in_abi, out_abi); ++ } ++ ++ /* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes ++ and merge non-conflicting ones. */ ++ in_attr = &in_attrs[Tag_GNU_Power_ABI_Struct_Return]; ++ out_attr = &out_attrs[Tag_GNU_Power_ABI_Struct_Return]; ++ if (in_attr->i != out_attr->i) ++ { ++ out_attr->type = 1; ++ if (out_attr->i == 0) ++ out_attr->i = in_attr->i; ++ else if (in_attr->i == 0) ++ ; ++ else if (out_attr->i == 1 && in_attr->i == 2) ++ _bfd_error_handler ++ (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), obfd, ibfd); ++ else if (out_attr->i == 2 && in_attr->i == 1) ++ _bfd_error_handler ++ (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), ibfd, obfd); ++ else if (in_attr->i > 2) ++ _bfd_error_handler ++ (_("Warning: %B uses unknown small structure return convention %d"), ibfd, ++ in_attr->i); ++ else ++ _bfd_error_handler ++ (_("Warning: %B uses unknown small structure return convention %d"), obfd, ++ out_attr->i); ++ } ++ ++ /* Merge Tag_compatibility attributes and any common GNU ones. */ ++ _bfd_elf_merge_object_attributes (ibfd, obfd); ++ ++ return TRUE; ++} ++ ++/* Merge backend specific data from an object file to the output ++ object file when linking. */ ++ ++static bfd_boolean ++ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) ++{ ++ flagword old_flags; ++ flagword new_flags; ++ bfd_boolean error; ++ ++ if (!is_ppc_elf (ibfd) || !is_ppc_elf (obfd)) ++ return TRUE; ++ ++ /* Check if we have the same endianness. */ ++ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) ++ return FALSE; ++ ++ if (!ppc_elf_merge_obj_attributes (ibfd, obfd)) ++ return FALSE; ++ ++ new_flags = elf_elfheader (ibfd)->e_flags; ++ old_flags = elf_elfheader (obfd)->e_flags; ++ if (!elf_flags_init (obfd)) ++ { ++ /* First call, no flags set. */ ++ elf_flags_init (obfd) = TRUE; ++ elf_elfheader (obfd)->e_flags = new_flags; ++ } ++ ++ /* Compatible flags are ok. */ ++ else if (new_flags == old_flags) ++ ; ++ ++ /* Incompatible flags. */ ++ else ++ { ++ /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib ++ to be linked with either. */ ++ error = FALSE; ++ if ((new_flags & EF_PPC_RELOCATABLE) != 0 ++ && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0) ++ { ++ error = TRUE; ++ (*_bfd_error_handler) ++ (_("%B: compiled with -mrelocatable and linked with " ++ "modules compiled normally"), ibfd); ++ } ++ else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0 ++ && (old_flags & EF_PPC_RELOCATABLE) != 0) ++ { ++ error = TRUE; ++ (*_bfd_error_handler) ++ (_("%B: compiled normally and linked with " ++ "modules compiled with -mrelocatable"), ibfd); ++ } ++ ++ /* The output is -mrelocatable-lib iff both the input files are. */ ++ if (! (new_flags & EF_PPC_RELOCATABLE_LIB)) ++ elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB; ++ ++ /* The output is -mrelocatable iff it can't be -mrelocatable-lib, ++ but each input file is either -mrelocatable or -mrelocatable-lib. */ ++ if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB) ++ && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)) ++ && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))) ++ elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE; ++ ++ /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if ++ any module uses it. */ ++ elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB); ++ ++ new_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ old_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ ++ /* Warn about any other mismatches. */ ++ if (new_flags != old_flags) ++ { ++ error = TRUE; ++ (*_bfd_error_handler) ++ (_("%B: uses different e_flags (0x%lx) fields " ++ "than previous modules (0x%lx)"), ++ ibfd, (long) new_flags, (long) old_flags); ++ } ++ ++ if (error) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++static void ++ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents, ++ bfd_vma offset, bfd_vma relocation, ++ split16_format_type split16_format) ++ ++{ ++ bfd_vma insn, top5, bottom11; ++ ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ top5 = relocation >> 11; ++ top5 = top5 << (split16_format == split16a_type ? 20 : 16); ++ bottom11 = relocation & 0x7ff; ++ insn |= top5; ++ insn |= bottom11; ++ bfd_put_32 (output_bfd, insn, contents + offset); ++} ++ ++ ++/* Choose which PLT scheme to use, and set .plt flags appropriately. ++ Returns -1 on error, 0 for old PLT, 1 for new PLT. */ ++int ++ppc_elf_amigaos_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *info, ++ enum ppc_elf_plt_type plt_style, ++ int emit_stub_syms) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ flagword flags; ++ ++ htab = ppc_elf_hash_table (info); ++ ++ htab->emit_stub_syms = emit_stub_syms; ++ ++ if (htab->plt_type == PLT_UNSET) ++ { ++ struct elf_link_hash_entry *h; ++ ++ if (plt_style == PLT_OLD) ++ htab->plt_type = PLT_OLD; ++ else if (info->shared ++ && htab->elf.dynamic_sections_created ++ && (h = elf_link_hash_lookup (&htab->elf, "_mcount", ++ FALSE, FALSE, TRUE)) != NULL ++ && (h->type == STT_FUNC ++ || 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))) ++ { ++ /* Profiling of shared libs (and pies) is not supported with ++ secure plt, because ppc32 does profiling before a ++ function prologue and a secure plt pic call stubs needs ++ r30 to be set up. */ ++ htab->plt_type = PLT_OLD; ++ } ++ else ++ { ++ bfd *ibfd; ++ enum ppc_elf_plt_type plt_type = plt_style; ++ ++ /* Look through the reloc flags left by ppc_elf_check_relocs. ++ Use the old style bss plt if a file makes plt calls ++ without using the new relocs, and if ld isn't given ++ --secure-plt and we never see REL16 relocs. */ ++ if (plt_type == PLT_UNSET) ++ plt_type = PLT_OLD; ++ for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next) ++ if (is_ppc_elf (ibfd)) ++ { ++ if (ppc_elf_tdata (ibfd)->has_rel16) ++ plt_type = PLT_NEW; ++ else if (ppc_elf_tdata (ibfd)->makes_plt_call) ++ { ++ plt_type = PLT_OLD; ++ htab->old_bfd = ibfd; ++ break; ++ } ++ } ++ htab->plt_type = plt_type; ++ } ++ } ++ if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW) ++ { ++ if (htab->old_bfd != NULL) ++ info->callbacks->einfo (_("%P: bss-plt forced due to %B\n"), ++ htab->old_bfd); ++ else ++ info->callbacks->einfo (_("%P: bss-plt forced by profiling\n")); ++ } ++ ++ BFD_ASSERT (htab->plt_type != PLT_VXWORKS); ++ ++ if (htab->plt_type == PLT_NEW) ++ { ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ ++ /* The new PLT is a loaded section. */ ++ if (htab->plt != NULL ++ && !bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags)) ++ return -1; ++ ++ /* The new GOT is not executable. */ ++ if (htab->got != NULL ++ && !bfd_set_section_flags (htab->elf.dynobj, htab->got, flags)) ++ return -1; ++ } ++ else ++ { ++ /* Stop an unused .glink section from affecting .text alignment. */ ++ if (htab->glink != NULL ++ && !bfd_set_section_alignment (htab->elf.dynobj, htab->glink, 0)) ++ return -1; ++ } ++ return htab->plt_type == PLT_NEW; ++} ++ ++/* Return the section that should be marked against GC for a given ++ relocation. */ ++ ++static asection * ++ppc_elf_gc_mark_hook (asection *sec, ++ struct bfd_link_info *info, ++ Elf_Internal_Rela *rel, ++ struct elf_link_hash_entry *h, ++ Elf_Internal_Sym *sym) ++{ ++ if (h != NULL) ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_PPC_GNU_VTINHERIT: ++ case R_PPC_GNU_VTENTRY: ++ return NULL; ++ } ++ ++ 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) ++{ ++ 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; ++ ++ if (info->relocatable) ++ return TRUE; ++ ++ if ((sec->flags & SEC_ALLOC) == 0) ++ return TRUE; ++ ++ elf_section_data (sec)->local_dynrel = NULL; ++ ++ 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"); ++ ++ relend = relocs + sec->reloc_count; ++ for (rel = relocs; rel < relend; rel++) ++ { ++ unsigned long r_symndx; ++ enum elf_ppc_reloc_type r_type; ++ struct elf_link_hash_entry *h = NULL; ++ ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ struct elf_dyn_relocs **pp, *p; ++ struct ppc_elf_link_hash_entry *eh; ++ ++ 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; ++ ++ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) ++ if (p->sec == sec) ++ { ++ /* Everything must go for SEC. */ ++ *pp = p->next; ++ break; ++ } ++ } ++ ++ r_type = ELF32_R_TYPE (rel->r_info); ++ if (!htab->is_vxworks ++ && h == NULL ++ && local_got_refcounts != NULL ++ && (!info->shared ++ || is_branch_reloc (r_type))) ++ { ++ 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; ++ ++ if (r_type == R_PPC_PLTREL24 && info->shared) ++ addend = rel->r_addend; ++ ent = find_plt_ent (ifunc, got2, addend); ++ if (ent->plt.refcount > 0) ++ ent->plt.refcount -= 1; ++ continue; ++ } ++ } ++ ++ 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 (!info->shared) ++ { ++ struct plt_entry *ent; ++ ++ 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; ++ ++ 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 thru */ ++ ++ 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 (info->shared) ++ break; ++ ++ 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; ++ ++ if (r_type == R_PPC_PLTREL24 && info->shared) ++ 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; ++ ++ default: ++ break; ++ } ++ } ++ return TRUE; ++} ++ ++/* Set plt output section type, htab->tls_get_addr, and call the ++ generic ELF tls_setup function. */ ++ ++asection * ++ppc_elf_amigaos_tls_setup (bfd *obfd, ++ struct bfd_link_info *info, ++ int no_tls_get_addr_opt) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ ++ htab = ppc_elf_hash_table (info); ++ htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", ++ FALSE, FALSE, TRUE); ++ if (!no_tls_get_addr_opt) ++ { ++ struct elf_link_hash_entry *opt, *tga; ++ opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt", ++ FALSE, FALSE, TRUE); ++ if (opt != NULL ++ && (opt->root.type == bfd_link_hash_defined ++ || opt->root.type == bfd_link_hash_defweak)) ++ { ++ /* If glibc supports an optimized __tls_get_addr call stub, ++ signalled by the presence of __tls_get_addr_opt, and we'll ++ be calling __tls_get_addr via a plt call stub, then ++ make __tls_get_addr point to __tls_get_addr_opt. */ ++ tga = htab->tls_get_addr; ++ if (htab->elf.dynamic_sections_created ++ && tga != NULL ++ && (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))) ++ { ++ struct plt_entry *ent; ++ for (ent = tga->plt.plist; ent != NULL; ent = ent->next) ++ if (ent->plt.refcount > 0) ++ break; ++ if (ent != NULL) ++ { ++ tga->root.type = bfd_link_hash_indirect; ++ tga->root.u.i.link = &opt->root; ++ ppc_elf_copy_indirect_symbol (info, opt, tga); ++ if (opt->dynindx != -1) ++ { ++ /* Use __tls_get_addr_opt in dynamic relocations. */ ++ opt->dynindx = -1; ++ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, ++ opt->dynstr_index); ++ if (!bfd_elf_link_record_dynamic_symbol (info, opt)) ++ return FALSE; ++ } ++ htab->tls_get_addr = opt; ++ } ++ } ++ } ++ else ++ no_tls_get_addr_opt = TRUE; ++ } ++ htab->no_tls_get_addr_opt = no_tls_get_addr_opt; ++ if (htab->plt_type == PLT_NEW ++ && htab->plt != NULL ++ && htab->plt->output_section != NULL) ++ { ++ elf_section_type (htab->plt->output_section) = SHT_PROGBITS; ++ elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE; ++ } ++ ++ return _bfd_elf_tls_setup (obfd, info); ++} ++ ++/* Return TRUE iff REL is a branch reloc with a global symbol matching ++ HASH. */ ++ ++static bfd_boolean ++branch_reloc_hash_match (const bfd *ibfd, ++ const Elf_Internal_Rela *rel, ++ const struct elf_link_hash_entry *hash) ++{ ++ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); ++ enum elf_ppc_reloc_type r_type = ELF32_R_TYPE (rel->r_info); ++ unsigned int r_symndx = ELF32_R_SYM (rel->r_info); ++ ++ if (r_symndx >= symtab_hdr->sh_info && is_branch_reloc (r_type)) ++ { ++ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); ++ struct elf_link_hash_entry *h; ++ ++ 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 == hash) ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++/* Run through all the TLS relocs looking for optimization ++ opportunities. */ ++ ++bfd_boolean ++ppc_elf_amigaos_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *info) ++{ ++ bfd *ibfd; ++ asection *sec; ++ struct ppc_elf_link_hash_table *htab; ++ int pass; ++ ++ if (info->relocatable || !info->executable) ++ return TRUE; ++ ++ htab = ppc_elf_hash_table (info); ++ if (htab == NULL) ++ return FALSE; ++ ++ /* Make two passes through the relocs. First time check that tls ++ relocs involved in setting up a tls_get_addr call are indeed ++ followed by such a call. If they are not, don't do any tls ++ optimization. On the second pass twiddle tls_mask flags to ++ notify relocate_section that optimization can be done, and ++ adjust got and plt refcounts. */ ++ 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"); ++ ++ for (sec = ibfd->sections; sec != NULL; sec = sec->next) ++ if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) ++ { ++ Elf_Internal_Rela *relstart, *rel, *relend; ++ int expecting_tls_get_addr = 0; ++ ++ /* 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; rel++) ++ { ++ 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; ++ bfd_boolean is_local; ++ bfd_signed_vma *got_count; ++ ++ r_symndx = ELF32_R_SYM (rel->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; ++ } ++ ++ is_local = FALSE; ++ if (h == NULL ++ || !h->def_dynamic) ++ is_local = TRUE; ++ ++ r_type = ELF32_R_TYPE (rel->r_info); ++ /* If this section has old-style __tls_get_addr calls ++ without marker relocs, then check that each ++ __tls_get_addr call reloc is preceded by a reloc ++ that conceivably belongs to the __tls_get_addr arg ++ setup insn. If we don't find matching arg setup ++ relocs, don't do any tls optimization. */ ++ if (pass == 0 ++ && sec->has_tls_get_addr_call ++ && h != NULL ++ && h == htab->tls_get_addr ++ && !expecting_tls_get_addr ++ && is_branch_reloc (r_type)) ++ { ++ info->callbacks->minfo ("%H __tls_get_addr lost arg, " ++ "TLS optimization disabled\n", ++ ibfd, sec, rel->r_offset); ++ if (elf_section_data (sec)->relocs != relstart) ++ free (relstart); ++ return TRUE; ++ } ++ ++ expecting_tls_get_addr = 0; ++ switch (r_type) ++ { ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ expecting_tls_get_addr = 1; ++ /* Fall thru */ ++ ++ case R_PPC_GOT_TLSLD16_HI: ++ case R_PPC_GOT_TLSLD16_HA: ++ /* These relocs should never be against a symbol ++ defined in a shared lib. Leave them alone if ++ that turns out to be the case. */ ++ if (!is_local) ++ continue; ++ ++ /* LD -> LE */ ++ tls_set = 0; ++ tls_clear = TLS_LD; ++ break; ++ ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ expecting_tls_get_addr = 1; ++ /* Fall thru */ ++ ++ case R_PPC_GOT_TLSGD16_HI: ++ case R_PPC_GOT_TLSGD16_HA: ++ if (is_local) ++ /* GD -> LE */ ++ tls_set = 0; ++ else ++ /* GD -> IE */ ++ tls_set = TLS_TLS | TLS_TPRELGD; ++ tls_clear = TLS_GD; ++ break; ++ ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ case R_PPC_GOT_TPREL16_HI: ++ case R_PPC_GOT_TPREL16_HA: ++ if (is_local) ++ { ++ /* IE -> LE */ ++ tls_set = 0; ++ tls_clear = TLS_TPREL; ++ break; ++ } ++ else ++ continue; ++ ++ case R_PPC_TLSGD: ++ case R_PPC_TLSLD: ++ expecting_tls_get_addr = 2; ++ tls_set = 0; ++ tls_clear = 0; ++ break; ++ ++ default: ++ continue; ++ } ++ ++ if (pass == 0) ++ { ++ if (!expecting_tls_get_addr ++ || (expecting_tls_get_addr == 1 ++ && !sec->has_tls_get_addr_call)) ++ continue; ++ ++ if (rel + 1 < relend ++ && branch_reloc_hash_match (ibfd, rel + 1, ++ htab->tls_get_addr)) ++ continue; ++ ++ /* Uh oh, we didn't find the expected call. We ++ could just mark this symbol to exclude it ++ from tls optimization but it's safer to skip ++ the entire optimization. */ ++ info->callbacks->minfo (_("%H arg lost __tls_get_addr, " ++ "TLS optimization disabled\n"), ++ ibfd, sec, rel->r_offset); ++ if (elf_section_data (sec)->relocs != relstart) ++ free (relstart); ++ return TRUE; ++ } ++ ++ if (expecting_tls_get_addr) ++ { ++ struct plt_entry *ent; ++ bfd_vma addend = 0; ++ ++ if (info->shared ++ && 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; ++ got_count = &h->got.refcount; ++ } ++ else ++ { ++ bfd_signed_vma *lgot_refs; ++ struct plt_entry **local_plt; ++ 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); ++ tls_mask = &lgot_masks[r_symndx]; ++ got_count = &lgot_refs[r_symndx]; ++ } ++ ++ if (tls_set == 0) ++ { ++ /* We managed to get rid of a got entry. */ ++ if (*got_count > 0) ++ *got_count -= 1; ++ } ++ ++ *tls_mask |= tls_set; ++ *tls_mask &= ~tls_clear; ++ } ++ ++ 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; ++ } ++ } ++ return TRUE; ++} ++ ++/* Return true if we have dynamic relocs that apply to read-only sections. */ ++ ++static bfd_boolean ++readonly_dynrelocs (struct elf_link_hash_entry *h) ++{ ++ struct elf_dyn_relocs *p; ++ ++ for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) ++ { ++ asection *s = p->sec->output_section; ++ ++ if (s != NULL ++ && ((s->flags & (SEC_READONLY | SEC_ALLOC)) ++ == (SEC_READONLY | SEC_ALLOC))) ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++/* Adjust a symbol defined by a dynamic object and referenced by a ++ regular object. The current definition is in some section of the ++ dynamic object, but we're not including those sections. We have to ++ change the definition to something the rest of the link can ++ understand. */ ++ ++static bfd_boolean ++ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, ++ struct elf_link_hash_entry *h) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ asection *s; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n", ++ h->root.root.string); ++#endif ++ ++ /* Make sure we know what is going on here. */ ++ htab = ppc_elf_hash_table (info); ++ BFD_ASSERT (htab->elf.dynobj != NULL ++ && (h->needs_plt ++ || h->type == STT_GNU_IFUNC ++ || h->u.weakdef != NULL ++ || (h->def_dynamic ++ && h->ref_regular ++ && !h->def_regular))); ++ ++ /* Deal with function syms. */ ++ if (h->type == STT_FUNC ++ || h->type == STT_GNU_IFUNC ++ || h->needs_plt) ++ { ++ /* Clear procedure linkage table information for any symbol that ++ won't need a .plt entry. */ ++ struct plt_entry *ent; ++ for (ent = h->plt.plist; ent != NULL; ent = ent->next) ++ if (ent->plt.refcount > 0) ++ 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)))) ++ { ++ /* A PLT entry is not required/allowed when: ++ ++ 1. We are not using ld.so; because then the PLT entry ++ can't be set up, so we can't use one. In this case, ++ ppc_elf_adjust_dynamic_symbol won't even be called. ++ ++ 2. GC has rendered the entry unused. ++ ++ 3. We know for certain that a call to this symbol ++ will go to this object, or will remain undefined. */ ++ h->plt.plist = NULL; ++ h->needs_plt = 0; ++ } ++ else ++ { ++ /* After adjust_dynamic_symbol, non_got_ref set in the ++ non-shared case means that we have allocated space in ++ .dynbss for the symbol and thus dyn_relocs for this ++ symbol should be discarded. ++ If we get here we know we are making a PLT entry for this ++ symbol, and in an executable we'd normally resolve ++ relocations against this symbol to the PLT entry. Allow ++ dynamic relocs if the reference is weak, and the dynamic ++ relocs will not cause text relocation. */ ++ if (!h->ref_regular_nonweak ++ && h->non_got_ref ++ && h->type != STT_GNU_IFUNC ++ && !htab->is_vxworks ++ && !ppc_elf_hash_entry (h)->has_sda_refs ++ && !readonly_dynrelocs (h)) ++ h->non_got_ref = 0; ++ } ++ return TRUE; ++ } ++ else ++ h->plt.plist = NULL; ++ ++ /* 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; ++ return TRUE; ++ } ++ ++ /* This is a reference to a symbol defined by a dynamic object which ++ is not a function. */ ++ ++ /* If we are creating a shared library, we must presume that the ++ only references to the symbol are via the global offset table. ++ For such cases we need not do anything here; the relocations will ++ be handled correctly by relocate_section. */ ++ if (info->shared) ++ return TRUE; ++ ++ /* If there are no references to this symbol that do not use the ++ GOT, we don't need to generate a copy reloc. */ ++ if (!h->non_got_ref) ++ return TRUE; ++ ++ /* If we didn't find any dynamic relocs in read-only sections, then ++ we'll be keeping the dynamic relocs and avoiding the copy reloc. ++ We can't do this if there are any small data relocations. This ++ doesn't work on VxWorks, where we can not have dynamic ++ relocations (other than copy and jump slot relocations) in an ++ executable. */ ++ if (ELIMINATE_COPY_RELOCS ++ && !ppc_elf_hash_entry (h)->has_sda_refs ++ && !htab->is_vxworks ++ && !h->def_regular ++ && !readonly_dynrelocs (h)) ++ { ++ h->non_got_ref = 0; ++ 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 ++ an entry for this symbol in the .dynsym section. The dynamic ++ object will contain position independent code, so all references ++ from the dynamic object to this symbol will go through the global ++ offset table. The dynamic linker will use the .dynsym entry to ++ determine the address it must put in the global offset table, so ++ both the dynamic object and the regular object will refer to the ++ same memory location for the variable. ++ ++ 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 ++ s = htab->dynbss; ++ 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; ++ ++ if (ppc_elf_hash_entry (h)->has_sda_refs) ++ srel = htab->relsbss; ++ else ++ srel = htab->relbss; ++ BFD_ASSERT (srel != NULL); ++ srel->size += sizeof (Elf32_External_Rela); ++ h->needs_copy = 1; ++ } ++ ++ return _bfd_elf_adjust_dynamic_copy (h, s); ++} ++ ++/* Generate a symbol to mark plt call stubs. For non-PIC code the sym is ++ xxxxxxxx.plt_call32. where xxxxxxxx is a hex number, usually 0, ++ specifying the addend on the plt relocation. For -fpic code, the sym ++ is xxxxxxxx.plt_pic32., and for -fPIC ++ xxxxxxxx.got2.plt_pic32.. */ ++ ++static bfd_boolean ++add_stub_sym (struct plt_entry *ent, ++ struct elf_link_hash_entry *h, ++ struct bfd_link_info *info) ++{ ++ struct elf_link_hash_entry *sh; ++ size_t len1, len2, len3; ++ char *name; ++ const char *stub; ++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); ++ ++ if (info->shared) ++ stub = ".plt_pic32."; ++ else ++ stub = ".plt_call32."; ++ ++ len1 = strlen (h->root.root.string); ++ len2 = strlen (stub); ++ len3 = 0; ++ if (ent->sec) ++ len3 = strlen (ent->sec->name); ++ name = bfd_malloc (len1 + len2 + len3 + 9); ++ if (name == NULL) ++ return FALSE; ++ sprintf (name, "%08x", (unsigned) ent->addend & 0xffffffff); ++ if (ent->sec) ++ memcpy (name + 8, ent->sec->name, len3); ++ memcpy (name + 8 + len3, stub, len2); ++ memcpy (name + 8 + len3 + len2, h->root.root.string, len1 + 1); ++ sh = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); ++ if (sh == NULL) ++ return FALSE; ++ if (sh->root.type == bfd_link_hash_new) ++ { ++ sh->root.type = bfd_link_hash_defined; ++ sh->root.u.def.section = htab->glink; ++ sh->root.u.def.value = ent->glink_offset; ++ sh->ref_regular = 1; ++ sh->def_regular = 1; ++ sh->ref_regular_nonweak = 1; ++ sh->forced_local = 1; ++ sh->non_elf = 0; ++ } ++ return TRUE; ++} ++ ++/* Allocate NEED contiguous space in .got, and return the offset. ++ Handles allocation of the got header when crossing 32k. */ ++ ++static bfd_vma ++allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need) ++{ ++ bfd_vma where; ++ unsigned int max_before_header; ++ ++ if (htab->plt_type == PLT_VXWORKS) ++ { ++ where = htab->got->size; ++ htab->got->size += need; ++ } ++ else ++ { ++ max_before_header = htab->plt_type == PLT_NEW ? 32768 : 32764; ++ if (need <= htab->got_gap) ++ { ++ where = max_before_header - htab->got_gap; ++ htab->got_gap -= need; ++ } ++ else ++ { ++ if (htab->got->size + need > max_before_header ++ && htab->got->size <= max_before_header) ++ { ++ htab->got_gap = max_before_header - htab->got->size; ++ htab->got->size = max_before_header + htab->got_header_size; ++ } ++ where = htab->got->size; ++ htab->got->size += need; ++ } ++ } ++ return where; ++} ++ ++/* Allocate space in associated reloc sections for dynamic relocs. */ ++ ++static bfd_boolean ++allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) ++{ ++ struct bfd_link_info *info = inf; ++ struct ppc_elf_link_hash_entry *eh; ++ struct ppc_elf_link_hash_table *htab; ++ struct elf_dyn_relocs *p; ++ ++ if (h->root.type == bfd_link_hash_indirect) ++ return TRUE; ++ ++ htab = ppc_elf_hash_table (info); ++ if (htab->elf.dynamic_sections_created ++ || h->type == STT_GNU_IFUNC) ++ { ++ struct plt_entry *ent; ++ bfd_boolean doneone = FALSE; ++ bfd_vma plt_offset = 0, glink_offset = 0; ++ bfd_boolean dyn; ++ ++ for (ent = h->plt.plist; ent != NULL; ent = ent->next) ++ if (ent->plt.refcount > 0) ++ { ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1 ++ && !h->forced_local ++ && !h->def_regular ++ && htab->elf.dynamic_sections_created) ++ { ++ if (! bfd_elf_link_record_dynamic_symbol (info, h)) ++ return FALSE; ++ } ++ ++ dyn = htab->elf.dynamic_sections_created; ++ if (info->shared ++ || h->type == STT_GNU_IFUNC ++ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) ++ { ++ asection *s = htab->plt; ++ if (!dyn || h->dynindx == -1) ++ s = htab->iplt; ++ ++ if (htab->plt_type == PLT_NEW || !dyn || h->dynindx == -1) ++ { ++ if (!doneone) ++ { ++ plt_offset = s->size; ++ s->size += 4; ++ } ++ ent->plt.offset = plt_offset; ++ ++ s = htab->glink; ++ if (!doneone || info->shared) ++ { ++ glink_offset = s->size; ++ s->size += GLINK_ENTRY_SIZE; ++ if (h == htab->tls_get_addr ++ && !htab->no_tls_get_addr_opt) ++ s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE; ++ } ++ if (!doneone ++ && !info->shared ++ && 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->emit_stub_syms ++ && !add_stub_sym (ent, h, info)) ++ return FALSE; ++ } ++ else ++ { ++ if (!doneone) ++ { ++ /* If this is the first .plt entry, make room ++ for the special first entry. */ ++ if (s->size == 0) ++ s->size += htab->plt_initial_entry_size; ++ ++ /* The PowerPC PLT is actually composed of two ++ parts, the first part is 2 words (for a load ++ and a jump), and then there is a remaining ++ word available at the end. */ ++ plt_offset = (htab->plt_initial_entry_size ++ + (htab->plt_slot_size ++ * ((s->size ++ - htab->plt_initial_entry_size) ++ / htab->plt_entry_size))); ++ ++ /* If this symbol is not defined in a regular ++ file, and we are not generating a shared ++ library, then set the symbol to this location ++ in the .plt. This is to avoid text ++ relocations, and is required to make ++ function pointers compare as equal between ++ the normal executable and the shared library. */ ++ if (! info->shared ++ && h->def_dynamic ++ && !h->def_regular) ++ { ++ h->root.u.def.section = s; ++ h->root.u.def.value = plt_offset; ++ } ++ ++ /* Make room for this entry. */ ++ s->size += htab->plt_entry_size; ++ /* After the 8192nd entry, room for two entries ++ is allocated. */ ++ if (htab->plt_type == PLT_OLD ++ && (s->size - htab->plt_initial_entry_size) ++ / htab->plt_entry_size ++ > PLT_NUM_SINGLE_ENTRIES) ++ s->size += htab->plt_entry_size; ++ } ++ ent->plt.offset = plt_offset; ++ } ++ ++ /* We also need to make an entry in the .rela.plt section. */ ++ if (!doneone) ++ { ++ if (!htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ htab->reliplt->size += sizeof (Elf32_External_Rela); ++ else ++ { ++ htab->relplt->size += sizeof (Elf32_External_Rela); ++ ++ if (htab->plt_type == PLT_VXWORKS) ++ { ++ /* Allocate space for the unloaded relocations. */ ++ if (!info->shared ++ && htab->elf.dynamic_sections_created) ++ { ++ if (ent->plt.offset ++ == (bfd_vma) htab->plt_initial_entry_size) ++ { ++ htab->srelplt2->size ++ += (sizeof (Elf32_External_Rela) ++ * VXWORKS_PLTRESOLVE_RELOCS); ++ } ++ ++ htab->srelplt2->size ++ += (sizeof (Elf32_External_Rela) ++ * VXWORKS_PLT_NON_JMP_SLOT_RELOCS); ++ } ++ ++ /* Every PLT entry has an associated GOT entry in ++ .got.plt. */ ++ htab->sgotplt->size += 4; ++ } ++ } ++ doneone = TRUE; ++ } ++ } ++ else ++ ent->plt.offset = (bfd_vma) -1; ++ } ++ else ++ ent->plt.offset = (bfd_vma) -1; ++ ++ if (!doneone) ++ { ++ h->plt.plist = NULL; ++ h->needs_plt = 0; ++ } ++ } ++ else ++ { ++ h->plt.plist = NULL; ++ h->needs_plt = 0; ++ } ++ ++ eh = (struct ppc_elf_link_hash_entry *) h; ++ if (eh->elf.got.refcount > 0) ++ { ++ bfd_boolean dyn; ++ unsigned int need; ++ ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (eh->elf.dynindx == -1 ++ && !eh->elf.forced_local ++ && eh->elf.type != STT_GNU_IFUNC ++ && htab->elf.dynamic_sections_created) ++ { ++ if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf)) ++ return FALSE; ++ } ++ ++ need = 0; ++ if ((eh->tls_mask & TLS_TLS) != 0) ++ { ++ 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) ++ 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; ++ if (need == 0) ++ eh->elf.got.offset = (bfd_vma) -1; ++ else ++ { ++ eh->elf.got.offset = allocate_got (htab, need); ++ dyn = htab->elf.dynamic_sections_created; ++ if ((info->shared ++ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf)) ++ && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT ++ || eh->elf.root.type != bfd_link_hash_undefweak)) ++ { ++ asection *rsec = htab->relgot; ++ /* 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); ++ } ++ } ++ } ++ else ++ eh->elf.got.offset = (bfd_vma) -1; ++ ++ if (eh->dyn_relocs == NULL ++ || !htab->elf.dynamic_sections_created) ++ return TRUE; ++ ++ /* In the shared -Bsymbolic case, discard space allocated for ++ dynamic pc-relative relocs against symbols which turn out to be ++ defined in regular objects. For the normal shared case, discard ++ space for relocs that have become local due to symbol visibility ++ changes. */ ++ ++ if (info->shared) ++ { ++ /* Relocs that use pc_count are those that appear on a call insn, ++ or certain REL relocs (see must_be_dyn_reloc) that can be ++ generated via assembly. We want calls to protected symbols to ++ resolve directly to the function rather than going via the plt. ++ If people want function pointer comparisons to work as expected ++ then they should avoid writing weird assembly. */ ++ if (SYMBOL_CALLS_LOCAL (info, h)) ++ { ++ struct elf_dyn_relocs **pp; ++ ++ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) ++ { ++ p->count -= p->pc_count; ++ p->pc_count = 0; ++ if (p->count == 0) ++ *pp = p->next; ++ else ++ pp = &p->next; ++ } ++ } ++ ++ if (htab->is_vxworks) ++ { ++ struct elf_dyn_relocs **pp; ++ ++ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) ++ { ++ if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) ++ *pp = p->next; ++ else ++ pp = &p->next; ++ } ++ } ++ ++ /* 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 (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 (h->dynindx == -1 ++ && !h->forced_local ++ && !h->def_regular) ++ { ++ if (! bfd_elf_link_record_dynamic_symbol (info, h)) ++ return FALSE; ++ } ++ } ++ } ++ else if (ELIMINATE_COPY_RELOCS) ++ { ++ /* For the non-shared case, discard space for relocs against ++ symbols which turn out to need copy relocs or are not ++ dynamic. */ ++ ++ if (!h->non_got_ref ++ && !h->def_regular) ++ { ++ /* Make sure this symbol is output as a dynamic symbol. ++ Undefined weak syms won't yet be marked as dynamic. */ ++ if (h->dynindx == -1 ++ && !h->forced_local) ++ { ++ if (! bfd_elf_link_record_dynamic_symbol (info, h)) ++ return FALSE; ++ } ++ ++ /* If that succeeded, we know we'll be keeping all the ++ relocs. */ ++ if (h->dynindx != -1) ++ goto keep; ++ } ++ ++ eh->dyn_relocs = NULL; ++ ++ keep: ; ++ } ++ ++ /* Finally, allocate space. */ ++ for (p = eh->dyn_relocs; p != NULL; p = p->next) ++ { ++ asection *sreloc = elf_section_data (p->sec)->sreloc; ++ if (!htab->elf.dynamic_sections_created) ++ sreloc = htab->reliplt; ++ sreloc->size += p->count * sizeof (Elf32_External_Rela); ++ } ++ ++ return TRUE; ++} ++ ++/* Set DF_TEXTREL if we find any dynamic relocs that apply to ++ read-only sections. */ ++ ++static bfd_boolean ++maybe_set_textrel (struct elf_link_hash_entry *h, void *info) ++{ ++ if (h->root.type == bfd_link_hash_indirect) ++ return TRUE; ++ ++ if (readonly_dynrelocs (h)) ++ { ++ ((struct bfd_link_info *) info)->flags |= DF_TEXTREL; ++ ++ /* Not an error, just cut short the traversal. */ ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++static const unsigned char glink_eh_frame_cie[] = ++{ ++ 0, 0, 0, 16, /* length. */ ++ 0, 0, 0, 0, /* id. */ ++ 1, /* CIE version. */ ++ 'z', 'R', 0, /* Augmentation string. */ ++ 4, /* Code alignment. */ ++ 0x7c, /* Data alignment. */ ++ 65, /* RA reg. */ ++ 1, /* Augmentation size. */ ++ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */ ++ DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */ ++}; ++ ++/* Set the sizes of the dynamic sections. */ ++ ++static bfd_boolean ++ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *info) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ asection *s; ++ bfd_boolean relocs; ++ bfd *ibfd; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections called\n"); ++#endif ++ ++ htab = ppc_elf_hash_table (info); ++ BFD_ASSERT (htab->elf.dynobj != NULL); ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections: dynamic_sections_created = %d\n", elf_hash_table (info)->dynamic_sections_created); ++#endif ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ /* Set the contents of the .interp section to the interpreter. */ ++ if (info->executable) ++ { ++ s = bfd_get_linker_section (htab->elf.dynobj, ".interp"); ++ BFD_ASSERT (s != NULL); ++ s->size = sizeof ELF_DYNAMIC_INTERPRETER; ++ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; ++ } ++ } ++ ++ if (htab->plt_type == PLT_OLD) ++ htab->got_header_size = 16; ++ else if (htab->plt_type == PLT_NEW) ++ htab->got_header_size = 12; ++ ++ /* Set up .got offsets for local syms, and space for local dynamic ++ relocs. */ ++ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) ++ { ++ bfd_signed_vma *local_got; ++ bfd_signed_vma *end_local_got; ++ struct plt_entry **local_plt; ++ struct plt_entry **end_local_plt; ++ char *lgot_masks; ++ bfd_size_type locsymcount; ++ Elf_Internal_Shdr *symtab_hdr; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections: is_ppc_elf() = %d (flavour = %d)\n", is_ppc_elf (ibfd), bfd_get_flavour (ibfd)); ++#endif ++ ++ if (!is_ppc_elf (ibfd)) ++ continue; ++ ++ for (s = ibfd->sections; s != NULL; s = s->next) ++ { ++ struct elf_dyn_relocs *p; ++ ++ for (p = ((struct elf_dyn_relocs *) ++ elf_section_data (s)->local_dynrel); ++ p != NULL; ++ p = p->next) ++ { ++ if (!bfd_is_abs_section (p->sec) ++ && bfd_is_abs_section (p->sec->output_section)) ++ { ++ /* Input section has been discarded, either because ++ it is a copy of a linkonce section or due to ++ linker script /DISCARD/, so we'll be discarding ++ the relocs too. */ ++ } ++ else if (htab->is_vxworks ++ && strcmp (p->sec->output_section->name, ++ ".tls_vars") == 0) ++ { ++ /* Relocations in vxworks .tls_vars sections are ++ handled specially by the loader. */ ++ } ++ else if (p->count != 0) ++ { ++ asection *sreloc = elf_section_data (p->sec)->sreloc; ++ if (!htab->elf.dynamic_sections_created) ++ sreloc = htab->reliplt; ++ sreloc->size += p->count * sizeof (Elf32_External_Rela); ++ if ((p->sec->output_section->flags ++ & (SEC_READONLY | SEC_ALLOC)) ++ == (SEC_READONLY | SEC_ALLOC)) ++ info->flags |= DF_TEXTREL; ++ } ++ } ++ } ++ ++ local_got = elf_local_got_refcounts (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; ++ lgot_masks = (char *) end_local_plt; ++ ++ 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; ++ if (need == 0) ++ *local_got = (bfd_vma) -1; ++ else ++ { ++ *local_got = allocate_got (htab, need); ++ if (info->shared) ++ htab->relgot->size += (need ++ * (sizeof (Elf32_External_Rela) / 4)); ++ } ++ } ++ else ++ *local_got = (bfd_vma) -1; ++ ++ if (htab->is_vxworks) ++ continue; ++ ++ /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */ ++ for (; local_plt < end_local_plt; ++local_plt) ++ { ++ struct plt_entry *ent; ++ bfd_boolean doneone = FALSE; ++ bfd_vma plt_offset = 0, glink_offset = 0; ++ ++ for (ent = *local_plt; ent != NULL; ent = ent->next) ++ if (ent->plt.refcount > 0) ++ { ++ s = htab->iplt; ++ ++ if (!doneone) ++ { ++ plt_offset = s->size; ++ s->size += 4; ++ } ++ ent->plt.offset = plt_offset; ++ ++ s = htab->glink; ++ if (!doneone || info->shared) ++ { ++ glink_offset = s->size; ++ s->size += GLINK_ENTRY_SIZE; ++ } ++ ent->glink_offset = glink_offset; ++ ++ if (!doneone) ++ { ++ htab->reliplt->size += sizeof (Elf32_External_Rela); ++ doneone = TRUE; ++ } ++ } ++ else ++ ent->plt.offset = (bfd_vma) -1; ++ } ++ } ++ ++ /* Allocate space for global sym dynamic relocs. */ ++ elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info); ++ ++ if (htab->tlsld_got.refcount > 0) ++ { ++ htab->tlsld_got.offset = allocate_got (htab, 8); ++ if (info->shared) ++ htab->relgot->size += sizeof (Elf32_External_Rela); ++ } ++ else ++ htab->tlsld_got.offset = (bfd_vma) -1; ++ ++ if (htab->got != NULL && htab->plt_type != PLT_VXWORKS) ++ { ++ unsigned int g_o_t = 32768; ++ ++ /* If we haven't allocated the header, do so now. When we get here, ++ for old plt/got the got size will be 0 to 32764 (not allocated), ++ or 32780 to 65536 (header allocated). For new plt/got, the ++ corresponding ranges are 0 to 32768 and 32780 to 65536. */ ++ if (htab->got->size <= 32768) ++ { ++ g_o_t = htab->got->size; ++ if (htab->plt_type == PLT_OLD) ++ g_o_t += 4; ++ htab->got->size += htab->got_header_size; ++ } ++ ++ htab->elf.hgot->root.u.def.value = g_o_t; ++ } ++ if (info->shared) ++ { ++ struct elf_link_hash_entry *sda = htab->sdata[0].sym; ++ if (sda != NULL ++ && !(sda->root.type == bfd_link_hash_defined ++ || sda->root.type == bfd_link_hash_defweak)) ++ { ++ sda->root.type = bfd_link_hash_defined; ++ sda->root.u.def.section = htab->elf.hgot->root.u.def.section; ++ sda->root.u.def.value = htab->elf.hgot->root.u.def.value; ++ } ++ } ++ ++ if (htab->glink != NULL ++ && htab->glink->size != 0 ++ && htab->elf.dynamic_sections_created) ++ { ++ htab->glink_pltresolve = htab->glink->size; ++ /* Space for the branch table. */ ++ htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4; ++ /* Pad out to align the start of PLTresolve. */ ++ htab->glink->size += -htab->glink->size & 15; ++ htab->glink->size += GLINK_PLTRESOLVE; ++ ++ if (htab->emit_stub_syms) ++ { ++ struct elf_link_hash_entry *sh; ++ sh = elf_link_hash_lookup (&htab->elf, "__glink", ++ TRUE, FALSE, FALSE); ++ if (sh == NULL) ++ return FALSE; ++ if (sh->root.type == bfd_link_hash_new) ++ { ++ sh->root.type = bfd_link_hash_defined; ++ sh->root.u.def.section = htab->glink; ++ sh->root.u.def.value = htab->glink_pltresolve; ++ sh->ref_regular = 1; ++ sh->def_regular = 1; ++ sh->ref_regular_nonweak = 1; ++ sh->forced_local = 1; ++ sh->non_elf = 0; ++ } ++ sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve", ++ TRUE, FALSE, FALSE); ++ if (sh == NULL) ++ return FALSE; ++ if (sh->root.type == bfd_link_hash_new) ++ { ++ sh->root.type = bfd_link_hash_defined; ++ sh->root.u.def.section = htab->glink; ++ sh->root.u.def.value = htab->glink->size - GLINK_PLTRESOLVE; ++ sh->ref_regular = 1; ++ sh->def_regular = 1; ++ sh->ref_regular_nonweak = 1; ++ sh->forced_local = 1; ++ sh->non_elf = 0; ++ } ++ } ++ } ++ ++ if (htab->glink != NULL ++ && htab->glink->size != 0 ++ && htab->glink_eh_frame != NULL ++ && !bfd_is_abs_section (htab->glink_eh_frame->output_section) ++ && _bfd_elf_eh_frame_present (info)) ++ { ++ s = htab->glink_eh_frame; ++ s->size = sizeof (glink_eh_frame_cie) + 20; ++ if (info->shared) ++ { ++ s->size += 4; ++ if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256) ++ s->size += 4; ++ } ++ } ++ ++ /* We've now determined the sizes of the various dynamic sections. ++ Allocate memory for them. */ ++ relocs = FALSE; ++ for (s = htab->elf.dynobj->sections; s != NULL; s = s->next) ++ { ++ bfd_boolean strip_section = TRUE; ++ ++ if ((s->flags & SEC_LINKER_CREATED) == 0) ++ continue; ++ ++ if (s == htab->plt ++ || s == htab->got) ++ { ++ /* We'd like to strip these sections if they aren't needed, but if ++ we've exported dynamic symbols from them we must leave them. ++ It's too late to tell BFD to get rid of the symbols. */ ++ if (htab->elf.hplt != NULL) ++ strip_section = FALSE; ++ /* Strip this section if we don't need it; see the ++ comment below. */ ++ } ++ else if (s == htab->iplt ++ || s == htab->glink ++ || s == htab->glink_eh_frame ++ || s == htab->sgotplt ++ || s == htab->sbss ++ || s == htab->dynbss ++ || s == htab->dynsbss ++ || s == htab->sdata[0].section ++ || s == htab->sdata[1].section) ++ { ++ /* Strip these too. */ ++ } ++ else if (CONST_STRNEQ (bfd_get_section_name (htab->elf.dynobj, s), ++ ".rela")) ++ { ++ if (s->size != 0) ++ { ++ /* Remember whether there are any relocation sections. */ ++ relocs = TRUE; ++ ++ /* We use the reloc_count field as a counter if we need ++ to copy relocs into the output file. */ ++ s->reloc_count = 0; ++ } ++ } ++ else ++ { ++ /* It's not one of our sections, so don't allocate space. */ ++ continue; ++ } ++ ++ if (s->size == 0 && strip_section) ++ { ++ /* If we don't need this section, strip it from the ++ output file. This is mostly to handle .rela.bss and ++ .rela.plt. We must create both sections in ++ create_dynamic_sections, because they must be created ++ before the linker maps input sections to output ++ sections. The linker does that before ++ adjust_dynamic_symbol is called, and it is that ++ function which decides whether anything needs to go ++ into these sections. */ ++ s->flags |= SEC_EXCLUDE; ++ continue; ++ } ++ ++ if ((s->flags & SEC_HAS_CONTENTS) == 0) ++ continue; ++ ++ /* Allocate memory for the section contents. */ ++ s->contents = bfd_zalloc (htab->elf.dynobj, s->size); ++ if (s->contents == NULL) ++ return FALSE; ++ } ++ ++ if (htab->elf.dynamic_sections_created) ++ { ++ /* Add some entries to the .dynamic section. We fill in the ++ values later, in ppc_elf_finish_dynamic_sections, but we ++ must add the entries now so that we get the correct size for ++ the .dynamic section. The DT_DEBUG entry is filled in by the ++ dynamic linker and used by the debugger. */ ++#define add_dynamic_entry(TAG, VAL) \ ++ _bfd_elf_add_dynamic_entry (info, TAG, VAL) ++ ++ if (info->executable) ++ { ++ if (!add_dynamic_entry (DT_DEBUG, 0)) ++ return FALSE; ++ } ++ ++ if (htab->plt != NULL && htab->plt->size != 0) ++ { ++ if (!add_dynamic_entry (DT_PLTGOT, 0) ++ || !add_dynamic_entry (DT_PLTRELSZ, 0) ++ || !add_dynamic_entry (DT_PLTREL, DT_RELA) ++ || !add_dynamic_entry (DT_JMPREL, 0)) ++ return FALSE; ++ } ++ ++ if (htab->glink != NULL && htab->glink->size != 0) ++ { ++ if (!add_dynamic_entry (DT_PPC_GOT, 0)) ++ return FALSE; ++ if (!htab->no_tls_get_addr_opt ++ && htab->tls_get_addr != NULL ++ && htab->tls_get_addr->plt.plist != NULL ++ && !add_dynamic_entry (DT_PPC_TLSOPT, 0)) ++ return FALSE; ++ } ++ ++ if (relocs) ++ { ++ if (!add_dynamic_entry (DT_RELA, 0) ++ || !add_dynamic_entry (DT_RELASZ, 0) ++ || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) ++ return FALSE; ++ } ++ ++ /* If any dynamic relocs apply to a read-only section, then we ++ need a DT_TEXTREL entry. */ ++ if ((info->flags & DF_TEXTREL) == 0) ++ elf_link_hash_traverse (elf_hash_table (info), maybe_set_textrel, ++ info); ++ ++ if ((info->flags & DF_TEXTREL) != 0) ++ { ++ if (!add_dynamic_entry (DT_TEXTREL, 0)) ++ return FALSE; ++ } ++ if (htab->is_vxworks ++ && !elf_vxworks_add_dynamic_entries (output_bfd, info)) ++ return FALSE; ++ ++ /* Flag it as a version 2 dynamic binary */ ++ if (!add_dynamic_entry(DT_AMIGAOS_DYNVERSION, 2)) ++ return FALSE; ++ } ++#undef add_dynamic_entry ++ ++ if (htab->glink_eh_frame != NULL ++ && htab->glink_eh_frame->contents != NULL) ++ { ++ unsigned char *p = htab->glink_eh_frame->contents; ++ bfd_vma val; ++ ++ memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); ++ /* CIE length (rewrite in case little-endian). */ ++ bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p); ++ p += sizeof (glink_eh_frame_cie); ++ /* FDE length. */ ++ val = htab->glink_eh_frame->size - 4 - sizeof (glink_eh_frame_cie); ++ bfd_put_32 (htab->elf.dynobj, val, p); ++ p += 4; ++ /* CIE pointer. */ ++ val = p - htab->glink_eh_frame->contents; ++ bfd_put_32 (htab->elf.dynobj, val, p); ++ p += 4; ++ /* Offset to .glink. Set later. */ ++ p += 4; ++ /* .glink size. */ ++ bfd_put_32 (htab->elf.dynobj, htab->glink->size, p); ++ p += 4; ++ /* Augmentation. */ ++ p += 1; ++ ++ if (info->shared ++ && htab->elf.dynamic_sections_created) ++ { ++ bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2; ++ if (adv < 64) ++ *p++ = DW_CFA_advance_loc + adv; ++ else if (adv < 256) ++ { ++ *p++ = DW_CFA_advance_loc1; ++ *p++ = adv; ++ } ++ else if (adv < 65536) ++ { ++ *p++ = DW_CFA_advance_loc2; ++ bfd_put_16 (htab->elf.dynobj, adv, p); ++ p += 2; ++ } ++ else ++ { ++ *p++ = DW_CFA_advance_loc4; ++ bfd_put_32 (htab->elf.dynobj, adv, p); ++ p += 4; ++ } ++ *p++ = DW_CFA_register; ++ *p++ = 65; ++ p++; ++ *p++ = DW_CFA_advance_loc + 4; ++ *p++ = DW_CFA_restore_extended; ++ *p++ = 65; ++ } ++ BFD_ASSERT ((bfd_vma) ((p + 3 - htab->glink_eh_frame->contents) & -4) ++ == htab->glink_eh_frame->size); ++ } ++ ++ return TRUE; ++} ++ ++/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ ++ ++static bfd_boolean ++ppc_elf_hash_symbol (struct elf_link_hash_entry *h) ++{ ++ if (h->plt.plist != NULL ++ && !h->def_regular ++ && (!h->pointer_equality_needed ++ || !h->ref_regular_nonweak)) ++ return FALSE; ++ ++ return _bfd_elf_hash_symbol (h); ++} ++ ++#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) ++ ++/* Relaxation trampolines. r12 is available for clobbering (r11, is ++ used for some functions that are allowed to break the ABI). */ ++static const int shared_stub_entry[] = ++ { ++ 0x7c0802a6, /* mflr 0 */ ++ 0x429f0005, /* bcl 20, 31, .Lxxx */ ++ 0x7d8802a6, /* mflr 12 */ ++ 0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */ ++ 0x398c0008, /* addi 12, 12, (xxx-.Lxxx)@l */ ++ 0x7c0803a6, /* mtlr 0 */ ++ 0x7d8903a6, /* mtctr 12 */ ++ 0x4e800420, /* bctr */ ++ }; ++ ++static const int stub_entry[] = ++ { ++ 0x3d800000, /* lis 12,xxx@ha */ ++ 0x398c0000, /* addi 12,12,xxx@l */ ++ 0x7d8903a6, /* mtctr 12 */ ++ 0x4e800420, /* bctr */ ++ }; ++ ++static bfd_boolean ++ppc_elf_relax_section (bfd *abfd, ++ asection *isec, ++ struct bfd_link_info *link_info, ++ bfd_boolean *again) ++{ ++ struct one_fixup ++ { ++ struct one_fixup *next; ++ asection *tsec; ++ /* Final link, can use the symbol offset. For a ++ relocatable link we use the symbol's index. */ ++ bfd_vma toff; ++ bfd_vma trampoff; ++ }; ++ ++ Elf_Internal_Shdr *symtab_hdr; ++ bfd_byte *contents = NULL; ++ Elf_Internal_Sym *isymbuf = NULL; ++ Elf_Internal_Rela *internal_relocs = NULL; ++ Elf_Internal_Rela *irel, *irelend; ++ struct one_fixup *fixups = NULL; ++ unsigned changes = 0; ++ struct ppc_elf_link_hash_table *htab; ++ bfd_size_type trampoff; ++ asection *got2; ++ bfd_boolean maybe_pasted; ++ ++ *again = FALSE; ++ ++ /* Nothing to do if there are no relocations, and no need to do ++ anything with non-alloc or non-code sections. */ ++ if ((isec->flags & SEC_ALLOC) == 0 ++ || (isec->flags & SEC_CODE) == 0 ++ || (isec->flags & SEC_RELOC) == 0 ++ || isec->reloc_count == 0) ++ return TRUE; ++ ++ /* We cannot represent the required PIC relocs in the output, so don't ++ do anything. The linker doesn't support mixing -shared and -r ++ anyway. */ ++ if (link_info->relocatable && link_info->shared) ++ return TRUE; ++ ++ trampoff = (isec->size + 3) & (bfd_vma) -4; ++ maybe_pasted = (strcmp (isec->output_section->name, ".init") == 0 ++ || strcmp (isec->output_section->name, ".fini") == 0); ++ /* Space for a branch around any trampolines. */ ++ if (maybe_pasted) ++ trampoff += 4; ++ ++ symtab_hdr = &elf_symtab_hdr (abfd); ++ ++ /* Get a copy of the native relocations. */ ++ internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, ++ link_info->keep_memory); ++ if (internal_relocs == NULL) ++ goto error_return; ++ ++ htab = ppc_elf_hash_table (link_info); ++ got2 = bfd_get_section_by_name (abfd, ".got2"); ++ ++ irelend = internal_relocs + isec->reloc_count; ++ for (irel = internal_relocs; irel < irelend; irel++) ++ { ++ unsigned long r_type = ELF32_R_TYPE (irel->r_info); ++ bfd_vma toff, roff; ++ asection *tsec; ++ struct one_fixup *f; ++ size_t insn_offset = 0; ++ bfd_vma max_branch_offset, val; ++ bfd_byte *hit_addr; ++ unsigned long t0; ++ struct elf_link_hash_entry *h; ++ struct plt_entry **plist; ++ unsigned char sym_type; ++ ++ switch (r_type) ++ { ++ case R_PPC_REL24: ++ case R_PPC_LOCAL24PC: ++ case R_PPC_PLTREL24: ++ max_branch_offset = 1 << 25; ++ break; ++ ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ max_branch_offset = 1 << 15; ++ break; ++ ++ default: ++ continue; ++ } ++ ++ /* 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; ++ ++ /* 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; ++ 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); ++ ++ 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; ++ } ++ else if (h->root.type == bfd_link_hash_undefined ++ || h->root.type == bfd_link_hash_undefweak) ++ { ++ tsec = bfd_und_section_ptr; ++ toff = link_info->relocatable ? indx : 0; ++ } ++ else ++ continue; ++ ++ sym_type = h->type; ++ } ++ ++ /* The condition here under which we call find_plt_ent must ++ match that in relocate_section. If we call find_plt_ent here ++ but not in relocate_section, or vice versa, then the branch ++ destination used here may be incorrect. */ ++ plist = NULL; ++ if (h != NULL) ++ { ++ /* We know is_branch_reloc (r_type) is true. */ ++ if (h->type == STT_GNU_IFUNC ++ || r_type == R_PPC_PLTREL24) ++ plist = &h->plt.plist; ++ } ++ else if (sym_type == STT_GNU_IFUNC ++ && elf_local_got_offsets (abfd) != NULL) ++ { ++ bfd_vma *local_got_offsets = elf_local_got_offsets (abfd); ++ struct plt_entry **local_plt = (struct plt_entry **) ++ (local_got_offsets + symtab_hdr->sh_info); ++ plist = local_plt + ELF32_R_SYM (irel->r_info); ++ } ++ if (plist != NULL) ++ { ++ bfd_vma addend = 0; ++ struct plt_entry *ent; ++ ++ if (r_type == R_PPC_PLTREL24 && link_info->shared) ++ addend = irel->r_addend; ++ ent = find_plt_ent (plist, got2, addend); ++ if (ent != NULL) ++ { ++ if (htab->plt_type == PLT_NEW ++ || h == NULL ++ || !htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ { ++ tsec = htab->glink; ++ toff = ent->glink_offset; ++ } ++ else ++ { ++ tsec = htab->plt; ++ toff = ent->plt.offset; ++ } ++ } ++ } ++ ++ /* If the branch and target are in the same section, you have ++ no hope of adding stubs. We'll error out later should the ++ branch overflow. */ ++ if (tsec == isec) ++ 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 ++ branches. However, implement it correctly here as a ++ reference for other target relax_section functions. */ ++ if (0 && tsec->sec_info_type == SEC_INFO_TYPE_MERGE) ++ { ++ /* At this stage in linking, no SEC_MERGE symbol has been ++ adjusted, so all references to such symbols need to be ++ passed through _bfd_merged_section_offset. (Later, in ++ relocate_section, all SEC_MERGE symbols *except* for ++ section symbols have been adjusted.) ++ ++ gas may reduce relocations against symbols in SEC_MERGE ++ sections to a relocation against the section symbol when ++ the original addend was zero. When the reloc is against ++ a section symbol we should include the addend in the ++ offset passed to _bfd_merged_section_offset, since the ++ location of interest is the original symbol. On the ++ other hand, an access to "sym+addend" where "sym" is not ++ 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) ++ toff += irel->r_addend; ++ ++ toff = _bfd_merged_section_offset (abfd, &tsec, ++ elf_section_data (tsec)->sec_info, ++ toff); ++ ++ if (sym_type != STT_SECTION) ++ toff += irel->r_addend; ++ } ++ /* PLTREL24 addends are special. */ ++ else if (r_type != R_PPC_PLTREL24) ++ toff += irel->r_addend; ++ ++ /* Attempted -shared link of non-pic code loses. */ ++ if (tsec->output_section == NULL) ++ continue; ++ ++ roff = irel->r_offset; ++ ++ /* If the branch is in range, no need to do anything. */ ++ if (tsec != bfd_und_section_ptr ++ && (!link_info->relocatable ++ /* A relocatable link may have sections moved during ++ final link, so do not presume they remain in range. */ ++ || tsec->output_section == isec->output_section)) ++ { ++ bfd_vma symaddr, reladdr; ++ ++ symaddr = tsec->output_section->vma + tsec->output_offset + toff; ++ reladdr = isec->output_section->vma + isec->output_offset + roff; ++ if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset) ++ continue; ++ } ++ ++ /* Look for an existing fixup to this address. */ ++ for (f = fixups; f ; f = f->next) ++ if (f->tsec == tsec && f->toff == toff) ++ break; ++ ++ if (f == NULL) ++ { ++ size_t size; ++ unsigned long stub_rtype; ++ ++ val = trampoff - roff; ++ if (val >= max_branch_offset) ++ /* Oh dear, we can't reach a trampoline. Don't try to add ++ one. We'll report an error later. */ ++ continue; ++ ++ if (link_info->shared) ++ { ++ size = 4 * ARRAY_SIZE (shared_stub_entry); ++ insn_offset = 12; ++ } ++ else ++ { ++ size = 4 * ARRAY_SIZE (stub_entry); ++ insn_offset = 0; ++ } ++ stub_rtype = R_PPC_RELAX; ++ if (tsec == htab->plt ++ || tsec == htab->glink) ++ { ++ stub_rtype = R_PPC_RELAX_PLT; ++ if (r_type == R_PPC_PLTREL24) ++ stub_rtype = R_PPC_RELAX_PLTREL24; ++ } ++ ++ /* Hijack the old relocation. Since we need two ++ relocations for this use a "composite" reloc. */ ++ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), ++ stub_rtype); ++ irel->r_offset = trampoff + insn_offset; ++ if (r_type == R_PPC_PLTREL24 ++ && stub_rtype != R_PPC_RELAX_PLTREL24) ++ irel->r_addend = 0; ++ ++ /* Record the fixup so we don't do it again this section. */ ++ f = bfd_malloc (sizeof (*f)); ++ f->next = fixups; ++ f->tsec = tsec; ++ f->toff = toff; ++ f->trampoff = trampoff; ++ fixups = f; ++ ++ trampoff += size; ++ changes++; ++ } ++ else ++ { ++ val = f->trampoff - roff; ++ if (val >= max_branch_offset) ++ continue; ++ ++ /* Nop out the reloc, since we're finalizing things here. */ ++ irel->r_info = ELF32_R_INFO (0, R_PPC_NONE); ++ } ++ ++ /* Get the section contents. */ ++ if (contents == NULL) ++ { ++ /* Get cached copy if it exists. */ ++ if (elf_section_data (isec)->this_hdr.contents != NULL) ++ contents = elf_section_data (isec)->this_hdr.contents; ++ else ++ { ++ /* Go get them off disk. */ ++ if (!bfd_malloc_and_get_section (abfd, isec, &contents)) ++ goto error_return; ++ } ++ } ++ ++ /* Fix up the existing branch to hit the trampoline. */ ++ hit_addr = contents + roff; ++ switch (r_type) ++ { ++ case R_PPC_REL24: ++ case R_PPC_LOCAL24PC: ++ case R_PPC_PLTREL24: ++ t0 = bfd_get_32 (abfd, hit_addr); ++ t0 &= ~0x3fffffc; ++ t0 |= val & 0x3fffffc; ++ bfd_put_32 (abfd, t0, hit_addr); ++ break; ++ ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ t0 = bfd_get_32 (abfd, hit_addr); ++ t0 &= ~0xfffc; ++ t0 |= val & 0xfffc; ++ bfd_put_32 (abfd, t0, hit_addr); ++ break; ++ } ++ } ++ ++ /* Write out the trampolines. */ ++ if (fixups != NULL) ++ { ++ const int *stub; ++ bfd_byte *dest; ++ int i, size; ++ ++ do ++ { ++ struct one_fixup *f = fixups; ++ fixups = fixups->next; ++ free (f); ++ } ++ while (fixups); ++ ++ contents = bfd_realloc_or_free (contents, trampoff); ++ if (contents == NULL) ++ goto error_return; ++ ++ isec->size = (isec->size + 3) & (bfd_vma) -4; ++ dest = contents + isec->size; ++ /* Branch around the trampolines. */ ++ if (maybe_pasted) ++ { ++ bfd_vma val = B + trampoff - isec->size; ++ bfd_put_32 (abfd, val, dest); ++ dest += 4; ++ } ++ isec->size = trampoff; ++ ++ if (link_info->shared) ++ { ++ stub = shared_stub_entry; ++ size = ARRAY_SIZE (shared_stub_entry); ++ } ++ else ++ { ++ stub = stub_entry; ++ size = ARRAY_SIZE (stub_entry); ++ } ++ ++ i = 0; ++ while (dest < contents + trampoff) ++ { ++ bfd_put_32 (abfd, stub[i], dest); ++ i++; ++ if (i == size) ++ i = 0; ++ dest += 4; ++ } ++ BFD_ASSERT (i == 0); ++ } ++ ++ if (isymbuf != NULL ++ && symtab_hdr->contents != (unsigned char *) isymbuf) ++ { ++ if (! link_info->keep_memory) ++ free (isymbuf); ++ else ++ { ++ /* Cache the symbols for elf_link_input_bfd. */ ++ symtab_hdr->contents = (unsigned char *) isymbuf; ++ } ++ } ++ ++ if (contents != NULL ++ && elf_section_data (isec)->this_hdr.contents != contents) ++ { ++ if (!changes && !link_info->keep_memory) ++ free (contents); ++ else ++ { ++ /* Cache the section contents for elf_link_input_bfd. */ ++ elf_section_data (isec)->this_hdr.contents = contents; ++ } ++ } ++ ++ if (changes != 0) ++ { ++ /* Append sufficient NOP relocs so we can write out relocation ++ information for the trampolines. */ ++ Elf_Internal_Shdr *rel_hdr; ++ Elf_Internal_Rela *new_relocs = bfd_malloc ((changes + isec->reloc_count) ++ * sizeof (*new_relocs)); ++ unsigned ix; ++ ++ if (!new_relocs) ++ goto error_return; ++ memcpy (new_relocs, internal_relocs, ++ isec->reloc_count * sizeof (*new_relocs)); ++ for (ix = changes; ix--;) ++ { ++ irel = new_relocs + ix + isec->reloc_count; ++ ++ irel->r_info = ELF32_R_INFO (0, R_PPC_NONE); ++ } ++ if (internal_relocs != elf_section_data (isec)->relocs) ++ free (internal_relocs); ++ elf_section_data (isec)->relocs = new_relocs; ++ isec->reloc_count += changes; ++ rel_hdr = _bfd_elf_single_rel_hdr (isec); ++ rel_hdr->sh_size += changes * rel_hdr->sh_entsize; ++ } ++ else if (elf_section_data (isec)->relocs != internal_relocs) ++ free (internal_relocs); ++ ++ *again = changes != 0; ++ if (!*again && link_info->relocatable) ++ { ++ /* Convert the internal relax relocs to external form. */ ++ for (irel = internal_relocs; irel < irelend; irel++) ++ if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX) ++ { ++ unsigned long r_symndx = ELF32_R_SYM (irel->r_info); ++ ++ /* Rewrite the reloc and convert one of the trailing nop ++ relocs to describe this relocation. */ ++ BFD_ASSERT (ELF32_R_TYPE (irelend[-1].r_info) == R_PPC_NONE); ++ /* The relocs are at the bottom 2 bytes */ ++ irel[0].r_offset += 2; ++ memmove (irel + 1, irel, (irelend - irel - 1) * sizeof (*irel)); ++ irel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); ++ irel[1].r_offset += 4; ++ irel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); ++ irel++; ++ } ++ } ++ ++ return TRUE; ++ ++ error_return: ++ if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) ++ free (isymbuf); ++ if (contents != NULL ++ && elf_section_data (isec)->this_hdr.contents != contents) ++ free (contents); ++ if (internal_relocs != NULL ++ && elf_section_data (isec)->relocs != internal_relocs) ++ free (internal_relocs); ++ return FALSE; ++} ++ ++/* What to do when ld finds relocations against symbols defined in ++ discarded sections. */ ++ ++static unsigned int ++ppc_elf_action_discarded (asection *sec) ++{ ++ if (strcmp (".fixup", sec->name) == 0) ++ return 0; ++ ++ if (strcmp (".got2", sec->name) == 0) ++ return 0; ++ ++ return _bfd_elf_default_action_discarded (sec); ++} ++ ++/* Fill in the address for a pointer generated in a linker section. */ ++ ++static bfd_vma ++elf_finish_pointer_linker_section (bfd *input_bfd, ++ elf_linker_section_t *lsect, ++ struct elf_link_hash_entry *h, ++ bfd_vma relocation, ++ const Elf_Internal_Rela *rel) ++{ ++ elf_linker_section_pointers_t *linker_section_ptr; ++ ++ BFD_ASSERT (lsect != NULL); ++ ++ if (h != NULL) ++ { ++ /* Handle global symbol. */ ++ struct ppc_elf_link_hash_entry *eh; ++ ++ eh = (struct ppc_elf_link_hash_entry *) h; ++ BFD_ASSERT (eh->elf.def_regular); ++ linker_section_ptr = eh->linker_section_pointer; ++ } ++ else ++ { ++ /* Handle local symbol. */ ++ unsigned long r_symndx = ELF32_R_SYM (rel->r_info); ++ ++ BFD_ASSERT (is_ppc_elf (input_bfd)); ++ BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL); ++ linker_section_ptr = elf_local_ptr_offsets (input_bfd)[r_symndx]; ++ } ++ ++ linker_section_ptr = elf_find_pointer_linker_section (linker_section_ptr, ++ rel->r_addend, ++ lsect); ++ BFD_ASSERT (linker_section_ptr != NULL); ++ ++ /* Offset will always be a multiple of four, so use the bottom bit ++ as a "written" flag. */ ++ if ((linker_section_ptr->offset & 1) == 0) ++ { ++ bfd_put_32 (lsect->section->owner, ++ relocation + linker_section_ptr->addend, ++ lsect->section->contents + linker_section_ptr->offset); ++ linker_section_ptr->offset += 1; ++ } ++ ++ relocation = (lsect->section->output_section->vma ++ + lsect->section->output_offset ++ + linker_section_ptr->offset - 1 ++ - SYM_VAL (lsect->sym)); ++ ++#ifdef DEBUG ++ fprintf (stderr, ++ "Finish pointer in linker section %s, offset = %ld (0x%lx)\n", ++ lsect->name, (long) relocation, (long) relocation); ++#endif ++ ++ return relocation; ++} ++ ++#define PPC_LO(v) ((v) & 0xffff) ++#define PPC_HI(v) (((v) >> 16) & 0xffff) ++#define PPC_HA(v) PPC_HI ((v) + 0x8000) ++ ++static void ++write_glink_stub (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; ++ ++ plt = ((ent->plt.offset & ~1) ++ + plt_sec->output_section->vma ++ + plt_sec->output_offset); ++ ++ if (info->shared) ++ { ++ bfd_vma got = 0; ++ ++ if (ent->addend >= 32768) ++ got = (ent->addend ++ + ent->sec->output_section->vma ++ + ent->sec->output_offset); ++ else if (htab->elf.hgot != NULL) ++ got = SYM_VAL (htab->elf.hgot); ++ ++ 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, NOP, p); ++ p += 4; ++ } ++ 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; ++ } ++} ++ ++/* Return true if symbol is defined statically. */ ++ ++static bfd_boolean ++is_static_defined (struct elf_link_hash_entry *h) ++{ ++ return ((h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && h->root.u.def.section != NULL ++ && h->root.u.def.section->output_section != NULL); ++} ++ ++/* If INSN is an opcode that may be used with an @tls operand, return ++ the transformed insn for TLS optimisation, otherwise return 0. If ++ REG is non-zero only match an insn with RB or RA equal to REG. */ ++ ++unsigned int ++_bfd_elf_amigaos_ppc_at_tls_transform (unsigned int insn, unsigned int reg) ++{ ++ unsigned int rtra; ++ ++ if ((insn & (0x3f << 26)) != 31 << 26) ++ return 0; ++ ++ if (reg == 0 || ((insn >> 11) & 0x1f) == reg) ++ rtra = insn & ((1 << 26) - (1 << 16)); ++ else if (((insn >> 16) & 0x1f) == reg) ++ rtra = (insn & (0x1f << 21)) | ((insn & (0x1f << 11)) << 5); ++ else ++ return 0; ++ ++ if ((insn & (0x3ff << 1)) == 266 << 1) ++ /* add -> addi. */ ++ insn = 14 << 26; ++ else if ((insn & (0x1f << 1)) == 23 << 1 ++ && ((insn & (0x1f << 6)) < 14 << 6 ++ || ((insn & (0x1f << 6)) >= 16 << 6 ++ && (insn & (0x1f << 6)) < 24 << 6))) ++ /* load and store indexed -> dform. */ ++ insn = (32 | ((insn >> 6) & 0x1f)) << 26; ++ else if ((insn & (((0x1a << 5) | 0x1f) << 1)) == 21 << 1) ++ /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ ++ insn = ((58 | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1); ++ else if ((insn & (((0x1f << 5) | 0x1f) << 1)) == 341 << 1) ++ /* lwax -> lwa. */ ++ insn = (58 << 26) | 2; ++ else ++ return 0; ++ insn |= rtra; ++ return insn; ++} ++ ++/* If INSN is an opcode that may be used with an @tprel operand, return ++ the transformed insn for an undefined weak symbol, ie. with the ++ thread pointer REG operand removed. Otherwise return 0. */ ++ ++unsigned int ++_bfd_elf_amigaos_ppc_at_tprel_transform (unsigned int insn, unsigned int reg) ++{ ++ if ((insn & (0x1f << 16)) == reg << 16 ++ && ((insn & (0x3f << 26)) == 14u << 26 /* addi */ ++ || (insn & (0x3f << 26)) == 15u << 26 /* addis */ ++ || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ ++ || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ ++ || (insn & (0x3f << 26)) == 36u << 26 /* stw */ ++ || (insn & (0x3f << 26)) == 38u << 26 /* stb */ ++ || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ ++ || (insn & (0x3f << 26)) == 42u << 26 /* lha */ ++ || (insn & (0x3f << 26)) == 44u << 26 /* sth */ ++ || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ ++ || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ ++ || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ ++ || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ ++ || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ ++ || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ ++ || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */ ++ && (insn & 3) != 1) ++ || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */ ++ && ((insn & 3) == 0 || (insn & 3) == 3)))) ++ { ++ insn &= ~(0x1f << 16); ++ } ++ else if ((insn & (0x1f << 21)) == reg << 21 ++ && ((insn & (0x3e << 26)) == 24u << 26 /* ori, oris */ ++ || (insn & (0x3e << 26)) == 26u << 26 /* xori,xoris */ ++ || (insn & (0x3e << 26)) == 28u << 26 /* andi,andis */)) ++ { ++ insn &= ~(0x1f << 21); ++ insn |= (insn & (0x1f << 16)) << 5; ++ if ((insn & (0x3e << 26)) == 26 << 26 /* xori,xoris */) ++ insn -= 2 >> 26; /* convert to ori,oris */ ++ } ++ else ++ insn = 0; ++ return insn; ++} ++ ++static bfd_boolean ++is_insn_ds_form (unsigned int insn) ++{ ++ return ((insn & (0x3f << 26)) == 58u << 26 /* ld,ldu,lwa */ ++ || (insn & (0x3f << 26)) == 62u << 26 /* std,stdu,stq */ ++ || (insn & (0x3f << 26)) == 57u << 26 /* lfdp */ ++ || (insn & (0x3f << 26)) == 61u << 26 /* stfdp */); ++} ++ ++static bfd_boolean ++is_insn_dq_form (unsigned int insn) ++{ ++ return (insn & (0x3f << 26)) == 56u << 26; /* lq */ ++} ++ ++/* The RELOCATE_SECTION function is called by the ELF backend linker ++ to handle the relocations for a section. ++ ++ The relocs are always passed as Rela structures; if the section ++ actually uses Rel structures, the r_addend field will always be ++ zero. ++ ++ This function is responsible for adjust the section contents as ++ necessary, and (if using Rela relocs and generating a ++ relocatable output file) adjusting the reloc addend as ++ necessary. ++ ++ This function does not have to worry about setting the reloc ++ address or the reloc symbol index. ++ ++ LOCAL_SYMS is a pointer to the swapped in local symbols. ++ ++ LOCAL_SECTIONS is an array giving the section in the input file ++ corresponding to the st_shndx field of each local symbol. ++ ++ The global hash table entry for the global symbols can be found ++ via elf_sym_hashes (input_bfd). ++ ++ When generating relocatable output, this function must handle ++ STB_LOCAL/STT_SECTION symbols specially. The output symbol is ++ going to be the section symbol corresponding to the output ++ section, which means that the addend must be adjusted ++ accordingly. */ ++ ++static bfd_boolean ++ppc_elf_relocate_section (bfd *output_bfd, ++ struct bfd_link_info *info, ++ bfd *input_bfd, ++ asection *input_section, ++ bfd_byte *contents, ++ Elf_Internal_Rela *relocs, ++ Elf_Internal_Sym *local_syms, ++ asection **local_sections) ++{ ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes; ++ struct ppc_elf_link_hash_table *htab; ++ Elf_Internal_Rela *rel; ++ Elf_Internal_Rela *relend; ++ Elf_Internal_Rela outrel; ++ asection *got2, *sreloc = NULL; ++ bfd_vma *local_got_offsets; ++ bfd_boolean ret = TRUE; ++ bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0); ++ bfd_boolean is_vxworks_tls; ++ ++#ifdef DEBUG ++ _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, " ++ "%ld relocations%s", ++ input_bfd, input_section, ++ (long) input_section->reloc_count, ++ (info->relocatable) ? " (relocatable)" : ""); ++#endif ++ ++ got2 = bfd_get_section_by_name (input_bfd, ".got2"); ++ ++ /* Initialize howto table if not already done. */ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ ppc_elf_howto_init (); ++ ++ htab = ppc_elf_hash_table (info); ++ local_got_offsets = elf_local_got_offsets (input_bfd); ++ symtab_hdr = &elf_symtab_hdr (input_bfd); ++ sym_hashes = elf_sym_hashes (input_bfd); ++ /* We have to handle relocations in vxworks .tls_vars sections ++ specially, because the dynamic loader is 'weird'. */ ++ is_vxworks_tls = (htab->is_vxworks && info->shared ++ && !strcmp (input_section->output_section->name, ++ ".tls_vars")); ++ rel = relocs; ++ relend = relocs + input_section->reloc_count; ++ for (; rel < relend; rel++) ++ { ++ enum elf_ppc_reloc_type r_type; ++ bfd_vma addend; ++ bfd_reloc_status_type r; ++ Elf_Internal_Sym *sym; ++ asection *sec; ++ struct elf_link_hash_entry *h; ++ const char *sym_name; ++ reloc_howto_type *howto; ++ unsigned long r_symndx; ++ bfd_vma relocation; ++ bfd_vma branch_bit, from; ++ bfd_boolean unresolved_reloc; ++ bfd_boolean warned; ++ unsigned int tls_type, tls_mask, tls_gd; ++ struct plt_entry **ifunc; ++ ++ r_type = ELF32_R_TYPE (rel->r_info); ++ sym = NULL; ++ sec = NULL; ++ h = NULL; ++ unresolved_reloc = FALSE; ++ warned = FALSE; ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ ++ if (r_symndx < symtab_hdr->sh_info) ++ { ++ sym = local_syms + r_symndx; ++ sec = local_sections[r_symndx]; ++ sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); ++ ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); ++ } ++ else ++ { ++ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, ++ r_symndx, symtab_hdr, sym_hashes, ++ h, sec, relocation, ++ unresolved_reloc, warned); ++ ++ sym_name = h->root.root.string; ++ } ++ ++ if (sec != NULL && discarded_section (sec)) ++ { ++ /* For relocs against symbols from removed linkonce sections, ++ or sections discarded by a linker script, we just want the ++ section contents zeroed. Avoid any special processing. */ ++ howto = NULL; ++ if (r_type < R_PPC_max) ++ howto = ppc_elf_howto_table[r_type]; ++ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, ++ rel, 1, relend, howto, 0, contents); ++ } ++ ++ if (info->relocatable) ++ { ++ if (got2 != NULL ++ && r_type == R_PPC_PLTREL24 ++ && rel->r_addend != 0) ++ { ++ /* R_PPC_PLTREL24 is rather special. If non-zero, the ++ addend specifies the GOT pointer offset within .got2. */ ++ rel->r_addend += got2->output_offset; ++ } ++ continue; ++ } ++ ++ /* TLS optimizations. Replace instruction sequences and relocs ++ based on information we collected in tls_optimize. We edit ++ RELOCS so that --emit-relocs will output something sensible ++ for the final instruction stream. */ ++ tls_mask = 0; ++ tls_gd = 0; ++ if (h != NULL) ++ tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask; ++ else if (local_got_offsets != NULL) ++ { ++ struct plt_entry **local_plt; ++ char *lgot_masks; ++ local_plt ++ = (struct plt_entry **) (local_got_offsets + symtab_hdr->sh_info); ++ lgot_masks = (char *) (local_plt + symtab_hdr->sh_info); ++ tls_mask = lgot_masks[r_symndx]; ++ } ++ ++ /* Ensure reloc mapping code below stays sane. */ ++ if ((R_PPC_GOT_TLSLD16 & 3) != (R_PPC_GOT_TLSGD16 & 3) ++ || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TLSGD16_LO & 3) ++ || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TLSGD16_HI & 3) ++ || (R_PPC_GOT_TLSLD16_HA & 3) != (R_PPC_GOT_TLSGD16_HA & 3) ++ || (R_PPC_GOT_TLSLD16 & 3) != (R_PPC_GOT_TPREL16 & 3) ++ || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TPREL16_LO & 3) ++ || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TPREL16_HI & 3) ++ || (R_PPC_GOT_TLSLD16_HA & 3) != (R_PPC_GOT_TPREL16_HA & 3)) ++ abort (); ++ switch (r_type) ++ { ++ default: ++ break; ++ ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ if ((tls_mask & TLS_TLS) != 0 ++ && (tls_mask & TLS_TPREL) == 0) ++ { ++ bfd_vma insn; ++ ++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); ++ insn &= 31 << 21; ++ insn |= 0x3c020000; /* addis 0,2,0 */ ++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); ++ r_type = R_PPC_TPREL16_HA; ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ } ++ break; ++ ++ case R_PPC_TLS: ++ if ((tls_mask & TLS_TLS) != 0 ++ && (tls_mask & TLS_TPREL) == 0) ++ { ++ bfd_vma insn; ++ ++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset); ++ insn = _bfd_elf_ppc_at_tls_transform (insn, 2); ++ if (insn == 0) ++ abort (); ++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset); ++ r_type = R_PPC_TPREL16_LO; ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ ++ /* Was PPC_TLS which sits on insn boundary, now ++ PPC_TPREL16_LO which is at low-order half-word. */ ++ rel->r_offset += d_offset; ++ } ++ break; ++ ++ case R_PPC_GOT_TLSGD16_HI: ++ case R_PPC_GOT_TLSGD16_HA: ++ tls_gd = TLS_TPRELGD; ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) ++ goto tls_gdld_hi; ++ break; ++ ++ case R_PPC_GOT_TLSLD16_HI: ++ case R_PPC_GOT_TLSLD16_HA: ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) ++ { ++ tls_gdld_hi: ++ if ((tls_mask & tls_gd) != 0) ++ r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3) ++ + R_PPC_GOT_TPREL16); ++ else ++ { ++ bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); ++ rel->r_offset -= d_offset; ++ r_type = R_PPC_NONE; ++ } ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ } ++ break; ++ ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ tls_gd = TLS_TPRELGD; ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) ++ goto tls_ldgd_opt; ++ break; ++ ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) ++ { ++ unsigned int insn1, insn2; ++ bfd_vma offset; ++ ++ tls_ldgd_opt: ++ offset = (bfd_vma) -1; ++ /* If not using the newer R_PPC_TLSGD/LD to mark ++ __tls_get_addr calls, we must trust that the call ++ stays with its arg setup insns, ie. that the next ++ reloc is the __tls_get_addr call associated with ++ the current reloc. Edit both insns. */ ++ if (input_section->has_tls_get_addr_call ++ && rel + 1 < relend ++ && branch_reloc_hash_match (input_bfd, rel + 1, ++ htab->tls_get_addr)) ++ offset = rel[1].r_offset; ++ if ((tls_mask & tls_gd) != 0) ++ { ++ /* IE */ ++ insn1 = bfd_get_32 (output_bfd, ++ contents + rel->r_offset - d_offset); ++ insn1 &= (1 << 26) - 1; ++ insn1 |= 32 << 26; /* lwz */ ++ if (offset != (bfd_vma) -1) ++ { ++ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); ++ insn2 = 0x7c631214; /* add 3,3,2 */ ++ bfd_put_32 (output_bfd, insn2, contents + offset); ++ } ++ r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3) ++ + R_PPC_GOT_TPREL16); ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ } ++ else ++ { ++ /* LE */ ++ insn1 = 0x3c620000; /* addis 3,2,0 */ ++ if (tls_gd == 0) ++ { ++ /* Was an LD reloc. */ ++ for (r_symndx = 0; ++ r_symndx < symtab_hdr->sh_info; ++ r_symndx++) ++ if (local_sections[r_symndx] == sec) ++ break; ++ if (r_symndx >= symtab_hdr->sh_info) ++ r_symndx = STN_UNDEF; ++ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; ++ if (r_symndx != STN_UNDEF) ++ rel->r_addend -= (local_syms[r_symndx].st_value ++ + sec->output_offset ++ + sec->output_section->vma); ++ } ++ r_type = R_PPC_TPREL16_HA; ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ if (offset != (bfd_vma) -1) ++ { ++ rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO); ++ rel[1].r_offset = offset + d_offset; ++ rel[1].r_addend = rel->r_addend; ++ insn2 = 0x38630000; /* addi 3,3,0 */ ++ bfd_put_32 (output_bfd, insn2, contents + offset); ++ } ++ } ++ bfd_put_32 (output_bfd, insn1, ++ contents + rel->r_offset - d_offset); ++ if (tls_gd == 0) ++ { ++ /* We changed the symbol on an LD reloc. Start over ++ in order to get h, sym, sec etc. right. */ ++ rel--; ++ continue; ++ } ++ } ++ break; ++ ++ case R_PPC_TLSGD: ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) ++ { ++ unsigned int insn2; ++ bfd_vma offset = rel->r_offset; ++ ++ if ((tls_mask & TLS_TPRELGD) != 0) ++ { ++ /* IE */ ++ r_type = R_PPC_NONE; ++ insn2 = 0x7c631214; /* add 3,3,2 */ ++ } ++ else ++ { ++ /* LE */ ++ r_type = R_PPC_TPREL16_LO; ++ rel->r_offset += d_offset; ++ insn2 = 0x38630000; /* addi 3,3,0 */ ++ } ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ bfd_put_32 (output_bfd, insn2, contents + offset); ++ /* Zap the reloc on the _tls_get_addr call too. */ ++ BFD_ASSERT (offset == rel[1].r_offset); ++ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); ++ } ++ break; ++ ++ case R_PPC_TLSLD: ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) ++ { ++ unsigned int insn2; ++ ++ for (r_symndx = 0; ++ r_symndx < symtab_hdr->sh_info; ++ r_symndx++) ++ if (local_sections[r_symndx] == sec) ++ break; ++ if (r_symndx >= symtab_hdr->sh_info) ++ r_symndx = STN_UNDEF; ++ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; ++ if (r_symndx != STN_UNDEF) ++ rel->r_addend -= (local_syms[r_symndx].st_value ++ + sec->output_offset ++ + sec->output_section->vma); ++ ++ rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO); ++ rel->r_offset += d_offset; ++ insn2 = 0x38630000; /* addi 3,3,0 */ ++ bfd_put_32 (output_bfd, insn2, ++ contents + rel->r_offset - d_offset); ++ /* Zap the reloc on the _tls_get_addr call too. */ ++ BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset); ++ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); ++ rel--; ++ continue; ++ } ++ break; ++ } ++ ++ /* Handle other relocations that tweak non-addend part of insn. */ ++ branch_bit = 0; ++ switch (r_type) ++ { ++ default: ++ break; ++ ++ /* Branch taken prediction relocations. */ ++ case R_PPC_ADDR14_BRTAKEN: ++ case R_PPC_REL14_BRTAKEN: ++ branch_bit = BRANCH_PREDICT_BIT; ++ /* Fall thru */ ++ ++ /* Branch not taken prediction relocations. */ ++ case R_PPC_ADDR14_BRNTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ { ++ bfd_vma insn; ++ ++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset); ++ insn &= ~BRANCH_PREDICT_BIT; ++ insn |= branch_bit; ++ ++ from = (rel->r_offset ++ + input_section->output_offset ++ + input_section->output_section->vma); ++ ++ /* Invert 'y' bit if not the default. */ ++ if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0) ++ insn ^= BRANCH_PREDICT_BIT; ++ ++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset); ++ break; ++ } ++ } ++ ++ ifunc = NULL; ++ if (!htab->is_vxworks) ++ { ++ struct plt_entry *ent; ++ ++ if (h != NULL) ++ { ++ if (h->type == STT_GNU_IFUNC) ++ ifunc = &h->plt.plist; ++ } ++ else if (local_got_offsets != NULL ++ && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) ++ { ++ struct plt_entry **local_plt; ++ ++ local_plt = (struct plt_entry **) (local_got_offsets ++ + symtab_hdr->sh_info); ++ ifunc = local_plt + r_symndx; ++ } ++ ++ ent = NULL; ++ if (ifunc != NULL ++ && (!info->shared ++ || is_branch_reloc (r_type))) ++ { ++ addend = 0; ++ if (r_type == R_PPC_PLTREL24 && info->shared) ++ addend = rel->r_addend; ++ ent = find_plt_ent (ifunc, got2, addend); ++ } ++ if (ent != NULL) ++ { ++ if (h == NULL && (ent->plt.offset & 1) == 0) ++ { ++ Elf_Internal_Rela rela; ++ bfd_byte *loc; ++ ++ rela.r_offset = (htab->iplt->output_section->vma ++ + htab->iplt->output_offset ++ + ent->plt.offset); ++ rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); ++ rela.r_addend = relocation; ++ loc = htab->reliplt->contents; ++ loc += (htab->reliplt->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->iplt, p, info); ++ ent->glink_offset |= 1; ++ } ++ ++ unresolved_reloc = FALSE; ++ if (htab->plt_type == PLT_NEW ++ || !htab->elf.dynamic_sections_created ++ || h == NULL) ++ relocation = (htab->glink->output_section->vma ++ + htab->glink->output_offset ++ + (ent->glink_offset & ~1)); ++ else ++ relocation = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + ent->plt.offset); ++ } ++ } ++ ++ addend = rel->r_addend; ++ tls_type = 0; ++ howto = NULL; ++ if (r_type < R_PPC_max) ++ howto = ppc_elf_howto_table[r_type]; ++ switch (r_type) ++ { ++ default: ++ info->callbacks->einfo ++ (_("%P: %B: unknown relocation type %d for symbol %s\n"), ++ input_bfd, (int) r_type, sym_name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ continue; ++ ++ case R_PPC_NONE: ++ case R_PPC_TLS: ++ case R_PPC_TLSGD: ++ case R_PPC_TLSLD: ++ case R_PPC_EMB_MRKREF: ++ case R_PPC_GNU_VTINHERIT: ++ case R_PPC_GNU_VTENTRY: ++ continue; ++ ++ /* GOT16 relocations. Like an ADDR16 using the symbol's ++ address in the GOT as relocation value instead of the ++ symbol's value itself. Also, create a GOT entry for the ++ symbol and put the symbol value there. */ ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ case R_PPC_GOT_TLSGD16_HI: ++ case R_PPC_GOT_TLSGD16_HA: ++ tls_type = TLS_TLS | TLS_GD; ++ goto dogot; ++ ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ case R_PPC_GOT_TLSLD16_HI: ++ case R_PPC_GOT_TLSLD16_HA: ++ tls_type = TLS_TLS | TLS_LD; ++ goto dogot; ++ ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ case R_PPC_GOT_TPREL16_HI: ++ case R_PPC_GOT_TPREL16_HA: ++ tls_type = TLS_TLS | TLS_TPREL; ++ goto dogot; ++ ++ case R_PPC_GOT_DTPREL16: ++ case R_PPC_GOT_DTPREL16_LO: ++ case R_PPC_GOT_DTPREL16_HI: ++ case R_PPC_GOT_DTPREL16_HA: ++ tls_type = TLS_TLS | TLS_DTPREL; ++ goto dogot; ++ ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ tls_mask = 0; ++ dogot: ++ { ++ /* Relocation is to the entry for this symbol in the global ++ offset table. */ ++ bfd_vma off; ++ bfd_vma *offp; ++ unsigned long indx; ++ ++ if (htab->got == NULL) ++ abort (); ++ ++ indx = 0; ++ if (tls_type == (TLS_TLS | TLS_LD) ++ && (h == NULL ++ || !h->def_dynamic)) ++ offp = &htab->tlsld_got.offset; ++ else if (h != NULL) ++ { ++ bfd_boolean dyn; ++ dyn = htab->elf.dynamic_sections_created; ++ if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) ++ || (info->shared ++ && SYMBOL_REFERENCES_LOCAL (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 ++ because of a version file. */ ++ ; ++ else ++ { ++ BFD_ASSERT (h->dynindx != -1); ++ indx = h->dynindx; ++ unresolved_reloc = FALSE; ++ } ++ offp = &h->got.offset; ++ } ++ else ++ { ++ if (local_got_offsets == NULL) ++ abort (); ++ offp = &local_got_offsets[r_symndx]; ++ } ++ ++ /* The offset must always be a multiple of 4. We use the ++ least significant bit to record whether we have already ++ processed this entry. */ ++ off = *offp; ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ unsigned int tls_m = (tls_mask ++ & (TLS_LD | TLS_GD | TLS_DTPREL ++ | TLS_TPREL | TLS_TPRELGD)); ++ ++ if (offp == &htab->tlsld_got.offset) ++ tls_m = TLS_LD; ++ else if (h == NULL ++ || !h->def_dynamic) ++ tls_m &= ~TLS_LD; ++ ++ /* We might have multiple got entries for this sym. ++ Initialize them all. */ ++ do ++ { ++ int tls_ty = 0; ++ ++ if ((tls_m & TLS_LD) != 0) ++ { ++ tls_ty = TLS_TLS | TLS_LD; ++ tls_m &= ~TLS_LD; ++ } ++ else if ((tls_m & TLS_GD) != 0) ++ { ++ tls_ty = TLS_TLS | TLS_GD; ++ tls_m &= ~TLS_GD; ++ } ++ else if ((tls_m & TLS_DTPREL) != 0) ++ { ++ tls_ty = TLS_TLS | TLS_DTPREL; ++ tls_m &= ~TLS_DTPREL; ++ } ++ else if ((tls_m & (TLS_TPREL | TLS_TPRELGD)) != 0) ++ { ++ tls_ty = TLS_TLS | TLS_TPREL; ++ tls_m = 0; ++ } ++ ++ /* Generate relocs for the dynamic linker. */ ++ if ((info->shared || indx != 0) ++ && (offp == &htab->tlsld_got.offset ++ || h == NULL ++ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT ++ || h->root.type != bfd_link_hash_undefweak)) ++ { ++ asection *rsec = htab->relgot; ++ bfd_byte * loc; ++ ++ outrel.r_offset = (htab->got->output_section->vma ++ + htab->got->output_offset ++ + off); ++ outrel.r_addend = 0; ++ if (tls_ty & (TLS_LD | TLS_GD)) ++ { ++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32); ++ if (tls_ty == (TLS_TLS | TLS_GD)) ++ { ++ loc = rsec->contents; ++ loc += (rsec->reloc_count++ ++ * sizeof (Elf32_External_Rela)); ++ bfd_elf32_swap_reloca_out (output_bfd, ++ &outrel, loc); ++ outrel.r_offset += 4; ++ outrel.r_info ++ = ELF32_R_INFO (indx, R_PPC_DTPREL32); ++ } ++ } ++ else if (tls_ty == (TLS_TLS | TLS_DTPREL)) ++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32); ++ else if (tls_ty == (TLS_TLS | TLS_TPREL)) ++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_TPREL32); ++ else if (indx != 0) ++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT); ++ else if (ifunc != NULL) ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); ++ else ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ if (indx == 0 && tls_ty != (TLS_TLS | TLS_LD)) ++ { ++ outrel.r_addend += relocation; ++ if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL)) ++ outrel.r_addend -= htab->elf.tls_sec->vma; ++ } ++ loc = rsec->contents; ++ loc += (rsec->reloc_count++ ++ * sizeof (Elf32_External_Rela)); ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); ++ } ++ ++ /* Init the .got section contents if we're not ++ emitting a reloc. */ ++ else ++ { ++ bfd_vma value = relocation; ++ ++ if (tls_ty == (TLS_TLS | TLS_LD)) ++ value = 1; ++ else if (tls_ty != 0) ++ { ++ value -= htab->elf.tls_sec->vma + DTP_OFFSET; ++ if (tls_ty == (TLS_TLS | TLS_TPREL)) ++ value += DTP_OFFSET - TP_OFFSET; ++ ++ if (tls_ty == (TLS_TLS | TLS_GD)) ++ { ++ bfd_put_32 (output_bfd, value, ++ htab->got->contents + off + 4); ++ value = 1; ++ } ++ } ++ bfd_put_32 (output_bfd, value, ++ htab->got->contents + off); ++ } ++ ++ off += 4; ++ if (tls_ty & (TLS_LD | TLS_GD)) ++ off += 4; ++ } ++ while (tls_m != 0); ++ ++ off = *offp; ++ *offp = off | 1; ++ } ++ ++ if (off >= (bfd_vma) -2) ++ abort (); ++ ++ if ((tls_type & TLS_TLS) != 0) ++ { ++ if (tls_type != (TLS_TLS | TLS_LD)) ++ { ++ if ((tls_mask & TLS_LD) != 0 ++ && !(h == NULL ++ || !h->def_dynamic)) ++ off += 8; ++ if (tls_type != (TLS_TLS | TLS_GD)) ++ { ++ if ((tls_mask & TLS_GD) != 0) ++ off += 8; ++ if (tls_type != (TLS_TLS | TLS_DTPREL)) ++ { ++ if ((tls_mask & TLS_DTPREL) != 0) ++ off += 4; ++ } ++ } ++ } ++ } ++ ++ relocation = (htab->got->output_section->vma ++ + htab->got->output_offset ++ + off ++ - SYM_VAL (htab->elf.hgot)); ++ ++ /* Addends on got relocations don't make much sense. ++ x+off@got is actually x@got+off, and since the got is ++ generated by a hash table traversal, the value in the ++ got at entry m+n bears little relation to the entry m. */ ++ if (addend != 0) ++ info->callbacks->einfo ++ (_("%P: %H: non-zero addend on %s reloc against `%s'\n"), ++ input_bfd, input_section, rel->r_offset, ++ howto->name, ++ sym_name); ++ } ++ break; ++ ++ /* Relocations that need no special processing. */ ++ case R_PPC_LOCAL24PC: ++ /* It makes no sense to point a local relocation ++ at a symbol not in this object. */ ++ if (unresolved_reloc) ++ { ++ if (! (*info->callbacks->undefined_symbol) (info, ++ h->root.root.string, ++ input_bfd, ++ input_section, ++ rel->r_offset, ++ TRUE)) ++ return FALSE; ++ continue; ++ } ++ break; ++ ++ case R_PPC_DTPREL16: ++ case R_PPC_DTPREL16_LO: ++ case R_PPC_DTPREL16_HI: ++ case R_PPC_DTPREL16_HA: ++ addend -= htab->elf.tls_sec->vma + DTP_OFFSET; ++ break; ++ ++ /* Relocations that may need to be propagated if this is a shared ++ object. */ ++ case R_PPC_TPREL16: ++ case R_PPC_TPREL16_LO: ++ case R_PPC_TPREL16_HI: ++ case R_PPC_TPREL16_HA: ++ if (h != NULL ++ && h->root.type == bfd_link_hash_undefweak ++ && h->dynindx == -1) ++ { ++ /* Make this relocation against an undefined weak symbol ++ resolve to zero. This is really just a tweak, since ++ code using weak externs ought to check that they are ++ defined before using them. */ ++ bfd_byte *p = contents + rel->r_offset - d_offset; ++ unsigned int insn = bfd_get_32 (output_bfd, p); ++ insn = _bfd_elf_amigaos_ppc_at_tprel_transform (insn, 2); ++ if (insn != 0) ++ bfd_put_32 (output_bfd, insn, p); ++ break; ++ } ++ 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. */ ++ goto dodyn; ++ ++ case R_PPC_TPREL32: ++ addend -= htab->elf.tls_sec->vma + TP_OFFSET; ++ goto dodyn; ++ ++ case R_PPC_DTPREL32: ++ addend -= htab->elf.tls_sec->vma + DTP_OFFSET; ++ goto dodyn; ++ ++ case R_PPC_DTPMOD32: ++ relocation = 1; ++ addend = 0; ++ goto dodyn; ++ ++ case R_PPC_REL16: ++ case R_PPC_REL16_LO: ++ case R_PPC_REL16_HI: ++ case R_PPC_REL16_HA: ++ break; ++ ++ case R_PPC_REL32: ++ if (h == NULL || h == htab->elf.hgot) ++ break; ++ /* fall through */ ++ ++ case R_PPC_ADDR32: ++ case R_PPC_ADDR16: ++ case R_PPC_ADDR16_LO: ++ case R_PPC_ADDR16_HI: ++ case R_PPC_ADDR16_HA: ++ case R_PPC_UADDR32: ++ case R_PPC_UADDR16: ++ goto dodyn; ++ ++ case R_PPC_VLE_REL8: ++ case R_PPC_VLE_REL15: ++ case R_PPC_VLE_REL24: ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ /* If these relocations are not to a named symbol, they can be ++ handled right here, no need to bother the dynamic linker. */ ++ if (SYMBOL_CALLS_LOCAL (info, h) ++ || h == htab->elf.hgot) ++ break; ++ /* fall through */ ++ ++ case R_PPC_ADDR24: ++ case R_PPC_ADDR14: ++ case R_PPC_ADDR14_BRTAKEN: ++ case R_PPC_ADDR14_BRNTAKEN: ++ if (h != NULL && !info->shared) ++ break; ++ /* fall through */ ++ ++ dodyn: ++ if ((input_section->flags & SEC_ALLOC) == 0 ++ || is_vxworks_tls) ++ break; ++ ++ if ((info->shared ++ && !(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 ++ && !info->shared ++ && h != NULL ++ && h->dynindx != -1 ++ && !h->non_got_ref ++ && !h->def_regular)) ++ { ++ int skip; ++ bfd_byte * loc; ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_relocate_section needs to " ++ "create relocation for %s\n", ++ (h && h->root.root.string ++ ? h->root.root.string : "")); ++#endif ++ ++ /* When generating a shared object, these relocations ++ are copied into the output file to be resolved at run ++ time. */ ++ if (sreloc == NULL) ++ { ++ sreloc = elf_section_data (input_section)->sreloc; ++ if (!htab->elf.dynamic_sections_created) ++ sreloc = htab->reliplt; ++ if (sreloc == NULL) ++ return FALSE; ++ } ++ ++ skip = 0; ++ outrel.r_offset = _bfd_elf_section_offset (output_bfd, info, ++ input_section, ++ rel->r_offset); ++ if (outrel.r_offset == (bfd_vma) -1 ++ || outrel.r_offset == (bfd_vma) -2) ++ skip = (int) outrel.r_offset; ++ outrel.r_offset += (input_section->output_section->vma ++ + input_section->output_offset); ++ ++ 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)) ++ { ++ BFD_ASSERT (h->dynindx != -1); ++ unresolved_reloc = FALSE; ++ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); ++ outrel.r_addend = rel->r_addend; ++ } ++ else ++ { ++ outrel.r_addend = relocation + rel->r_addend; ++ ++ if (r_type != R_PPC_ADDR32) ++ { ++ long indx = 0; ++ ++ if (ifunc != NULL) ++ { ++ /* If we get here when building a static ++ executable, then the libc startup function ++ responsible for applying indirect function ++ relocations is going to complain about ++ the reloc type. ++ If we get here when building a dynamic ++ executable, it will be because we have ++ a text relocation. The dynamic loader ++ will set the text segment writable and ++ non-executable to apply text relocations. ++ So we'll segfault when trying to run the ++ indirection function to resolve the reloc. */ ++ info->callbacks->einfo ++ (_("%P: %H: relocation %s for indirect " ++ "function %s unsupported\n"), ++ input_bfd, input_section, rel->r_offset, ++ howto->name, ++ sym_name); ++ ret = FALSE; ++ } ++ else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec)) ++ ; ++ else if (sec == NULL || sec->owner == NULL) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ } ++ else ++ { ++ asection *osec; ++ ++ /* We are turning this relocation into one ++ against a section symbol. It would be ++ proper to subtract the symbol's value, ++ osec->vma, from the emitted reloc addend, ++ 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) ++ { ++ osec = htab->elf.text_index_section; ++ indx = elf_section_data (osec)->dynindx; ++ } ++ 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 ++ } ++ ++ outrel.r_info = ELF32_R_INFO (indx, r_type); ++ } ++ else if (ifunc != NULL) ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); ++ else ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ } ++ ++ loc = sreloc->contents; ++ loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); ++ ++ if (skip == -1) ++ continue; ++ ++ /* This reloc will be computed at runtime. We clear the memory ++ so that it contains predictable value. */ ++ if (! skip ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ || ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE)) ++ { ++ relocation = howto->pc_relative ? outrel.r_offset : 0; ++ addend = 0; ++ break; ++ } ++ } ++ break; ++ ++ case R_PPC_RELAX_PLT: ++ case R_PPC_RELAX_PLTREL24: ++ if (h != NULL) ++ { ++ struct plt_entry *ent; ++ bfd_vma got2_addend = 0; ++ ++ if (r_type == R_PPC_RELAX_PLTREL24) ++ { ++ if (info->shared) ++ got2_addend = addend; ++ addend = 0; ++ } ++ ent = find_plt_ent (&h->plt.plist, got2, got2_addend); ++ if (htab->plt_type == PLT_NEW) ++ relocation = (htab->glink->output_section->vma ++ + htab->glink->output_offset ++ + ent->glink_offset); ++ else ++ relocation = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + ent->plt.offset); ++ } ++ /* Fall thru */ ++ ++ case R_PPC_RELAX: ++ if (info->shared) ++ relocation -= (input_section->output_section->vma ++ + input_section->output_offset ++ + rel->r_offset - 4); ++ ++ { ++ unsigned long t0; ++ unsigned long t1; ++ ++ t0 = bfd_get_32 (output_bfd, contents + rel->r_offset); ++ t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4); ++ ++ /* We're clearing the bits for R_PPC_ADDR16_HA ++ and R_PPC_ADDR16_LO here. */ ++ t0 &= ~0xffff; ++ t1 &= ~0xffff; ++ ++ /* t0 is HA, t1 is LO */ ++ relocation += addend; ++ t0 |= ((relocation + 0x8000) >> 16) & 0xffff; ++ t1 |= relocation & 0xffff; ++ ++ bfd_put_32 (output_bfd, t0, contents + rel->r_offset); ++ bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4); ++ ++ /* Rewrite the reloc and convert one of the trailing nop ++ relocs to describe this relocation. */ ++ BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE); ++ /* The relocs are at the bottom 2 bytes */ ++ rel[0].r_offset += 2; ++ memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel)); ++ rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); ++ rel[1].r_offset += 4; ++ rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); ++ rel++; ++ } ++ continue; ++ ++ /* Indirect .sdata relocation. */ ++ case R_PPC_EMB_SDAI16: ++ BFD_ASSERT (htab->sdata[0].section != NULL); ++ if (!is_static_defined (htab->sdata[0].sym)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ relocation ++ = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[0], ++ h, relocation, rel); ++ addend = 0; ++ break; ++ ++ /* Indirect .sdata2 relocation. */ ++ case R_PPC_EMB_SDA2I16: ++ BFD_ASSERT (htab->sdata[1].section != NULL); ++ if (!is_static_defined (htab->sdata[1].sym)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ relocation ++ = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[1], ++ h, relocation, rel); ++ addend = 0; ++ break; ++ ++ /* Handle the TOC16 reloc. We want to use the offset within the .got ++ section, not the actual VMA. This is appropriate when generating ++ an embedded ELF object, for which the .got section acts like the ++ AIX .toc section. */ ++ case R_PPC_TOC16: /* phony GOT16 relocations */ ++ if (sec == NULL || sec->output_section == NULL) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ BFD_ASSERT (strcmp (bfd_get_section_name (sec->owner, sec), ++ ".got") == 0 ++ || strcmp (bfd_get_section_name (sec->owner, sec), ++ ".cgot") == 0); ++ ++ addend -= sec->output_section->vma + sec->output_offset + 0x8000; ++ break; ++ ++ case R_PPC_PLTREL24: ++ if (h != NULL && ifunc == NULL) ++ { ++ struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2, ++ info->shared ? addend : 0); ++ if (ent == NULL ++ || htab->plt == NULL) ++ { ++ /* We didn't make a PLT entry for this symbol. This ++ happens when statically linking PIC code, or when ++ using -Bsymbolic. */ ++ } ++ else ++ { ++ /* Relocation is to the entry for this symbol in the ++ procedure linkage table. */ ++ unresolved_reloc = FALSE; ++ if (htab->plt_type == PLT_NEW) ++ relocation = (htab->glink->output_section->vma ++ + htab->glink->output_offset ++ + ent->glink_offset); ++ else ++ relocation = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + ent->plt.offset); ++ } ++ } ++ ++ /* R_PPC_PLTREL24 is rather special. If non-zero, the ++ addend specifies the GOT pointer offset within .got2. ++ Don't apply it to the relocation field. */ ++ addend = 0; ++ break; ++ ++ /* Relocate against _SDA_BASE_. */ ++ case R_PPC_SDAREL16: ++ { ++ const char *name; ++ struct elf_link_hash_entry *sda = htab->sdata[0].sym; ++ ++ if (sec == NULL ++ || sec->output_section == NULL ++ || !is_static_defined (sda)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ addend -= SYM_VAL (sda); ++ ++ name = bfd_get_section_name (output_bfd, sec->output_section); ++ if (! ((CONST_STRNEQ (name, ".sdata") ++ && (name[6] == 0 || name[6] == '.')) ++ || (CONST_STRNEQ (name, ".sbss") ++ && (name[5] == 0 || name[5] == '.')))) ++ { ++ info->callbacks->einfo ++ (_("%P: %B: the target (%s) of a %s relocation is " ++ "in the wrong output section (%s)\n"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ } ++ } ++ break; ++ ++ /* Relocate against _SDA2_BASE_. */ ++ case R_PPC_EMB_SDA2REL: ++ { ++ const char *name; ++ struct elf_link_hash_entry *sda = htab->sdata[1].sym; ++ ++ if (sec == NULL ++ || sec->output_section == NULL ++ || !is_static_defined (sda)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ addend -= SYM_VAL (sda); ++ ++ name = bfd_get_section_name (output_bfd, sec->output_section); ++ if (! (CONST_STRNEQ (name, ".sdata2") ++ || CONST_STRNEQ (name, ".sbss2"))) ++ { ++ info->callbacks->einfo ++ (_("%P: %B: the target (%s) of a %s relocation is " ++ "in the wrong output section (%s)\n"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ } ++ } ++ break; ++#if 0 ++ case R_PPC_AMIGAOS_BREL: ++ case R_PPC_AMIGAOS_BREL_HI: ++ case R_PPC_AMIGAOS_BREL_LO: ++ case R_PPC_AMIGAOS_BREL_HA: ++ { ++ if (data_section == NULL) ++ data_section = bfd_get_section_by_name (output_bfd, ".data"); ++ ++ if (sec) ++ { ++ const char *name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sbss") != 0 ++ && strcmp (name, ".data") != 0 ++ && strcmp (name, ".bss") != 0 ++ && strncmp (name, ".ctors", 6) != 0 ++ && strncmp (name, ".dtors", 6) != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ } ++ } ++ ++ addend = addend - data_section->vma; ++ ++ if (r_type == R_PPC_AMIGAOS_BREL_HA) ++ addend += ((relocation + addend) & 0x8000) << 1; ++ ++ } ++ break; ++#endif ++ case R_PPC_VLE_LO16A: ++ relocation = (relocation + addend) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ relocation, split16a_type); ++ continue; ++ ++ case R_PPC_VLE_LO16D: ++ relocation = (relocation + addend) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ relocation, split16d_type); ++ continue; ++ ++ case R_PPC_VLE_HI16A: ++ relocation = ((relocation + addend) >> 16) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ relocation, split16a_type); ++ continue; ++ ++ case R_PPC_VLE_HI16D: ++ relocation = ((relocation + addend) >> 16) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ relocation, split16d_type); ++ continue; ++ ++ case R_PPC_VLE_HA16A: ++ { ++ bfd_vma value = relocation + addend; ++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16a_type); ++ } ++ continue; ++ ++ case R_PPC_VLE_HA16D: ++ { ++ bfd_vma value = relocation + addend; ++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16d_type); ++ } ++ continue; ++ ++ /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */ ++ case R_PPC_EMB_SDA21: ++ case R_PPC_VLE_SDA21: ++ case R_PPC_EMB_RELSDA: ++ case R_PPC_VLE_SDA21_LO: ++ { ++ const char *name; ++ int reg; ++ struct elf_link_hash_entry *sda = NULL; ++ ++ if (sec == NULL || sec->output_section == NULL) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ ++ name = bfd_get_section_name (output_bfd, sec->output_section); ++ if (((CONST_STRNEQ (name, ".sdata") ++ && (name[6] == 0 || name[6] == '.')) ++ || (CONST_STRNEQ (name, ".sbss") ++ && (name[5] == 0 || name[5] == '.')))) ++ { ++ reg = 13; ++ sda = htab->sdata[0].sym; ++ } ++ else if (CONST_STRNEQ (name, ".sdata2") ++ || CONST_STRNEQ (name, ".sbss2")) ++ { ++ reg = 2; ++ sda = htab->sdata[1].sym; ++ } ++ else if (strcmp (name, ".PPC.EMB.sdata0") == 0 ++ || strcmp (name, ".PPC.EMB.sbss0") == 0) ++ { ++ reg = 0; ++ } ++ else ++ { ++ info->callbacks->einfo ++ (_("%P: %B: the target (%s) of a %s relocation is " ++ "in the wrong output section (%s)\n"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ continue; ++ } ++ ++ if (sda != NULL) ++ { ++ if (!is_static_defined (sda)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ addend -= SYM_VAL (sda); ++ } ++ ++ if (reg == 0 ++ && (r_type == R_PPC_VLE_SDA21 ++ || r_type == R_PPC_VLE_SDA21_LO)) ++ { ++ /* Use the split20 format. */ ++ bfd_vma insn, bits12to15, bits21to31; ++ bfd_vma value = (relocation + rel->r_offset) & 0xffff; ++ /* Propagate sign bit, if necessary. */ ++ insn = (value & 0x8000) ? 0x70107800 : 0x70000000; ++ bits12to15 = value & 0x700; ++ bits21to31 = value & 0x7ff; ++ insn |= bits12to15; ++ insn |= bits21to31; ++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset); ++ continue; ++ } ++ else if (r_type == R_PPC_EMB_SDA21 ++ || r_type == R_PPC_VLE_SDA21 ++ || r_type == R_PPC_VLE_SDA21_LO) ++ { ++ bfd_vma insn; /* Fill in register field. */ ++ ++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset); ++ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); ++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset); ++ } ++ } ++ break; ++ ++ case R_PPC_VLE_SDAREL_LO16A: ++ case R_PPC_VLE_SDAREL_LO16D: ++ case R_PPC_VLE_SDAREL_HI16A: ++ case R_PPC_VLE_SDAREL_HI16D: ++ case R_PPC_VLE_SDAREL_HA16A: ++ case R_PPC_VLE_SDAREL_HA16D: ++ { ++ bfd_vma value; ++ const char *name; ++ //int reg; ++ struct elf_link_hash_entry *sda = NULL; ++ ++ if (sec == NULL || sec->output_section == NULL) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ ++ name = bfd_get_section_name (output_bfd, sec->output_section); ++ if (((CONST_STRNEQ (name, ".sdata") ++ && (name[6] == 0 || name[6] == '.')) ++ || (CONST_STRNEQ (name, ".sbss") ++ && (name[5] == 0 || name[5] == '.')))) ++ { ++ //reg = 13; ++ sda = htab->sdata[0].sym; ++ } ++ else if (CONST_STRNEQ (name, ".sdata2") ++ || CONST_STRNEQ (name, ".sbss2")) ++ { ++ //reg = 2; ++ sda = htab->sdata[1].sym; ++ } ++ else ++ { ++ (*_bfd_error_handler) ++ (_("%B: the target (%s) of a %s relocation is " ++ "in the wrong output section (%s)"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ continue; ++ } ++ ++ if (sda != NULL) ++ { ++ if (!is_static_defined (sda)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ } ++ ++ value = sda->root.u.def.section->output_section->vma ++ + sda->root.u.def.section->output_offset; ++ ++ if (r_type == R_PPC_VLE_SDAREL_LO16A) ++ { ++ value = (value + addend) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16a_type); ++ } ++ else if (r_type == R_PPC_VLE_SDAREL_LO16D) ++ { ++ value = (value + addend) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16d_type); ++ } ++ else if (r_type == R_PPC_VLE_SDAREL_HI16A) ++ { ++ value = ((value + addend) >> 16) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16a_type); ++ } ++ else if (r_type == R_PPC_VLE_SDAREL_HI16D) ++ { ++ value = ((value + addend) >> 16) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16d_type); ++ } ++ else if (r_type == R_PPC_VLE_SDAREL_HA16A) ++ { ++ value += addend; ++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16a_type); ++ } ++ else if (r_type == R_PPC_VLE_SDAREL_HA16D) ++ { ++ value += addend; ++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16d_type); ++ } ++ } ++ continue; ++ ++ /* Relocate against the beginning of the section. */ ++ case R_PPC_SECTOFF: ++ case R_PPC_SECTOFF_LO: ++ case R_PPC_SECTOFF_HI: ++ case R_PPC_SECTOFF_HA: ++ if (sec == NULL || sec->output_section == NULL) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ addend -= sec->output_section->vma; ++ break; ++ ++ /* Negative relocations. */ ++ case R_PPC_EMB_NADDR32: ++ case R_PPC_EMB_NADDR16: ++ case R_PPC_EMB_NADDR16_LO: ++ case R_PPC_EMB_NADDR16_HI: ++ case R_PPC_EMB_NADDR16_HA: ++ addend -= 2 * relocation; ++ break; ++ ++ case R_PPC_COPY: ++ case R_PPC_GLOB_DAT: ++ case R_PPC_JMP_SLOT: ++ case R_PPC_RELATIVE: ++ 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 ++ (_("%P: %B: relocation %s is not yet supported for symbol %s\n"), ++ input_bfd, ++ howto->name, ++ sym_name); ++ ++ bfd_set_error (bfd_error_invalid_operation); ++ ret = FALSE; ++ continue; ++ } ++ ++ /* Do any further special processing. */ ++ switch (r_type) ++ { ++ default: ++ break; ++ ++ case R_PPC_ADDR16_HA: ++ case R_PPC_REL16_HA: ++ case R_PPC_SECTOFF_HA: ++ case R_PPC_TPREL16_HA: ++ case R_PPC_DTPREL16_HA: ++ case R_PPC_EMB_NADDR16_HA: ++ case R_PPC_EMB_RELST_HA: ++ /* It's just possible that this symbol is a weak symbol ++ that's not actually defined anywhere. In that case, ++ 'sec' would be NULL, and we should leave the symbol ++ alone (it will be set to zero elsewhere in the link). */ ++ if (sec == NULL) ++ break; ++ /* Fall thru */ ++ ++ case R_PPC_PLT16_HA: ++ case R_PPC_GOT16_HA: ++ case R_PPC_GOT_TLSGD16_HA: ++ case R_PPC_GOT_TLSLD16_HA: ++ case R_PPC_GOT_TPREL16_HA: ++ case R_PPC_GOT_DTPREL16_HA: ++ /* Add 0x10000 if sign bit in 0:15 is set. ++ Bits 0:15 are not used. */ ++ addend += 0x8000; ++ break; ++ ++ case R_PPC_ADDR16: ++ case R_PPC_ADDR16_LO: ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_SDAREL16: ++ case R_PPC_SECTOFF: ++ case R_PPC_SECTOFF_LO: ++ case R_PPC_DTPREL16: ++ case R_PPC_DTPREL16_LO: ++ case R_PPC_TPREL16: ++ case R_PPC_TPREL16_LO: ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ case R_PPC_GOT_DTPREL16: ++ case R_PPC_GOT_DTPREL16_LO: ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ { ++ /* The 32-bit ABI lacks proper relocations to deal with ++ certain 64-bit instructions. Prevent damage to bits ++ that make up part of the insn opcode. */ ++ unsigned int insn, mask, lobit; ++ ++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); ++ mask = 0; ++ if (is_insn_ds_form (insn)) ++ mask = 3; ++ else if (is_insn_dq_form (insn)) ++ mask = 15; ++ else ++ break; ++ lobit = mask & (relocation + addend); ++ if (lobit != 0) ++ { ++ addend -= lobit; ++ info->callbacks->einfo ++ (_("%P: %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); ++ ret = FALSE; ++ } ++ addend += insn & mask; ++ } ++ break; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, " ++ "offset = %ld, addend = %ld\n", ++ howto->name, ++ (int) r_type, ++ sym_name, ++ r_symndx, ++ (long) rel->r_offset, ++ (long) addend); ++#endif ++ ++ if (unresolved_reloc ++ && !((input_section->flags & SEC_DEBUGGING) != 0 ++ && h->def_dynamic) ++ && _bfd_elf_section_offset (output_bfd, info, input_section, ++ rel->r_offset) != (bfd_vma) -1) ++ { ++ info->callbacks->einfo ++ (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"), ++ input_bfd, input_section, rel->r_offset, ++ howto->name, ++ sym_name); ++ ret = FALSE; ++ } ++ ++ r = _bfd_final_link_relocate (howto, ++ input_bfd, ++ input_section, ++ contents, ++ rel->r_offset, ++ relocation, ++ addend); ++ ++#ifdef DEBUG ++ fprintf (stderr, "%p %p %p\n", (void *)rel->r_offset, (void *)relocation, (void *)addend); ++#endif ++ if (r != bfd_reloc_ok) ++ { ++ if (r == bfd_reloc_overflow) ++ { ++ if (warned) ++ continue; ++ if (h != NULL ++ && h->root.type == bfd_link_hash_undefweak ++ && howto->pc_relative) ++ { ++ /* Assume this is a call protected by other code that ++ detect the symbol is undefined. If this is the case, ++ we can safely ignore the overflow. If not, the ++ program is hosed anyway, and a little warning isn't ++ going to help. */ ++ ++ continue; ++ } ++ ++ if (! (*info->callbacks->reloc_overflow) (info, ++ (h ? &h->root : NULL), ++ sym_name, ++ howto->name, ++ rel->r_addend, ++ input_bfd, ++ input_section, ++ rel->r_offset)) ++ return FALSE; ++ } ++ else ++ { ++ info->callbacks->einfo ++ (_("%P: %H: %s reloc against `%s': error %d\n"), ++ input_bfd, input_section, rel->r_offset, ++ howto->name, sym_name, (int) r); ++ ret = FALSE; ++ } ++ } ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ return ret; ++} ++ ++/* 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; ++ 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) ++ { ++ if (!doneone) ++ { ++ Elf_Internal_Rela rela; ++ bfd_byte *loc; ++ bfd_vma reloc_index; ++ ++ if (htab->plt_type == PLT_NEW ++ || !htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ reloc_index = ent->plt.offset / 4; ++ else ++ { ++ reloc_index = ((ent->plt.offset - htab->plt_initial_entry_size) ++ / htab->plt_slot_size); ++ if (reloc_index > PLT_NUM_SINGLE_ENTRIES ++ && htab->plt_type == PLT_OLD) ++ reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; ++ } ++ ++ /* This symbol has an entry in the procedure linkage table. ++ Set it up. */ ++ if (htab->plt_type == PLT_VXWORKS ++ && htab->elf.dynamic_sections_created ++ && h->dynindx != -1) ++ { ++ bfd_vma got_offset; ++ const bfd_vma *plt_entry; ++ ++ /* The first three entries in .got.plt are reserved. */ ++ got_offset = (reloc_index + 3) * 4; ++ ++ /* Use the right PLT. */ ++ plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry ++ : ppc_elf_vxworks_plt_entry; ++ ++ /* Fill in the .plt on VxWorks. */ ++ if (info->shared) ++ { ++ bfd_put_32 (output_bfd, ++ plt_entry[0] | PPC_HA (got_offset), ++ htab->plt->contents + ent->plt.offset + 0); ++ bfd_put_32 (output_bfd, ++ plt_entry[1] | PPC_LO (got_offset), ++ htab->plt->contents + ent->plt.offset + 4); ++ } ++ else ++ { ++ bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot); ++ ++ bfd_put_32 (output_bfd, ++ plt_entry[0] | PPC_HA (got_loc), ++ htab->plt->contents + ent->plt.offset + 0); ++ bfd_put_32 (output_bfd, ++ plt_entry[1] | PPC_LO (got_loc), ++ htab->plt->contents + ent->plt.offset + 4); ++ } ++ ++ bfd_put_32 (output_bfd, plt_entry[2], ++ htab->plt->contents + ent->plt.offset + 8); ++ bfd_put_32 (output_bfd, plt_entry[3], ++ htab->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 ++ start of the .rela.plt section. The value is stored in 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, ++ plt_entry[4] | reloc_index, ++ htab->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, ++ (plt_entry[5] ++ | (-(ent->plt.offset + 20) & 0x03fffffc)), ++ htab->plt->contents + ent->plt.offset + 20); ++ bfd_put_32 (output_bfd, plt_entry[6], ++ htab->plt->contents + ent->plt.offset + 24); ++ bfd_put_32 (output_bfd, plt_entry[7], ++ htab->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->plt->output_section->vma ++ + htab->plt->output_offset ++ + ent->plt.offset + 16), ++ htab->sgotplt->contents + got_offset); ++ ++ if (!info->shared) ++ { ++ /* Fill in a couple of entries in .rela.plt.unloaded. */ ++ loc = htab->srelplt2->contents ++ + ((VXWORKS_PLTRESOLVE_RELOCS + reloc_index ++ * VXWORKS_PLT_NON_JMP_SLOT_RELOCS) ++ * sizeof (Elf32_External_Rela)); ++ ++ /* Provide the @ha relocation for the first instruction. */ ++ rela.r_offset = (htab->plt->output_section->vma ++ + htab->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); ++ loc += sizeof (Elf32_External_Rela); ++ ++ /* Provide the @l relocation for the second instruction. */ ++ rela.r_offset = (htab->plt->output_section->vma ++ + htab->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); ++ loc += sizeof (Elf32_External_Rela); ++ ++ /* Provide a relocation for the GOT entry corresponding to this ++ PLT slot. Point it at the middle of the .plt entry. */ ++ rela.r_offset = (htab->sgotplt->output_section->vma ++ + htab->sgotplt->output_offset ++ + got_offset); ++ 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); ++ } ++ ++ /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT. ++ In particular, the offset for the relocation is not the ++ address of the PLT entry for this function, as specified ++ by the ABI. Instead, the offset is set to the address of ++ the GOT slot for this function. See EABI 4.4.4.1. */ ++ rela.r_offset = (htab->sgotplt->output_section->vma ++ + htab->sgotplt->output_offset ++ + got_offset); ++ ++ } ++ else ++ { ++ asection *splt = htab->plt; ++ if (!htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ splt = htab->iplt; ++ ++ rela.r_offset = (splt->output_section->vma ++ + splt->output_offset ++ + ent->plt.offset); ++#ifdef DEBUG ++ fprintf (stderr, " r_offset = %p ", (void *)rela.r_offset); ++#endif ++ 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. */ ++#ifdef DEBUG ++ fprintf (stderr, " not filling in .plt "); ++#endif ++ } ++ 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); ++ } ++ } ++ ++ /* 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); ++ } ++ else ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); ++ ++ if (!htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ loc = (htab->reliplt->contents ++ + (htab->reliplt->reloc_count++ ++ * sizeof (Elf32_External_Rela))); ++ else ++ loc = (htab->relplt->contents ++ + reloc_index * sizeof (Elf32_External_Rela)); ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ ++#ifdef DEBUG ++ fprintf (stderr, " r_offset = %p r_addednd = %p, r_info = 0x%08x, h->def_regular = %d", (void *)rela.r_offset, (void *)rela.r_addend, (unsigned int)rela.r_info, (int)h->def_regular); ++#endif ++ 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) ++ { ++ /* THF: This is peculiar. The compiler generates a R_PPC_REL24 for externally referenced ++ * symbols impoted from libc.so. Relocation in elf.library requires the symbol to have it's .plt ++ * stub value, but the linker specifically clears the value to 0, resulting in run-time ++ * errors when the binary tries to call libc functions. ++ */ ++ // 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 if (h->type == STT_GNU_IFUNC ++ && !info->shared) ++ { ++ /* 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); ++ } ++ doneone = TRUE; ++ } ++ ++ if (htab->plt_type == PLT_NEW ++ || !htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ { ++ unsigned char *p; ++ asection *splt = htab->plt; ++ if (!htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ splt = htab->iplt; ++ ++ p = (unsigned char *) htab->glink->contents + ent->glink_offset; ++ ++ if (h == htab->tls_get_addr && !htab->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; ++ } ++ ++ write_glink_stub (ent, splt, p, info); ++ ++ if (!info->shared) ++ /* We only need one non-PIC glink stub. */ ++ break; ++ } ++ else ++ break; ++ } ++ ++ if (h->needs_copy) ++ { ++ asection *s; ++ Elf_Internal_Rela rela; ++ bfd_byte *loc; ++ ++ /* This symbols needs a copy reloc. Set it up. */ ++ ++#ifdef DEBUG ++ fprintf (stderr, ", copy"); ++#endif ++ ++ BFD_ASSERT (h->dynindx != -1); ++ ++ if (ppc_elf_hash_entry (h)->has_sda_refs) ++ s = htab->relsbss; ++ else ++ s = htab->relbss; ++ BFD_ASSERT (s != NULL); ++ ++ rela.r_offset = SYM_VAL (h); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY); ++ rela.r_addend = 0; ++ loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, " SYM_VAL(%p) ", (void *)SYM_VAL(h)); ++#endif ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ return TRUE; ++} ++ ++static enum elf_reloc_type_class ++ppc_elf_reloc_type_class (const Elf_Internal_Rela *rela) ++{ ++ switch (ELF32_R_TYPE (rela->r_info)) ++ { ++ case R_PPC_RELATIVE: ++ return reloc_class_relative; ++ case R_PPC_REL24: ++ case R_PPC_ADDR24: ++ case R_PPC_JMP_SLOT: ++ return reloc_class_plt; ++ case R_PPC_COPY: ++ return reloc_class_copy; ++ default: ++ return reloc_class_normal; ++ } ++} ++ ++/* Finish up the dynamic sections. */ ++ ++static bfd_boolean ++ppc_elf_finish_dynamic_sections (bfd *output_bfd, ++ struct bfd_link_info *info) ++{ ++ asection *sdyn; ++ asection *splt; ++ struct ppc_elf_link_hash_table *htab; ++ bfd_vma got; ++ bfd *dynobj; ++ bfd_boolean ret = TRUE; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); ++#endif ++ ++ htab = ppc_elf_hash_table (info); ++ dynobj = elf_hash_table (info)->dynobj; ++ sdyn = bfd_get_linker_section (dynobj, ".dynamic"); ++ if (htab->is_vxworks) ++ splt = bfd_get_linker_section (dynobj, ".plt"); ++ else ++ splt = NULL; ++ ++ got = 0; ++ if (htab->elf.hgot != NULL) ++ got = SYM_VAL (htab->elf.hgot); ++ ++ if (htab->elf.dynamic_sections_created) ++ { ++ Elf32_External_Dyn *dyncon, *dynconend; ++ ++ BFD_ASSERT (htab->plt != NULL && sdyn != NULL); ++ ++ dyncon = (Elf32_External_Dyn *) sdyn->contents; ++ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); ++ for (; dyncon < dynconend; dyncon++) ++ { ++ Elf_Internal_Dyn dyn; ++ asection *s; ++ ++ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); ++ ++ switch (dyn.d_tag) ++ { ++ case DT_PLTGOT: ++ if (htab->is_vxworks) ++ s = htab->sgotplt; ++ else ++ s = htab->plt; ++ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; ++ break; ++ ++ case DT_PLTRELSZ: ++ dyn.d_un.d_val = htab->relplt->size; ++ break; ++ ++ case DT_JMPREL: ++ s = htab->relplt; ++ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; ++ break; ++ ++ case DT_PPC_GOT: ++ dyn.d_un.d_ptr = got; ++ break; ++ ++ case DT_RELASZ: ++ if (htab->is_vxworks) ++ { ++ if (htab->relplt) ++ dyn.d_un.d_ptr -= htab->relplt->size; ++ break; ++ } ++ continue; ++ ++ default: ++ if (htab->is_vxworks ++ && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) ++ break; ++ continue; ++ } ++ ++ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); ++ } ++ } ++ ++ if (htab->got != NULL) ++ { ++ if (htab->elf.hgot->root.u.def.section == htab->got ++ || htab->elf.hgot->root.u.def.section == htab->sgotplt) ++ { ++ unsigned char *p = htab->elf.hgot->root.u.def.section->contents; ++ ++ p += htab->elf.hgot->root.u.def.value; ++ if (htab->plt_type == PLT_OLD) ++ { ++ /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 ++ so that a function can easily find the address of ++ _GLOBAL_OFFSET_TABLE_. */ ++ BFD_ASSERT (htab->elf.hgot->root.u.def.value - 4 ++ < htab->elf.hgot->root.u.def.section->size); ++ bfd_put_32 (output_bfd, 0x4e800021, p - 4); ++ } ++ ++ if (sdyn != NULL) ++ { ++ bfd_vma val = sdyn->output_section->vma + sdyn->output_offset; ++ BFD_ASSERT (htab->elf.hgot->root.u.def.value ++ < htab->elf.hgot->root.u.def.section->size); ++ bfd_put_32 (output_bfd, val, p); ++ } ++ } ++ else ++ { ++ info->callbacks->einfo (_("%P: %s not defined in linker created %s\n"), ++ htab->elf.hgot->root.root.string, ++ (htab->sgotplt != NULL ++ ? htab->sgotplt->name : htab->got->name)); ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ } ++ ++ elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4; ++ } ++ ++ /* Fill in the first entry in the VxWorks procedure linkage table. */ ++ if (splt && splt->size > 0) ++ { ++ /* Use the right PLT. */ ++ const bfd_vma *plt_entry = (info->shared ++ ? ppc_elf_vxworks_pic_plt0_entry ++ : ppc_elf_vxworks_plt0_entry); ++ ++ if (!info->shared) ++ { ++ bfd_vma got_value = SYM_VAL (htab->elf.hgot); ++ ++ bfd_put_32 (output_bfd, plt_entry[0] | PPC_HA (got_value), ++ splt->contents + 0); ++ bfd_put_32 (output_bfd, plt_entry[1] | PPC_LO (got_value), ++ splt->contents + 4); ++ } ++ else ++ { ++ bfd_put_32 (output_bfd, plt_entry[0], splt->contents + 0); ++ bfd_put_32 (output_bfd, plt_entry[1], splt->contents + 4); ++ } ++ bfd_put_32 (output_bfd, plt_entry[2], splt->contents + 8); ++ bfd_put_32 (output_bfd, plt_entry[3], splt->contents + 12); ++ bfd_put_32 (output_bfd, plt_entry[4], splt->contents + 16); ++ bfd_put_32 (output_bfd, plt_entry[5], splt->contents + 20); ++ bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24); ++ bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28); ++ ++ if (! info->shared) ++ { ++ Elf_Internal_Rela rela; ++ bfd_byte *loc; ++ ++ loc = htab->srelplt2->contents; ++ ++ /* Output the @ha relocation for the first instruction. */ ++ rela.r_offset = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + 2); ++ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); ++ rela.r_addend = 0; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ loc += sizeof (Elf32_External_Rela); ++ ++ /* Output the @l relocation for the second instruction. */ ++ rela.r_offset = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + 6); ++ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); ++ rela.r_addend = 0; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ loc += sizeof (Elf32_External_Rela); ++ ++ /* Fix up the remaining relocations. They may have the wrong ++ symbol index for _G_O_T_ or _P_L_T_ depending on the order ++ in which symbols were output. */ ++ while (loc < htab->srelplt2->contents + htab->srelplt2->size) ++ { ++ Elf_Internal_Rela rel; ++ ++ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); ++ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); ++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); ++ loc += sizeof (Elf32_External_Rela); ++ ++ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); ++ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); ++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); ++ loc += sizeof (Elf32_External_Rela); ++ ++ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); ++ rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_PPC_ADDR32); ++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); ++ loc += sizeof (Elf32_External_Rela); ++ } ++ } ++ } ++ ++ if (htab->glink != NULL ++ && htab->glink->contents != NULL ++ && htab->elf.dynamic_sections_created) ++ { ++ unsigned char *p; ++ unsigned char *endp; ++ bfd_vma res0; ++ unsigned int i; ++ ++ /* ++ * PIC glink code is the following: ++ * ++ * # ith PLT code stub. ++ * addis 11,30,(plt+(i-1)*4-got)@ha ++ * lwz 11,(plt+(i-1)*4-got)@l(11) ++ * mtctr 11 ++ * bctr ++ * ++ * # A table of branches, one for each plt entry. ++ * # The idea is that the plt call stub loads ctr and r11 with these ++ * # addresses, so (r11 - res_0) gives the plt index * 4. ++ * res_0: b PLTresolve ++ * res_1: b PLTresolve ++ * . ++ * # Some number of entries towards the end can be nops ++ * res_n_m3: nop ++ * res_n_m2: nop ++ * res_n_m1: ++ * ++ * PLTresolve: ++ * addis 11,11,(1f-res_0)@ha ++ * mflr 0 ++ * bcl 20,31,1f ++ * 1: addi 11,11,(1b-res_0)@l ++ * mflr 12 ++ * mtlr 0 ++ * 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 ++ * mtctr 0 ++ * add 0,11,11 ++ * 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. ++ * lis 11,(plt+(i-1)*4)@ha ++ * lwz 11,(plt+(i-1)*4)@l(11) ++ * mtctr 11 ++ * bctr ++ * ++ * The branch table is the same, then comes ++ * ++ * 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 ++ * 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. ++ * 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. */ ++ p = htab->glink->contents; ++ p += htab->glink_pltresolve; ++ endp = htab->glink->contents; ++ endp += htab->glink->size - GLINK_PLTRESOLVE; ++ while (p < endp - 8 * 4) ++ { ++ bfd_put_32 (output_bfd, B + endp - p, p); ++ p += 4; ++ } ++ while (p < endp) ++ { ++ bfd_put_32 (output_bfd, NOP, p); ++ p += 4; ++ } ++ ++ res0 = (htab->glink_pltresolve ++ + htab->glink->output_section->vma ++ + htab->glink->output_offset); ++ ++ /* Last comes the PLTresolve stub. */ ++ if (info->shared) ++ { ++ bfd_vma bcl; ++ ++ for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++) ++ { ++ bfd_put_32 (output_bfd, pic_plt_resolve[i], 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); ++ 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); ++ } ++ 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); ++ } ++ } ++ else ++ { ++ for (i = 0; i < ARRAY_SIZE (plt_resolve); i++) ++ { ++ bfd_put_32 (output_bfd, plt_resolve[i], 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); ++ 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); ++ } ++ 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); ++ } ++ } ++ } ++ ++ if (htab->glink_eh_frame != NULL ++ && htab->glink_eh_frame->contents != NULL) ++ { ++ unsigned char *p = htab->glink_eh_frame->contents; ++ bfd_vma val; ++ ++ p += sizeof (glink_eh_frame_cie); ++ /* FDE length. */ ++ p += 4; ++ /* CIE pointer. */ ++ p += 4; ++ /* Offset to .glink. */ ++ val = (htab->glink->output_section->vma ++ + htab->glink->output_offset); ++ val -= (htab->glink_eh_frame->output_section->vma ++ + htab->glink_eh_frame->output_offset); ++ val -= p - htab->glink_eh_frame->contents; ++ bfd_put_32 (htab->elf.dynobj, val, p); ++ ++ if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME ++ && !_bfd_elf_write_section_eh_frame (output_bfd, info, ++ htab->glink_eh_frame, ++ htab->glink_eh_frame->contents)) ++ return FALSE; ++ } ++ ++ return ret; ++} ++ ++#define TARGET_BIG_SYM bfd_elf32_amigaos_vec ++#define TARGET_BIG_NAME "elf32-amigaos" ++#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 ++#else ++#define ELF_MAXPAGESIZE 0x10000 ++#endif ++#define ELF_MINPAGESIZE 0x1000 ++#define ELF_COMMONPAGESIZE 0x1000 ++#define elf_info_to_howto ppc_elf_info_to_howto ++ ++#ifdef EM_CYGNUS_POWERPC ++#define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC ++#endif ++ ++#ifdef EM_PPC_OLD ++#define ELF_MACHINE_ALT2 EM_PPC_OLD ++#endif ++ ++#define elf_backend_plt_not_loaded 1 ++#define elf_backend_can_gc_sections 1 ++#define elf_backend_can_refcount 1 ++#define elf_backend_rela_normal 1 ++ ++#define bfd_elf32_mkobject ppc_elf_mkobject ++#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data ++#define bfd_elf32_bfd_relax_section ppc_elf_relax_section ++#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup ++#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup ++#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags ++#define bfd_elf32_bfd_link_hash_table_create ppc_elf_link_hash_table_create ++#define bfd_elf32_get_synthetic_symtab ppc_elf_get_synthetic_symtab ++ ++#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_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_size_dynamic_sections ppc_elf_size_dynamic_sections ++#define elf_backend_hash_symbol ppc_elf_hash_symbol ++#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol ++#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_amigaos_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 ++#define elf_backend_reloc_type_class ppc_elf_reloc_type_class ++#define elf_backend_begin_write_processing ppc_elf_amigaos_begin_write_processing ++#define elf_backend_final_write_processing ppc_elf_amigaos_final_write_processing ++#define elf_backend_write_section ppc_elf_amigaos_write_section ++#define elf_backend_get_sec_type_attr ppc_elf_get_sec_type_attr ++#define elf_backend_plt_sym_val ppc_elf_plt_sym_val ++#define elf_backend_action_discarded ppc_elf_action_discarded ++#define elf_backend_init_index_section _bfd_elf_init_1_index_section ++#define elf_backend_post_process_headers _bfd_elf_set_osabi ++#define elf_backend_lookup_section_flags_hook ppc_elf_lookup_section_flags ++#define elf_backend_section_processing ppc_elf_amigaos_section_processing ++ ++#include "elf32-target.h" +--- /dev/null 2015-09-06 08:42:34.091999986 +0100 ++++ ld/emultempl/amigaos.em 2016-01-03 01:46:50.647001071 +0000 +@@ -0,0 +1,2513 @@ ++# This shell script emits a C file. -*- C -*- ++# It does some substitutions. ++# This file is now misnamed, because it supports both 32 bit and 64 bit ++# ELF emulations. ++test -z "${ELFSIZE}" && ELFSIZE=32 ++if [ -z "$MACHINE" ]; then ++ OUTPUT_ARCH=${ARCH} ++else ++ OUTPUT_ARCH=${ARCH}:${MACHINE} ++fi ++fragment < ++ ELF support by Ian Lance Taylor ++ ++ This file is part of the GNU Binutils. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, ++ MA 02110-1301, USA. */ ++ ++#define TARGET_IS_${EMULATION_NAME} ++ ++#include "sysdep.h" ++#include "bfd.h" ++#include "libiberty.h" ++#include "filenames.h" ++#include "safe-ctype.h" ++#include "getopt.h" ++#include "md5.h" ++#include "sha1.h" ++#include ++ ++#include "bfdlink.h" ++ ++#include "ld.h" ++#include "ldmain.h" ++#include "ldmisc.h" ++#include "ldexp.h" ++#include "ldlang.h" ++#include "ldfile.h" ++#include "ldemul.h" ++#include ++#include "elf/common.h" ++#include "elf-bfd.h" ++#include "filenames.h" ++ ++/* Declare functions used by various EXTRA_EM_FILEs. */ ++static void gld${EMULATION_NAME}_before_parse (void); ++static void gld${EMULATION_NAME}_after_open (void); ++static void gld${EMULATION_NAME}_before_allocation (void); ++static void gld${EMULATION_NAME}_after_allocation (void); ++static lang_output_section_statement_type *gld${EMULATION_NAME}_place_orphan ++ (asection *, const char *, int); ++EOF ++ ++if [ "x${USE_LIBPATH}" = xyes ] ; then ++ case ${target} in ++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) ++ fragment < ++#endif ++EOF ++ ;; ++ esac ++fi ++ ++# Import any needed special functions and/or overrides. ++# ++source_em ${srcdir}/emultempl/elf-generic.em ++if test -n "$EXTRA_EM_FILE" ; then ++ source_em ${srcdir}/emultempl/${EXTRA_EM_FILE}.em ++fi ++ ++# Functions in this file can be overridden by setting the LDEMUL_* shell ++# variables. If the name of the overriding function is the same as is ++# defined in this file, then don't output this file's version. ++# If a different overriding name is given then output the standard function ++# as presumably it is called from the overriding function. ++# ++if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then ++fragment <flags.add_DT_NEEDED_for_regular) ++ link_class = DYN_AS_NEEDED; ++ ++ /* Tell the ELF linker that we don't want the output file to have a ++ DT_NEEDED entry for any dynamic library in DT_NEEDED tags from ++ this file at all. */ ++ if (!entry->flags.add_DT_NEEDED_for_dynamic) ++ link_class |= DYN_NO_ADD_NEEDED; ++ ++ if (entry->flags.just_syms ++ && (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) != 0) ++ einfo (_("%P%F: --just-symbols may not be used on DSO: %B\n"), ++ entry->the_bfd); ++ ++ if (link_class == 0 ++ || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0) ++ return FALSE; ++ ++ bfd_elf_set_dyn_lib_class (entry->the_bfd, ++ (enum dynamic_lib_link_class) link_class); ++ ++ /* Continue on with normal load_symbols processing. */ ++ return FALSE; ++} ++EOF ++fi ++ ++fragment <the_bfd == NULL ++ || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0) ++ return; ++ ++ soname = bfd_elf_get_dt_soname (s->the_bfd); ++ if (soname == NULL) ++ soname = lbasename (bfd_get_filename (s->the_bfd)); ++ ++ for (l = global_vercheck_needed; l != NULL; l = l->next) ++ { ++ const char *suffix; ++ ++ if (filename_cmp (soname, l->name) == 0) ++ { ++ /* Probably can't happen, but it's an easy check. */ ++ continue; ++ } ++ ++ if (strchr (l->name, '/') != NULL) ++ continue; ++ ++ suffix = strstr (l->name, ".so."); ++ if (suffix == NULL) ++ continue; ++ ++ suffix += sizeof ".so." - 1; ++ ++ if (filename_ncmp (soname, l->name, suffix - l->name) == 0) ++ { ++ /* Here we know that S is a dynamic object FOO.SO.VER1, and ++ the object we are considering needs a dynamic object ++ FOO.SO.VER2, and VER1 and VER2 are different. This ++ appears to be a version mismatch, so we tell the caller ++ to try a different version of this library. */ ++ global_vercheck_failed = TRUE; ++ return; ++ } ++ } ++} ++ ++ ++/* See if an input file matches a DT_NEEDED entry by running stat on ++ the file. */ ++ ++static void ++gld${EMULATION_NAME}_stat_needed (lang_input_statement_type *s) ++{ ++ struct stat st; ++ const char *suffix; ++ const char *soname; ++ ++ if (global_found != NULL) ++ return; ++ if (s->the_bfd == NULL) ++ return; ++ ++ /* If this input file was an as-needed entry, and wasn't found to be ++ needed at the stage it was linked, then don't say we have loaded it. */ ++ if ((bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0) ++ return; ++ ++ if (bfd_stat (s->the_bfd, &st) != 0) ++ { ++ einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd); ++ return; ++ } ++ ++ /* Some operating systems, e.g. Windows, do not provide a meaningful ++ st_ino; they always set it to zero. (Windows does provide a ++ meaningful st_dev.) Do not indicate a duplicate library in that ++ case. While there is no guarantee that a system that provides ++ meaningful inode numbers will never set st_ino to zero, this is ++ merely an optimization, so we do not need to worry about false ++ negatives. */ ++ if (st.st_dev == global_stat.st_dev ++ && st.st_ino == global_stat.st_ino ++ && st.st_ino != 0) ++ { ++ global_found = s; ++ return; ++ } ++ ++ /* We issue a warning if it looks like we are including two ++ different versions of the same shared library. For example, ++ there may be a problem if -lc picks up libc.so.6 but some other ++ shared library has a DT_NEEDED entry of libc.so.5. This is a ++ heuristic test, and it will only work if the name looks like ++ NAME.so.VERSION. FIXME: Depending on file names is error-prone. ++ If we really want to issue warnings about mixing version numbers ++ of shared libraries, we need to find a better way. */ ++ ++ if (strchr (global_needed->name, '/') != NULL) ++ return; ++ suffix = strstr (global_needed->name, ".so."); ++ if (suffix == NULL) ++ return; ++ suffix += sizeof ".so." - 1; ++ ++ soname = bfd_elf_get_dt_soname (s->the_bfd); ++ if (soname == NULL) ++ soname = lbasename (s->filename); ++ ++ if (filename_ncmp (soname, global_needed->name, suffix - global_needed->name) == 0) ++ einfo ("%P: warning: %s, needed by %B, may conflict with %s\n", ++ global_needed->name, global_needed->by, soname); ++} ++ ++struct dt_needed ++{ ++ bfd *by; ++ const char *name; ++}; ++ ++/* This function is called for each possible name for a dynamic object ++ named by a DT_NEEDED entry. The FORCE parameter indicates whether ++ to skip the check for a conflicting version. */ ++ ++static bfd_boolean ++gld${EMULATION_NAME}_try_needed (struct dt_needed *needed, ++ int force) ++{ ++ bfd *abfd; ++ const char *name = needed->name; ++ const char *soname; ++ int link_class; ++ ++ abfd = bfd_openr (name, bfd_get_target (link_info.output_bfd)); ++ if (abfd == NULL) ++ return FALSE; ++ ++ /* Linker needs to decompress sections. */ ++ abfd->flags |= BFD_DECOMPRESS; ++ ++ if (! bfd_check_format (abfd, bfd_object)) ++ { ++ bfd_close (abfd); ++ return FALSE; ++ } ++ if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0) ++ { ++ bfd_close (abfd); ++ return FALSE; ++ } ++ ++ /* For DT_NEEDED, they have to match. */ ++ if (abfd->xvec != link_info.output_bfd->xvec) ++ { ++ bfd_close (abfd); ++ return FALSE; ++ } ++ ++ /* Check whether this object would include any conflicting library ++ versions. If FORCE is set, then we skip this check; we use this ++ the second time around, if we couldn't find any compatible ++ instance of the shared library. */ ++ ++ if (! force) ++ { ++ struct bfd_link_needed_list *needs; ++ ++ if (! bfd_elf_get_bfd_needed_list (abfd, &needs)) ++ einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd); ++ ++ if (needs != NULL) ++ { ++ global_vercheck_needed = needs; ++ global_vercheck_failed = FALSE; ++ lang_for_each_input_file (gld${EMULATION_NAME}_vercheck); ++ if (global_vercheck_failed) ++ { ++ bfd_close (abfd); ++ /* Return FALSE to force the caller to move on to try ++ another file on the search path. */ ++ return FALSE; ++ } ++ ++ /* But wait! It gets much worse. On Linux, if a shared ++ library does not use libc at all, we are supposed to skip ++ it the first time around in case we encounter a shared ++ library later on with the same name which does use the ++ version of libc that we want. This is much too horrible ++ to use on any system other than Linux. */ ++ ++EOF ++case ${target} in ++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) ++ fragment <next) ++ if (CONST_STRNEQ (l->name, "libc.so")) ++ break; ++ if (l == NULL) ++ { ++ bfd_close (abfd); ++ return FALSE; ++ } ++ } ++ ++EOF ++ ;; ++esac ++fragment <filename); ++ ++ if (verbose) ++ info_msg (_("found %s at %s\n"), soname, name); ++ ++ global_found = NULL; ++ lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed); ++ if (global_found != NULL) ++ { ++ /* Return TRUE to indicate that we found the file, even though ++ we aren't going to do anything with it. */ ++ return TRUE; ++ } ++ ++ /* Specify the soname to use. */ ++ bfd_elf_set_dt_needed_name (abfd, soname); ++ ++ /* Tell the ELF linker that we don't want the output file to have a ++ DT_NEEDED entry for this file, unless it is used to resolve ++ references in a regular object. */ ++ link_class = DYN_DT_NEEDED; ++ ++ /* Tell the ELF linker that we don't want the output file to have a ++ DT_NEEDED entry for this file at all if the entry is from a file ++ with DYN_NO_ADD_NEEDED. */ ++ if (needed->by != NULL ++ && (bfd_elf_get_dyn_lib_class (needed->by) & DYN_NO_ADD_NEEDED) != 0) ++ link_class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED; ++ ++ bfd_elf_set_dyn_lib_class (abfd, (enum dynamic_lib_link_class) link_class); ++ ++ /* Add this file into the symbol table. */ ++ if (! bfd_link_add_symbols (abfd, &link_info)) ++ einfo ("%F%B: could not read symbols: %E\n", abfd); ++ ++ return TRUE; ++} ++ ++ ++/* Search for a needed file in a path. */ ++ ++static bfd_boolean ++gld${EMULATION_NAME}_search_needed (const char *path, ++ struct dt_needed *n, int force) ++{ ++ const char *s; ++ const char *name = n->name; ++ size_t len; ++ struct dt_needed needed; ++ ++ if (name[0] == '/') ++ return gld${EMULATION_NAME}_try_needed (n, force); ++ ++ if (path == NULL || *path == '\0') ++ return FALSE; ++ ++ needed.by = n->by; ++ needed.name = n->name; ++ ++ len = strlen (name); ++ while (1) ++ { ++ char *filename, *sset; ++ ++ s = strchr (path, config.rpath_separator); ++ if (s == NULL) ++ s = path + strlen (path); ++ ++#if HAVE_DOS_BASED_FILE_SYSTEM ++ /* Assume a match on the second char is part of drive specifier. */ ++ else if (config.rpath_separator == ':' ++ && s == path + 1 ++ && ISALPHA (*path)) ++ { ++ s = strchr (s + 1, config.rpath_separator); ++ if (s == NULL) ++ s = path + strlen (path); ++ } ++#endif ++ filename = (char *) xmalloc (s - path + len + 2); ++ if (s == path) ++ sset = filename; ++ else ++ { ++ memcpy (filename, path, s - path); ++ filename[s - path] = '/'; ++ sset = filename + (s - path) + 1; ++ } ++ strcpy (sset, name); ++ ++ needed.name = filename; ++ if (gld${EMULATION_NAME}_try_needed (&needed, force)) ++ return TRUE; ++ ++ free (filename); ++ ++ if (*s == '\0') ++ break; ++ path = s + 1; ++ } ++ ++ return FALSE; ++} ++ ++EOF ++if [ "x${USE_LIBPATH}" = xyes ] ; then ++ fragment < ++#else ++#include "elf-hints-local.h" ++#endif ++ ++static bfd_boolean ++gld${EMULATION_NAME}_check_ld_elf_hints (const struct bfd_link_needed_list *l, ++ int force) ++{ ++ static bfd_boolean initialized; ++ static char *ld_elf_hints; ++ struct dt_needed needed; ++ ++ if (!initialized) ++ { ++ FILE *f; ++ char *tmppath; ++ ++ tmppath = concat (ld_sysroot, _PATH_ELF_HINTS, (const char *) NULL); ++ f = fopen (tmppath, FOPEN_RB); ++ free (tmppath); ++ if (f != NULL) ++ { ++ struct elfhints_hdr hdr; ++ ++ if (fread (&hdr, 1, sizeof (hdr), f) == sizeof (hdr) ++ && hdr.magic == ELFHINTS_MAGIC ++ && hdr.version == 1) ++ { ++ if (fseek (f, hdr.strtab + hdr.dirlist, SEEK_SET) != -1) ++ { ++ char *b; ++ ++ b = xmalloc (hdr.dirlistlen + 1); ++ if (fread (b, 1, hdr.dirlistlen + 1, f) == ++ hdr.dirlistlen + 1) ++ ld_elf_hints = gld${EMULATION_NAME}_add_sysroot (b); ++ ++ free (b); ++ } ++ } ++ fclose (f); ++ } ++ ++ initialized = TRUE; ++ } ++ ++ if (ld_elf_hints == NULL) ++ return FALSE; ++ ++ needed.by = l->by; ++ needed.name = l->name; ++ return gld${EMULATION_NAME}_search_needed (ld_elf_hints, &needed, force); ++} ++EOF ++ # FreeBSD ++ ;; ++ ++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) ++ fragment <path == NULL) ++ { ++ info->alloc = p - dir + 1 + 256; ++ info->path = xmalloc (info->alloc); ++ info->len = 0; ++ } ++ else ++ { ++ if (info->len + 1 + (p - dir) >= info->alloc) ++ { ++ info->alloc += p - dir + 256; ++ info->path = xrealloc (info->path, info->alloc); ++ } ++ info->path[info->len++] = config.rpath_separator; ++ } ++ memcpy (info->path + info->len, dir, p - dir); ++ info->len += p - dir; ++ info->path[info->len] = '\0'; ++ } ++ } ++ while (! feof (f)); ++ free (line); ++ fclose (f); ++ return TRUE; ++} ++ ++static bfd_boolean ++gld${EMULATION_NAME}_check_ld_so_conf (const struct bfd_link_needed_list *l, ++ int force) ++{ ++ static bfd_boolean initialized; ++ static char *ld_so_conf; ++ struct dt_needed needed; ++ ++ if (! initialized) ++ { ++ char *tmppath; ++ struct gld${EMULATION_NAME}_ld_so_conf info; ++ ++ info.path = NULL; ++ info.len = info.alloc = 0; ++ tmppath = concat (ld_sysroot, "${prefix}/etc/ld.so.conf", ++ (const char *) NULL); ++ if (!gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath)) ++ { ++ free (tmppath); ++ tmppath = concat (ld_sysroot, "/etc/ld.so.conf", ++ (const char *) NULL); ++ gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath); ++ } ++ free (tmppath); ++ ++ if (info.path) ++ { ++ char *d = gld${EMULATION_NAME}_add_sysroot (info.path); ++ free (info.path); ++ ld_so_conf = d; ++ } ++ initialized = TRUE; ++ } ++ ++ if (ld_so_conf == NULL) ++ return FALSE; ++ ++ ++ needed.by = l->by; ++ needed.name = l->name; ++ return gld${EMULATION_NAME}_search_needed (ld_so_conf, &needed, force); ++} ++ ++EOF ++ # Linux ++ ;; ++ esac ++fi ++fragment <the_bfd) ++ & DYN_AS_NEEDED) == 0) ++ return; ++ ++ if (s->filename == NULL || s->the_bfd == NULL) ++ return; ++ ++ /* Don't look for a second non-loaded as-needed lib. */ ++ if (global_found != NULL ++ && (bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0) ++ return; ++ ++ if (filename_cmp (s->filename, global_needed->name) == 0) ++ { ++ global_found = s; ++ return; ++ } ++ ++ if (s->flags.search_dirs) ++ { ++ const char *f = strrchr (s->filename, '/'); ++ if (f != NULL ++ && filename_cmp (f + 1, global_needed->name) == 0) ++ { ++ global_found = s; ++ return; ++ } ++ } ++ ++ soname = bfd_elf_get_dt_soname (s->the_bfd); ++ if (soname != NULL ++ && filename_cmp (soname, global_needed->name) == 0) ++ { ++ global_found = s; ++ return; ++ } ++} ++ ++EOF ++ ++if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then ++fragment <emit_note_gnu_build_id; ++ bfd_size_type size; ++ ++ abfd = abfd; ++ ++ size = offsetof (Elf_External_Note, name[sizeof "GNU"]); ++ size = (size + 3) & -(bfd_size_type) 4; ++ ++ if (!strcmp (style, "md5") || !strcmp (style, "uuid")) ++ size += 128 / 8; ++ else if (!strcmp (style, "sha1")) ++ size += 160 / 8; ++ else if (!strncmp (style, "0x", 2)) ++ { ++ /* ID is in string form (hex). Convert to bits. */ ++ const char *id = style + 2; ++ do ++ { ++ if (ISXDIGIT (id[0]) && ISXDIGIT (id[1])) ++ { ++ ++size; ++ id += 2; ++ } ++ else if (*id == '-' || *id == ':') ++ ++id; ++ else ++ { ++ size = 0; ++ break; ++ } ++ } while (*id != '\0'); ++ } ++ else ++ size = 0; ++ ++ return size; ++} ++ ++static unsigned char ++read_hex (const char xdigit) ++{ ++ if (ISDIGIT (xdigit)) ++ return xdigit - '0'; ++ if (ISUPPER (xdigit)) ++ return xdigit - 'A' + 0xa; ++ if (ISLOWER (xdigit)) ++ return xdigit - 'a' + 0xa; ++ abort (); ++ return 0; ++} ++ ++struct build_id_info ++{ ++ const char *style; ++ asection *sec; ++}; ++ ++static bfd_boolean ++gld${EMULATION_NAME}_write_build_id_section (bfd *abfd) ++{ ++ const struct elf_backend_data *bed = get_elf_backend_data (abfd); ++ struct build_id_info *info = (struct build_id_info *) ++ elf_tdata (abfd)->after_write_object_contents_info; ++ asection *asec; ++ Elf_Internal_Shdr *i_shdr; ++ unsigned char *contents, *id_bits; ++ bfd_size_type size; ++ Elf_External_Note *e_note; ++ ++ asec = info->sec; ++ if (bfd_is_abs_section (asec->output_section)) ++ { ++ einfo (_("%P: warning: .note.gnu.build-id section discarded," ++ " --build-id ignored.\n")); ++ return TRUE; ++ } ++ i_shdr = &elf_section_data (asec->output_section)->this_hdr; ++ ++ if (i_shdr->contents == NULL) ++ { ++ if (asec->contents == NULL) ++ asec->contents = (unsigned char *) xmalloc (asec->size); ++ contents = asec->contents; ++ } ++ else ++ contents = i_shdr->contents + asec->output_offset; ++ ++ e_note = (Elf_External_Note *) contents; ++ size = offsetof (Elf_External_Note, name[sizeof "GNU"]); ++ size = (size + 3) & -(bfd_size_type) 4; ++ id_bits = contents + size; ++ size = asec->size - size; ++ ++ bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz); ++ bfd_h_put_32 (abfd, size, &e_note->descsz); ++ bfd_h_put_32 (abfd, NT_GNU_BUILD_ID, &e_note->type); ++ memcpy (e_note->name, "GNU", sizeof "GNU"); ++ ++ if (!strcmp (info->style, "md5")) ++ { ++ struct md5_ctx ctx; ++ md5_init_ctx (&ctx); ++ if (bed->s->checksum_contents (abfd, ++ (void (*) (const void *, size_t, void *)) ++ &md5_process_bytes, ++ &ctx)) ++ md5_finish_ctx (&ctx, id_bits); ++ else ++ return FALSE; ++ } ++ else if (!strcmp (info->style, "sha1")) ++ { ++ struct sha1_ctx ctx; ++ sha1_init_ctx (&ctx); ++ if (bed->s->checksum_contents (abfd, ++ (void (*) (const void *, size_t, void *)) ++ &sha1_process_bytes, ++ &ctx)) ++ sha1_finish_ctx (&ctx, id_bits); ++ else ++ return FALSE; ++ } ++ else if (!strcmp (info->style, "uuid")) ++ { ++ int n; ++ int fd = open ("/dev/urandom", O_RDONLY); ++ if (fd < 0) ++ return FALSE; ++ n = read (fd, id_bits, size); ++ close (fd); ++ if (n < (int) size) ++ return FALSE; ++ } ++ else if (!strncmp (info->style, "0x", 2)) ++ { ++ /* ID is in string form (hex). Convert to bits. */ ++ const char *id = info->style + 2; ++ size_t n = 0; ++ do ++ { ++ if (ISXDIGIT (id[0]) && ISXDIGIT (id[1])) ++ { ++ id_bits[n] = read_hex (*id++) << 4; ++ id_bits[n++] |= read_hex (*id++); ++ } ++ else if (*id == '-' || *id == ':') ++ ++id; ++ else ++ abort (); /* Should have been validated earlier. */ ++ } while (*id != '\0'); ++ } ++ else ++ abort (); /* Should have been validated earlier. */ ++ ++ size = asec->size; ++ return (bfd_seek (abfd, ++ i_shdr->sh_offset + asec->output_offset, SEEK_SET) == 0 ++ && bfd_bwrite (contents, size, abfd) == size); ++} ++ ++ ++/* This is called after all the input files have been opened. */ ++ ++static void ++gld${EMULATION_NAME}_after_open (void) ++{ ++ struct bfd_link_needed_list *needed, *l; ++ struct elf_link_hash_table *htab; ++ ++ after_open_default (); ++ ++ htab = elf_hash_table (&link_info); ++ if (!is_elf_hash_table (htab)) ++ return; ++ ++ if (link_info.emit_note_gnu_build_id) ++ { ++ bfd *abfd; ++ asection *s; ++ bfd_size_type size; ++ ++ /* Find an ELF input. */ ++ for (abfd = link_info.input_bfds; ++ abfd != (bfd *) NULL; abfd = abfd->link_next) ++ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) ++ break; ++ ++ if (abfd == NULL) ++ { ++ /* PR 10555: If there are no input files do not ++ try to create a .note.gnu-build-id section. */ ++ free (link_info.emit_note_gnu_build_id); ++ link_info.emit_note_gnu_build_id = NULL; ++ } ++ else ++ { ++ size = gld${EMULATION_NAME}_id_note_section_size (abfd, &link_info); ++ if (size == 0) ++ { ++ einfo ("%P: warning: unrecognized --build-id style ignored.\n"); ++ free (link_info.emit_note_gnu_build_id); ++ link_info.emit_note_gnu_build_id = NULL; ++ } ++ else ++ { ++ s = bfd_make_section_with_flags (abfd, ".note.gnu.build-id", ++ SEC_ALLOC | SEC_LOAD ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED ++ | SEC_READONLY | SEC_DATA); ++ if (s != NULL && bfd_set_section_alignment (abfd, s, 2)) ++ { ++ struct elf_obj_tdata *t = elf_tdata (link_info.output_bfd); ++ struct build_id_info *b = ++ (struct build_id_info *) xmalloc (sizeof *b); ++ ++ b->style = link_info.emit_note_gnu_build_id; ++ b->sec = s; ++ elf_section_type (s) = SHT_NOTE; ++ s->size = size; ++ t->after_write_object_contents ++ = &gld${EMULATION_NAME}_write_build_id_section; ++ t->after_write_object_contents_info = b; ++ } ++ else ++ { ++ einfo ("%P: warning: Cannot create .note.gnu.build-id section," ++ " --build-id ignored.\n"); ++ free (link_info.emit_note_gnu_build_id); ++ link_info.emit_note_gnu_build_id = NULL; ++ } ++ } ++ } ++ } ++ ++ if (link_info.relocatable) ++ return; ++ ++ if (link_info.eh_frame_hdr ++ && !link_info.traditional_format) ++ { ++ bfd *abfd, *elfbfd = NULL; ++ bfd_boolean warn_eh_frame = FALSE; ++ asection *s; ++ ++ for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next) ++ { ++ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) ++ elfbfd = abfd; ++ if (!warn_eh_frame) ++ { ++ s = bfd_get_section_by_name (abfd, ".eh_frame"); ++ while (s != NULL ++ && (s->size <= 8 ++ || bfd_is_abs_section (s->output_section))) ++ s = bfd_get_next_section_by_name (s); ++ warn_eh_frame = s != NULL; ++ } ++ if (elfbfd && warn_eh_frame) ++ break; ++ } ++ if (elfbfd) ++ { ++ const struct elf_backend_data *bed; ++ ++ bed = get_elf_backend_data (elfbfd); ++ s = bfd_make_section_with_flags (elfbfd, ".eh_frame_hdr", ++ bed->dynamic_sec_flags ++ | SEC_READONLY); ++ if (s != NULL ++ && bfd_set_section_alignment (elfbfd, s, 2)) ++ { ++ htab->eh_info.hdr_sec = s; ++ warn_eh_frame = FALSE; ++ } ++ } ++ if (warn_eh_frame) ++ einfo ("%P: warning: Cannot create .eh_frame_hdr section," ++ " --eh-frame-hdr ignored.\n"); ++ } ++ ++ /* Get the list of files which appear in DT_NEEDED entries in ++ dynamic objects included in the link (often there will be none). ++ For each such file, we want to track down the corresponding ++ library, and include the symbol table in the link. This is what ++ the runtime dynamic linker will do. Tracking the files down here ++ permits one dynamic object to include another without requiring ++ special action by the person doing the link. Note that the ++ needed list can actually grow while we are stepping through this ++ loop. */ ++ needed = bfd_elf_get_needed_list (link_info.output_bfd, &link_info); ++ for (l = needed; l != NULL; l = l->next) ++ { ++ struct bfd_link_needed_list *ll; ++ struct dt_needed n, nn; ++ int force; ++ ++ /* If the lib that needs this one was --as-needed and wasn't ++ found to be needed, then this lib isn't needed either. Skip ++ the lib when creating a shared object unless we are copying ++ DT_NEEDED entres. */ ++ if (l->by != NULL ++ && ((bfd_elf_get_dyn_lib_class (l->by) & DYN_AS_NEEDED) != 0 ++ || (!link_info.executable ++ && bfd_elf_get_dyn_lib_class (l->by) & DYN_NO_ADD_NEEDED) != 0)) ++ continue; ++ ++ /* If we've already seen this file, skip it. */ ++ for (ll = needed; ll != l; ll = ll->next) ++ if ((ll->by == NULL ++ || (bfd_elf_get_dyn_lib_class (ll->by) & DYN_AS_NEEDED) == 0) ++ && strcmp (ll->name, l->name) == 0) ++ break; ++ if (ll != l) ++ continue; ++ ++ /* See if this file was included in the link explicitly. */ ++ global_needed = l; ++ global_found = NULL; ++ lang_for_each_input_file (gld${EMULATION_NAME}_check_needed); ++ if (global_found != NULL ++ && (bfd_elf_get_dyn_lib_class (global_found->the_bfd) ++ & DYN_AS_NEEDED) == 0) ++ continue; ++ ++ n.by = l->by; ++ n.name = l->name; ++ nn.by = l->by; ++ if (verbose) ++ info_msg (_("%s needed by %B\n"), l->name, l->by); ++ ++ /* As-needed libs specified on the command line (or linker script) ++ take priority over libs found in search dirs. */ ++ if (global_found != NULL) ++ { ++ nn.name = global_found->filename; ++ if (gld${EMULATION_NAME}_try_needed (&nn, TRUE)) ++ continue; ++ } ++ ++ /* We need to find this file and include the symbol table. We ++ want to search for the file in the same way that the dynamic ++ linker will search. That means that we want to use ++ rpath_link, rpath, then the environment variable ++ LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH ++ entries (native only), then the linker script LIB_SEARCH_DIRS. ++ We do not search using the -L arguments. ++ ++ We search twice. The first time, we skip objects which may ++ introduce version mismatches. The second time, we force ++ their use. See gld${EMULATION_NAME}_vercheck comment. */ ++ for (force = 0; force < 2; force++) ++ { ++ size_t len; ++ search_dirs_type *search; ++EOF ++if [ "x${NATIVE}" = xyes ] ; then ++fragment <next) ++ { ++ char *tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name); ++ found = (rp->by == l->by ++ && gld${EMULATION_NAME}_search_needed (tmpname, ++ &n, ++ force)); ++ free (tmpname); ++ } ++ if (found) ++ break; ++ ++EOF ++fi ++if [ "x${USE_LIBPATH}" = xyes ] ; then ++ case ${target} in ++ *-*-freebsd* | *-*-dragonfly*) ++ fragment <name); ++ for (search = search_head; search != NULL; search = search->next) ++ { ++ char *filename; ++ ++ if (search->cmdline) ++ continue; ++ filename = (char *) xmalloc (strlen (search->name) + len + 2); ++ sprintf (filename, "%s/%s", search->name, l->name); ++ nn.name = filename; ++ if (gld${EMULATION_NAME}_try_needed (&nn, force)) ++ break; ++ free (filename); ++ } ++ if (search != NULL) ++ break; ++EOF ++fragment <name, l->by); ++ } ++} ++ ++EOF ++fi ++ ++fragment <type.node_class) ++ { ++ case etree_provide: ++ case etree_provided: ++ provide = TRUE; ++ /* Fall thru */ ++ case etree_assign: ++ /* We call record_link_assignment even if the symbol is defined. ++ This is because if it is defined by a dynamic object, we ++ actually want to use the value defined by the linker script, ++ not the value from the dynamic object (because we are setting ++ symbols like etext). If the symbol is defined by a regular ++ object, then, as it happens, calling record_link_assignment ++ will do no harm. */ ++ if (strcmp (exp->assign.dst, ".") != 0) ++ { ++ if (!bfd_elf_record_link_assignment (link_info.output_bfd, ++ &link_info, ++ exp->assign.dst, provide, ++ exp->assign.hidden)) ++ einfo ("%P%F: failed to record assignment to %s: %E\n", ++ exp->assign.dst); ++ } ++ gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src); ++ break; ++ ++ case etree_binary: ++ gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs); ++ gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs); ++ break; ++ ++ case etree_trinary: ++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond); ++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); ++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs); ++ break; ++ ++ case etree_unary: ++ gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++ ++/* This is called by the before_allocation routine via ++ lang_for_each_statement. It locates any assignment statements, and ++ tells the ELF backend about them, in case they are assignments to ++ symbols which are referred to by dynamic objects. */ ++ ++static void ++gld${EMULATION_NAME}_find_statement_assignment (lang_statement_union_type *s) ++{ ++ if (s->header.type == lang_assignment_statement_enum) ++ gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp); ++} ++ ++EOF ++ ++if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then ++ if test x"${ELF_INTERPRETER_NAME+set}" = xset; then ++ ELF_INTERPRETER_SET_DEFAULT=" ++ if (sinterp != NULL) ++ { ++ sinterp->contents = (unsigned char *) ${ELF_INTERPRETER_NAME}; ++ sinterp->size = strlen ((char *) sinterp->contents) + 1; ++ } ++ ++" ++ else ++ ELF_INTERPRETER_SET_DEFAULT= ++ fi ++fragment <type == bfd_link_elf_hash_table) ++ _bfd_elf_tls_setup (link_info.output_bfd, &link_info); ++ ++ /* If we are going to make any variable assignments, we need to let ++ the ELF backend know about them in case the variables are ++ referred to by dynamic objects. */ ++ lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment); ++ ++ /* Let the ELF backend work out the sizes of any sections required ++ by dynamic linking. */ ++ rpath = command_line.rpath; ++ if (rpath == NULL) ++ rpath = (const char *) getenv ("LD_RUN_PATH"); ++ ++ for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next) ++ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) ++ { ++ const char *audit_libs = elf_dt_audit (abfd); ++ ++ /* If the input bfd contains an audit entry, we need to add it as ++ a dep audit entry. */ ++ if (audit_libs && *audit_libs != '\0') ++ { ++ char *cp = xstrdup (audit_libs); ++ do ++ { ++ int more = 0; ++ char *cp2 = strchr (cp, config.rpath_separator); ++ ++ if (cp2) ++ { ++ *cp2 = '\0'; ++ more = 1; ++ } ++ ++ if (cp != NULL && *cp != '\0') ++ gld${EMULATION_NAME}_append_to_separated_string (&depaudit, cp); ++ ++ cp = more ? ++cp2 : NULL; ++ } ++ while (cp != NULL); ++ } ++ } ++ ++ if (! (bfd_elf_size_dynamic_sections ++ (link_info.output_bfd, command_line.soname, rpath, ++ command_line.filter_shlib, audit, depaudit, ++ (const char * const *) command_line.auxiliary_filters, ++ &link_info, &sinterp))) ++ einfo ("%P%F: failed to set dynamic section sizes: %E\n"); ++ ++${ELF_INTERPRETER_SET_DEFAULT} ++ /* Let the user override the dynamic linker we are using. */ ++ if (command_line.interpreter != NULL ++ && sinterp != NULL) ++ { ++ sinterp->contents = (bfd_byte *) command_line.interpreter; ++ sinterp->size = strlen (command_line.interpreter) + 1; ++ } ++ ++ /* Look for any sections named .gnu.warning. As a GNU extensions, ++ we treat such sections as containing warning messages. We print ++ out the warning message, and then zero out the section size so ++ that it does not get copied into the output file. */ ++ ++ { ++ LANG_FOR_EACH_INPUT_STATEMENT (is) ++ { ++ asection *s; ++ bfd_size_type sz; ++ char *msg; ++ bfd_boolean ret; ++ ++ if (is->flags.just_syms) ++ continue; ++ ++ s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning"); ++ if (s == NULL) ++ continue; ++ ++ sz = s->size; ++ msg = (char *) xmalloc ((size_t) (sz + 1)); ++ if (! bfd_get_section_contents (is->the_bfd, s, msg, ++ (file_ptr) 0, sz)) ++ einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n", ++ is->the_bfd); ++ msg[sz] = '\0'; ++ ret = link_info.callbacks->warning (&link_info, msg, ++ (const char *) NULL, ++ is->the_bfd, (asection *) NULL, ++ (bfd_vma) 0); ++ ASSERT (ret); ++ free (msg); ++ ++ /* Clobber the section size, so that we don't waste space ++ copying the warning into the output file. If we've already ++ sized the output section, adjust its size. The adjustment ++ is on rawsize because targets that size sections early will ++ have called lang_reset_memory_regions after sizing. */ ++ if (s->output_section != NULL ++ && s->output_section->rawsize >= s->size) ++ s->output_section->rawsize -= s->size; ++ ++ s->size = 0; ++ ++ /* Also set SEC_EXCLUDE, so that local symbols defined in the ++ warning section don't get copied to the output. */ ++ s->flags |= SEC_EXCLUDE | SEC_KEEP; ++ } ++ } ++ ++ before_allocation_default (); ++ ++ if (!bfd_elf_size_dynsym_hash_dynstr (link_info.output_bfd, &link_info)) ++ einfo ("%P%F: failed to set dynamic section sizes: %E\n"); ++} ++ ++EOF ++fi ++ ++if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then ++fragment <flags.maybe_archive) ++ return FALSE; ++ ++ filename = entry->filename; ++ ++ /* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION ++ is defined, but it does not seem worth the headache to optimize ++ away those two bytes of space. */ ++ string = (char *) xmalloc (strlen (search->name) ++ + strlen (filename) ++ + strlen (arch) ++#ifdef EXTRA_SHLIB_EXTENSION ++ + strlen (EXTRA_SHLIB_EXTENSION) ++#endif ++ + sizeof "/lib.so"); ++ ++ sprintf (string, "%s/lib%s%s.so", search->name, filename, arch); ++ ++#ifdef EXTRA_SHLIB_EXTENSION ++ /* Try the .so extension first. If that fails build a new filename ++ using EXTRA_SHLIB_EXTENSION. */ ++ if (! ldfile_try_open_bfd (string, entry)) ++ { ++ sprintf (string, "%s/lib%s%s%s", search->name, ++ filename, arch, EXTRA_SHLIB_EXTENSION); ++#endif ++ ++ if (! ldfile_try_open_bfd (string, entry)) ++ { ++ free (string); ++ return FALSE; ++ } ++#ifdef EXTRA_SHLIB_EXTENSION ++ } ++#endif ++ ++ entry->filename = string; ++ ++ /* We have found a dynamic object to include in the link. The ELF ++ backend linker will create a DT_NEEDED entry in the .dynamic ++ section naming this file. If this file includes a DT_SONAME ++ entry, it will be used. Otherwise, the ELF linker will just use ++ the name of the file. For an archive found by searching, like ++ this one, the DT_NEEDED entry should consist of just the name of ++ the file, without the path information used to find it. Note ++ that we only need to do this if we have a dynamic object; an ++ archive will never be referenced by a DT_NEEDED entry. ++ ++ FIXME: This approach--using bfd_elf_set_dt_needed_name--is not ++ very pretty. I haven't been able to think of anything that is ++ pretty, though. */ ++ if (bfd_check_format (entry->the_bfd, bfd_object) ++ && (entry->the_bfd->flags & DYNAMIC) != 0) ++ { ++ ASSERT (entry->flags.maybe_archive && entry->flags.search_dirs); ++ ++ /* Rather than duplicating the logic above. Just use the ++ filename we recorded earlier. */ ++ ++ filename = lbasename (entry->filename); ++ bfd_elf_set_dt_needed_name (entry->the_bfd, filename); ++ } ++ ++ return TRUE; ++} ++ ++EOF ++fi ++ ++if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then ++fragment <name[4] == 'a'; ++ ++ for (lookup = &lang_output_section_statement.head->output_section_statement; ++ lookup != NULL; ++ lookup = lookup->next) ++ { ++ if (lookup->constraint >= 0 ++ && CONST_STRNEQ (lookup->name, ".rel")) ++ { ++ int lookrela = lookup->name[4] == 'a'; ++ ++ /* .rel.dyn must come before all other reloc sections, to suit ++ GNU ld.so. */ ++ if (isdyn) ++ break; ++ ++ /* Don't place after .rel.plt as doing so results in wrong ++ dynamic tags. */ ++ if (strcmp (".plt", lookup->name + 4 + lookrela) == 0) ++ break; ++ ++ if (rela == lookrela || last_rel == NULL) ++ last_rel = lookup; ++ if ((rela == lookrela || last_rel_alloc == NULL) ++ && lookup->bfd_section != NULL ++ && (lookup->bfd_section->flags & SEC_ALLOC) != 0) ++ last_rel_alloc = lookup; ++ } ++ ++ last = lookup; ++ if (lookup->bfd_section != NULL ++ && (lookup->bfd_section->flags & SEC_ALLOC) != 0) ++ { ++ last_alloc = lookup; ++ if ((lookup->bfd_section->flags & SEC_READONLY) != 0) ++ last_ro_alloc = lookup; ++ } ++ } ++ ++ if (last_rel_alloc) ++ return last_rel_alloc; ++ ++ if (last_rel) ++ return last_rel; ++ ++ if (last_ro_alloc) ++ return last_ro_alloc; ++ ++ if (last_alloc) ++ return last_alloc; ++ ++ return last; ++} ++ ++/* Place an orphan section. We use this to put random SHF_ALLOC ++ sections in the right segment. */ ++ ++static lang_output_section_statement_type * ++gld${EMULATION_NAME}_place_orphan (asection *s, ++ const char *secname, ++ int constraint) ++{ ++ static struct orphan_save hold[] = ++ { ++ { ".text", ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, ++ 0, 0, 0, 0 }, ++ { ".rodata", ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, ++ 0, 0, 0, 0 }, ++ { ".data", ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, ++ 0, 0, 0, 0 }, ++ { ".bss", ++ SEC_ALLOC, ++ 0, 0, 0, 0 }, ++ { 0, ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, ++ 0, 0, 0, 0 }, ++ { ".interp", ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, ++ 0, 0, 0, 0 }, ++ { ".sdata", ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA, ++ 0, 0, 0, 0 }, ++ { ".comment", ++ SEC_HAS_CONTENTS, ++ 0, 0, 0, 0 }, ++ }; ++ enum orphan_save_index ++ { ++ orphan_text = 0, ++ orphan_rodata, ++ orphan_data, ++ orphan_bss, ++ orphan_rel, ++ orphan_interp, ++ orphan_sdata, ++ orphan_nonalloc ++ }; ++ static int orphan_init_done = 0; ++ struct orphan_save *place; ++ lang_output_section_statement_type *after; ++ lang_output_section_statement_type *os; ++ lang_output_section_statement_type *match_by_name = NULL; ++ int isdyn = 0; ++ int iself = s->owner->xvec->flavour == bfd_target_elf_flavour; ++ unsigned int sh_type = iself ? elf_section_type (s) : SHT_NULL; ++ ++ if (! link_info.relocatable ++ && link_info.combreloc ++ && (s->flags & SEC_ALLOC)) ++ { ++ if (iself) ++ switch (sh_type) ++ { ++ case SHT_RELA: ++ secname = ".rela.dyn"; ++ isdyn = 1; ++ break; ++ case SHT_REL: ++ secname = ".rel.dyn"; ++ isdyn = 1; ++ break; ++ default: ++ break; ++ } ++ else if (CONST_STRNEQ (secname, ".rel")) ++ { ++ secname = secname[4] == 'a' ? ".rela.dyn" : ".rel.dyn"; ++ isdyn = 1; ++ } ++ } ++ ++ /* Look through the script to see where to place this section. */ ++ if (constraint == 0) ++ for (os = lang_output_section_find (secname); ++ os != NULL; ++ os = next_matching_output_section_statement (os, 0)) ++ { ++ /* If we don't match an existing output section, tell ++ lang_insert_orphan to create a new output section. */ ++ constraint = SPECIAL; ++ ++ if (os->bfd_section != NULL ++ && (os->bfd_section->flags == 0 ++ || (_bfd_elf_match_sections_by_type (link_info.output_bfd, ++ os->bfd_section, ++ s->owner, s) ++ && ((s->flags ^ os->bfd_section->flags) ++ & (SEC_LOAD | SEC_ALLOC)) == 0))) ++ { ++ /* We already have an output section statement with this ++ name, and its bfd section has compatible flags. ++ If the section already exists but does not have any flags ++ set, then it has been created by the linker, probably as a ++ result of a --section-start command line switch. */ ++ lang_add_section (&os->children, s, NULL, os); ++ return os; ++ } ++ ++ /* Save unused output sections in case we can match them ++ against orphans later. */ ++ if (os->bfd_section == NULL) ++ match_by_name = os; ++ } ++ ++ /* If we didn't match an active output section, see if we matched an ++ unused one and use that. */ ++ if (match_by_name) ++ { ++ lang_add_section (&match_by_name->children, s, NULL, match_by_name); ++ return match_by_name; ++ } ++ ++ if (!orphan_init_done) ++ { ++ struct orphan_save *ho; ++ ++ for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho) ++ if (ho->name != NULL) ++ { ++ ho->os = lang_output_section_find (ho->name); ++ if (ho->os != NULL && ho->os->flags == 0) ++ ho->os->flags = ho->flags; ++ } ++ orphan_init_done = 1; ++ } ++ ++ /* If this is a final link, then always put .gnu.warning.SYMBOL ++ sections into the .text section to get them out of the way. */ ++ if (link_info.executable ++ && ! link_info.relocatable ++ && CONST_STRNEQ (s->name, ".gnu.warning.") ++ && hold[orphan_text].os != NULL) ++ { ++ os = hold[orphan_text].os; ++ lang_add_section (&os->children, s, NULL, os); ++ return os; ++ } ++ ++ /* Decide which segment the section should go in based on the ++ section name and section flags. We put loadable .note sections ++ right after the .interp section, so that the PT_NOTE segment is ++ stored right after the program headers where the OS can read it ++ in the first page. */ ++ ++ place = NULL; ++ if ((s->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0) ++ place = &hold[orphan_nonalloc]; ++ else if ((s->flags & SEC_ALLOC) == 0) ++ ; ++ else if ((s->flags & SEC_LOAD) != 0 ++ && ((iself && sh_type == SHT_NOTE) ++ || (!iself && CONST_STRNEQ (secname, ".note")))) ++ place = &hold[orphan_interp]; ++ else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) == 0) ++ place = &hold[orphan_bss]; ++ else if ((s->flags & SEC_SMALL_DATA) != 0) ++ place = &hold[orphan_sdata]; ++ else if ((s->flags & SEC_READONLY) == 0) ++ place = &hold[orphan_data]; ++ else if (((iself && (sh_type == SHT_RELA || sh_type == SHT_REL)) ++ || (!iself && CONST_STRNEQ (secname, ".rel"))) ++ && (s->flags & SEC_LOAD) != 0) ++ place = &hold[orphan_rel]; ++ else if ((s->flags & SEC_CODE) == 0) ++ place = &hold[orphan_rodata]; ++ else ++ place = &hold[orphan_text]; ++ ++ after = NULL; ++ if (place != NULL) ++ { ++ if (place->os == NULL) ++ { ++ if (place->name != NULL) ++ place->os = lang_output_section_find (place->name); ++ else ++ place->os = output_rel_find (s, isdyn); ++ } ++ after = place->os; ++ if (after == NULL) ++ after = lang_output_section_find_by_flags ++ (s, &place->os, _bfd_elf_match_sections_by_type); ++ if (after == NULL) ++ /* *ABS* is always the first output section statement. */ ++ after = &lang_output_section_statement.head->output_section_statement; ++ } ++ ++ return lang_insert_orphan (s, secname, constraint, after, place, NULL, NULL); ++} ++EOF ++fi ++ ++if test x"$LDEMUL_AFTER_ALLOCATION" != xgld"$EMULATION_NAME"_after_allocation; then ++fragment <> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c ++echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c ++if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else ++echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c ++fi ++if test -n "$GENERATE_PIE_SCRIPT" ; then ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++echo ' ; else if (link_info.pie && link_info.combreloc' >> e${EMULATION_NAME}.c ++echo ' && link_info.relro' >> e${EMULATION_NAME}.c ++echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.pie && link_info.combreloc) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c ++fi ++echo ' ; else if (link_info.pie) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xd >> e${EMULATION_NAME}.c ++fi ++if test -n "$GENERATE_SHLIB_SCRIPT" ; then ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++echo ' ; else if (link_info.shared && link_info.combreloc' >> e${EMULATION_NAME}.c ++echo ' && link_info.relro' >> e${EMULATION_NAME}.c ++echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c ++fi ++echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c ++fi ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++echo ' ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c ++echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c ++fi ++echo ' ; else return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c ++echo '; }' >> e${EMULATION_NAME}.c ++ ++else ++# Scripts read from the filesystem. ++ ++fragment <