summaryrefslogtreecommitdiff
path: root/ppc-amigaos/recipes
diff options
context:
space:
mode:
authorChris Young <chris@unsatisfactorysoftware.co.uk>2018-01-08 22:27:57 +0000
committerChris Young <chris@unsatisfactorysoftware.co.uk>2018-01-08 22:27:57 +0000
commit17496c103b69193a7c03cb737d841a6906390bb2 (patch)
tree8ffaaee7e2b4f33958ba6354b14926bf40f619e3 /ppc-amigaos/recipes
parent515b4483c99475ef2a4bee095bf056afa1893c3d (diff)
downloadtoolchains-17496c103b69193a7c03cb737d841a6906390bb2.tar.gz
toolchains-17496c103b69193a7c03cb737d841a6906390bb2.tar.bz2
Still need missing-files.p
Diffstat (limited to 'ppc-amigaos/recipes')
-rw-r--r--ppc-amigaos/recipes/patches/binutils/missing-files.p12492
1 files changed, 12492 insertions, 0 deletions
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..7911090
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/binutils/missing-files.p
@@ -0,0 +1,12492 @@
+--- /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 <stdarg.h>
++#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 : "<unknown>"));
++#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.<callee> where xxxxxxxx is a hex number, usually 0,
++ specifying the addend on the plt relocation. For -fpic code, the sym
++ is xxxxxxxx.plt_pic32.<callee>, and for -fPIC
++ xxxxxxxx.got2.plt_pic32.<callee>. */
++
++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 : "<unknown>"));
++#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 <<EOF
++/* This file is is generated by a shell script. DO NOT EDIT! */
++
++/* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME}
++ Copyright 1991, 1993, 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 Steve Chamberlain <sac@cygnus.com>
++ ELF support by Ian Lance Taylor <ian@cygnus.com>
++
++ 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 <fcntl.h>
++
++#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 <ldgram.h>
++#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 <<EOF
++#ifdef HAVE_GLOB
++#include <glob.h>
++#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 <<EOF
++
++static void
++gld${EMULATION_NAME}_before_parse (void)
++{
++ ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`);
++ input_flags.dynamic = ${DYNAMIC_LINK-TRUE};
++ config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`;
++ config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then echo TRUE ; else echo FALSE ; fi`;
++}
++
++EOF
++fi
++
++if test x"$LDEMUL_RECOGNIZED_FILE" != xgld"${EMULATION_NAME}"_load_symbols; then
++fragment <<EOF
++/* Handle the generation of DT_NEEDED tags. */
++
++static bfd_boolean
++gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry)
++{
++ int link_class = 0;
++
++ /* 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. */
++ if (entry->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 <<EOF
++
++/* These variables are required to pass information back and forth
++ between after_open and check_needed and stat_needed and vercheck. */
++
++static struct bfd_link_needed_list *global_needed;
++static struct stat global_stat;
++static lang_input_statement_type *global_found;
++static struct bfd_link_needed_list *global_vercheck_needed;
++static bfd_boolean global_vercheck_failed;
++
++/* These variables are used to implement target options */
++
++static char *audit; /* colon (typically) separated list of libs */
++static char *depaudit; /* colon (typically) separated list of libs */
++
++/* On Linux, it's possible to have different versions of the same
++ shared library linked against different versions of libc. The
++ dynamic linker somehow tags which libc version to use in
++ /etc/ld.so.cache, and, based on the libc that it sees in the
++ executable, chooses which version of the shared library to use.
++
++ We try to do a similar check here by checking whether this shared
++ library needs any other shared libraries which may conflict with
++ libraries we have already included in the link. If it does, we
++ skip it, and try to find another shared library farther on down the
++ link path.
++
++ This is called via lang_for_each_input_file.
++ GLOBAL_VERCHECK_NEEDED is the list of objects needed by the object
++ which we are checking. This sets GLOBAL_VERCHECK_FAILED if we find
++ a conflicting version. */
++
++static void
++gld${EMULATION_NAME}_vercheck (lang_input_statement_type *s)
++{
++ const char *soname;
++ struct bfd_link_needed_list *l;
++
++ if (global_vercheck_failed)
++ return;
++ if (s->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 <<EOF
++ {
++ struct bfd_link_needed_list *l;
++
++ for (l = needs; l != NULL; l = l->next)
++ if (CONST_STRNEQ (l->name, "libc.so"))
++ break;
++ if (l == NULL)
++ {
++ bfd_close (abfd);
++ return FALSE;
++ }
++ }
++
++EOF
++ ;;
++esac
++fragment <<EOF
++ }
++ }
++
++ /* We've found a dynamic object matching the DT_NEEDED entry. */
++
++ /* We have already checked that there is no other input file of the
++ same name. We must now check again that we are not including the
++ same file twice. We need to do this because on many systems
++ libc.so is a symlink to, e.g., libc.so.1. The SONAME entry will
++ reference libc.so.1. If we have already included libc.so, we
++ don't want to include libc.so.1 if they are the same file, and we
++ can only check that using stat. */
++
++ if (bfd_stat (abfd, &global_stat) != 0)
++ einfo ("%F%P:%B: bfd_stat failed: %E\n", abfd);
++
++ /* First strip off everything before the last '/'. */
++ soname = lbasename (abfd->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 <<EOF
++
++/* Add the sysroot to every entry in a path separated by
++ config.rpath_separator. */
++
++static char *
++gld${EMULATION_NAME}_add_sysroot (const char *path)
++{
++ int len, colons, i;
++ char *ret, *p;
++
++ len = strlen (path);
++ colons = 0;
++ i = 0;
++ while (path[i])
++ if (path[i++] == config.rpath_separator)
++ colons++;
++
++ if (path[i])
++ colons++;
++
++ len = len + (colons + 1) * strlen (ld_sysroot);
++ ret = xmalloc (len + 1);
++ strcpy (ret, ld_sysroot);
++ p = ret + strlen (ret);
++ i = 0;
++ while (path[i])
++ if (path[i] == config.rpath_separator)
++ {
++ *p++ = path[i++];
++ strcpy (p, ld_sysroot);
++ p = p + strlen (p);
++ }
++ else
++ *p++ = path[i++];
++
++ *p = 0;
++ return ret;
++}
++
++EOF
++ case ${target} in
++ *-*-freebsd* | *-*-dragonfly*)
++ fragment <<EOF
++/* Read the system search path the FreeBSD way rather than the Linux way. */
++#ifdef HAVE_ELF_HINTS_H
++#include <elf-hints.h>
++#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 <<EOF
++/* For a native linker, check the file /etc/ld.so.conf for directories
++ in which we may find shared libraries. /etc/ld.so.conf is really
++ only meaningful on Linux. */
++
++struct gld${EMULATION_NAME}_ld_so_conf
++{
++ char *path;
++ size_t len, alloc;
++};
++
++static bfd_boolean
++gld${EMULATION_NAME}_parse_ld_so_conf
++ (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename);
++
++static void
++gld${EMULATION_NAME}_parse_ld_so_conf_include
++ (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename,
++ const char *pattern)
++{
++ char *newp = NULL;
++#ifdef HAVE_GLOB
++ glob_t gl;
++#endif
++
++ if (pattern[0] != '/')
++ {
++ char *p = strrchr (filename, '/');
++ size_t patlen = strlen (pattern) + 1;
++
++ newp = xmalloc (p - filename + 1 + patlen);
++ memcpy (newp, filename, p - filename + 1);
++ memcpy (newp + (p - filename + 1), pattern, patlen);
++ pattern = newp;
++ }
++
++#ifdef HAVE_GLOB
++ if (glob (pattern, 0, NULL, &gl) == 0)
++ {
++ size_t i;
++
++ for (i = 0; i < gl.gl_pathc; ++i)
++ gld${EMULATION_NAME}_parse_ld_so_conf (info, gl.gl_pathv[i]);
++ globfree (&gl);
++ }
++#else
++ /* If we do not have glob, treat the pattern as a literal filename. */
++ gld${EMULATION_NAME}_parse_ld_so_conf (info, pattern);
++#endif
++
++ if (newp)
++ free (newp);
++}
++
++static bfd_boolean
++gld${EMULATION_NAME}_parse_ld_so_conf
++ (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename)
++{
++ FILE *f = fopen (filename, FOPEN_RT);
++ char *line;
++ size_t linelen;
++
++ if (f == NULL)
++ return FALSE;
++
++ linelen = 256;
++ line = xmalloc (linelen);
++ do
++ {
++ char *p = line, *q;
++
++ /* Normally this would use getline(3), but we need to be portable. */
++ while ((q = fgets (p, linelen - (p - line), f)) != NULL
++ && strlen (q) == linelen - (p - line) - 1
++ && line[linelen - 2] != '\n')
++ {
++ line = xrealloc (line, 2 * linelen);
++ p = line + linelen - 1;
++ linelen += linelen;
++ }
++
++ if (q == NULL && p == line)
++ break;
++
++ p = strchr (line, '\n');
++ if (p)
++ *p = '\0';
++
++ /* Because the file format does not know any form of quoting we
++ can search forward for the next '#' character and if found
++ make it terminating the line. */
++ p = strchr (line, '#');
++ if (p)
++ *p = '\0';
++
++ /* Remove leading whitespace. NUL is no whitespace character. */
++ p = line;
++ while (*p == ' ' || *p == '\f' || *p == '\r' || *p == '\t' || *p == '\v')
++ ++p;
++
++ /* If the line is blank it is ignored. */
++ if (p[0] == '\0')
++ continue;
++
++ if (CONST_STRNEQ (p, "include") && (p[7] == ' ' || p[7] == '\t'))
++ {
++ char *dir, c;
++ p += 8;
++ do
++ {
++ while (*p == ' ' || *p == '\t')
++ ++p;
++
++ if (*p == '\0')
++ break;
++
++ dir = p;
++
++ while (*p != ' ' && *p != '\t' && *p)
++ ++p;
++
++ c = *p;
++ *p++ = '\0';
++ if (dir[0] != '\0')
++ gld${EMULATION_NAME}_parse_ld_so_conf_include (info, filename,
++ dir);
++ }
++ while (c != '\0');
++ }
++ else
++ {
++ char *dir = p;
++ while (*p && *p != '=' && *p != ' ' && *p != '\t' && *p != '\f'
++ && *p != '\r' && *p != '\v')
++ ++p;
++
++ while (p != dir && p[-1] == '/')
++ --p;
++ if (info->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 <<EOF
++
++/* See if an input file matches a DT_NEEDED entry by name. */
++
++static void
++gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s)
++{
++ const char *soname;
++
++ /* Stop looking if we've found a loaded lib. */
++ if (global_found != NULL
++ && (bfd_elf_get_dyn_lib_class (global_found->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 <<EOF
++
++static bfd_size_type
++gld${EMULATION_NAME}_id_note_section_size (bfd *abfd,
++ struct bfd_link_info *linfo)
++{
++ const char *style = linfo->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 <<EOF
++ const char *lib_path;
++EOF
++fi
++if [ "x${USE_LIBPATH}" = xyes ] ; then
++fragment <<EOF
++ struct bfd_link_needed_list *rp;
++ int found;
++EOF
++fi
++fragment <<EOF
++
++ if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
++ &n, force))
++ break;
++EOF
++if [ "x${USE_LIBPATH}" = xyes ] ; then
++fragment <<EOF
++ if (gld${EMULATION_NAME}_search_needed (command_line.rpath,
++ &n, force))
++ break;
++EOF
++fi
++if [ "x${NATIVE}" = xyes ] ; then
++fragment <<EOF
++ if (command_line.rpath_link == NULL
++ && command_line.rpath == NULL)
++ {
++ lib_path = (const char *) getenv ("LD_RUN_PATH");
++ if (gld${EMULATION_NAME}_search_needed (lib_path, &n,
++ force))
++ break;
++ }
++ lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
++ if (gld${EMULATION_NAME}_search_needed (lib_path, &n, force))
++ break;
++EOF
++fi
++if [ "x${USE_LIBPATH}" = xyes ] ; then
++fragment <<EOF
++ found = 0;
++ rp = bfd_elf_get_runpath_list (link_info.output_bfd, &link_info);
++ for (; !found && rp != NULL; rp = rp->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 <<EOF
++ if (gld${EMULATION_NAME}_check_ld_elf_hints (l, force))
++ break;
++EOF
++ # FreeBSD
++ ;;
++
++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*)
++ # Linux
++ fragment <<EOF
++ if (gld${EMULATION_NAME}_check_ld_so_conf (l, force))
++ break;
++
++EOF
++ ;;
++ esac
++fi
++fragment <<EOF
++ len = strlen (l->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 <<EOF
++ }
++
++ if (force < 2)
++ continue;
++
++ einfo ("%P: warning: %s, needed by %B, not found (try using -rpath or -rpath-link)\n",
++ l->name, l->by);
++ }
++}
++
++EOF
++fi
++
++fragment <<EOF
++
++/* Look through an expression for an assignment statement. */
++
++static void
++gld${EMULATION_NAME}_find_exp_assignment (etree_type *exp)
++{
++ bfd_boolean provide = FALSE;
++
++ switch (exp->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 <<EOF
++
++/* used by before_allocation and handle_option. */
++static void
++gld${EMULATION_NAME}_append_to_separated_string (char **to, char *op_arg)
++{
++ if (*to == NULL)
++ *to = xstrdup (op_arg);
++ else
++ {
++ size_t to_len = strlen (*to);
++ size_t op_arg_len = strlen (op_arg);
++ char *buf;
++ char *cp = *to;
++
++ /* First see whether OPTARG is already in the path. */
++ do
++ {
++ if (strncmp (op_arg, cp, op_arg_len) == 0
++ && (cp[op_arg_len] == 0
++ || cp[op_arg_len] == config.rpath_separator))
++ /* We found it. */
++ break;
++
++ /* Not yet found. */
++ cp = strchr (cp, config.rpath_separator);
++ if (cp != NULL)
++ ++cp;
++ }
++ while (cp != NULL);
++
++ if (cp == NULL)
++ {
++ buf = xmalloc (to_len + op_arg_len + 2);
++ sprintf (buf, "%s%c%s", *to,
++ config.rpath_separator, op_arg);
++ free (*to);
++ *to = buf;
++ }
++ }
++}
++
++/* This is called after the sections have been attached to output
++ sections, but before any sizes or addresses have been set. */
++
++static void
++gld${EMULATION_NAME}_before_allocation (void)
++{
++ const char *rpath;
++ asection *sinterp;
++ bfd *abfd;
++
++ if (link_info.hash->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 <<EOF
++
++/* Try to open a dynamic archive. This is where we know that ELF
++ dynamic libraries have an extension of .so (or .sl on oddball systems
++ like hpux). */
++
++static bfd_boolean
++gld${EMULATION_NAME}_open_dynamic_archive
++ (const char *arch, search_dirs_type *search, lang_input_statement_type *entry)
++{
++ const char *filename;
++ char *string;
++
++ if (! entry->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 <<EOF
++
++/* A variant of lang_output_section_find used by place_orphan. */
++
++static lang_output_section_statement_type *
++output_rel_find (asection *sec, int isdyn)
++{
++ lang_output_section_statement_type *lookup;
++ lang_output_section_statement_type *last = NULL;
++ lang_output_section_statement_type *last_alloc = NULL;
++ lang_output_section_statement_type *last_ro_alloc = NULL;
++ lang_output_section_statement_type *last_rel = NULL;
++ lang_output_section_statement_type *last_rel_alloc = NULL;
++ int rela = sec->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 <<EOF
++
++static void
++gld${EMULATION_NAME}_after_allocation (void)
++{
++ bfd_boolean need_layout = bfd_elf_discard_info (link_info.output_bfd,
++ &link_info);
++ gld${EMULATION_NAME}_map_segments (need_layout);
++}
++EOF
++fi
++
++if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then
++fragment <<EOF
++
++static char *
++gld${EMULATION_NAME}_get_script (int *isfile)
++EOF
++
++if test -n "$COMPILE_IN"
++then
++# Scripts compiled in.
++
++# sed commands to quote an ld script as a C string.
++sc="-f stringify.sed"
++
++fragment <<EOF
++{
++ *isfile = 0;
++
++ if (link_info.relocatable && config.build_constructors)
++ return
++EOF
++sed $sc ldscripts/${EMULATION_NAME}.xu >> 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 <<EOF
++{
++ *isfile = 1;
++
++ if (link_info.relocatable && config.build_constructors)
++ return "ldscripts/${EMULATION_NAME}.xu";
++ else if (link_info.relocatable)
++ return "ldscripts/${EMULATION_NAME}.xr";
++ else if (!config.text_read_only)
++ return "ldscripts/${EMULATION_NAME}.xbn";
++EOF
++if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then :
++else
++fragment <<EOF
++ else if (!config.magic_demand_paged)
++ return "ldscripts/${EMULATION_NAME}.xn";
++EOF
++fi
++if test -n "$GENERATE_PIE_SCRIPT" ; then
++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
++fragment <<EOF
++ else if (link_info.pie && link_info.combreloc
++ && link_info.relro && (link_info.flags & DF_BIND_NOW))
++ return "ldscripts/${EMULATION_NAME}.xdw";
++ else if (link_info.pie && link_info.combreloc)
++ return "ldscripts/${EMULATION_NAME}.xdc";
++EOF
++fi
++fragment <<EOF
++ else if (link_info.pie)
++ return "ldscripts/${EMULATION_NAME}.xd";
++EOF
++fi
++if test -n "$GENERATE_SHLIB_SCRIPT" ; then
++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
++fragment <<EOF
++ else if (link_info.shared && link_info.combreloc
++ && link_info.relro && (link_info.flags & DF_BIND_NOW))
++ return "ldscripts/${EMULATION_NAME}.xsw";
++ else if (link_info.shared && link_info.combreloc)
++ return "ldscripts/${EMULATION_NAME}.xsc";
++EOF
++fi
++fragment <<EOF
++ else if (link_info.shared)
++ return "ldscripts/${EMULATION_NAME}.xs";
++EOF
++fi
++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
++fragment <<EOF
++ else if (link_info.combreloc && link_info.relro
++ && (link_info.flags & DF_BIND_NOW))
++ return "ldscripts/${EMULATION_NAME}.xw";
++ else if (link_info.combreloc)
++ return "ldscripts/${EMULATION_NAME}.xc";
++EOF
++fi
++fragment <<EOF
++ else
++ return "ldscripts/${EMULATION_NAME}.x";
++}
++
++EOF
++fi
++fi
++
++if test -n "$PARSE_AND_LIST_PROLOGUE" ; then
++fragment <<EOF
++ $PARSE_AND_LIST_PROLOGUE
++EOF
++fi
++
++fragment <<EOF
++
++#define OPTION_DISABLE_NEW_DTAGS (400)
++#define OPTION_ENABLE_NEW_DTAGS (OPTION_DISABLE_NEW_DTAGS + 1)
++#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1)
++#define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1)
++#define OPTION_EXCLUDE_LIBS (OPTION_EH_FRAME_HDR + 1)
++#define OPTION_HASH_STYLE (OPTION_EXCLUDE_LIBS + 1)
++#define OPTION_BUILD_ID (OPTION_HASH_STYLE + 1)
++#define OPTION_AUDIT (OPTION_BUILD_ID + 1)
++
++static void
++gld${EMULATION_NAME}_add_options
++ (int ns, char **shortopts, int nl, struct option **longopts,
++ int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED)
++{
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ static const char xtra_short[] = "${PARSE_AND_LIST_SHORTOPTS}z:P:";
++EOF
++else
++fragment <<EOF
++ static const char xtra_short[] = "${PARSE_AND_LIST_SHORTOPTS}z:";
++EOF
++fi
++fragment <<EOF
++ static const struct option xtra_long[] = {
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ {"audit", required_argument, NULL, OPTION_AUDIT},
++ {"Bgroup", no_argument, NULL, OPTION_GROUP},
++EOF
++fi
++fragment <<EOF
++ {"build-id", optional_argument, NULL, OPTION_BUILD_ID},
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ {"depaudit", required_argument, NULL, 'P'},
++ {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
++ {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
++ {"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR},
++ {"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS},
++ {"hash-style", required_argument, NULL, OPTION_HASH_STYLE},
++EOF
++fi
++if test -n "$PARSE_AND_LIST_LONGOPTS" ; then
++fragment <<EOF
++ $PARSE_AND_LIST_LONGOPTS
++EOF
++fi
++fragment <<EOF
++ {NULL, no_argument, NULL, 0}
++ };
++
++ *shortopts = (char *) xrealloc (*shortopts, ns + sizeof (xtra_short));
++ memcpy (*shortopts + ns, &xtra_short, sizeof (xtra_short));
++ *longopts = (struct option *)
++ xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long));
++ memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long));
++}
++
++#define DEFAULT_BUILD_ID_STYLE "sha1"
++
++static bfd_boolean
++gld${EMULATION_NAME}_handle_option (int optc)
++{
++ switch (optc)
++ {
++ default:
++ return FALSE;
++
++ case OPTION_BUILD_ID:
++ if (link_info.emit_note_gnu_build_id != NULL)
++ {
++ free (link_info.emit_note_gnu_build_id);
++ link_info.emit_note_gnu_build_id = NULL;
++ }
++ if (optarg == NULL)
++ optarg = DEFAULT_BUILD_ID_STYLE;
++ if (strcmp (optarg, "none"))
++ link_info.emit_note_gnu_build_id = xstrdup (optarg);
++ break;
++
++EOF
++
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ case OPTION_AUDIT:
++ gld${EMULATION_NAME}_append_to_separated_string (&audit, optarg);
++ break;
++
++ case 'P':
++ gld${EMULATION_NAME}_append_to_separated_string (&depaudit, optarg);
++ break;
++
++ case OPTION_DISABLE_NEW_DTAGS:
++ link_info.new_dtags = FALSE;
++ break;
++
++ case OPTION_ENABLE_NEW_DTAGS:
++ link_info.new_dtags = TRUE;
++ break;
++
++ case OPTION_EH_FRAME_HDR:
++ link_info.eh_frame_hdr = TRUE;
++ break;
++
++ case OPTION_GROUP:
++ link_info.flags_1 |= (bfd_vma) DF_1_GROUP;
++ /* Groups must be self-contained. */
++ link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR;
++ link_info.unresolved_syms_in_shared_libs = RM_GENERATE_ERROR;
++ break;
++
++ case OPTION_EXCLUDE_LIBS:
++ add_excluded_libs (optarg);
++ break;
++
++ case OPTION_HASH_STYLE:
++ link_info.emit_hash = FALSE;
++ link_info.emit_gnu_hash = FALSE;
++ if (strcmp (optarg, "sysv") == 0)
++ link_info.emit_hash = TRUE;
++ else if (strcmp (optarg, "gnu") == 0)
++ link_info.emit_gnu_hash = TRUE;
++ else if (strcmp (optarg, "both") == 0)
++ {
++ link_info.emit_hash = TRUE;
++ link_info.emit_gnu_hash = TRUE;
++ }
++ else
++ einfo (_("%P%F: invalid hash style \`%s'\n"), optarg);
++ break;
++
++EOF
++fi
++fragment <<EOF
++ case 'z':
++ if (strcmp (optarg, "defs") == 0)
++ link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR;
++ else if (strcmp (optarg, "muldefs") == 0)
++ link_info.allow_multiple_definition = TRUE;
++ else if (CONST_STRNEQ (optarg, "max-page-size="))
++ {
++ char *end;
++
++ config.maxpagesize = strtoul (optarg + 14, &end, 0);
++ if (*end || (config.maxpagesize & (config.maxpagesize - 1)) != 0)
++ einfo (_("%P%F: invalid maxium page size \`%s'\n"),
++ optarg + 14);
++ }
++ else if (CONST_STRNEQ (optarg, "common-page-size="))
++ {
++ char *end;
++ config.commonpagesize = strtoul (optarg + 17, &end, 0);
++ if (*end
++ || (config.commonpagesize & (config.commonpagesize - 1)) != 0)
++ einfo (_("%P%F: invalid common page size \`%s'\n"),
++ optarg + 17);
++ }
++ else if (strcmp (optarg, "execstack") == 0)
++ {
++ link_info.execstack = TRUE;
++ link_info.noexecstack = FALSE;
++ }
++ else if (strcmp (optarg, "noexecstack") == 0)
++ {
++ link_info.noexecstack = TRUE;
++ link_info.execstack = FALSE;
++ }
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ else if (strcmp (optarg, "initfirst") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST;
++ else if (strcmp (optarg, "interpose") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_INTERPOSE;
++ else if (strcmp (optarg, "loadfltr") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_LOADFLTR;
++ else if (strcmp (optarg, "nodefaultlib") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_NODEFLIB;
++ else if (strcmp (optarg, "nodelete") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_NODELETE;
++ else if (strcmp (optarg, "nodlopen") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_NOOPEN;
++ else if (strcmp (optarg, "nodump") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_NODUMP;
++ else if (strcmp (optarg, "now") == 0)
++ {
++ link_info.flags |= (bfd_vma) DF_BIND_NOW;
++ link_info.flags_1 |= (bfd_vma) DF_1_NOW;
++ }
++ else if (strcmp (optarg, "lazy") == 0)
++ {
++ link_info.flags &= ~(bfd_vma) DF_BIND_NOW;
++ link_info.flags_1 &= ~(bfd_vma) DF_1_NOW;
++ }
++ else if (strcmp (optarg, "origin") == 0)
++ {
++ link_info.flags |= (bfd_vma) DF_ORIGIN;
++ link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN;
++ }
++ else if (strcmp (optarg, "combreloc") == 0)
++ link_info.combreloc = TRUE;
++ else if (strcmp (optarg, "nocombreloc") == 0)
++ link_info.combreloc = FALSE;
++ else if (strcmp (optarg, "nocopyreloc") == 0)
++ link_info.nocopyreloc = TRUE;
++ else if (strcmp (optarg, "relro") == 0)
++ link_info.relro = TRUE;
++ else if (strcmp (optarg, "norelro") == 0)
++ link_info.relro = FALSE;
++ else if (strcmp (optarg, "text") == 0)
++ link_info.error_textrel = TRUE;
++ else if (strcmp (optarg, "notext") == 0)
++ link_info.error_textrel = FALSE;
++ else if (strcmp (optarg, "textoff") == 0)
++ link_info.error_textrel = FALSE;
++EOF
++fi
++
++fragment <<EOF
++ else
++ einfo (_("%P: warning: -z %s ignored.\n"), optarg);
++ break;
++EOF
++
++if test -n "$PARSE_AND_LIST_ARGS_CASES" ; then
++fragment <<EOF
++ $PARSE_AND_LIST_ARGS_CASES
++EOF
++fi
++
++fragment <<EOF
++ }
++
++ return TRUE;
++}
++
++EOF
++
++if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then
++fragment <<EOF
++
++static void
++gld${EMULATION_NAME}_list_options (FILE * file)
++{
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ fprintf (file, _("\
++ --audit=AUDITLIB Specify a library to use for auditing\n"));
++ fprintf (file, _("\
++ -Bgroup Selects group name lookup rules for DSO\n"));
++EOF
++fi
++fragment <<EOF
++ fprintf (file, _("\
++ --build-id[=STYLE] Generate build ID note\n"));
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ fprintf (file, _("\
++ -P AUDITLIB, --depaudit=AUDITLIB\n" "\
++ Specify a library to use for auditing dependencies\n"));
++ fprintf (file, _("\
++ --disable-new-dtags Disable new dynamic tags\n"));
++ fprintf (file, _("\
++ --enable-new-dtags Enable new dynamic tags\n"));
++ fprintf (file, _("\
++ --eh-frame-hdr Create .eh_frame_hdr section\n"));
++ fprintf (file, _("\
++ --exclude-libs=LIBS Make all symbols in LIBS hidden\n"));
++ fprintf (file, _("\
++ --hash-style=STYLE Set hash style to sysv, gnu or both\n"));
++ fprintf (file, _("\
++ -z combreloc Merge dynamic relocs into one section and sort\n"));
++EOF
++fi
++
++fragment <<EOF
++ fprintf (file, _("\
++ -z common-page-size=SIZE Set common page size to SIZE\n"));
++ fprintf (file, _("\
++ -z defs Report unresolved symbols in object files.\n"));
++ fprintf (file, _("\
++ -z execstack Mark executable as requiring executable stack\n"));
++EOF
++
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ fprintf (file, _("\
++ -z initfirst Mark DSO to be initialized first at runtime\n"));
++ fprintf (file, _("\
++ -z interpose Mark object to interpose all DSOs but executable\n"));
++ fprintf (file, _("\
++ -z lazy Mark object lazy runtime binding (default)\n"));
++ fprintf (file, _("\
++ -z loadfltr Mark object requiring immediate process\n"));
++EOF
++fi
++
++fragment <<EOF
++ fprintf (file, _("\
++ -z max-page-size=SIZE Set maximum page size to SIZE\n"));
++ fprintf (file, _("\
++ -z muldefs Allow multiple definitions\n"));
++EOF
++
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ fprintf (file, _("\
++ -z nocombreloc Don't merge dynamic relocs into one section\n"));
++ fprintf (file, _("\
++ -z nocopyreloc Don't create copy relocs\n"));
++ fprintf (file, _("\
++ -z nodefaultlib Mark object not to use default search paths\n"));
++ fprintf (file, _("\
++ -z nodelete Mark DSO non-deletable at runtime\n"));
++ fprintf (file, _("\
++ -z nodlopen Mark DSO not available to dlopen\n"));
++ fprintf (file, _("\
++ -z nodump Mark DSO not available to dldump\n"));
++EOF
++fi
++fragment <<EOF
++ fprintf (file, _("\
++ -z noexecstack Mark executable as not requiring executable stack\n"));
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ fprintf (file, _("\
++ -z norelro Don't create RELRO program header\n"));
++ fprintf (file, _("\
++ -z now Mark object non-lazy runtime binding\n"));
++ fprintf (file, _("\
++ -z origin Mark object requiring immediate \$ORIGIN\n\
++ processing at runtime\n"));
++ fprintf (file, _("\
++ -z relro Create RELRO program header\n"));
++EOF
++fi
++
++if test -n "$PARSE_AND_LIST_OPTIONS" ; then
++fragment <<EOF
++ $PARSE_AND_LIST_OPTIONS
++EOF
++fi
++
++fragment <<EOF
++}
++EOF
++
++if test -n "$PARSE_AND_LIST_EPILOGUE" ; then
++fragment <<EOF
++ $PARSE_AND_LIST_EPILOGUE
++EOF
++fi
++fi
++
++fragment <<EOF
++
++struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
++{
++ ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
++ ${LDEMUL_SYSLIB-syslib_default},
++ ${LDEMUL_HLL-hll_default},
++ ${LDEMUL_AFTER_PARSE-after_parse_default},
++ ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open},
++ ${LDEMUL_AFTER_ALLOCATION-gld${EMULATION_NAME}_after_allocation},
++ ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
++ ${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
++ ${LDEMUL_BEFORE_ALLOCATION-gld${EMULATION_NAME}_before_allocation},
++ ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script},
++ "${EMULATION_NAME}",
++ "${OUTPUT_FORMAT}",
++ ${LDEMUL_FINISH-finish_default},
++ ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
++ ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-gld${EMULATION_NAME}_open_dynamic_archive},
++ ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
++ ${LDEMUL_SET_SYMBOLS-NULL},
++ ${LDEMUL_PARSE_ARGS-NULL},
++ gld${EMULATION_NAME}_add_options,
++ gld${EMULATION_NAME}_handle_option,
++ ${LDEMUL_UNRECOGNIZED_FILE-NULL},
++ ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options},
++ ${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols},
++ ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
++ ${LDEMUL_NEW_VERS_PATTERN-NULL}
++};
++EOF
+