diff -ru --new-file a/bfd/amigaos.c b/bfd/amigaos.c
--- a/bfd/amigaos.c	1970-01-01 03:00:00.000000000 +0300
+++ b/bfd/amigaos.c	2021-02-01 23:12:49.058762200 +0300
@@ -0,0 +1,3189 @@
+/* BFD back-end for Commodore-Amiga AmigaOS binaries.
+   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
+   Free Software Foundation, Inc.
+   Contributed by Leonard Norrgard.  Partially based on the bout
+   and ieee BFD backends and Markus Wild's tool hunk2gcc.
+   Revised and updated by Stephan Thesing.
+
+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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/*
+SECTION
+	amiga back end
+
+This section describes the overall structure of the Amiga BFD back end.
+The linker stuff can be found in @xref{amigalink}.
+@menu
+@* implementation::
+@* amigalink::
+@end menu
+
+INODE
+implementation, amigalink, amiga, amiga
+
+SECTION
+	implementation
+
+The need for a port of the bfd library for Amiga style object (hunk) files
+arose by the desire to port the GNU debugger gdb to the Amiga.
+Also, the linker ld should be updated to the current version (2.5.2).
+@@*
+This port bases on the work done by Leonard Norrgard, who started porting
+gdb. Raphael Luebbert, who supports the ixemul.library, has also worked on
+implementing the needed @code{ptrace()} system call and gas2.5.
+
+@menu
+@* not supported::
+@* Does it work?::
+@* TODO::
+@end menu
+
+INODE
+not supported, Does it work?, implementation, implementation
+
+SUBSECTION
+	not supported
+
+Currently, the implementation does not support Amiga link library files, like
+e.g. amiga.lib. This may be added in a later version, if anyone starts work
+on it, or I find some time for it.
+
+The handling of the symbols in hunk files is a little bit broken:
+	  o The symbols in a load file are totally ignored at the moment, so gdb and gprof
+	    do not work.
+	  o The symbols of a object module (Hunk file, starting with HUNK_UNIT) are read in
+	    correctly, but HUNK_SYMBOL hunks are also ignored.
+
+The reason for this is the following:
+Amiga symbol hunks do not allow for much information. Only a name and a value are allowed.
+On the other hand, a.out format carries along much more information (see, e.g. the
+entry on set symbols in the ld manual). The old linker copied this information into
+a HUNK_DEBUG hunk. Now there is the choice:
+	o ignoring the debug hunk, read in only HUNK_SYMBOL definitions => extra info is lost.
+	o read in the debug hunk and use the information therein => How can clashs between the
+	  information in the debug hunk and HUNK_SYMBOL or HUNK_EXT hunks be avoided?
+I haven't decided yet, what to do about this.
+
+Although bfd allows to link together object modules of different flavours,
+producing a.out style executables does not work on Amiga :-)
+It should, however, be possible to create a.out files with the -r option of ld
+(incremental link).
+
+INODE
+Does it work?, TODO, not supported, implementation
+
+SUBSECTION
+	Does it work?
+
+Currently, the following utilities work:
+	o objdump
+	o objcopy
+	o strip
+	o nm
+	o ar
+	o gas
+
+INODE
+TODO, , Does it work?, implementation
+
+SUBSECTION
+	TODO
+
+	o fix FIXME:s
+
+@*
+BFD:
+	o add flag to say if the format allows multiple sections with the
+	  same name. Fix bfd_get_section_by_name() and bfd_make_section()
+	  accordingly.
+
+	o dumpobj.c: the disassembler: use relocation record data to find symbolic
+	  names of addresses, when available.  Needs new routine where one can
+	  specify the source section of the symbol to be printed as well as some
+	  rewrite of the disassemble functions.
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "libamiga.h"
+
+#define BYTES_IN_WORD 4
+#include "aout/aout64.h" /* struct external_nlist */
+
+#ifndef alloca
+extern PTR alloca PARAMS ((size_t));
+#endif
+
+#define bfd_is_bfd_section(sec) \
+  (bfd_is_abs_section(sec)||bfd_is_com_section(sec)||bfd_is_und_section(sec)||bfd_is_ind_section(sec))
+
+struct arch_syms {
+  unsigned long offset;		/* disk offset in the archive */
+  unsigned long size;		/* size of the block of symbols */
+  unsigned long unit_offset;	/* start of unit on disk */
+  struct arch_syms *next;	/* linked list */
+};
+
+typedef struct amiga_ardata_struct {
+  /* generic stuff */
+  struct artdata generic;
+  /* amiga-specific stuff */
+  unsigned long filesize;
+  struct arch_syms *defsyms;
+  unsigned long defsym_count;
+  unsigned long outnum;
+} amiga_ardata_type;
+
+#define amiga_ardata(bfd) (*(amiga_ardata_type **)(void *)&(bfd)->tdata.aout_ar_data)
+
+#define bfd_msg (*_bfd_error_handler)
+
+#define GL(x) bfd_get_32 (abfd, (bfd_byte *) (x))
+#define GW(x) bfd_get_16 (abfd, (bfd_byte *) (x))
+#define LONGSIZE(l) (((l)+3) >> 2)
+
+/* AmigaOS doesn't like HUNK_SYMBOL with symbol names longer than 124 characters */
+#define MAX_NAME_SIZE 124
+
+static bfd_boolean get_long PARAMS ((bfd *, unsigned long *));
+static const struct bfd_target *amiga_object_p PARAMS ((bfd *));
+static sec_ptr amiga_get_section_by_hunk_number PARAMS ((bfd *, long));
+static bfd_boolean amiga_add_reloc PARAMS ((bfd *, sec_ptr, bfd_size_type,
+	amiga_symbol_type *, reloc_howto_type *, long));
+static sec_ptr amiga_make_unique_section PARAMS ((bfd *, const char *));
+static bfd_boolean parse_archive_units PARAMS ((bfd *, int *, unsigned long,
+	bfd_boolean, struct arch_syms **, symindex *));
+static bfd_boolean amiga_digest_file PARAMS ((bfd *));
+static bfd_boolean amiga_read_unit PARAMS ((bfd *, unsigned long));
+static bfd_boolean amiga_read_load PARAMS ((bfd *));
+static bfd_boolean amiga_handle_cdb_hunk PARAMS ((bfd *, unsigned long,
+	unsigned long, unsigned long, unsigned long));
+static bfd_boolean amiga_handle_rest PARAMS ((bfd *, sec_ptr, bfd_boolean));
+static bfd_boolean amiga_mkobject PARAMS ((bfd *));
+static bfd_boolean amiga_mkarchive PARAMS ((bfd *));
+static bfd_boolean write_longs PARAMS ((const unsigned long *, unsigned long,
+	bfd *));
+static long determine_datadata_relocs PARAMS ((bfd *, sec_ptr));
+static void remove_section_index PARAMS ((sec_ptr, int *));
+static bfd_boolean amiga_write_object_contents PARAMS ((bfd *));
+static bfd_boolean write_name PARAMS ((bfd *, const char *, unsigned long));
+static bfd_boolean amiga_write_archive_contents PARAMS ((bfd *));
+static bfd_boolean amiga_write_armap PARAMS ((bfd *, unsigned int,
+	struct orl *, unsigned int, int));
+static int determine_type PARAMS ((arelent *));
+static bfd_boolean amiga_write_section_contents PARAMS ((bfd *, sec_ptr,
+	sec_ptr, unsigned long, int *, int));
+static bfd_boolean amiga_write_symbols PARAMS ((bfd *, sec_ptr));
+static bfd_boolean amiga_get_section_contents PARAMS ((bfd *, sec_ptr, PTR,
+	file_ptr, bfd_size_type));
+static bfd_boolean amiga_new_section_hook PARAMS ((bfd *, sec_ptr));
+static bfd_boolean amiga_slurp_symbol_table PARAMS ((bfd *));
+static long amiga_get_symtab_upper_bound PARAMS ((bfd *));
+static long amiga_get_symtab PARAMS ((bfd *, asymbol **));
+static asymbol *amiga_make_empty_symbol PARAMS ((bfd *));
+static void amiga_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *));
+static void amiga_print_symbol PARAMS ((bfd *, PTR,   asymbol *,
+	bfd_print_symbol_type));
+static long amiga_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr));
+static bfd_boolean read_raw_relocs PARAMS ((bfd *, sec_ptr, unsigned long,
+	unsigned long));
+static bfd_boolean amiga_slurp_relocs PARAMS ((bfd *, sec_ptr, asymbol **));
+static long amiga_canonicalize_reloc PARAMS ((bfd *, sec_ptr, arelent **,
+	asymbol **));
+static bfd_boolean amiga_set_section_contents PARAMS ((bfd *, sec_ptr, PTR,
+	file_ptr, bfd_size_type));
+static bfd_boolean amiga_set_arch_mach PARAMS ((bfd *, enum bfd_architecture,
+	unsigned long));
+static int amiga_sizeof_headers PARAMS ((bfd *, bfd_boolean));
+static bfd_boolean amiga_find_nearest_line PARAMS ((bfd *, sec_ptr,
+	asymbol **, bfd_vma, const char **, const char **, unsigned int *));
+static reloc_howto_type *amiga_bfd_reloc_type_lookup PARAMS ((bfd *,
+	bfd_reloc_code_real_type));
+static bfd_boolean amiga_bfd_copy_private_bfd_data PARAMS ((bfd *, bfd *));
+static bfd_boolean amiga_bfd_copy_private_section_data PARAMS ((bfd *,
+	sec_ptr, bfd *, sec_ptr));
+static bfd_boolean amiga_slurp_armap PARAMS ((bfd *));
+static void amiga_truncate_arname PARAMS ((bfd *, const char *, char *));
+static const struct bfd_target *amiga_archive_p PARAMS ((bfd *));
+static bfd *amiga_openr_next_archived_file PARAMS ((bfd *, bfd *));
+static PTR amiga_read_ar_hdr PARAMS ((bfd *));
+static int amiga_generic_stat_arch_elt PARAMS ((bfd *, struct stat *));
+
+/*#define DEBUG_AMIGA 1*/
+#if DEBUG_AMIGA
+#include <stdarg.h>
+static void
+error_print (const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  vfprintf (stderr, fmt, args);
+  va_end (args);
+}
+#define DPRINT(L,x) if (L>=DEBUG_AMIGA) error_print x
+#else
+#define DPRINT(L,x)
+#endif
+
+enum {R_ABS32=0,R_PC16,R_PC8,R_SD32,R_SD16,R_SD8,R_ABS32SHORT,R_PC26,R_PC32,R__MAX};
+static reloc_howto_type howto_table[R__MAX] =
+{
+  {H_ABS32,   /* type */
+  0,          /* rightshift */
+  2,          /* size */
+  32,         /* bitsize */
+  FALSE,      /* pc_relative */
+  0,          /* bitpos */
+  complain_overflow_bitfield,/* complain_on_overflow */
+  0,          /* special_function */
+  "RELOC32",  /* textual name */
+  FALSE,      /* partial_inplace */
+  0xffffffff, /* src_mask */
+  0xffffffff, /* dst_mask */
+  FALSE},     /* pcrel_offset */
+  {H_PC16,       0, 1, 16, TRUE,  0, complain_overflow_signed,   0, "RELRELOC16",   FALSE, 0x0000ffff, 0x0000ffff, TRUE},
+  {H_PC8,        0, 0,  8, TRUE,  0, complain_overflow_signed,   0, "RELRELOC8",    FALSE, 0x000000ff, 0x000000ff, TRUE},
+  {H_SD32,       0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "DREL32",       FALSE, 0xffffffff, 0xffffffff, FALSE},
+  {H_SD16,       0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "DREL16",       FALSE, 0x0000ffff, 0x0000ffff, FALSE},
+  {H_SD8,        0, 0,  8, FALSE, 0, complain_overflow_bitfield, 0, "DREL8",        FALSE, 0x000000ff, 0x000000ff, FALSE},
+  {H_ABS32SHORT, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "RELOC32SHORT", FALSE, 0x0000ffff, 0x0000ffff, FALSE},
+  {H_PC26,       0, 2, 26, TRUE,  0, complain_overflow_signed,   0, "RELRELOC26",   FALSE, 0x03fffffc, 0x03fffffc, TRUE},
+  {H_PC32,       0, 2, 32, TRUE,  0, complain_overflow_signed,   0, "RELRELOC32",   FALSE, 0xffffffff, 0xffffffff, TRUE}
+};
+
+/* The following are gross hacks that need to be fixed.  The problem is
+   that the linker unconditionally references these values without
+   going through any of bfd's standard interface.  Thus they need to
+   be defined in a bfd module that is included in *all* configurations,
+   and are currently in bfd.c, otherwise linking the linker will fail
+   on non-Amiga target configurations. */
+
+/* This one is used by the linker and tells us, if a debug hunk should
+   be written out. */
+extern int write_debug_hunk;
+
+/* This is also used by the linker to set the attribute of sections. */
+extern int amiga_attribute;
+
+/* used with base-relative linking */
+extern int amiga_base_relative;
+
+/* used with -resident linking */
+extern int amiga_resident;
+
+static bfd_boolean
+get_long (abfd, n)
+     bfd *abfd;
+     unsigned long *n;
+{
+  if (bfd_bread ((PTR)n, 4, abfd) != 4)
+    return FALSE;
+  *n = GL (n);
+  return TRUE;
+}
+
+static const struct bfd_target *
+amiga_object_p (abfd)
+     bfd *abfd;
+{
+  unsigned long x;
+  char buf[8];
+
+  /* An Amiga object file must be at least 8 bytes long.  */
+  if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf))
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return NULL;
+    }
+
+  bfd_seek (abfd, 0, SEEK_SET);
+
+  /* Does it look like an Amiga object file?  */
+  x = GL (&buf[0]);
+  if ((x != HUNK_UNIT) && (x != HUNK_HEADER))
+    {
+      /* Not an Amiga file.  */
+      bfd_set_error (bfd_error_wrong_format);
+      return NULL;
+    }
+
+  /* Can't fail and return (but must be declared bfd_boolean to suit
+     other bfd requirements).  */
+  (void) amiga_mkobject (abfd);
+
+  AMIGA_DATA(abfd)->IsLoadFile = (x == HUNK_HEADER);
+
+  if (!amiga_digest_file (abfd))
+    {
+      /* Something went wrong.  */
+      DPRINT(20,("bfd parser stopped at offset 0x%lx\n",bfd_tell(abfd)));
+      return NULL;
+    }
+
+  /* Set default architecture to m68k:68000.  */
+  /* So we can link on 68000 AMIGAs... */
+  abfd->arch_info = bfd_scan_arch ("m68k:68000");
+
+  return abfd->xvec;
+}
+
+static sec_ptr
+amiga_get_section_by_hunk_number (abfd, hunk_number)
+     bfd *abfd;
+     long hunk_number;
+{
+  /* A cache, so we don't have to search the entire list every time.  */
+  static sec_ptr last_reference;
+  static bfd *last_bfd;
+  sec_ptr p;
+
+  if (last_reference)
+    if (last_bfd == abfd && last_reference->target_index == hunk_number)
+       return last_reference;
+  for (p = abfd->sections; p != NULL; p = p->next)
+    if (p->target_index == hunk_number)
+      {
+	last_reference = p;
+	last_bfd = abfd;
+	return p;
+      }
+  BFD_FAIL ();
+  return NULL;
+}
+
+static bfd_boolean
+amiga_add_reloc (abfd, section, offset, symbol, howto, target_hunk)
+     bfd *abfd;
+     sec_ptr section;
+     bfd_size_type offset;
+     amiga_symbol_type *symbol;
+     reloc_howto_type *howto;
+     long target_hunk;
+{
+  amiga_reloc_type *reloc;
+  sec_ptr target_sec;
+
+  reloc = (amiga_reloc_type *) bfd_alloc (abfd, sizeof (amiga_reloc_type));
+  if (reloc == NULL)
+    return FALSE;
+
+  abfd->flags |= HAS_RELOC;
+  section->flags |= SEC_RELOC;
+
+  if (amiga_per_section(section)->reloc_tail)
+    amiga_per_section(section)->reloc_tail->next = reloc;
+  else
+    section->relocation = &reloc->relent;
+  amiga_per_section(section)->reloc_tail = reloc;
+
+  reloc->relent.sym_ptr_ptr = &reloc->symbol;
+  reloc->relent.address = offset;
+  reloc->relent.addend = 0;
+  reloc->relent.howto = howto;
+
+  reloc->next = NULL;
+  if (symbol==NULL) {		/* relative to section */
+    target_sec = amiga_get_section_by_hunk_number (abfd, target_hunk);
+    if (target_sec)
+      reloc->symbol = target_sec->symbol;
+    else
+      return FALSE;
+  }
+  else
+    reloc->symbol = &symbol->symbol;
+
+  return TRUE;
+}
+
+/* BFD doesn't currently allow multiple sections with the same
+   name, so we try a little harder to get a unique name.  */
+static sec_ptr
+amiga_make_unique_section (abfd, name)
+     bfd *abfd;
+     const char *name;
+{
+  sec_ptr section;
+
+  bfd_set_error (bfd_error_no_error);
+  section = bfd_make_section (abfd, name);
+  if ((section == NULL) && (bfd_get_error() == bfd_error_no_error))
+    {
+#if 0
+      char *new_name = bfd_alloc (abfd, strlen(name) + 4);
+      int i = 1;
+
+      /* We try to come up with an original name (since BFD currently
+	 requires all sections to have different names).  */
+      while (!section && (i<=99))
+	{
+	  sprintf (new_name, "%s_%u", name, i++);
+	  section = bfd_make_section (abfd, new_name);
+	}
+#else
+      section = bfd_make_section_anyway (abfd, name);
+#endif
+    }
+  return section;
+}
+
+#if DEBUG_AMIGA
+#define DPRINTHUNK(x) fprintf(stderr,"Processing %s hunk (0x%x)...",\
+	(x) == HUNK_UNIT ? "HUNK_UNIT" :\
+	(x) == HUNK_NAME ? "HUNK_NAME" :\
+	(x) == HUNK_CODE ? "HUNK_CODE" :\
+	(x) == HUNK_DATA ? "HUNK_DATA" :\
+	(x) == HUNK_BSS ? "HUNK_BSS" :\
+	(x) == HUNK_ABSRELOC32 ? "HUNK_RELOC32" :\
+	(x) == HUNK_RELRELOC16 ? "HUNK_RELRELOC16" :\
+	(x) == HUNK_RELRELOC8 ? "HUNK_RELRELOC8" :\
+	(x) == HUNK_EXT ? "HUNK_EXT" :\
+	(x) == HUNK_SYMBOL ? "HUNK_SYMBOL" :\
+	(x) == HUNK_DEBUG ? "HUNK_DEBUG" :\
+	(x) == HUNK_END ? "HUNK_END" :\
+	(x) == HUNK_HEADER ? "HUNK_HEADER" :\
+	(x) == HUNK_OVERLAY ? "HUNK_OVERLAY" :\
+	(x) == HUNK_BREAK ? "HUNK_BREAK" :\
+	(x) == HUNK_DREL32 ? "HUNK_DREL32" :\
+	(x) == HUNK_DREL16 ? "HUNK_DREL16" :\
+	(x) == HUNK_DREL8 ? "HUNK_DREL8" :\
+	(x) == HUNK_LIB ? "HUNK_LIB" :\
+	(x) == HUNK_INDEX ? "HUNK_INDEX" :\
+	(x) == HUNK_RELOC32SHORT ? "HUNK_RELOC32SHORT" :\
+	(x) == HUNK_RELRELOC32 ? "HUNK_RELRELOC32" :\
+	(x) == HUNK_PPC_CODE ? "HUNK_PPC_CODE" :\
+	(x) == HUNK_RELRELOC26 ? "HUNK_RELRELOC26" :\
+	"*unknown*",(x))
+#define DPRINTHUNKEND fprintf(stderr,"done\n")
+#else
+#define DPRINTHUNK(x)
+#define DPRINTHUNKEND
+#endif
+
+static bfd_boolean
+parse_archive_units (abfd, n_units, filesize, one, syms, symcount)
+     bfd *abfd;
+     int *n_units;
+     unsigned long filesize;
+     bfd_boolean one;			/* parse only the first unit? */
+     struct arch_syms **syms;
+     symindex *symcount;
+{
+  struct arch_syms *nsyms,*syms_tail=NULL;
+  unsigned long unit_offset,defsym_pos=0;
+  unsigned long hunk_type,type,len,no,n;
+  symindex defsymcount=0;
+
+  *n_units = 0;
+  while (get_long (abfd, &hunk_type)) {
+    switch (hunk_type) {
+    case HUNK_END:
+      break;
+    case HUNK_UNIT:
+      unit_offset = bfd_tell (abfd) - 4;
+      (*n_units)++;
+      if (one && *n_units>1) {
+	bfd_seek (abfd, -4, SEEK_CUR);
+	return TRUE;
+      }
+      /* Fall through */
+    case HUNK_NAME:
+    case HUNK_CODE:
+    case HUNK_DATA:
+    case HUNK_DEBUG:
+    case HUNK_PPC_CODE:
+      if (!get_long (abfd, &len)
+	  || bfd_seek (abfd, HUNK_VALUE (len) << 2, SEEK_CUR))
+	return FALSE;
+      break;
+    case HUNK_BSS:
+      if (!get_long (abfd, &len))
+	return FALSE;
+      break;
+    case HUNK_ABSRELOC32:
+    case HUNK_RELRELOC16:
+    case HUNK_RELRELOC8:
+    case HUNK_SYMBOL:
+    case HUNK_DREL32:
+    case HUNK_DREL16:
+    case HUNK_DREL8:
+      for (;;) {
+	/* read offsets count */
+	if (!get_long (abfd, &no))
+	  return FALSE;
+	if (!no)
+	  break;
+	/* skip hunk+offsets */
+	if (bfd_seek (abfd, (no+1)<<2, SEEK_CUR))
+	  return FALSE;
+      }
+      break;
+    case HUNK_EXT:
+      defsym_pos = 0;
+      if (!get_long (abfd, &n))
+	return FALSE;
+      while (n) {
+	len = n & 0xffffff;
+	type = (n>>24) & 0xff;
+	switch (type) {
+	case EXT_SYMB:
+	case EXT_DEF:
+	case EXT_ABS:
+	  /* retain the positions of defined symbols for each object
+	     in the archive. They'll be used later to build a
+	     pseudo-armap, which _bfd_generic_link_add_archive_symbols
+	     needs */
+	  if (defsym_pos==0)
+	    defsym_pos = bfd_tell (abfd) - 4;
+	  /* skip name & value */
+	  if (bfd_seek (abfd, (len+1)<<2, SEEK_CUR))
+	    return FALSE;
+	  defsymcount++;
+	  break;
+
+	case EXT_ABSREF32:
+	case EXT_RELREF16:
+	case EXT_RELREF8:
+	case EXT_DEXT32:
+	case EXT_DEXT16:
+	case EXT_DEXT8:
+	case EXT_RELREF32:
+	case EXT_RELREF26:
+	  /* skip name */
+	  if (bfd_seek (abfd, len<<2, SEEK_CUR))
+	    return FALSE;
+	  /* skip references */
+	  if (!get_long (abfd, &no))
+	    return FALSE;
+	  if (no && bfd_seek (abfd, no<<2, SEEK_CUR))
+	    return FALSE;
+	  break;
+
+	case EXT_ABSCOMMON:
+	case EXT_DEXT32COMMON:
+	case EXT_DEXT16COMMON:
+	case EXT_DEXT8COMMON:
+	  /* skip name & value */
+	  if (bfd_seek (abfd, (len+1)<<2, SEEK_CUR))
+	    return FALSE;
+	  /* skip references */
+	  if (!get_long (abfd, &no))
+	    return FALSE;
+	  if (no && bfd_seek (abfd, no<<2, SEEK_CUR))
+	    return FALSE;
+	  break;
+
+	default: /* error */
+	  bfd_msg ("unexpected type %ld(0x%lx) in hunk_ext1 at offset 0x%lx",
+		   type, type, bfd_tell (abfd));
+	  return FALSE;
+	}
+
+	if (!get_long (abfd, &n))
+	  return FALSE;
+      }
+      if (defsym_pos != 0 && syms) {
+	/* there are some defined symbols, keep enough information on
+	   them to simulate an armap later on */
+	nsyms = (struct arch_syms *) bfd_alloc (abfd, sizeof (struct arch_syms));
+	nsyms->next = NULL;
+	if (syms_tail)
+	  syms_tail->next = nsyms;
+	else
+	  *syms = nsyms;
+	syms_tail = nsyms;
+	nsyms->offset = defsym_pos;
+	nsyms->size = bfd_tell (abfd) - defsym_pos;
+	nsyms->unit_offset = unit_offset;
+      }
+      break; /* of HUNK_EXT */
+
+    default:
+#if 0
+      bfd_msg ("unexpected hunk 0x%lx at offset 0x%lx",
+	       hunk_type, bfd_tell (abfd));
+#endif
+      return FALSE;
+    }
+  }
+  if (syms && symcount)
+    *symcount = defsymcount;
+  return (bfd_tell (abfd) == filesize);
+}
+
+static bfd_boolean
+amiga_digest_file (abfd)
+     bfd *abfd;
+{
+  struct stat stat_buffer;
+  unsigned long tmp;
+
+  if (!get_long (abfd, &tmp))
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+
+  switch (HUNK_VALUE (tmp))
+    {
+    case HUNK_UNIT:
+      /* Read the unit(s) */
+      if (bfd_stat (abfd, &stat_buffer) < 0)
+	return FALSE;
+/*
+      while ((pos=bfd_tell (abfd)) < stat_buffer.st_size)
+	{*/
+      if (!amiga_read_unit (abfd, stat_buffer.st_size - abfd->origin))
+	return FALSE;
+      if (abfd->arelt_data)
+	arelt_size (abfd) = bfd_tell (abfd);
+/*	}*/
+      break;
+
+    case HUNK_HEADER:
+      /* This is a load file */
+      if (!amiga_read_load (abfd))
+	return FALSE;
+      break;
+    }
+
+  return TRUE;
+}/* of amiga_digest_file */
+
+
+/* Read in Unit file */
+/* file pointer is located after the HUNK_UNIT LW */
+static bfd_boolean
+amiga_read_unit (abfd, size)
+     bfd *abfd;
+     unsigned long size;
+{
+  unsigned long hunk_number=0,hunk_type,tmp;
+
+  /* read LW length of unit's name */
+  if (!get_long (abfd, &tmp))
+    return FALSE;
+
+  /* and skip it (FIXME maybe) */
+  if (bfd_seek (abfd, tmp<<2, SEEK_CUR))
+    return FALSE;
+
+  while (bfd_tell (abfd) < size)
+    {
+      if (!get_long (abfd, &tmp))
+	return FALSE;
+
+      /* Now there may be CODE, DATA, BSS, SYMBOL, DEBUG, RELOC Hunks */
+      hunk_type = HUNK_VALUE (tmp);
+      switch (hunk_type)
+	{
+	case HUNK_UNIT:
+	  /* next unit, seek back and return */
+	  return (bfd_seek (abfd, -4, SEEK_CUR) == 0);
+
+	case HUNK_DEBUG:
+	  /* we don't parse hunk_debug at the moment */
+	  if (!get_long (abfd, &tmp) || bfd_seek (abfd, tmp<<2, SEEK_CUR))
+	    return FALSE;
+	  break;
+
+	case HUNK_NAME:
+	case HUNK_CODE:
+	case HUNK_DATA:
+	case HUNK_BSS:
+	case HUNK_PPC_CODE:
+	  /* Handle this hunk, including relocs, etc.
+	     The finishing HUNK_END is consumed by the routine */
+	  if (!amiga_handle_cdb_hunk (abfd, hunk_type, hunk_number++, 0, -1))
+	    return FALSE;
+	  break;
+
+	default:
+	  /* Something very nasty happened: invalid hunk occured... */
+	  bfd_set_error (bfd_error_wrong_format);
+	  return FALSE;
+	  break;
+	}/* Of switch hunk_type */
+
+      /* Next hunk */
+    }
+  return TRUE;
+}
+
+
+/* Read a load file */
+static bfd_boolean
+amiga_read_load (abfd)
+     bfd *abfd;
+{
+  unsigned long max_hunk_number,hunk_type,tmp,i;
+  unsigned long *hunk_attributes,*hunk_sizes;
+  char buf[16];
+
+  /* Read hunk lengths (and memory attributes...) */
+  /* Read in each hunk */
+
+  if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf))
+    return FALSE;
+
+  /* If there are resident libs: abort (obsolete feature) */
+  if (GL (&buf[0]) != 0)
+    return FALSE;
+
+  max_hunk_number = GL (&buf[4]);
+
+  /* Sanity */
+  if (max_hunk_number<1)
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+
+  AMIGA_DATA(abfd)->nb_hunks = max_hunk_number;
+
+  /* Num of root hunk must be 0 */
+  if (GL (&buf[8]) != 0)
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+
+  /* Num of last hunk must be mhn-1 */
+  if (GL (&buf[12]) != max_hunk_number-1)
+    {
+      bfd_msg ("Overlay loadfiles are not supported");
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+
+  hunk_sizes = alloca (max_hunk_number * sizeof (unsigned long));
+  hunk_attributes = alloca (max_hunk_number * sizeof (unsigned long));
+  if (hunk_sizes == NULL || hunk_attributes == NULL)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return FALSE;
+    }
+
+  /* Now, read in sizes and memory attributes */
+  for (i=0; i<max_hunk_number; i++)
+    {
+      if (!get_long (abfd, &hunk_sizes[i]))
+	return FALSE;
+      switch (HUNK_ATTRIBUTE (hunk_sizes[i]))
+	{
+	case HUNK_ATTR_CHIP:
+	  hunk_attributes[i] = MEMF_CHIP;
+	  break;
+	case HUNK_ATTR_FAST:
+	  hunk_attributes[i] = MEMF_FAST;
+	  break;
+	case HUNK_ATTR_FOLLOWS:
+	  if (!get_long (abfd, &hunk_attributes[i]))
+	    return FALSE;
+	  break;
+	default:
+	  hunk_attributes[i] = 0;
+	  break;
+	}
+      hunk_sizes[i] = HUNK_VALUE (hunk_sizes[i]) << 2;
+    }
+
+  for (i=0; i<max_hunk_number; i++)
+    {
+      if (!get_long (abfd, &tmp))
+	return FALSE;
+
+      /* This may be HUNK_NAME, CODE, DATA, BSS, DEBUG */
+      hunk_type = HUNK_VALUE (tmp);
+      switch (hunk_type)
+	{
+	case HUNK_NAME:
+	case HUNK_CODE:
+	case HUNK_DATA:
+	case HUNK_BSS:
+	case HUNK_PPC_CODE:
+	  if (!amiga_handle_cdb_hunk (abfd, hunk_type, i,
+				      hunk_attributes[i], hunk_sizes[i]))
+	    {
+	      bfd_set_error (bfd_error_wrong_format);
+	      return FALSE;
+	    }
+	  break;
+
+	case HUNK_DEBUG:
+	  if (--i,!amiga_handle_cdb_hunk (abfd, hunk_type, -1, 0, 0))
+	    {
+	      bfd_set_error (bfd_error_wrong_format);
+	      return FALSE;
+	    }
+	  break;
+
+	default:
+	  /* invalid hunk */
+	  bfd_set_error (bfd_error_wrong_format);
+	  return FALSE;
+	  break;
+	}/* Of switch */
+    }
+
+  return TRUE;
+}/* Of amiga_read_load */
+
+
+/* Handle NAME, CODE, DATA, BSS, DEBUG Hunks */
+static bfd_boolean
+amiga_handle_cdb_hunk (abfd, hunk_type, hunk_number, hunk_attribute,
+		       hunk_size)
+     bfd *abfd;
+     unsigned long hunk_type;
+     unsigned long hunk_number;
+     unsigned long hunk_attribute;
+     unsigned long hunk_size;
+/* If hunk_size==-1, then we are digesting a HUNK_UNIT */
+{
+  sec_ptr current_section;
+  char *sec_name,*current_name=NULL;
+  unsigned long len,tmp;
+  int secflags,is_load=(hunk_size!=(unsigned long)-1);
+
+  if (hunk_type==HUNK_NAME) /* get name */
+    {
+      if (!get_long (abfd, &tmp))
+	return FALSE;
+
+      len = HUNK_VALUE (tmp) << 2;
+      if (len != 0)
+	{
+	  current_name = bfd_alloc (abfd, len+1);
+	  if (!current_name)
+	    return FALSE;
+
+	  if (bfd_bread (current_name, len, abfd) != len)
+	    return FALSE;
+
+	  current_name[len] = '\0';
+	  if (current_name[0] == '\0')
+	    {
+	       bfd_release (abfd, current_name);
+	       current_name = NULL;
+	    }
+	}
+
+      if (!get_long (abfd, &hunk_type))
+	return FALSE;
+    }
+
+  /* file_pointer is now after hunk_type */
+  secflags = 0;
+  switch (hunk_type)
+    {
+    case HUNK_CODE:
+    case HUNK_PPC_CODE:
+      secflags = SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS;
+      sec_name = ".text";
+      goto do_section;
+
+    case HUNK_DATA:
+      secflags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS;
+      sec_name = ".data";
+      goto do_section;
+
+    case HUNK_BSS:
+      secflags = SEC_ALLOC;
+      sec_name = ".bss";
+
+    do_section:
+      if (!current_name)
+	current_name = sec_name;
+      if (!get_long (abfd, &tmp))
+	return FALSE;
+      len = HUNK_VALUE (tmp) << 2; /* Length of section */
+      if (!is_load)
+	{
+	  hunk_attribute=HUNK_ATTRIBUTE (len);
+	  hunk_attribute=(hunk_attribute==HUNK_ATTR_CHIP)?MEMF_CHIP:
+			 (hunk_attribute==HUNK_ATTR_FAST)?MEMF_FAST:0;
+	}
+
+      /* Make new section */
+      current_section = amiga_make_unique_section (abfd, current_name);
+      if (!current_section)
+	return FALSE;
+
+      current_section->filepos = bfd_tell (abfd);
+      /* For a loadfile, the section size in memory comes from the
+	 hunk header. The size on disk may be smaller. */
+      current_section->_cooked_size = current_section->_raw_size =
+	((hunk_size==(unsigned long)-1) ? len : hunk_size);
+      current_section->target_index = hunk_number;
+      bfd_set_section_flags (abfd, current_section, secflags);
+
+      amiga_per_section(current_section)->disk_size = len; /* size on disk */
+      amiga_per_section(current_section)->attribute = hunk_attribute;
+
+      /* skip the contents */
+      if ((secflags & SEC_HAS_CONTENTS) && bfd_seek (abfd, len, SEEK_CUR))
+	return FALSE;
+
+      if (!amiga_handle_rest (abfd, current_section, is_load))
+	return FALSE;
+      break;
+
+      /* Currently, there is one debug hunk per executable, instead of one
+	 per unit as it would with a "standard" AmigaOS implementation. So
+	 the debug hunk is at the same level as code/data/bss.
+	 This will change in the future */
+    case HUNK_DEBUG:
+      /* format of gnu debug hunk is:
+	  HUNK_DEBUG
+	      N
+	    ZMAGIC
+	  symtabsize
+	  strtabsize
+	  symtabdata  [length=symtabsize]
+	  strtabdata  [length=strtabsize]
+	  [pad bytes]
+	  */
+
+      /* read LW length */
+      if (!get_long (abfd, &tmp))
+	return FALSE;
+      len = tmp << 2;
+      if (len > 12)
+	{
+	  char buf[12];
+	  if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf))
+	    return FALSE;
+	  if (GL (&buf[0]) == ZMAGIC) /* GNU DEBUG HUNK */
+	    {
+	      amiga_data_type *amiga_data=AMIGA_DATA(abfd);
+	      /* FIXME: we should add the symbols in the debug hunk to symtab... */
+	      amiga_data->symtab_size = GL (&buf[4]);
+	      amiga_data->stringtab_size = GL (&buf[8]);
+	      adata(abfd).sym_filepos = bfd_tell (abfd);
+	      adata(abfd).str_filepos = adata(abfd).sym_filepos +
+		amiga_data->symtab_size;
+	    }
+	  len -= sizeof(buf);
+	}
+      if (bfd_seek (abfd, len, SEEK_CUR))
+	return FALSE;
+      break;
+
+    default:
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+      break;
+    }/* switch (hunk_type) */
+
+  return TRUE;
+}/* Of amiga_handle_cdb_hunk */
+
+
+/* Handle rest of a hunk
+   I.e.: Relocs, EXT, SYMBOLS... */
+static bfd_boolean
+amiga_handle_rest (abfd, current_section, isload)
+     bfd *abfd;
+     sec_ptr current_section;
+     bfd_boolean isload;
+{
+  amiga_per_section_type *asect=amiga_per_section(current_section);
+  unsigned long hunk_type,relno,type,len,no;
+  raw_reloc_type *relp;
+
+  for (relno=0;;)
+    {
+      if (!get_long (abfd, &hunk_type))
+	return FALSE;
+      switch (hunk_type)
+	{
+	case HUNK_END:
+	  if (relno)
+	    {
+	      abfd->flags |= HAS_RELOC;
+	      current_section->flags |= SEC_RELOC;
+	      current_section->reloc_count = relno;
+	    }
+	  return TRUE;
+	  break;
+
+	case HUNK_DREL32:
+	  if (isload)
+	    hunk_type = HUNK_RELOC32SHORT;
+	case HUNK_ABSRELOC32:
+	case HUNK_RELRELOC16:
+	case HUNK_RELRELOC8:
+	case HUNK_DREL16:
+	case HUNK_DREL8:
+	case HUNK_RELOC32SHORT:
+	  /* count and skip relocs */
+	  relp = (raw_reloc_type *) bfd_alloc (abfd, sizeof (*relp));
+	  relp->next = asect->relocs;
+	  asect->relocs = relp;
+	  relp->pos = bfd_tell (abfd) - 4;
+	  relp->num = 0;
+	  if (hunk_type != HUNK_RELOC32SHORT) {
+	    for (;;) {
+	      if (!get_long (abfd, &no))
+		return FALSE;
+	      if (!no)
+		break;
+	      relp->num += no;
+	      if (bfd_seek (abfd, (no+1)<<2, SEEK_CUR))
+		return FALSE;
+	    }
+	  }
+	  else {
+	    for (;;) {
+	      char buf[2];
+	      if (bfd_bread (buf, 2, abfd) != 2)
+		return FALSE;
+	      if (no=GW(buf),!no)
+		break;
+	      relp->num += no;
+	      if (bfd_seek (abfd, (no+1)<<1, SEEK_CUR))
+		return FALSE;
+	    }
+	    if ((bfd_tell (abfd) & 2) && bfd_seek (abfd, 2, SEEK_CUR))
+	      return FALSE;
+	  }
+	  relno += relp->num;
+	  break;
+
+	case HUNK_SYMBOL:
+	  /* In a unit, we ignore these, since all symbol information
+	     comes with HUNK_EXT, in a load file, these are added */
+	  if (!isload)
+	    {
+	      asect->hunk_symbol_pos = bfd_tell (abfd);
+	      for (;;) {
+		/* size of symbol */
+		if (!get_long (abfd, &no))
+		  return FALSE;
+		if (!no)
+		  break;
+		/* skip the name */
+		if (bfd_seek (abfd, (no+1)<<2, SEEK_CUR))
+		  return FALSE;
+	      }
+	      break;
+	    }
+	  /* We add these, by falling through... */
+
+	case HUNK_EXT:
+	  /* We leave these alone, until they are requested by the user */
+	  asect->hunk_ext_pos = bfd_tell (abfd);
+	  for (;;)
+	    {
+	      if (!get_long (abfd, &no))
+	        return FALSE;
+	      if (!no)
+	        break;
+
+	      /* symbol type and length */
+	      type = (no>>24) & 0xff;
+	      len = no & 0xffffff;
+
+	      /* skip symbol name */
+	      if (bfd_seek (abfd, len<<2, SEEK_CUR))
+		return FALSE;
+
+	      /* We have symbols */
+	      abfd->flags |= HAS_SYMS;
+	      abfd->symcount++;
+
+	      switch (type)
+		{
+		case EXT_SYMB: /* Symbol hunks are relative to hunk start... */
+		case EXT_DEF: /* def relative to hunk */
+		case EXT_ABS: /* def absolute */
+		  /* skip the value */
+		  if (!get_long (abfd, &no))
+		    return FALSE;
+		  break;
+
+		case EXT_ABSCOMMON: /* Common ref/def */
+		case EXT_DEXT32COMMON:
+		case EXT_DEXT16COMMON:
+		case EXT_DEXT8COMMON:
+		  /* FIXME: skip the size of common block */
+		  if (!get_long (abfd, &no))
+		    return FALSE;
+
+		  /* Fall through */
+
+		case EXT_ABSREF32: /* 32 bit ref */
+		case EXT_RELREF16: /* 16 bit ref */
+		case EXT_RELREF8: /* 8 bit ref */
+		case EXT_DEXT32: /* 32 bit baserel */
+		case EXT_DEXT16: /* 16 bit baserel */
+		case EXT_DEXT8: /* 8 bit baserel */
+		case EXT_RELREF32:
+		case EXT_RELREF26:
+		  if (!get_long (abfd, &no))
+		    return FALSE;
+		  if (no)
+		    {
+		      relno += no;
+		      /* skip references */
+		      if (bfd_seek (abfd, no<<2, SEEK_CUR))
+			return FALSE;
+		    }
+		  break;
+
+		default: /* error */
+		  bfd_msg ("unexpected type %ld(0x%lx) in hunk_ext2 at offset 0x%lx",
+			   type, type, bfd_tell (abfd));
+		  bfd_set_error (bfd_error_wrong_format);
+		  return FALSE;
+		  break;
+		}/* of switch type */
+	    }
+	  break;
+
+	case HUNK_DEBUG:
+	  /* If a debug hunk is found at this position, the file has
+	     been generated by a third party tool and the debug info
+	     here are useless to us. Just skip the hunk, then. */
+	  if (!get_long (abfd, &no) || bfd_seek (abfd, no<<2, SEEK_CUR))
+	    return FALSE;
+	  break;
+
+	default: /* error */
+	  bfd_seek (abfd, -4, SEEK_CUR);
+	  bfd_msg ("missing HUNK_END: unexpected hunktype %ld(0x%lx) at offset 0x%lx",
+		   hunk_type, hunk_type, bfd_tell (abfd));
+	  hunk_type = HUNK_VALUE(hunk_type);
+	  if (hunk_type == HUNK_CODE || hunk_type == HUNK_DATA || hunk_type == HUNK_BSS)
+	    return TRUE;
+	  bfd_set_error (bfd_error_wrong_format);
+	  return FALSE;
+	  break;
+	}/* Of switch */
+    }/* Of for */
+  return TRUE;
+}/* of amiga_handle_rest */
+
+static bfd_boolean
+amiga_mkobject (abfd)
+     bfd *abfd;
+{
+  amiga_data_type *rawptr;
+  rawptr = (amiga_data_type *) bfd_zalloc (abfd, sizeof (*rawptr));
+  abfd->tdata.amiga_data = rawptr;
+  return (rawptr!=NULL);
+}
+
+static bfd_boolean
+amiga_mkarchive (abfd)
+     bfd *abfd;
+{
+  amiga_ardata_type *ar;
+  ar = (amiga_ardata_type *) bfd_zalloc (abfd, sizeof (*ar));
+  amiga_ardata (abfd) = ar;
+  return (ar!=NULL);
+}
+
+/* write nb long words (possibly swapped out) to the output file */
+static bfd_boolean
+write_longs (in, nb, abfd)
+     const unsigned long *in;
+     unsigned long nb;
+     bfd *abfd;
+{
+  unsigned char out[10*4];
+  unsigned long i;
+
+  while (nb)
+    {
+      for (i=0; i<nb && i<10; in++,i++)
+        bfd_putb32 (in[0], &out[i*4]);
+      if (bfd_bwrite ((PTR)out, 4*i, abfd) != 4*i)
+	return FALSE;
+      nb -= i;
+    }
+  return TRUE;
+}
+
+static long
+determine_datadata_relocs (abfd, section)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     sec_ptr section;
+{
+  sec_ptr insection;
+  asymbol *sym_p;
+  unsigned int i;
+  long relocs=1;
+
+  for (i=0;i<section->reloc_count;i++)
+    {
+      arelent *r=section->orelocation[i];
+      if (r == NULL)
+	continue;
+      sym_p=*(r->sym_ptr_ptr); /* The symbol for this relocation */
+      insection=sym_p->section;
+
+      /* Is reloc relative to a special section? */
+      if (bfd_is_bfd_section(insection))
+	continue; /* Nothing to do, since this translates to HUNK_EXT */
+      if (insection->output_section == section)
+	relocs++;
+    }
+  return relocs;
+}
+
+/* Adjust the indices map when we decide not to output the section <sec> */
+static void
+remove_section_index (sec, index_map)
+     sec_ptr sec;
+     int *index_map;
+{
+  int i=sec->index;
+  for (sec=sec->next,index_map[i++]=-1; sec; sec=sec->next)
+    (index_map[i++])--;
+}
+
+/* Write out the contents of a bfd */
+static bfd_boolean
+amiga_write_object_contents (abfd)
+     bfd *abfd;
+{
+  long datadata_relocs=0,bss_size=0,idx;
+  int *index_map,max_hunk=-1;
+  sec_ptr data_sec,p;
+  unsigned long i,n[5];
+
+  /* Distinguish UNITS, LOAD Files
+    Write out hunks+relocs+HUNK_EXT+HUNK_DEBUG (GNU format) */
+  DPRINT(5,("Entering write_object_conts\n"));
+
+  abfd->output_has_begun=TRUE; /* Output has begun */
+
+  index_map = bfd_alloc (abfd, abfd->section_count * sizeof (int));
+  if (!index_map)
+    return FALSE;
+
+  for (idx=0, p=abfd->sections; p!=NULL; p=p->next)
+    index_map[idx++] = p->index;
+
+  /* Distinguish Load files and Unit files */
+  if (AMIGA_DATA(abfd)->IsLoadFile)
+    {
+      DPRINT(5,("Writing load file\n"));
+
+      if (amiga_base_relative)
+	BFD_ASSERT (abfd->section_count==3);
+
+      /* Write out load file header */
+      n[0] = HUNK_HEADER;
+      n[1] = n[2] = 0;
+      for (p=abfd->sections; p!=NULL; p=p->next) {
+	/* For baserel linking, don't remove empty sections, since they
+	   may get some contents later on */
+	if ((amiga_base_relative || p->_raw_size!=0 || p->_cooked_size!=0) &&
+	    !(amiga_base_relative && !strcmp (p->name, ".bss")))
+	  n[2]++;
+	else
+	  remove_section_index (p, index_map);
+      }
+      n[3] = 0;
+      n[4] = n[2]-1;
+      if (!write_longs (n, 5, abfd))
+	return FALSE;
+
+      /* Write out sizes and memory specifiers... */
+      /* We have to traverse the section list again, bad but no other way... */
+      if (amiga_base_relative) {
+	for (p=abfd->sections; p!=NULL; p=p->next)
+	  {
+	    if (amiga_resident && !strcmp(p->name,".data"))
+	      {
+		datadata_relocs = determine_datadata_relocs (abfd, p);
+		data_sec = p;
+	      }
+	    else if (!strcmp(p->name,".bss"))
+	      {
+		/* Get size for header */
+		bss_size = p->_raw_size;
+	      }
+	  }
+      }
+
+      for (p=abfd->sections; p!=NULL; p=p->next)
+	{
+	  long extra = 0, i;
+
+	  if (index_map[p->index] < 0)
+	    continue;
+
+	  if (datadata_relocs && !strcmp(p->name,".text"))
+	    extra = datadata_relocs * 4;
+	  else if (bss_size && !strcmp (p->name, ".data"))
+	    extra = bss_size;
+	  /* convert to a size in long words */
+	  n[0] = LONGSIZE (p->_raw_size + extra);
+
+	  i = amiga_per_section(p)->attribute;
+	  switch (i)
+	    {
+	    case MEMF_CHIP:
+	      n[0]|=HUNKF_CHIP;
+	      i=1;
+	      break;
+	    case MEMF_FAST:
+	      n[0]|=HUNKF_FAST;
+	      i=1;
+	      break;
+	    case 0: /* nothing */
+	      i=1;
+	      break;
+	    default: /* special one */
+	      n[0]|=0xc0000000;
+	      n[1]=i;
+	      i=2;
+	      break;
+	    }/* Of switch */
+
+	  if (!write_longs (n, i, abfd))
+	    return FALSE;
+	}/* Of for */
+    }
+  else
+    { /* Unit, no base-relative linking here.. */
+      DPRINT(5,("Writing unit\n"));
+
+      /* Write out unit header */
+      n[0]=HUNK_UNIT;
+      if (!write_longs (n, 1, abfd) || !write_name (abfd, abfd->filename, 0))
+	return FALSE;
+
+      for (i=0;i<bfd_get_symcount (abfd);i++) {
+	asymbol *sym_p=abfd->outsymbols[i];
+	sec_ptr osection=sym_p->section;
+	if (!osection || !bfd_is_com_section(osection->output_section))
+	  continue;
+	for (p=abfd->sections; p!=NULL; p=p->next) {
+	  if (!strcmp(p->name, ".bss")) {
+	    if (!p->_raw_size && !p->_cooked_size)
+	      p->_cooked_size = sym_p->value;
+	    break;
+	  }
+	}
+	break;
+      }
+
+      for (p=abfd->sections; p!=NULL; p=p->next) {
+	if (p->_raw_size==0 && p->_cooked_size==0)
+	  remove_section_index (p, index_map);
+      }
+    }
+
+  /* Compute the maximum hunk number of the ouput file */
+  for (p=abfd->sections; p!=NULL; p=p->next)
+    max_hunk++;
+
+  /* Write out every section */
+  for (p=abfd->sections; p!=NULL; p=p->next)
+    {
+      if (index_map[p->index] < 0)
+	continue;
+
+#define ddrels (datadata_relocs&&!strcmp(p->name,".text")?datadata_relocs:0)
+      if (!amiga_write_section_contents (abfd,p,data_sec,ddrels,index_map,
+					 max_hunk))
+	return FALSE;
+
+      if (!amiga_write_symbols (abfd,p)) /* Write out symbols + HUNK_END */
+	return FALSE;
+    }/* of for sections */
+
+  /* Write out debug hunk, if requested */
+  if (AMIGA_DATA(abfd)->IsLoadFile && write_debug_hunk)
+    {
+      extern bfd_boolean
+	translate_to_native_sym_flags (bfd*, asymbol*, struct external_nlist*);
+
+      unsigned int offset = 4, symbols = 0, i;
+      unsigned long str_size = 4; /* the first 4 bytes will be replaced with the length */
+      asymbol *sym;
+      sec_ptr s;
+
+      /* We have to convert all the symbols in abfd to a.out style... */
+      if (bfd_get_symcount (abfd))
+	{
+#define CAN_WRITE_OUTSYM(sym) (sym!=NULL && sym->section && \
+				((sym->section->owner && \
+				 bfd_get_flavour (sym->section->owner) == \
+				 bfd_target_aout_flavour) || \
+				 bfd_asymbol_flavour (sym) == \
+				 bfd_target_aout_flavour))
+
+	  for (i = 0; i < bfd_get_symcount (abfd); i++)
+	    {
+	      sym = abfd->outsymbols[i];
+	      /* NULL entries have been written already... */
+	      if (CAN_WRITE_OUTSYM (sym))
+	        {
+		  str_size += strlen(sym->name) + 1;
+		  symbols++;
+		}
+	    }
+
+	  if (!symbols)
+	    return TRUE;
+
+	  /* Now, set the .text, .data and .bss fields in the tdata struct
+	     because translate_to_native_sym_flags needs them... */
+	  for (i=0,s=abfd->sections;s!=NULL;s=s->next)
+	    if (!strcmp(s->name,".text"))
+	      {
+		i|=1;
+		adata(abfd).textsec=s;
+	      }
+	    else if (!strcmp(s->name,".data"))
+	      {
+	        i|=2;
+	        adata(abfd).datasec=s;
+	      }
+	    else if (!strcmp(s->name,".bss"))
+	      {
+	        i|=4;
+	        adata(abfd).bsssec=s;
+	      }
+
+	  if (i!=7) /* section(s) missing... */
+	    {
+	      bfd_msg ("Missing section, debughunk not written");
+	      return TRUE;
+	    }
+
+	  /* Write out HUNK_DEBUG, size, ZMAGIC, ... */
+	  n[0] = HUNK_DEBUG;
+	  n[1] = 3 + ((symbols * sizeof(struct internal_nlist) + str_size + 3) >> 2);
+	  n[2] = ZMAGIC; /* Magic number */
+	  n[3] = symbols * sizeof(struct internal_nlist);
+	  n[4] = str_size;
+	  if (!write_longs (n, 5, abfd))
+	    return FALSE;
+
+	  /* Write out symbols */
+	  for (i = 0; i < bfd_get_symcount (abfd); i++) /* Translate every symbol */
+	    {
+	      sym = abfd->outsymbols[i];
+	      if (CAN_WRITE_OUTSYM (sym))
+		{
+		  amiga_symbol_type *t = (amiga_symbol_type *) sym;
+		  struct external_nlist data;
+
+		  bfd_h_put_16(abfd, t->desc, data.e_desc);
+		  bfd_h_put_8(abfd, t->other, data.e_other);
+		  bfd_h_put_8(abfd, t->type, data.e_type);
+		  if (!translate_to_native_sym_flags(abfd,sym,&data))
+		    {
+		      bfd_msg ("Cannot translate flags for %s", sym->name);
+		    }
+		  bfd_h_put_32(abfd, offset, &data.e_strx[0]); /* Store index */
+		  offset += strlen(sym->name) + 1;
+		  if (bfd_bwrite ((PTR)&data, sizeof(data), abfd)
+		      != sizeof(data))
+		    return FALSE;
+		}
+	    }
+
+	  /* Write out strings */
+	  if (!write_longs (&str_size, 1, abfd))
+	    return FALSE;
+
+	  for (i = 0; i < bfd_get_symcount (abfd); i++)
+	    {
+	      sym = abfd->outsymbols[i];
+	      if (CAN_WRITE_OUTSYM (sym))
+		{
+		  size_t len = strlen(sym->name) + 1;
+
+	          /* Write string tab */
+	          if (bfd_bwrite (sym->name, len, abfd) != len)
+	            return FALSE;
+		}
+	    }
+
+	  /* Write padding */
+	  n[0] = 0;
+	  i = (4 - (str_size & 3)) & 3;
+	  if (i && bfd_bwrite ((PTR)n, i, abfd) != i)
+	    return FALSE;
+
+	  /* write a HUNK_END here to finish the loadfile, or AmigaOS
+	     will refuse to load it */
+	  n[0] = HUNK_END;
+	  if (!write_longs (n, 1, abfd))
+	    return FALSE;
+	}/* Of if bfd_get_symcount (abfd) */
+    }/* Of write out debug hunk */
+
+  bfd_release (abfd, index_map);
+  return TRUE;
+}
+
+/* Write a string padded to 4 bytes and preceded by it's length in
+   long words ORed with <value> */
+static bfd_boolean
+write_name (abfd, name, value)
+     bfd *abfd;
+     const char *name;
+     unsigned long value;
+{
+  unsigned long n[1];
+  size_t l;
+
+  l = strlen (name);
+  if (AMIGA_DATA(abfd)->IsLoadFile && l > MAX_NAME_SIZE)
+    l = MAX_NAME_SIZE;
+  n[0] = (LONGSIZE (l) | value);
+  if (!write_longs (n, 1, abfd))
+    return FALSE;
+  if (bfd_bwrite (name, l, abfd) != l)
+    return FALSE;
+  n[0] = 0;
+  l = (4 - (l & 3)) & 3;
+  return (l && bfd_bwrite ((PTR)n, l, abfd) != l ? FALSE : TRUE);
+}
+
+static bfd_boolean
+amiga_write_archive_contents (arch)
+     bfd *arch;
+{
+  struct stat status;
+  bfd *object;
+
+  for (object = arch->archive_head; object; object = object->next)
+    {
+      unsigned long remaining;
+
+      if (bfd_write_p (object))
+	{
+	  bfd_set_error (bfd_error_invalid_operation);
+	  return FALSE;
+	}
+
+      if (object->arelt_data != NULL)
+	{
+	  remaining = arelt_size (object);
+	}
+      else
+	{
+	  if (stat (object->filename, &status) != 0)
+	    {
+	      bfd_set_error (bfd_error_system_call);
+	      return FALSE;
+	    }
+	  remaining = status.st_size;
+	}
+
+      if (bfd_seek (object, 0, SEEK_SET))
+	return FALSE;
+
+      while (remaining)
+	{
+	  char buf[DEFAULT_BUFFERSIZE];
+	  unsigned long amt = sizeof(buf);
+	  if (amt > remaining)
+	    amt = remaining;
+	  errno = 0;
+	  if (bfd_bread (buf, amt, object) != amt)
+	    {
+	      if (bfd_get_error () != bfd_error_system_call)
+		bfd_set_error (bfd_error_malformed_archive);
+	      return FALSE;
+	    }
+	  if (bfd_bwrite (buf, amt, arch) != amt)
+	    return FALSE;
+	  remaining -= amt;
+	}
+    }
+  return TRUE;
+}
+
+static bfd_boolean
+amiga_write_armap (arch, elength, map, orl_count, stridx)
+     bfd *arch ATTRIBUTE_UNUSED;
+     unsigned int elength ATTRIBUTE_UNUSED;
+     struct orl *map ATTRIBUTE_UNUSED;
+     unsigned int orl_count ATTRIBUTE_UNUSED;
+     int stridx ATTRIBUTE_UNUSED;
+{
+  return TRUE;
+}
+
+static int
+determine_type (r)
+     arelent *r;
+{
+  switch (r->howto->type)
+    {
+      case H_ABS8: /* 8 bit absolute */
+      case H_PC8:  /* 8 bit pcrel */
+	return 2;
+
+      case H_ABS16: /* 16 bit absolute */
+      case H_PC16:  /* 16 bit pcrel */
+	return 1;
+
+      case H_ABS32: /* 32 bit absolute */
+    /*case H_PC32:*//* 32 bit pcrel */
+	return 0;
+
+      case H_SD8: /* 8 bit base rel */
+	return 5;
+
+      case H_SD16: /* 16 bit base rel */
+	return 4;
+
+      case H_SD32: /* 32 bit baserel */
+	return 3;
+
+      default: /* Error, can't represent this */
+	bfd_set_error (bfd_error_nonrepresentable_section);
+	return -1;
+    }/* Of switch */
+}
+
+#define NB_RELOC_TYPES 6
+static const unsigned long reloc_types[NB_RELOC_TYPES] = {
+  HUNK_ABSRELOC32, HUNK_RELRELOC16, HUNK_RELRELOC8,
+  HUNK_DREL32,     HUNK_DREL16,     HUNK_DREL8
+};
+
+/* Write out section contents, including relocs */
+static bfd_boolean
+amiga_write_section_contents (abfd, section, data_sec, datadata_relocs,
+			      index_map, max_hunk)
+     bfd *abfd;
+     sec_ptr section;
+     sec_ptr data_sec;
+     unsigned long datadata_relocs;
+     int *index_map;
+     int max_hunk;
+{
+  sec_ptr insection;
+  asymbol *sym_p;
+  arelent *r;
+  unsigned long zero=0,disksize,pad,n[2],k,l,s;
+  long *reloc_counts,reloc_count=0;
+  unsigned char *values;
+  int i,j,x,type;
+
+  DPRINT(5,("Entering write_section_contents\n"));
+
+  /* If we are base-relative linking and the section is .bss and abfd
+     is a load file, then return */
+  if (AMIGA_DATA(abfd)->IsLoadFile)
+    {
+      if (amiga_base_relative && !strcmp(section->name, ".bss"))
+	return TRUE; /* Nothing to do */
+    }
+  else
+    {
+      /* WRITE out HUNK_NAME + section name */
+      n[0] = HUNK_NAME;
+      if (!write_longs (n, 1, abfd) || !write_name (abfd, section->name, 0))
+	return FALSE;
+    }
+
+  /* Depending on the type of the section, write out HUNK_{CODE|DATA|BSS} */
+  if (section->flags & SEC_CODE) /* Code section */
+    n[0] = HUNK_CODE;
+  else if (section->flags & (SEC_DATA | SEC_LOAD)) /* data section */
+    n[0] = HUNK_DATA;
+  else if (section->flags & SEC_ALLOC) /* BSS */
+    n[0] = HUNK_BSS;
+  else if (section->flags & SEC_DEBUGGING) /* debug section */
+    n[0] = HUNK_DEBUG;
+  else /* Error */
+    {
+#if 0
+      bfd_set_error (bfd_error_nonrepresentable_section);
+      return FALSE;
+#else
+      /* FIXME: Just dump everything we don't currently recognize into
+	 a DEBUG hunk. */
+      n[0] = HUNK_DEBUG;
+#endif
+    }
+
+  DPRINT(10,("Section type is %lx\n",n[0]));
+
+  /* Get real size in n[1], this may be shorter than the size in the header */
+  if (amiga_per_section(section)->disk_size == 0)
+    amiga_per_section(section)->disk_size = section->_raw_size;
+  disksize = LONGSIZE (amiga_per_section(section)->disk_size) + datadata_relocs;
+  n[1] = disksize;
+
+  /* in a load file, we put section attributes only in the header */
+  if (!AMIGA_DATA(abfd)->IsLoadFile)
+    {
+      /* Get attribute for section */
+      switch (amiga_per_section(section)->attribute)
+	{
+	case MEMF_CHIP:
+	  n[1] |= HUNKF_CHIP;
+	  break;
+	case MEMF_FAST:
+	  n[1] |= HUNKF_FAST;
+	  break;
+	case 0:
+	  break;
+	default: /* error, can't represent this */
+	  bfd_set_error (bfd_error_nonrepresentable_section);
+	  return FALSE;
+	  break;
+	}
+    }/* Of switch */
+
+  if (!write_longs (n, 2, abfd))
+      return FALSE;
+
+  DPRINT(5,("Wrote code and size=%lx\n",n[1]));
+
+  /* If a BSS hunk, we're done, else write out section contents */
+  if (HUNK_VALUE (n[0]) == HUNK_BSS)
+    return TRUE;
+
+  DPRINT(5,("Non bss hunk...\n"));
+
+  /* Traverse through the relocs, sample them in reloc_data, adjust section
+     data to get 0 addend
+     Then compactify reloc_data
+     Set the entry in the section for the reloc to NULL */
+
+  if (disksize != 0)
+    BFD_ASSERT ((section->flags & SEC_IN_MEMORY) != 0);
+
+  reloc_counts = (long *) bfd_zalloc (abfd, NB_RELOC_TYPES * (max_hunk+1)
+				      * sizeof (long));
+  if (!reloc_counts)
+    return FALSE;
+
+  DPRINT(5,("Section has %d relocs\n",section->reloc_count));
+
+  for (l = 0; l < section->reloc_count; l++)
+    {
+      r = section->orelocation[l];
+      if (r == NULL)
+	continue;
+
+      sym_p = *(r->sym_ptr_ptr); /* The symbol for this relocation */
+      insection = sym_p->section;
+      DPRINT(5,("Sec for reloc is %lx(%s)\n",insection,insection->name));
+      DPRINT(5,("Symbol for this reloc is %lx(%s)\n",sym_p,sym_p->name));
+      /* Is reloc relative to a special section? */
+      if (bfd_is_bfd_section(insection))
+	continue; /* Nothing to do, since this translates to HUNK_EXT */
+
+      r->addend += sym_p->value; /* Add offset of symbol from section start */
+
+      /* Address of reloc has been unchanged since original reloc, or has
+	 been adjusted by get_relocated_section_contents. */
+      /* For relocs, the vma of the target section is in the data, the
+	 addend is -vma of that section =>No need to add vma */
+      /* Add in offset */
+      r->addend += insection->output_offset;
+
+      /* Determine which hunk to write, and index of target */
+      x = index_map[insection->output_section->index];
+      if (x<0 || x>max_hunk) {
+	bfd_msg ("erroneous relocation to hunk %d/%s from %s",
+		 x, insection->output_section->name, insection->name);
+	bfd_set_error (bfd_error_nonrepresentable_section);
+	return FALSE;
+      }
+
+      type = determine_type(r);
+      if (type == -1)
+	return FALSE;
+      if (type >= NB_RELOC_TYPES) {
+	bfd_set_error (bfd_error_nonrepresentable_section);
+	return FALSE;
+      }
+      reloc_counts[type+(x*NB_RELOC_TYPES)]++;
+      reloc_count++;
+
+      /* There is no error checking with these... */
+      DPRINT(5,("reloc address=%lx,addend=%lx\n",r->address,r->addend));
+      values = &section->contents[r->address];
+
+      switch (type)
+	{
+	case 2: case 5: /* adjust byte */
+	  x = ((char *)values)[0] + r->addend;
+	  values[0] = x & 0xff;
+	  break;
+	case 1: case 4: /* adjust word */
+	  k = values[1] | (values[0] << 8);
+	  x = (int)k + r->addend;
+	  values[0] = (x & 0xff00) >> 8;
+	  values[1] = x & 0xff;
+	  break;
+	case 0: case 3: /* adjust long */
+	  k = values[3] | (values[2] << 8) | (values[1] << 16) |
+	    (values[0] << 24);
+	  x = (int)k + r->addend;
+	  values[3] = x & 0xff;
+	  values[2] = (x & 0xff00) >> 8;
+	  values[1] = (x & 0xff0000) >> 16;
+	  values[0] = ((unsigned int)x & 0xff000000) >> 24;
+	  break;
+	}/* of switch */
+
+      r->addend = 0;
+      DPRINT(5,("Did adjusting\n"));
+    }/* of for l */
+
+  DPRINT(5,("Did all relocs\n"));
+
+  /* We applied all the relocs, as far as possible to obtain 0 addend fields */
+  /* Write the section contents */
+  if (amiga_per_section(section)->disk_size != 0)
+    {
+      if (bfd_bwrite ((PTR)section->contents,
+		      amiga_per_section(section)->disk_size, abfd) !=
+	  amiga_per_section(section)->disk_size)
+	return FALSE;
+
+      /* pad the section on disk if necessary (to a long boundary) */
+      pad = (4 - (amiga_per_section(section)->disk_size & 3)) & 3;
+      if (pad && (bfd_bwrite ((PTR)&zero, pad, abfd) != pad))
+	return FALSE;
+    }
+
+#if 0
+  /* write bss data in the data hunk if needed */
+  for (; bss_size--;)
+    if (!write_longs (&zero, 1, abfd))
+      return FALSE;
+#endif
+
+  if (datadata_relocs)
+    {
+      datadata_relocs--;
+      if (!write_longs (&datadata_relocs, 1, abfd))
+	return FALSE;
+      for (s = 0; s < data_sec->reloc_count; s++)
+	{
+	  r = data_sec->orelocation[s];
+	  if (r == NULL)
+	    continue;
+
+	  sym_p = *(r->sym_ptr_ptr); /* The symbol for this relocation */
+	  insection = sym_p->section;
+	  /* Is reloc relative to a special section? */
+	  if (bfd_is_bfd_section(insection))
+	    continue; /* Nothing to do, since this translates to HUNK_EXT */
+
+	  if (insection->output_section == data_sec)
+	    {
+	      if (determine_type(r) == 0)
+		if (!write_longs (&r->address, 1, abfd))
+		  return FALSE;
+	    }
+	}
+    }
+
+  DPRINT(10,("Wrote contents, writing relocs now\n"));
+
+  if (reloc_count > 0) {
+    /* Sample every reloc type */
+    for (i = 0; i < NB_RELOC_TYPES; i++) {
+      int written = FALSE;
+      for (j = 0; j <= max_hunk; j++) {
+	long relocs;
+	while ((relocs = reloc_counts[i+(j*NB_RELOC_TYPES)]) > 0) {
+
+	  if (!written) {
+	    if (!write_longs (&reloc_types[i], 1, abfd))
+	      return FALSE;
+	    written = TRUE;
+	  }
+
+	  if (relocs > 0xffff)
+	    relocs = 0xffff;
+
+	  n[0] = relocs;
+	  n[1] = j;
+	  if (!write_longs (n, 2, abfd))
+	    return FALSE;
+
+	  reloc_counts[i+(j*NB_RELOC_TYPES)] -= relocs;
+	  reloc_count -= relocs;
+
+	  for (k = 0; k < section->reloc_count; k++) {
+	    int jj;
+
+	    r = section->orelocation[k];
+	    if (r == NULL) /* already written */
+	      continue;
+
+	    sym_p = *(r->sym_ptr_ptr); /* The symbol for this relocation */
+	    insection = sym_p->section;
+	    /* Is reloc relative to a special section? */
+	    if (bfd_is_bfd_section(insection))
+	      continue; /* Nothing to do, since this translates to HUNK_EXT */
+#if 0
+	    /* Determine which hunk to write, and index of target */
+	    for (jj = 0, sec = abfd->sections; sec; sec = sec->next, jj++) {
+	      if (sec == insection->output_section)
+		break;
+	    }
+	    BFD_ASSERT (jj==index_map[insection->output_section->index]);
+#else
+	    jj=index_map[insection->output_section->index];
+#endif
+	    if (jj == j && i == determine_type(r)) {
+	      section->orelocation[k] = NULL;
+	      if (!write_longs (&r->address, 1, abfd))
+		return FALSE;
+	      if (--relocs == 0)
+		break;
+	    }
+	  }
+	}
+      }
+      /* write a zero to finish the relocs */
+      if (written && !write_longs (&zero, 1, abfd))
+	return FALSE;
+    }
+  }
+
+  bfd_release (abfd, reloc_counts);
+  DPRINT(5,("Leaving write_section...\n"));
+  if (reloc_count > 0) {
+    bfd_set_error (bfd_error_nonrepresentable_section);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+
+/* Write out symbol information, including HUNK_EXT, DEFS, ABS.
+   In the case, we were linking base relative, the symbols of the .bss
+   hunk have been converted already to belong to the .data hunk */
+
+static bfd_boolean
+amiga_write_symbols (abfd, section)
+     bfd *abfd;
+     sec_ptr section;
+{
+  sec_ptr osection;
+  asymbol *sym_p;
+  arelent *r;
+  unsigned long n[3],symbol_header,type;
+  unsigned int i,j,idx,ncnt,symbol_count;
+
+  /* If base rel linking and section is .bss ==> exit */
+  if (amiga_base_relative && !strcmp(section->name,".bss"))
+    return TRUE;
+
+  if (section->reloc_count==0 && bfd_get_symcount (abfd)==0)
+    {/* Write HUNK_END */
+    alldone:
+      DPRINT(5,("Leaving write_symbols\n"));
+      n[0]=HUNK_END;
+      return write_longs (n, 1, abfd);
+    }
+
+  /* If this is Loadfile, then do not write HUNK_EXT, but rather HUNK_SYMBOL */
+  symbol_header = AMIGA_DATA(abfd)->IsLoadFile ? HUNK_SYMBOL : HUNK_EXT;
+
+  /* Write out all the symbol definitions, then HUNK_END
+
+     Now, first traverse the relocs, all entries that are non NULL
+     have to be taken into account */
+  symbol_count = 0;
+
+  DPRINT(10,("Traversing relocation table\n"));
+  for (i=0;i<section->reloc_count;i++)
+    {
+      r=section->orelocation[i];
+      if (r==NULL)
+	continue;
+
+      sym_p=*(r->sym_ptr_ptr); /* The symbol for this relocation */
+      osection=sym_p->section; /* The section the symbol belongs to */
+      /* this section MUST be a special section */
+
+      DPRINT(5,("Symbol is %s, section is %lx(%s)\n",sym_p->name,osection,osection->name));
+
+      /* group together relocations referring to the same symbol and howto */
+      for(idx=i,j=i+1;j<section->reloc_count;j++)
+	{
+	  arelent *rj=section->orelocation[j];
+	  if (rj==NULL || sym_p!=*(rj->sym_ptr_ptr) || r->howto!=rj->howto)
+	    continue; /* no match */
+	  if (++i == j)
+	    continue; /* adjacent */
+	  section->orelocation[j] = section->orelocation[i];
+	  section->orelocation[i] = rj;
+	}
+
+      if ((symbol_count++)==0) /* First write out the HUNK_EXT */
+	{
+	  if (!write_longs (&symbol_header, 1, abfd))
+	    return FALSE;
+	}
+
+      if (!bfd_is_com_section(osection)) /* Not common symbol */
+	{
+	  DPRINT(5,("Non common ref\n"));
+	  /* Determine type of ref */
+	  switch (r->howto->type)
+	    {
+	    case H_ABS8:
+	    case H_PC8:
+	      type=EXT_RELREF8;
+	      break;
+
+	    case H_ABS16:
+	    case H_PC16:
+	      type=EXT_RELREF16;
+	      break;
+
+	    case H_ABS32:
+	      type=EXT_ABSREF32;
+	      break;
+
+	    case H_PC32:
+	      type=EXT_RELREF32;
+	      break;
+
+	    case H_SD8:
+	      type=EXT_DEXT8;
+	      break;
+
+	    case H_SD16:
+	      type=EXT_DEXT16;
+	      break;
+
+	    case H_SD32:
+	      type=EXT_DEXT32;
+	      break;
+
+	    case H_PC26:
+	      type=EXT_RELREF26;
+	      break;
+
+	    default: /* Error, can't represent this */
+	      bfd_msg ("unexpected reloc %d(%s) at offset 0x%lx",
+		       r->howto->type, r->howto->name, bfd_tell (abfd));
+	      bfd_set_error (bfd_error_nonrepresentable_section);
+	      return FALSE;
+	      break;
+	    }/* Of switch */
+	  ncnt=0;
+	}/* Of is ref to undefined or abs symbol */
+      else /* ref to common symbol */
+	{
+	  DPRINT(5,("Common ref\n"));
+	  switch (r->howto->type)
+	    {
+	    default:
+	      bfd_msg ("Warning: bad reloc %s for common symbol %s",
+		       r->howto->name, sym_p->name);
+	    case H_ABS32:
+	      type=EXT_ABSCOMMON;
+	      break;
+
+	    case H_SD8:
+	      type=EXT_DEXT8COMMON;
+	      break;
+
+	    case H_SD16:
+	      type=EXT_DEXT16COMMON;
+	      break;
+
+	    case H_SD32:
+	      type=EXT_DEXT32COMMON;
+	      break;
+	    }/* Of switch */
+	  n[0]=sym_p->value; /* Size of common block */
+	  ncnt=1;
+	}/* Of is common section */
+
+	DPRINT(5,("Type is %lx\n",type));
+	if (!write_name (abfd, sym_p->name, type << 24))
+	  return FALSE;
+	n[ncnt]=i-idx+1; /* refs for symbol... */
+	if (!write_longs (n, ncnt+1, abfd))
+	  return FALSE;
+	for(;idx<=i;++idx)
+	  {
+	    n[0]=section->orelocation[idx]->address;
+	    if (!write_longs (n, 1, abfd))
+	      return FALSE;
+	  }
+    }/* Of traverse relocs */
+
+  /* Now traverse the symbol table and write out all definitions, that are relative
+     to this hunk.
+     Absolute defs are always only written out with the first hunk.
+     Don't write out:
+	local symbols
+	undefined symbols
+	indirect symbols
+	warning symbols
+	debugging symbols
+	warning symbols
+	constructor symbols
+     since they are unrepresentable in HUNK format.. */
+
+  DPRINT(10,("Traversing symbol table\n"));
+  for (i=0;i<bfd_get_symcount (abfd);i++)
+    {
+      sym_p=abfd->outsymbols[i];
+      osection=sym_p->section;
+
+      DPRINT(5,("%d: symbol(%s), osec=%lx(%s)\n",
+	i,sym_p->name,osection,osection?osection->name:"null"));
+
+      if (osection==NULL) /* FIXME: Happens with constructor functions. */
+	continue;
+
+      if (bfd_is_und_section(osection)
+	/*||bfd_is_com_section(osection)*/
+	  ||bfd_is_ind_section(osection))
+	continue; /* Don't write these */
+
+      /* Only write abs defs, if not writing a Loadfile */
+      if (bfd_is_abs_section(osection)&&(section->index==0)&&
+	  !AMIGA_DATA(abfd)->IsLoadFile)
+	{
+	  DPRINT(5,("Abs symbol\n"));
+	  /* don't write debug symbols, they will be written in a
+	     HUNK_DEBUG later on */
+	  if (sym_p->flags & BSF_DEBUGGING)
+	    continue;
+
+	  if ((symbol_count++)==0) /* First write out the HUNK_EXT */
+	    {
+	      if (!write_longs (&symbol_header, 1, abfd))
+		return FALSE;
+	    }
+
+	  if (!write_name (abfd, sym_p->name, EXT_ABS << 24))
+	    return FALSE;
+	  n[0]=sym_p->value;
+	  if (!write_longs (n, 1, abfd))
+	    return FALSE;
+	  continue;
+	}/* Of abs def */
+      if (bfd_is_abs_section(osection))
+	continue; /* Not first hunk, already written */
+
+      /* If it is a warning symbol, or a constructor symbol or a
+	 debugging or a local symbol, don't write it */
+      if (sym_p->flags & (BSF_WARNING|BSF_CONSTRUCTOR|BSF_DEBUGGING|BSF_LOCAL))
+	continue;
+      if ((sym_p->flags & BSF_GLOBAL) == 0)
+	continue;
+
+      /* Now, if osection==section, write it out */
+      if (osection->output_section==section)
+	{
+	  DPRINT(5,("Writing it out\n"));
+
+	  if ((symbol_count++)==0) /* First write out the header */
+	    {
+	      if (!write_longs (&symbol_header, 1, abfd))
+		return FALSE;
+	    }
+
+	  type = symbol_header == HUNK_EXT ? EXT_DEF << 24 : 0;
+	  if (!write_name (abfd, sym_p->name, type))
+	    return FALSE;
+	  n[0] = sym_p->value + sym_p->section->output_offset;
+	  if (!write_longs (n, 1, abfd))
+	    return FALSE;
+	}
+      else
+	{
+	  /* write common definitions as bss common references */
+	  if (bfd_is_com_section(osection->output_section) &&
+	      section->index == 2)
+	    {
+	      if ((symbol_count++)==0) /* First write out the header */
+		{
+		  if (!write_longs (&symbol_header, 1, abfd))
+		    return FALSE;
+		}
+
+	      if (!write_name (abfd, sym_p->name, EXT_ABSCOMMON << 24))
+		return FALSE;
+	      n[0]=sym_p->value;
+	      n[1]=0;
+	      if (!write_longs (n, 2, abfd))
+		return FALSE;
+	    }
+	}
+    }/* Of for */
+
+  DPRINT(10,("Did traversing\n"));
+  if (symbol_count) /* terminate HUNK_EXT, HUNK_SYMBOL */
+    {
+      n[0]=0;
+      if (!write_longs (n, 1, abfd))
+	return FALSE;
+    }
+  DPRINT(5,("Leaving\n"));
+  goto alldone; /* Write HUNK_END, return */
+}
+
+static bfd_boolean
+amiga_get_section_contents (abfd, section, location, offset, count)
+     bfd *abfd;
+     sec_ptr section;
+     PTR location;
+     file_ptr offset;
+     bfd_size_type count;
+{
+  unsigned long disk_size=amiga_per_section(section)->disk_size;
+
+  if (bfd_seek (abfd, section->filepos + offset, SEEK_SET))
+    return FALSE;
+
+  if (offset+count > disk_size) {
+    /* the section's size on disk may be smaller than in memory
+       in this case, pad the contents */
+    if (bfd_bread (location, disk_size-offset, abfd) != disk_size-offset)
+      return FALSE;
+    memset ((char *) location + disk_size - offset, 0, count-(disk_size-offset));
+  }
+  else {
+    if (bfd_bread (location, count, abfd) != count)
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static bfd_boolean
+amiga_new_section_hook (abfd, newsect)
+     bfd *abfd;
+     sec_ptr newsect;
+{
+  newsect->used_by_bfd = (PTR) bfd_zalloc (abfd,
+					   sizeof (amiga_per_section_type));
+  newsect->alignment_power = 2;
+  if (!strcmp (newsect->name, ".data_chip")
+      || !strcmp (newsect->name, ".bss_chip"))
+    amiga_per_section(newsect)->attribute |= MEMF_CHIP;
+  return TRUE;
+}
+
+static bfd_boolean
+amiga_slurp_symbol_table (abfd)
+     bfd *abfd;
+{
+  amiga_data_type *amiga_data=AMIGA_DATA(abfd);
+  amiga_symbol_type *asp;
+  unsigned long l,len,type;
+  sec_ptr section;
+
+  if (amiga_data->symbols)
+    return TRUE; /* already read */
+
+  if (!bfd_get_symcount (abfd))
+    return TRUE;
+
+  asp = (amiga_symbol_type *) bfd_zalloc (abfd, sizeof (amiga_symbol_type) *
+					  bfd_get_symcount (abfd));
+  if ((amiga_data->symbols = asp) == NULL)
+    return FALSE;
+
+  /* Symbols are associated with every section */
+  for (section=abfd->sections; section!=NULL; section=section->next)
+    {
+      amiga_per_section_type *asect=amiga_per_section(section);
+
+      if (asect->hunk_ext_pos == 0)
+	continue;
+
+      if (bfd_seek (abfd, asect->hunk_ext_pos, SEEK_SET))
+	return FALSE;
+
+      for (asect->amiga_symbols=asp; get_long (abfd, &l) && l; asp++)
+	{
+	  type = l>>24;	/* type of entry */
+	  len = (l & 0xffffff) << 2; /* namelength */
+
+	  /* read the name */
+	  if ((asp->symbol.name = bfd_alloc (abfd, len+1))==NULL)
+	    return FALSE;
+	  if (bfd_bread ((PTR)asp->symbol.name, len, abfd) != len)
+	    return FALSE;
+	  ((char *)asp->symbol.name)[len] = '\0';
+
+	  asp->symbol.the_bfd = abfd;
+	  asp->symbol.flags = BSF_GLOBAL;
+	  /*asp->desc = 0;
+	  asp->other = 0;*/
+	  asp->type = type;
+	  asp->index = asp - amiga_data->symbols;
+
+	  switch (type) {
+	  case EXT_ABSCOMMON: /* Common reference/definition */
+	  case EXT_DEXT32COMMON:
+	  case EXT_DEXT16COMMON:
+	  case EXT_DEXT8COMMON:
+	    asp->symbol.section = bfd_com_section_ptr;
+	    /* size of common block -> symbol's value */
+	    if (!get_long (abfd, &l))
+	      return FALSE;
+	    asp->symbol.value = l;
+	    /* skip refs */
+	    if (!get_long (abfd, &l) || bfd_seek (abfd, l<<2, SEEK_CUR))
+	      return FALSE;
+	    asp->refnum = l;
+	    break;
+	  case EXT_ABS: /* Absolute */
+	    asp->symbol.section = bfd_abs_section_ptr;
+	    goto rval;
+	    break;
+	  case EXT_DEF: /* Relative Definition */
+	  case EXT_SYMB: /* Same as EXT_DEF for load files */
+	    asp->symbol.section = section;
+	  rval:
+	    /* read the value */
+	    if (!get_long (abfd, &l))
+	      return FALSE;
+	    asp->symbol.value = l;
+	    break;
+	  default: /* References to an undefined symbol */
+	    asp->symbol.section = bfd_und_section_ptr;
+	    asp->symbol.flags = 0;
+	    /* skip refs */
+	    if (!get_long (abfd, &l) || bfd_seek (abfd, l<<2, SEEK_CUR))
+	      return FALSE;
+	    asp->refnum = l;
+	    break;
+	  }
+	}
+    }
+  return TRUE;
+}
+
+
+/* Get size of symtab */
+static long
+amiga_get_symtab_upper_bound (abfd)
+     bfd *abfd;
+{
+  if (!amiga_slurp_symbol_table (abfd))
+    return -1;
+  return (bfd_get_symcount (abfd)+1) * (sizeof (amiga_symbol_type *));
+}
+
+
+static long
+amiga_get_symtab (abfd, location)
+     bfd *abfd;
+     asymbol **location;
+{
+  if(!amiga_slurp_symbol_table (abfd))
+    return -1;
+  if (bfd_get_symcount (abfd))
+    {
+      amiga_symbol_type *symp=AMIGA_DATA(abfd)->symbols;
+      unsigned int i;
+      for (i = 0; i < bfd_get_symcount (abfd); i++, symp++)
+	*location++ = &symp->symbol;
+      *location = 0;
+    }
+  return bfd_get_symcount (abfd);
+}
+
+
+static asymbol *
+amiga_make_empty_symbol (abfd)
+     bfd *abfd;
+{
+  amiga_symbol_type *new =
+    (amiga_symbol_type *) bfd_zalloc (abfd, sizeof (amiga_symbol_type));
+  new->symbol.the_bfd = abfd;
+  return &new->symbol;
+}
+
+
+static void
+amiga_get_symbol_info (ignore_abfd, symbol, ret)
+     bfd *ignore_abfd ATTRIBUTE_UNUSED;
+     asymbol *symbol;
+     symbol_info *ret;
+{
+  bfd_symbol_info (symbol, ret);
+  if (symbol->name[0] == ' ')
+    ret->name = "* empty table entry ";
+  if (bfd_is_abs_section(symbol->section))
+    ret->type = (symbol->flags & BSF_LOCAL) ? 'a' : 'A';
+}
+
+
+static void
+amiga_print_symbol (abfd, afile,  symbol, how)
+     bfd *abfd;
+     PTR afile;
+     asymbol *symbol;
+     bfd_print_symbol_type how;
+{
+  FILE *file = (FILE *)afile;
+
+  switch (how) {
+  case bfd_print_symbol_name:
+    fprintf (file, "%s", symbol->name);
+    break;
+  case bfd_print_symbol_more:
+    fprintf (file, "%4lx %2x",
+	     amiga_symbol(symbol)->refnum,
+	     (unsigned int)amiga_symbol(symbol)->type);
+    break;
+  case bfd_print_symbol_all:
+    if (symbol->name[0] == ' ')
+      {
+	fprintf (file, "* empty table entry ");
+      }
+    else
+      {
+	bfd_print_symbol_vandf (abfd, (PTR)file, symbol);
+	fprintf (file, " %-10s %04lx %02x %s",
+		 symbol->section->name,
+		 amiga_symbol(symbol)->refnum,
+		 (unsigned int)amiga_symbol(symbol)->type,
+		 symbol->name);
+      }
+    break;
+  }
+}
+
+
+static long
+amiga_get_reloc_upper_bound (abfd, asect)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     sec_ptr asect;
+{
+  return (asect->reloc_count + 1) * sizeof (arelent *);
+}
+
+
+static bfd_boolean
+read_raw_relocs (abfd, section, d_offset, count)
+     bfd *abfd;
+     sec_ptr section;
+     unsigned long d_offset;	/* offset in the bfd */
+     unsigned long count;	/* number of relocs */
+{
+  unsigned long hunk_number,offset,type,no,j;
+  reloc_howto_type *howto;
+
+  if (bfd_seek (abfd, d_offset, SEEK_SET))
+    return FALSE;
+  while ((long)count > 0)
+    {
+      /* first determine type of reloc */
+      if (!get_long (abfd, &type))
+	return FALSE;
+
+      if (type==HUNK_DREL32 && AMIGA_DATA(abfd)->IsLoadFile)
+	type = HUNK_RELOC32SHORT;
+
+      switch (type)
+	{
+	case HUNK_RELOC32SHORT:
+	  /* read reloc count, hunk number and offsets */
+	  for (howto=&howto_table[R_ABS32SHORT];;) {
+	    char buf[2];
+	    if (bfd_bread (buf, 2, abfd) != 2)
+	      return FALSE;
+	    if (no=GW(buf),!no)
+	      break;
+	    count -= no;
+	    if (bfd_bread (buf, 2, abfd) != 2)
+	      return FALSE;
+	    hunk_number = GW (buf);
+	    /* add relocs */
+	    for (j=0; j<no; j++) {
+	      if (bfd_bread (buf, 2, abfd) != 2)
+		return FALSE;
+	      offset = GW (buf);
+	      if (!amiga_add_reloc (abfd, section, offset, NULL, howto,
+				    hunk_number))
+	        return FALSE;
+	    }
+	  }
+	  break;
+
+	case HUNK_DREL32: /* 32 bit baserel */
+	case HUNK_DREL16: /* 16 bit baserel */
+	case HUNK_DREL8: /* 8 bit baserel */
+	  type -= 8;
+	case HUNK_ABSRELOC32: /* 32 bit ref */
+	case HUNK_RELRELOC16: /* 16 bit ref */
+	case HUNK_RELRELOC8: /* 8 bit ref */
+	  for (howto=&howto_table[R_ABS32+type-HUNK_ABSRELOC32];;) {
+	    /* read offsets and hunk number */
+	    if (!get_long (abfd, &no))
+	      return FALSE;
+	    if (!no)
+	      break;
+	    count -= no;
+	    if (!get_long (abfd, &hunk_number))
+	      return FALSE;
+	    /* add relocs */
+	    for (j=0; j<no; j++) {
+	      if (!get_long (abfd, &offset) ||
+		  !amiga_add_reloc (abfd, section, offset, NULL, howto,
+				    hunk_number))
+		return FALSE;
+	    }
+	  }
+	  break;
+
+	default: /* error */
+	  bfd_set_error (bfd_error_wrong_format);
+	  return FALSE;
+	  break;
+	}
+    }
+
+  return TRUE;
+}
+
+
+/* slurp in relocs, amiga_digest_file left various pointers for us */
+static bfd_boolean
+amiga_slurp_relocs (abfd, section, symbols)
+     bfd *abfd;
+     sec_ptr section;
+     asymbol **symbols ATTRIBUTE_UNUSED;
+{
+  amiga_per_section_type *asect=amiga_per_section(section);
+  reloc_howto_type *howto;
+  amiga_symbol_type *asp;
+  raw_reloc_type *relp;
+  unsigned long offset,type,n,i;
+
+  if (section->relocation)
+    return TRUE;
+
+  for (relp=asect->relocs; relp!=NULL; relp=relp->next)
+    if (relp->num && !read_raw_relocs (abfd, section, relp->pos, relp->num))
+      return FALSE;
+
+  /* Now step through the raw_symbols and add all relocs in them */
+  if (!AMIGA_DATA(abfd)->symbols && !amiga_slurp_symbol_table (abfd))
+    return FALSE;
+
+  if (asect->hunk_ext_pos == 0)
+    return TRUE;
+
+  if (bfd_seek (abfd, asect->hunk_ext_pos, SEEK_SET))
+    return FALSE;
+
+  for (asp=asect->amiga_symbols; get_long (abfd, &n) && n; asp++)
+    {
+      type = (n>>24) & 0xff;
+      n &= 0xffffff;
+
+      /* skip the name */
+      if (bfd_seek (abfd, n<<2, SEEK_CUR))
+	return FALSE;
+
+      switch (type)
+	{
+	case EXT_SYMB:
+	case EXT_DEF:
+	case EXT_ABS: /* no relocs here */
+	  if (bfd_seek (abfd, 4, SEEK_CUR))
+	    return FALSE;
+	  break;
+
+	  /* same as below, but advance lp by one to skip common size */
+	case EXT_DEXT32COMMON:
+	case EXT_DEXT16COMMON:
+	case EXT_DEXT8COMMON:
+	  type -= 75; /* convert to EXT_DEXT */
+	case EXT_ABSCOMMON:
+	  if (bfd_seek (abfd, 4, SEEK_CUR))
+	    return FALSE;
+	  /* Fall through */
+	default: /* reference to something */
+	  /* points to num of refs to hunk */
+	  if (!get_long (abfd, &n))
+	    return FALSE;
+	  /* Add relocs to this section, relative to asp */
+	  /* determine howto first */
+	  if (type==EXT_ABSCOMMON) /* 32 bit ref */
+	    howto=&howto_table[R_ABS32];
+	  else if (type==EXT_RELREF32)
+	    howto=&howto_table[R_PC32];
+	  else if (type==EXT_RELREF26)
+	    howto=&howto_table[R_PC26];
+	  else
+	    {
+	      type -= EXT_ABSREF32;
+	      if (type)
+		type--; /* skip EXT_ABSCOMMON gap */
+	      howto=&howto_table[R_ABS32+type];
+	    }/* of else */
+	  for (i=0;i<n;i++) /* refs follow */
+	    {
+	      if (!get_long (abfd, &offset))
+		return FALSE;
+	      if (!amiga_add_reloc (abfd, section, offset, abfd->outsymbols ?
+				    (amiga_symbol_type *) abfd->outsymbols[asp->index] : asp,
+				    howto, -4))
+		return FALSE;
+	    }
+	  break;
+	}/* of switch */
+    }
+  return TRUE;
+}/* Of slurp_relocs */
+
+
+static long
+amiga_canonicalize_reloc (abfd, section, relptr, symbols)
+     bfd *abfd;
+     sec_ptr section;
+     arelent **relptr;
+     asymbol **symbols;
+{
+  amiga_reloc_type *src;
+
+  if (!section->relocation && !amiga_slurp_relocs (abfd, section, symbols))
+    return -1;
+
+  for (src = (amiga_reloc_type *)section->relocation; src; src = src->next)
+    *relptr++ = &src->relent;
+  *relptr = NULL;
+
+  return section->reloc_count;
+}
+
+
+/* Set section contents */
+/* We do it the following way:
+   If this is a bss section ==> error
+   Otherwise, we try to allocate space for this section,
+   if this has not already been done
+   Then we set the memory area to the contents */
+static bfd_boolean
+amiga_set_section_contents (abfd, section, location, offset, count)
+     bfd *abfd;
+     sec_ptr section;
+     PTR location;
+     file_ptr offset;
+     bfd_size_type count;
+{
+  if ((section->flags&SEC_HAS_CONTENTS)==0) /* BSS */
+    {
+      bfd_set_error (bfd_error_no_contents);
+      return FALSE;
+    }
+
+  if ((section->flags&SEC_IN_MEMORY)==0) /* Not in memory, so alloc space */
+    {
+      section->contents = (bfd_byte *) bfd_zalloc (abfd, section->_raw_size);
+      if (section->contents == NULL)
+	return FALSE;
+      section->flags |= SEC_IN_MEMORY;
+      DPRINT(5,("Allocated %lx bytes at %lx\n",section->_raw_size,section->contents));
+    }
+
+  /* Copy mem */
+  memmove(&section->contents[offset],location,count);
+
+  return TRUE;
+}/* Of set_section_contents */
+
+
+/* FIXME: Is this everything? */
+static bfd_boolean
+amiga_set_arch_mach (abfd, arch, machine)
+     bfd *abfd;
+     enum bfd_architecture arch;
+     unsigned long machine;
+{
+  bfd_default_set_arch_mach(abfd, arch, machine);
+  if (arch == bfd_arch_m68k)
+    {
+      switch (machine)
+	{
+	case bfd_mach_m68000:
+	case bfd_mach_m68008:
+	case bfd_mach_m68010:
+	case bfd_mach_m68020:
+	case bfd_mach_m68030:
+	case bfd_mach_m68040:
+	case bfd_mach_m68060:
+	case 0:
+	  return TRUE;
+	default:
+	  break;
+	}
+    }
+  return FALSE;
+}
+
+static int
+amiga_sizeof_headers (ignore_abfd, ignore)
+     bfd *ignore_abfd ATTRIBUTE_UNUSED;
+     bfd_boolean ignore ATTRIBUTE_UNUSED;
+{
+  /* The amiga hunk format doesn't have headers. */
+  return 0;
+}
+
+/* Provided a BFD, a section and an offset into the section, calculate
+   and return the name of the source file and the line nearest to the
+   wanted location.  */
+bfd_boolean
+amiga_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
+			 functionname_ptr, line_ptr)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     sec_ptr section ATTRIBUTE_UNUSED;
+     asymbol **symbols ATTRIBUTE_UNUSED;
+     bfd_vma offset ATTRIBUTE_UNUSED;
+     const char **filename_ptr ATTRIBUTE_UNUSED;
+     const char **functionname_ptr ATTRIBUTE_UNUSED;
+     unsigned int *line_ptr ATTRIBUTE_UNUSED;
+{
+  /* FIXME (see aoutx.h, for example) */
+  return FALSE;
+}
+
+static reloc_howto_type *
+amiga_bfd_reloc_type_lookup (abfd, code)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     bfd_reloc_code_real_type code;
+{
+  DPRINT(5,("reloc: %s (%d)\n",bfd_get_reloc_code_name(code),code));
+  switch (code)
+    {
+    case BFD_RELOC_8_PCREL:    return &howto_table[R_PC8];
+    case BFD_RELOC_16_PCREL:   return &howto_table[R_PC16];
+    case BFD_RELOC_32_PCREL:   return &howto_table[R_PC32];
+    case BFD_RELOC_8:          return &howto_table[R_PC8];
+    case BFD_RELOC_16:         return &howto_table[R_PC16];
+    case BFD_RELOC_32:         return &howto_table[R_ABS32];
+    case BFD_RELOC_8_BASEREL:  return &howto_table[R_SD8];
+    case BFD_RELOC_16_BASEREL: return &howto_table[R_SD16];
+    case BFD_RELOC_32_BASEREL: return &howto_table[R_SD32];
+    case BFD_RELOC_CTOR:       return &howto_table[R_ABS32];
+      /* FIXME: everything handled? */
+    default:                   return NULL;
+    }
+}
+
+static bfd_boolean
+amiga_bfd_copy_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  if (bfd_get_flavour (ibfd) == bfd_target_amiga_flavour
+      && bfd_get_flavour (obfd) == bfd_target_amiga_flavour) {
+    AMIGA_DATA(obfd)->IsLoadFile = AMIGA_DATA(ibfd)->IsLoadFile;
+  }
+  return TRUE;
+}
+
+static bfd_boolean
+amiga_bfd_copy_private_section_data (ibfd, isec, obfd, osec)
+     bfd *ibfd ATTRIBUTE_UNUSED;
+     sec_ptr isec;
+     bfd *obfd ATTRIBUTE_UNUSED;
+     sec_ptr osec;
+{
+  if (bfd_get_flavour (osec->owner) == bfd_target_amiga_flavour
+      && bfd_get_flavour (isec->owner) == bfd_target_amiga_flavour) {
+    amiga_per_section(osec)->disk_size = amiga_per_section(isec)->disk_size;
+    amiga_per_section(osec)->attribute = amiga_per_section(isec)->attribute;
+  }
+  return TRUE;
+}
+
+/* There is no armap in the amiga libraries, so we fill carsym entries
+   one by one after having parsed the whole archive. */
+static bfd_boolean
+amiga_slurp_armap (abfd)
+     bfd *abfd;
+{
+  struct arch_syms *syms;
+  carsym *defsyms,*csym;
+  unsigned long symcount;
+
+  /* allocate the carsyms */
+  syms = amiga_ardata(abfd)->defsyms;
+  symcount = amiga_ardata(abfd)->defsym_count;
+
+  defsyms = (carsym *) bfd_alloc (abfd, sizeof (carsym) * symcount);
+  if (!defsyms)
+    return FALSE;
+
+  bfd_ardata(abfd)->symdefs = defsyms;
+  bfd_ardata(abfd)->symdef_count = symcount;
+
+  for (csym = defsyms; syms; syms = syms->next) {
+    unsigned long type, len, n;
+    char *symblock;
+    if (bfd_seek (abfd, syms->offset, SEEK_SET))
+      return FALSE;
+    symblock = (char *) bfd_alloc (abfd, syms->size);
+    if (!symblock)
+      return FALSE;
+    if (bfd_bread (symblock, syms->size, abfd) != syms->size)
+      return FALSE;
+    while (n=GL(symblock),n)
+      {
+	symblock += 4;
+	len = n & 0xffffff;
+	type = (n>>24) & 0xff;
+	switch (type) {
+	case EXT_SYMB:
+	case EXT_DEF:
+	case EXT_ABS:
+	  len <<= 2;
+	  csym->name = symblock;
+	  csym->name[len] = '\0';
+	  csym->file_offset = syms->unit_offset;
+	  csym++;
+	  symblock += len+4; /* name+value */
+	  break;
+	case EXT_ABSREF32:
+	case EXT_RELREF16:
+	case EXT_RELREF8:
+	case EXT_DEXT32:
+	case EXT_DEXT16:
+	case EXT_DEXT8:
+	case EXT_RELREF32:
+	case EXT_RELREF26:
+	  symblock += len<<2;
+	  symblock += (1+GL (symblock))<<2;
+	  break;
+	case EXT_ABSCOMMON:
+	case EXT_DEXT32COMMON:
+	case EXT_DEXT16COMMON:
+	case EXT_DEXT8COMMON:
+	  symblock += (len<<2)+4;
+	  symblock += (1+GL (symblock))<<2;
+	  break;
+	default: /* error */
+	  bfd_msg ("unexpected type %ld(0x%lx) in hunk_ext3 at offset 0x%lx",
+		   type, type, bfd_tell (abfd));
+	  return FALSE;
+	}
+      }
+  }
+  bfd_has_map (abfd) = TRUE;
+  return TRUE;
+}
+
+static void
+amiga_truncate_arname (abfd, pathname, arhdr)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     const char *pathname ATTRIBUTE_UNUSED;
+     char *arhdr ATTRIBUTE_UNUSED;
+{
+}
+
+static const struct bfd_target *
+amiga_archive_p (abfd)
+     bfd *abfd;
+{
+  struct arch_syms *symbols=NULL;
+  struct stat stat_buffer;
+  symindex symcount=0;
+  int units;
+
+  if (bfd_stat (abfd, &stat_buffer) < 0)
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return NULL;
+    }
+
+  if (stat_buffer.st_size != 0)
+    {
+      /* scan the units */
+      if (!parse_archive_units (abfd, &units, stat_buffer.st_size, FALSE,
+				&symbols, &symcount))
+	{
+	  bfd_set_error (bfd_error_wrong_format);
+	  return NULL;
+	}
+
+      /* if there is only one unit, file suffix is not .a and .lib, we
+	 consider it an object, not an archive. Obviously it's not
+	 always true but taking objects for archives makes ld fail,
+	 so we don't have much of a choice */
+      if (units == 1)
+	{
+	  char *p = strrchr (abfd->filename, '.');
+	  if (p == NULL || (strcmp (p, ".a") && strcmp (p, ".lib")))
+	    {
+	      bfd_set_error (bfd_error_wrong_format);
+	      return NULL;
+	    }
+	}
+    }
+
+  if (abfd->arelt_data)
+    arelt_size (abfd) = bfd_tell (abfd);
+
+  bfd_seek (abfd, 0, SEEK_SET);
+  abfd->arch_info = bfd_scan_arch ("m68k:68000");
+
+  if (amiga_mkarchive (abfd))
+    {
+      bfd_ardata(abfd)->first_file_filepos = 0;
+      amiga_ardata(abfd)->filesize = stat_buffer.st_size;
+      amiga_ardata(abfd)->defsyms = symbols;
+      amiga_ardata(abfd)->defsym_count = symcount;
+      if (amiga_slurp_armap (abfd))
+	return abfd->xvec;
+    }
+
+  return NULL;
+}
+
+static bfd *
+amiga_openr_next_archived_file (archive, last_file)
+     bfd *archive;
+     bfd *last_file;
+{
+  file_ptr filestart;
+
+  if (!last_file)
+    filestart = bfd_ardata (archive)->first_file_filepos;
+  else
+    {
+      unsigned int size = arelt_size (last_file);
+      /* Pad to an even boundary... */
+      filestart = last_file->origin + size;
+      filestart += filestart % 2;
+    }
+
+  return _bfd_get_elt_at_filepos (archive, filestart);
+}
+
+static PTR
+amiga_read_ar_hdr (abfd)
+     bfd *abfd;
+{
+  struct areltdata *ared;
+  unsigned long start_pos,len;
+  char buf[8],*base,*name;
+
+  start_pos = bfd_tell (abfd);
+  if (start_pos >= amiga_ardata(abfd)->filesize) {
+    bfd_set_error (bfd_error_no_more_archived_files);
+    return NULL;
+  }
+
+  /* get unit type and name length in long words */
+  if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf))
+    return NULL;
+
+  if (GL (&buf[0]) != HUNK_UNIT) {
+    bfd_set_error (bfd_error_malformed_archive);
+    return NULL;
+  }
+
+  ared = bfd_zalloc (abfd, sizeof (struct areltdata));
+  if (ared == NULL)
+    return NULL;
+
+  len = GL (&buf[4]) << 2;
+
+  ared->filename = bfd_alloc (abfd, len+1 > 16 ? len+1 : 16);
+  if (ared->filename == NULL)
+    return NULL;
+
+  switch (len) {
+    default:
+      if (bfd_bread (ared->filename, len, abfd) != len)
+	return NULL;
+      ared->filename[len] = '\0';
+      /* strip path part */
+      base = strchr (name = ared->filename, ':');
+      if (base != NULL)
+	name = base + 1;
+      for (base = name; *name; ++name)
+	if (*name == '/')
+	  base = name + 1;
+      if (*base != '\0') {
+	ared->filename = base;
+	break;
+      }
+      /* Fall through */
+    case 0: /* fake a name */
+      sprintf (ared->filename, "obj-%08lu.o", ++amiga_ardata(abfd)->outnum);
+      break;
+  }
+
+  if (bfd_seek (abfd, start_pos+4, SEEK_SET))
+    return NULL;
+
+  if (!amiga_read_unit (abfd, amiga_ardata(abfd)->filesize))
+    return NULL;
+
+  ared->parsed_size = bfd_tell (abfd) - start_pos;
+  if (bfd_seek (abfd, start_pos, SEEK_SET))
+    return NULL;
+
+  return (PTR) ared;
+}
+
+static int
+amiga_generic_stat_arch_elt (abfd, buf)
+     bfd *abfd;
+     struct stat *buf;
+{
+  if (abfd->arelt_data == NULL)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  /* No header in amiga archives. Let's set reasonable default values */
+  buf->st_mode = 0644;
+  buf->st_uid = 0;
+  buf->st_gid = 0;
+  buf->st_mtime = 2922*24*60*60;
+  buf->st_size = arelt_size (abfd);
+
+  return 0;
+}
+
+/* Entry points through BFD_JUMP_TABLE_GENERIC */
+#define amiga_close_and_cleanup		_bfd_generic_close_and_cleanup
+#define amiga_bfd_free_cached_info	_bfd_generic_bfd_free_cached_info
+/* amiga_new_section_hook defined above */
+/* amiga_get_section_contents defined above */
+#define amiga_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
+
+/* Entry points through BFD_JUMP_TABLE_COPY */
+#define amiga_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
+/*#define amiga_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data*/
+#define amiga_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data
+#define amiga_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
+#define amiga_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data
+
+/* Entry points through BFD_JUMP_TABLE_ARCHIVE */
+/*#define amiga_slurp_armap		bfd_slurp_armap*/
+#define amiga_slurp_extended_name_table	_bfd_slurp_extended_name_table
+#define amiga_construct_extended_name_table _bfd_archive_bsd_construct_extended_name_table
+/*#define amiga_truncate_arname		bfd_gnu_truncate_arname*/
+/*#define amiga_write_armap		bsd_write_armap*/
+/*#define amiga_read_ar_hdr		_bfd_generic_read_ar_hdr*/
+/*#define amiga_openr_next_archived_file	bfd_generic_openr_next_archived_file*/
+#define amiga_get_elt_at_index		_bfd_generic_get_elt_at_index
+/*#define amiga_generic_stat_arch_elt	bfd_generic_stat_arch_elt*/
+#define amiga_update_armap_timestamp	_bfd_archive_bsd_update_armap_timestamp
+
+/* Entry points through BFD_JUMP_TABLE_SYMBOLS */
+/* amiga_get_symtab_upper_bound defined above */
+/* amiga_get_symtab defined above */
+/* amiga_make_empty_symbol defined above */
+/* amiga_print_symbol defined above */
+/* amiga_get_symbol_info defined above */
+#define amiga_bfd_is_local_label_name	bfd_generic_is_local_label_name
+#define amiga_get_lineno		(alent * (*)(bfd *, asymbol *)) bfd_nullvoidptr
+/* amiga_find_nearest_line defined above */
+#define amiga_bfd_make_debug_symbol	(asymbol * (*)(bfd *, PTR, unsigned long)) bfd_nullvoidptr
+#define amiga_read_minisymbols		_bfd_generic_read_minisymbols
+#define amiga_minisymbol_to_symbol	_bfd_generic_minisymbol_to_symbol
+
+/* Entry points through BFD_JUMP_TABLE_LINK
+   NOTE: We use a special get_relocated_section_contents both in amiga AND in a.out files.
+   In addition, we use an own final_link routine, which is nearly identical to _bfd_generic_final_link */
+bfd_byte *
+get_relocated_section_contents PARAMS ((bfd *, struct bfd_link_info *,
+	struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **));
+#define amiga_bfd_get_relocated_section_contents get_relocated_section_contents
+#define amiga_bfd_relax_section		bfd_generic_relax_section
+#define amiga_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
+#define amiga_bfd_link_hash_table_free	_bfd_generic_link_hash_table_free
+#define amiga_bfd_link_add_symbols	_bfd_generic_link_add_symbols
+#define amiga_bfd_link_just_syms	_bfd_generic_link_just_syms
+bfd_boolean amiga_final_link PARAMS ((bfd *, struct bfd_link_info *));
+#define amiga_bfd_final_link		amiga_final_link
+#define amiga_bfd_link_split_section	_bfd_generic_link_split_section
+#define amiga_bfd_gc_sections		bfd_generic_gc_sections
+#define amiga_bfd_merge_sections	bfd_generic_merge_sections
+#define amiga_bfd_discard_group		bfd_generic_discard_group
+
+#if defined (amiga)
+#undef amiga /* So that the JUMP_TABLE() macros below can work.  */
+#endif
+
+const bfd_target amiga_vec =
+{
+  "amiga",		/* name */
+  bfd_target_amiga_flavour,
+  BFD_ENDIAN_BIG,	/* data byte order */
+  BFD_ENDIAN_BIG,	/* header byte order */
+  HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS | WP_TEXT, /* object flags */
+  SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA, /* section flags */
+  '_',			/* symbol leading char */
+  ' ',			/* ar_pad_char */
+  15,			/* ar_max_namelen (15 for UNIX compatibility) */
+  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
+  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
+  {
+    /* bfd_check_format */
+    _bfd_dummy_target,
+    amiga_object_p,
+    amiga_archive_p,
+    _bfd_dummy_target
+  },
+  {
+    /* bfd_set_format */
+    bfd_false,
+    amiga_mkobject,
+    amiga_mkarchive,
+    bfd_false
+  },
+  {
+    /* bfd_write_contents */
+    bfd_false,
+    amiga_write_object_contents,
+    amiga_write_archive_contents,
+    bfd_false
+  },
+  BFD_JUMP_TABLE_GENERIC (amiga),
+  BFD_JUMP_TABLE_COPY (amiga),
+  BFD_JUMP_TABLE_CORE (_bfd_nocore),
+  BFD_JUMP_TABLE_ARCHIVE (amiga),
+  BFD_JUMP_TABLE_SYMBOLS (amiga),
+  BFD_JUMP_TABLE_RELOCS (amiga),
+  BFD_JUMP_TABLE_WRITE (amiga),
+  BFD_JUMP_TABLE_LINK (amiga),
+  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+  NULL,
+  NULL
+};
diff -ru --new-file a/bfd/amigaoslink.c b/bfd/amigaoslink.c
--- a/bfd/amigaoslink.c	1970-01-01 03:00:00.000000000 +0300
+++ b/bfd/amigaoslink.c	2021-02-01 23:12:49.061770000 +0300
@@ -0,0 +1,1032 @@
+/* BFD back-end for Commodore-Amiga AmigaOS binaries. Linker routines.
+   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
+   Free Software Foundation, Inc.
+   Contributed by Stephan Thesing.
+
+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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/*
+INODE
+amigalink, , implementation, amiga
+SECTION
+	amigalink
+
+This is the description of the linker routines for the amiga.
+In fact, this includes a description of the changes made to the
+a.out code, in order to build a working linker for the Amiga.
+@menu
+@* alterations::
+@end menu
+
+INODE
+alterations, , , amigalink
+SUBSECTION
+	alterations
+
+The file @file{aout-amiga.c} defines the amiga a.out backend. It differs from
+the sun3 backend only in these details:
+	o The @code{final_link} routine is @code{amiga_final_link}.
+	o The routine to get the relocated section contents is
+	  @code{get_relocated_section_contents}.
+
+This ensures that the link is performed properly, but has the side effect of
+loosing performance.
+
+The amiga bfd code uses the same functions since they check for the used flavour.
+@@*
+
+The usage of a special linker code has one reason:
+The bfd library assumes that a program is always loaded at a known memory
+address. This is not a case on an Amiga. So the Amiga format has to take over
+some relocs to an executable output file.
+This is not the case with a.out formats, so there relocations can be applied at link time,
+not at run time, like on the Amiga.
+The special routines compensate this: instead of applying the relocations, they are
+copied to the output file, if neccessary.
+As as consequence, @code{final_link} and @code{get_relocated_section_contents} are nearly identical to
+the original routines from @file{linker.c} and @file{reloc.c}.
+*/
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "bfdlink.h"
+#include "genlink.h"
+#include "libamiga.h"
+
+#define bfd_msg (*_bfd_error_handler)
+
+/*#define DEBUG_AMIGA 1*/
+#if DEBUG_AMIGA
+#include <stdarg.h>
+static void
+error_print (const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  vfprintf (stderr, fmt, args);
+  va_end (args);
+}
+#define DPRINT(L,x) if (L>=DEBUG_AMIGA) error_print x
+#else
+#define DPRINT(L,x)
+#endif
+
+/* This one is used by the linker and tells us, if a debug hunk should be
+   written out */
+int write_debug_hunk = 1;
+
+/* This is also used by the linker to set the attribute of sections */
+int amiga_attribute = 0;
+
+/* This one is used to indicate base-relative linking */
+int amiga_base_relative = 0;
+
+/* This one is used to indicate -resident linking */
+int amiga_resident = 0;
+
+bfd_boolean
+default_indirect_link_order PARAMS ((bfd *, struct bfd_link_info *,
+	 asection *, struct bfd_link_order *, bfd_boolean));
+bfd_byte *
+get_relocated_section_contents PARAMS ((bfd *, struct bfd_link_info *,
+	struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **));
+bfd_boolean
+amiga_final_link PARAMS ((bfd *, struct bfd_link_info *));
+bfd_boolean
+aout_amiga_final_link PARAMS ((bfd *, struct bfd_link_info *));
+
+static bfd_reloc_status_type
+my_add_to PARAMS ((arelent *, PTR, int, int));
+static bfd_reloc_status_type
+amiga_perform_reloc PARAMS ((bfd *, arelent *, PTR, sec_ptr, bfd *, char **));
+static bfd_reloc_status_type
+aout_perform_reloc PARAMS ((bfd *, arelent *, PTR, sec_ptr, bfd *, char **));
+static bfd_boolean
+amiga_reloc_link_order PARAMS ((bfd *, struct bfd_link_info *, asection *,
+	struct bfd_link_order *));
+
+enum { ADDEND_UNSIGNED=0x01, RELOC_SIGNED=0x02 };
+
+
+/* This one is nearly identical to bfd_generic_get_relocated_section_contents
+   in reloc.c */
+bfd_byte *
+get_relocated_section_contents (abfd, link_info, link_order, data,
+				relocateable, symbols)
+     bfd *abfd;
+     struct bfd_link_info *link_info;
+     struct bfd_link_order *link_order;
+     bfd_byte *data;
+     bfd_boolean relocateable;
+     asymbol **symbols;
+{
+  /* Get enough memory to hold the stuff.  */
+  bfd *input_bfd = link_order->u.indirect.section->owner;
+  asection *input_section = link_order->u.indirect.section;
+
+  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+  arelent **reloc_vector = NULL;
+  long reloc_count;
+  bfd_reloc_status_type (*reloc_func)(bfd *, arelent *, PTR, sec_ptr,
+				      bfd *, char **);
+
+  DPRINT(5,("Entering get_rel_sec_cont\n"));
+
+  if (reloc_size < 0)
+    goto error_return;
+
+  if (bfd_get_flavour (input_bfd) == bfd_target_amiga_flavour)
+    reloc_func = amiga_perform_reloc;
+  else if (bfd_get_flavour (input_bfd) == bfd_target_aout_flavour)
+    reloc_func = aout_perform_reloc;
+  else
+    {
+      bfd_set_error (bfd_error_bad_value);
+      goto error_return;
+    }
+
+  reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
+  if (reloc_vector == NULL && reloc_size != 0)
+    goto error_return;
+
+  DPRINT(5,("GRSC: GetSecCont()\n"));
+  /* Read in the section.  */
+  if (!bfd_get_section_contents (input_bfd,
+				 input_section,
+				 (PTR) data,
+				 (bfd_vma) 0,
+				 input_section->_raw_size))
+    goto error_return;
+
+  /* We're not relaxing the section, so just copy the size info.  */
+  input_section->_cooked_size = input_section->_raw_size;
+  input_section->reloc_done = TRUE;
+
+  DPRINT(5,("GRSC: CanReloc\n"));
+  reloc_count = bfd_canonicalize_reloc (input_bfd,
+					input_section,
+					reloc_vector,
+					symbols);
+  if (reloc_count < 0)
+    goto error_return;
+
+  if (reloc_count > 0)
+    {
+      arelent **parent;
+
+      DPRINT(5,("reloc_count=%ld\n",reloc_count));
+
+      for (parent = reloc_vector; *parent != (arelent *) NULL;
+	   parent++)
+	{
+	  char *error_message = (char *) NULL;
+	  bfd_reloc_status_type r;
+
+	  DPRINT(5,("Applying a reloc\nparent=%lx, reloc_vector=%lx, "
+		    "*parent=%lx\n",parent,reloc_vector,*parent));
+	  r=(*reloc_func) (input_bfd,
+			   *parent,
+			   (PTR) data,
+			   input_section,
+			   relocateable ? abfd : (bfd *) NULL,
+			   &error_message);
+	  if (relocateable)
+	    {
+	      asection *os = input_section->output_section;
+
+	      DPRINT(5,("Keeping reloc\n"));
+	      /* A partial link, so keep the relocs.  */
+	      os->orelocation[os->reloc_count] = *parent;
+	      os->reloc_count++;
+	    }
+
+	  if (r != bfd_reloc_ok)
+	    {
+	      switch (r)
+		{
+		case bfd_reloc_undefined:
+		  if (!((*link_info->callbacks->undefined_symbol)
+			(link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+			 input_bfd, input_section, (*parent)->address,
+			 TRUE)))
+		    goto error_return;
+		  break;
+		case bfd_reloc_dangerous:
+		  BFD_ASSERT (error_message != (char *) NULL);
+		  if (!((*link_info->callbacks->reloc_dangerous)
+			(link_info, error_message, input_bfd, input_section,
+			 (*parent)->address)))
+		    goto error_return;
+		  break;
+		case bfd_reloc_overflow:
+		  if (!((*link_info->callbacks->reloc_overflow)
+			(link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+			 (*parent)->howto->name, (*parent)->addend,
+			 input_bfd, input_section, (*parent)->address)))
+		    goto error_return;
+		  break;
+		case bfd_reloc_outofrange:
+		default:
+		  DPRINT(10,("get_rel_sec_cont fails, perform reloc "
+			     "returned $%x\n",r));
+		  abort ();
+		  break;
+		}
+
+	    }
+	}
+    }
+  if (reloc_vector != NULL)
+    free (reloc_vector);
+  DPRINT(5,("GRSC: Returning ok\n"));
+  return data;
+
+error_return:
+  DPRINT(5,("GRSC: Error_return\n"));
+  if (reloc_vector != NULL)
+    free (reloc_vector);
+  return NULL;
+}
+
+
+/* Add a value to a location */
+static bfd_reloc_status_type
+my_add_to (r, data, add, flags)
+     arelent *r;
+     PTR data;
+     int add, flags;
+{
+  bfd_reloc_status_type ret=bfd_reloc_ok;
+  bfd_byte *p=((bfd_byte *)data)+r->address;
+  int val;
+
+  DPRINT(5,("Entering add_value\n"));
+
+  switch (r->howto->size)
+    {
+    case 0: /* byte size */
+      if ((flags & ADDEND_UNSIGNED) == 0)
+	val = ((*p & 0xff) ^ 0x80) - 0x80 + add;
+      else
+	val = (*p & 0xff) + add;
+      /* check for overflow */
+      if ((flags & RELOC_SIGNED) != 0) {
+	if (val<-0x80 || val>0x7f)
+	  ret = bfd_reloc_overflow;
+      }
+      else {
+	if ((val&0xffffff00)!=0 && (val&0xffffff00)!=0xffffff00)
+	  ret=bfd_reloc_overflow;
+      }
+      /* set the value */
+      *p = val & 0xff;
+      break;
+
+    case 1: /* word size */
+      if ((flags & ADDEND_UNSIGNED) == 0)
+	val = bfd_getb_signed_16 (p) + add;
+      else
+	val = bfd_getb16 (p) + add;
+      /* check for overflow */
+      if ((flags & RELOC_SIGNED) != 0) {
+	if (val<-0x8000 || val>0x7fff)
+	  ret = bfd_reloc_overflow;
+      }
+      else {
+	if ((val&0xffff0000)!=0 && (val&0xffff0000)!=0xffff0000)
+	  ret=bfd_reloc_overflow;
+      }
+      /* set the value */
+      bfd_putb16 (val, p);
+      break;
+
+    case 2: /* long word */
+      val = bfd_getb_signed_32 (p) + add;
+      /* If we are linking a resident program, then we limit the reloc size
+	 to about +/- 1 GB.
+
+	 When linking a shared library all variables defined in other
+	 libraries are placed in memory >0x80000000, so if the library
+	 tries to use one of those variables an error is output.
+
+	 Without this it would be much more difficult to check for
+	 incorrect references. */
+      if (amiga_resident &&
+	  (val & 0xc0000000)!=0 && (val&0xc0000000)!=0xc0000000) /* Overflow */
+	{
+	  ret=bfd_reloc_overflow;
+	}
+      bfd_putb32 (val, p);
+      break;
+
+    default: /* Error */
+      ret=bfd_reloc_notsupported;
+      break;
+    }/* Of switch */
+
+  DPRINT(5,("Leaving add_value\n"));
+  return ret;
+}
+
+
+/* Perform an Amiga relocation */
+static bfd_reloc_status_type
+amiga_perform_reloc (abfd, r, data, sec, obfd, error_message)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *r;
+     PTR data;
+     sec_ptr sec;
+     bfd *obfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  asymbol *sym; /* Reloc is relative to sym */
+  sec_ptr target_section; /* reloc is relative to this section */
+  bfd_reloc_status_type ret;
+  bfd_boolean copy;
+  int relocation,flags;
+
+  DPRINT(5,("Entering APR\nflavour is %d (amiga_flavour=%d, aout_flavour=%d)\n",
+	    bfd_get_flavour (sec->owner), bfd_target_amiga_flavour,
+	    bfd_target_aout_flavour));
+
+  /* If obfd==NULL: Apply the reloc, if possible. */
+  /* Else: Modify it and return */
+
+  if (obfd!=NULL) /* Only modify the reloc */
+    {
+      r->address+=sec->output_offset;
+      sec->output_section->flags|=SEC_RELOC;
+      DPRINT(5,("Leaving amiga_perf_reloc, modified\n"));
+      return bfd_reloc_ok;
+    }
+
+  /* Try to apply the reloc */
+
+  sym=*(r->sym_ptr_ptr);
+
+  /* FIXME: XXX */
+   if (0 && sym->udata.p)
+     sym = ((struct generic_link_hash_entry *) sym->udata.p)->sym;
+
+  target_section=sym->section;
+
+  if (bfd_is_und_section(target_section)) /* Error */
+    {
+      DPRINT(10,("amiga_perf_reloc: target_sec==UND\n"));
+      return bfd_reloc_undefined;
+    }
+
+  relocation=0; flags=RELOC_SIGNED; copy=FALSE; ret=bfd_reloc_ok;
+
+  DPRINT(5,("%s: size=%u\n",r->howto->name,bfd_get_reloc_size(r->howto)));
+  switch (r->howto->type)
+    {
+    case H_ABS32:
+      if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */
+	relocation=sym->value;
+      else if (bfd_is_com_section(target_section)) /* ref to common */
+	{
+	  relocation=0;
+	  copy=TRUE;
+	}
+      else
+	{
+	  /* If we access a symbol in the .bss section, we have to convert
+	     this to an access to .data section */
+	  /* This is done through a change to the output section of
+	     the symbol.. */
+	  if (amiga_base_relative
+	      && !strcmp(target_section->output_section->name,".bss"))
+	    {
+	      /* get value for .data section */
+	      bfd *ibfd;
+	      sec_ptr s;
+
+	      ibfd=target_section->output_section->owner;
+	      for (s=ibfd->sections;s!=NULL;s=s->next)
+		if (!strcmp(s->name,".data"))
+		  {
+		    target_section->output_offset=s->_raw_size;
+		    target_section->output_section=s;
+		  }
+	    }
+	  relocation=0;
+	  copy=TRUE;
+	}
+      break;
+
+    case H_PC8: /* pcrel */
+    case H_PC16:
+    case H_PC32:
+      if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */
+	relocation=sym->value;
+      else if (bfd_is_com_section(target_section)) /* Error.. */
+	{
+	  ret=bfd_reloc_undefined;
+	}
+      else if (sec->output_section!=target_section->output_section) /* Error */
+	{
+	  DPRINT(5,("pc relative, but out-of-range\n"));
+	  ret=bfd_reloc_outofrange;
+	}
+      else /* Same section */
+	{
+	  DPRINT(5,("PC relative\n"));
+	  relocation = sym->value + target_section->output_offset
+	    - (r->address + sec->output_offset);
+	}
+      break;
+
+    case H_SD8: /* baserel */
+    case H_SD16:
+    case H_SD32:
+      /* Relocs are always relative to the symbol ___a4_init */
+      /* Relocs to .bss section are converted to a reloc to .data section,
+	 since .bss section contains only COMMON sections...... and should
+	 be following .data section.. */
+      if (bfd_is_abs_section(target_section))
+	relocation=sym->value;
+      else if (!AMIGA_DATA(target_section->output_section->owner)->baserel)
+	{
+	  bfd_msg ("Base symbol for base relative reloc not defined: "
+		   "section %s, reloc to symbol %s",sec->name,sym->name);
+	  ret=bfd_reloc_notsupported;
+	}
+      else if ((target_section->flags&SEC_CODE)!=0)
+        {
+	  bfd_msg ("%s: baserelative text relocation to \"%s\"",
+		    abfd->filename, sym->name);
+	  ret=bfd_reloc_notsupported;
+        }
+      else
+	{
+	  /* If target->out is .bss, add the value of the .data section to
+	     sym->value and set new output_section */
+	  if (!strcmp(target_section->output_section->name,".bss"))
+	    {
+	      bfd *ibfd;
+	      sec_ptr s;
+
+	      ibfd=target_section->output_section->owner;
+	      for (s=ibfd->sections;s!=NULL;s=s->next)
+		if (!strcmp(s->name,".data"))
+		  {
+		    target_section->output_offset=s->_raw_size;
+		    target_section->output_section=s;
+		  }
+	    }
+
+	  relocation = sym->value + target_section->output_offset
+	    - (AMIGA_DATA(target_section->output_section->owner))->a4init
+	    + r->addend;
+	  flags|=ADDEND_UNSIGNED;
+	}
+      break;
+
+    default:
+      bfd_msg ("Error: unsupported reloc: %s(%d)",r->howto->name,r->howto->size);
+      ret=bfd_reloc_notsupported;
+      break;
+    }/* Of switch */
+
+  /* Add in relocation */
+  if (relocation!=0)
+    ret = my_add_to (r, data, relocation, flags);
+
+  if (copy) /* Copy reloc to output section */
+    {
+      DPRINT(5,("Copying reloc\n"));
+      target_section=sec->output_section;
+      r->address+=sec->output_offset;
+      target_section->orelocation[target_section->reloc_count++]=r;
+      target_section->flags|=SEC_RELOC;
+    }
+  DPRINT(5,("Leaving amiga_perf_reloc with %d (OK=%d)\n",ret,bfd_reloc_ok));
+  return ret;
+}
+
+
+/* Perform an a.out relocation */
+static bfd_reloc_status_type
+aout_perform_reloc (abfd, r, data, sec, obfd, error_message)
+     bfd *abfd;
+     arelent *r;
+     PTR data;
+     sec_ptr sec;
+     bfd *obfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  asymbol *sym; /* Reloc is relative to sym */
+  sec_ptr target_section; /* reloc is relative to this section */
+  bfd_reloc_status_type ret;
+  bfd_boolean copy;
+  int relocation,flags;
+
+  DPRINT(5,("Entering aout_perf_reloc\n"));
+
+  /* If obfd==NULL: Apply the reloc, if possible. */
+  /* Else: Modify it and return */
+
+  if (obfd!=NULL) /* Only modify the reloc */
+    {
+      r->address+=sec->output_offset;
+      DPRINT(5,("Leaving aout_perf_reloc, modified\n"));
+      return bfd_reloc_ok;
+    }
+
+  /* Try to apply the reloc */
+
+  sym=*(r->sym_ptr_ptr);
+  target_section=sym->section;
+
+  if (bfd_is_und_section(target_section)) /* Error */
+    {
+      if ((sym->flags & BSF_WEAK) == 0)
+        {
+	  DPRINT(10,("aout_perf_reloc: target_sec==UND\n"));
+	  return bfd_reloc_undefined;
+	}
+      target_section=bfd_abs_section_ptr;
+    }
+
+  relocation=0; flags=RELOC_SIGNED; copy=FALSE; ret=bfd_reloc_ok;
+
+  DPRINT(10,("RELOC: %s: size=%u\n",r->howto->name,bfd_get_reloc_size(r->howto)));
+  switch (r->howto->type)
+    {
+    case H_ABS8: /* 8/16 bit reloc, pc relative or absolute */
+    case H_ABS16:
+      if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */
+	relocation=sym->value;
+      else if (bfd_is_com_section(target_section)) /* Error.. */
+	{
+	  bfd_msg ("pc relative relocation to common symbol \"%s\" in "
+		   "section %s",sym->name,sec->name);
+	  DPRINT(10,("Ref to common symbol...aout_perf_reloc\n"));
+	  ret=bfd_reloc_undefined;
+	}
+      else if (sec->output_section!=target_section->output_section)
+	{
+	  if ((target_section->output_section->flags&SEC_DATA)!=0)
+	    goto baserel; /* Dirty, but no code duplication.. */
+	  bfd_msg ("pc relative relocation out-of-range in section %s. "
+		   "Relocation was to symbol %s",sec->name,sym->name);
+	  DPRINT(10,("Section %s, target %s: Reloc out-of-range...not same "
+		     "section, aout_perf\nsec->out=%s, target->out=%s, "
+		     "offset=%lx\n",sec->name,target_section->name,
+		     sec->output_section->name,
+		     target_section->output_section->name,r->address));
+	  ret=bfd_reloc_outofrange;
+	}
+      else
+	{
+	  /* Same section, this is a pc relative hunk... */
+	  DPRINT(5,("Reloc to same section...\n"));
+	  relocation=-(r->address+sec->output_offset);
+	}
+      break;
+
+    case H_ABS32: /* 32 bit reloc, pc relative or absolute */
+      if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */
+	relocation=sym->value;
+      else if (bfd_is_com_section(target_section)) /* ref to common */
+	{
+	  relocation=0;
+	  copy=TRUE;
+	}
+      else
+	{
+	  /* If we access a symbol in the .bss section, we have to convert
+	     this to an access to .data section */
+	  /* This is done through a change to the output section of
+	     the symbol.. */
+	  if (amiga_base_relative
+	      && !strcmp(target_section->output_section->name,".bss"))
+	    {
+	      /* get value for .data section */
+	      bfd *ibfd;
+	      sec_ptr s;
+
+	      ibfd=target_section->output_section->owner;
+	      for (s=ibfd->sections;s!=NULL;s=s->next)
+		if (!strcmp(s->name,".data"))
+		  {
+		    target_section->output_offset+=s->_raw_size;
+		    target_section->output_section=s;
+		  }
+	    }
+	  relocation=0;
+	  copy=TRUE;
+	}
+      DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n",
+		 target_section->output_section->name,
+		 target_section->output_section,sec->output_section->name,
+		 sec->output_section,sym->name));
+      break;
+
+    case H_PC8: /* pcrel */
+    case H_PC16:
+    case H_PC32:
+      if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */
+	relocation=sym->value;
+      else
+	{
+	  relocation = sym->value + target_section->output_offset
+	    - sec->output_offset;
+	}
+      break;
+
+    case H_SD16: /* baserel */
+    case H_SD32:
+    baserel:
+      /* We use the symbol ___a4_init as base */
+      if (bfd_is_abs_section(target_section))
+	relocation=sym->value;
+      else if (bfd_is_com_section(target_section)) /* Error.. */
+	{
+	  bfd_msg ("baserelative relocation to common \"%s\"",sym->name);
+	  DPRINT(10,("Ref to common symbol...aout_perf_reloc\n"));
+	  ret=bfd_reloc_undefined;
+	}
+      else if (!AMIGA_DATA(target_section->output_section->owner)->baserel)
+	{
+	  bfd_msg ("Base symbol for base relative reloc not defined: "
+		   "section %s, reloc to symbol %s",sec->name,sym->name);
+	  ret=bfd_reloc_notsupported;
+	}
+      else if ((target_section->flags&SEC_CODE)!=0)
+        {
+	  bfd_msg ("%s: baserelative text relocation to \"%s\"",
+		    abfd->filename, sym->name);
+	  ret=bfd_reloc_notsupported;
+        }
+      else /* Target section and sec need not be the same.. */
+	{
+	  /* If target->out is .bss, add the value of the .data section to
+	     sym->value and set new output_section */
+	  if (!strcmp(target_section->output_section->name,".bss"))
+	    {
+	      bfd *ibfd;
+	      sec_ptr s;
+
+	      ibfd=target_section->output_section->owner;
+	      for (s=ibfd->sections;s!=NULL;s=s->next)
+		if (!strcmp(s->name,".data"))
+		  {
+		    target_section->output_offset+=s->_raw_size;
+		    target_section->output_section=s;
+		  }
+	    }
+
+	  relocation = sym->value + target_section->output_offset
+	    - (AMIGA_DATA(target_section->output_section->owner))->a4init;
+	  /* if the symbol is in .bss, subtract the offset that gas has put
+	     into the opcode */
+	  if (target_section->index == 2)
+	    relocation -= adata(abfd).datasec->_raw_size;
+	  DPRINT(20,("symbol=%s (0x%lx)\nsection %s (0x%lx; %s; output=0x%lx)"
+		     "\nrelocation @0x%lx\n", sym->name, sym->value,
+		     target_section->name, target_section,
+		     target_section->owner->filename, target_section->output_offset,
+		     r->address));
+	  flags|=ADDEND_UNSIGNED;
+	}
+      DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n",
+		 target_section->output_section->name,
+		 target_section->output_section,sec->output_section->name,
+		 sec->output_section,sym->name));
+      break;
+
+    default:
+      bfd_msg ("Error: unsupported reloc: %s(%d)",r->howto->name,r->howto->size);
+      ret=bfd_reloc_notsupported;
+      break;
+    }/* Of switch */
+
+  /* Add in relocation */
+  if (relocation!=0)
+    ret = my_add_to (r, data, relocation, flags);
+
+  if (copy) /* Copy reloc to output section */
+    {
+      DPRINT(5,("Copying reloc\n"));
+      target_section=sec->output_section;
+      r->address+=sec->output_offset;
+      target_section->orelocation[target_section->reloc_count++]=r;
+    }
+  DPRINT(5,("Leaving aout_perf_reloc with %d (OK=%d)\n",ret,bfd_reloc_ok));
+  return ret;
+}
+
+
+/* The final link routine, used both by Amiga and a.out backend */
+/* This is nearly a copy of linker.c/_bfd_generic_final_link */
+bfd_boolean
+amiga_final_link (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  bfd *sub;
+  asection *o;
+  struct bfd_link_order *p;
+  size_t outsymalloc;
+  struct generic_write_global_symbol_info wginfo;
+  struct bfd_link_hash_entry *h =
+    bfd_link_hash_lookup (info->hash, "___a4_init", FALSE, FALSE, TRUE);
+
+  if (amiga_base_relative && h && h->type == bfd_link_hash_defined) {
+    AMIGA_DATA(abfd)->baserel = TRUE;
+    AMIGA_DATA(abfd)->a4init = h->u.def.value;
+  }
+  else
+    AMIGA_DATA(abfd)->baserel = FALSE;
+
+  DPRINT(5,("Entering final_link\n"));
+
+  if (bfd_get_flavour (abfd) == bfd_target_aout_flavour)
+    return aout_amiga_final_link (abfd, info);
+
+  bfd_get_outsymbols (abfd) = (asymbol **) NULL;
+  bfd_get_symcount (abfd) = 0;
+  outsymalloc = 0;
+
+  /* Mark all sections which will be included in the output file.  */
+  for (o = abfd->sections; o != NULL; o = o->next)
+    for (p = o->link_order_head; p != NULL; p = p->next)
+      if (p->type == bfd_indirect_link_order)
+	p->u.indirect.section->linker_mark = TRUE;
+
+  /* Build the output symbol table.  */
+  for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
+    if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc))
+      return FALSE;
+
+  DPRINT(10,("Did build output symbol table\n"));
+
+  /* Accumulate the global symbols.  */
+  wginfo.info = info;
+  wginfo.output_bfd = abfd;
+  wginfo.psymalloc = &outsymalloc;
+  _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info),
+				   _bfd_generic_link_write_global_symbol,
+				   (PTR) &wginfo);
+
+  DPRINT(10,("Accumulated global symbols\n"));
+
+  DPRINT(10,("Output bfd is %s(%lx)\n",abfd->filename,abfd));
+
+  if (1)
+    {
+      /* Allocate space for the output relocs for each section.  */
+      /* We also handle base-relative linking special, by setting the .data
+	 sections real length to it's length + .bss length */
+      /* This is different to bfd_generic_final_link: We ALWAYS alloc space
+	 for the relocs, because we may need it anyway */
+      for (o = abfd->sections;
+	   o != (asection *) NULL;
+	   o = o->next)
+	{
+	  /* If section is .data, find .bss and add that length */
+	  if (!info->relocateable && amiga_base_relative &&
+	      !strcmp(o->name,".data"))
+	    {
+	      if (bfd_get_flavour(abfd)!=bfd_target_amiga_flavour) /* oops */
+		{
+		  bfd_msg ("You can't use base relative linking with "
+			   "partial links.");
+		}
+	      else if (0) /* XXX */
+		{
+		  asection *act_sec;
+		  for (act_sec=abfd->sections; act_sec!=NULL;act_sec=act_sec->next)
+		    if (!strcmp(act_sec->name,".bss"))
+		      amiga_per_section(o)->disk_size = o->_raw_size +
+			act_sec->_raw_size;
+		}
+	    }/* Of base-relative linking */
+
+	  DPRINT(10,("Section in output bfd is %s (%lx)\n",o->name,o));
+
+	  o->reloc_count = 0;
+	  for (p = o->link_order_head;
+	       p != (struct bfd_link_order *) NULL;
+	       p = p->next)
+	    {
+	      if (p->type == bfd_section_reloc_link_order
+		  || p->type == bfd_symbol_reloc_link_order)
+		++o->reloc_count;
+	      else if (p->type == bfd_indirect_link_order)
+		{
+		  asection *input_section;
+		  bfd *input_bfd;
+		  long relsize;
+		  arelent **relocs;
+		  asymbol **symbols;
+		  long reloc_count;
+
+		  input_section = p->u.indirect.section;
+		  input_bfd = input_section->owner;
+
+		  DPRINT(10,("\tIndirect section from bfd %s, section is %s(%lx) "
+			     "(COM=%lx)\n",
+			     input_bfd->filename,input_section->name,input_section,
+			     bfd_com_section_ptr));
+
+		  relsize = bfd_get_reloc_upper_bound (input_bfd,
+						       input_section);
+		  if (relsize < 0)
+		    {
+		      DPRINT(10,("Relsize<0.I..in bfd %s, sec %s\n",
+				 input_bfd->filename, input_section->name));
+		      return FALSE;
+		    }
+		  relocs = (arelent **) bfd_malloc ((bfd_size_type) relsize);
+		  if (!relocs && relsize != 0)
+		    return FALSE;
+		  symbols = _bfd_generic_link_get_symbols (input_bfd);
+		  reloc_count = bfd_canonicalize_reloc (input_bfd,
+							input_section,
+							relocs,
+							symbols);
+		  free (relocs);
+		  if (reloc_count < 0)
+		    {
+		      DPRINT(10,("Relsize<0.II..in bfd %s, sec %s\n",
+				 input_bfd->filename, input_section->name));
+		      return FALSE;
+		    }
+		  BFD_ASSERT ((unsigned long) reloc_count
+			      == input_section->reloc_count);
+		  o->reloc_count += reloc_count;
+		}
+	    }
+	  if (o->reloc_count > 0)
+	    {
+	      bfd_size_type amt;
+
+	      amt = o->reloc_count;
+	      amt *= sizeof (arelent *);
+	      o->orelocation = (arelent **) bfd_alloc (abfd, amt);
+	      if (!o->orelocation)
+		return FALSE;
+	      /* o->flags |= SEC_RELOC; There may be no relocs. This can
+		 be determined later only */
+	      /* Reset the count so that it can be used as an index
+		 when putting in the output relocs.  */
+	      o->reloc_count = 0;
+	    }
+	}
+    }
+
+  DPRINT(10,("Got all relocs\n"));
+
+  /* Handle all the link order information for the sections.  */
+  for (o = abfd->sections;
+       o != (asection *) NULL;
+       o = o->next)
+    {
+      for (p = o->link_order_head;
+	   p != (struct bfd_link_order *) NULL;
+	   p = p->next)
+	{
+	  switch (p->type)
+	    {
+	    case bfd_section_reloc_link_order:
+	    case bfd_symbol_reloc_link_order:
+	      if (! amiga_reloc_link_order (abfd, info, o, p)) /* We use an own routine */
+		return FALSE;
+	      break;
+	    case bfd_indirect_link_order:
+	      if (! default_indirect_link_order (abfd, info, o, p, FALSE))
+		/* Calls our get_relocated_section_contents */
+		return FALSE;
+	      break;
+	    default:
+	      if (! _bfd_default_link_order (abfd, info, o, p))
+		return FALSE;
+	      break;
+	    }
+	}
+    }
+
+  if (bfd_get_flavour(abfd)==bfd_target_amiga_flavour&&!info->relocateable)
+    AMIGA_DATA(abfd)->IsLoadFile = TRUE;
+
+  DPRINT(10,("Leaving final_link\n"));
+  return TRUE;
+}
+
+
+/* Handle reloc link order.
+   This is nearly a copy of linker.c/_bfd_generic_reloc_link_order */
+static bfd_boolean
+amiga_reloc_link_order (abfd, info, sec, link_order)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     struct bfd_link_order *link_order;
+{
+  arelent *r;
+
+  DPRINT(5,("Entering amiga_reloc_link_order\n"));
+
+  if (sec->orelocation == (arelent **) NULL)
+    {
+      DPRINT(10,("aborting, since orelocation==NULL\n"));
+      abort ();
+    }
+
+  /* We generate a new ***AMIGA*** style reloc */
+  r = (arelent *) bfd_zalloc (abfd, (bfd_size_type) sizeof (amiga_reloc_type));
+  if (r == (arelent *) NULL)
+    {
+      DPRINT(5,("Leaving amiga_reloc_link, no mem\n"));
+      return FALSE;
+    }
+
+  r->address = link_order->offset;
+  r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc);
+  if (r->howto == 0)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      DPRINT(5,("Leaving amiga_reloc_link, bad value\n"));
+      return FALSE;
+    }
+
+  /* Get the symbol to use for the relocation.  */
+  if (link_order->type == bfd_section_reloc_link_order)
+    r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr;
+  else
+    {
+      struct generic_link_hash_entry *h;
+
+      h = ((struct generic_link_hash_entry *)
+	   bfd_wrapped_link_hash_lookup (abfd, info,
+					 link_order->u.reloc.p->u.name,
+					 FALSE, FALSE, TRUE));
+      if (h == (struct generic_link_hash_entry *) NULL
+	  || ! h->written)
+	{
+	  if (! ((*info->callbacks->unattached_reloc)
+		 (info, link_order->u.reloc.p->u.name,
+		  (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+	    return FALSE;
+	  bfd_set_error (bfd_error_bad_value);
+	  DPRINT(5,("Leaving amiga_reloc_link, bad value in hash lookup\n"));
+	  return FALSE;
+	}
+      r->sym_ptr_ptr = &h->sym;
+    }
+  DPRINT(5,("Got symbol for relocation\n"));
+  /* Store the addend */
+  r->addend = link_order->u.reloc.p->addend;
+
+  /* If we are generating relocateable output, just add the reloc */
+  if (info->relocateable)
+    {
+      DPRINT(5,("Adding reloc\n"));
+      sec->orelocation[sec->reloc_count] = r;
+      ++sec->reloc_count;
+      sec->flags|=SEC_RELOC;
+    }
+  else /* Try to apply the reloc */
+    {
+      PTR data=(PTR)sec->contents;
+      bfd_reloc_status_type ret;
+      char *em=NULL;
+
+      DPRINT(5,("Apply link_order_reloc\n"));
+
+      /* FIXME: Maybe, we have to get the section contents, before we
+	  use them, if they have not been set by now.. */
+      BFD_ASSERT (data!=NULL);
+
+      if (bfd_get_flavour(abfd)==bfd_target_amiga_flavour)
+	ret=amiga_perform_reloc(abfd,r,data,sec,NULL,&em);
+      else
+	ret=aout_perform_reloc(abfd,r,data,sec,NULL,&em);
+
+      if (ret!=bfd_reloc_ok)
+	{
+	  DPRINT(5,("Leaving amiga_reloc_link, value FALSE\n"));
+	  return FALSE;
+	}
+    }
+  DPRINT(5,("Leaving amiga_reloc_link\n"));
+  return TRUE;
+}
diff -ru --new-file a/bfd/aout-amiga.c b/bfd/aout-amiga.c
--- a/bfd/aout-amiga.c	1970-01-01 03:00:00.000000000 +0300
+++ b/bfd/aout-amiga.c	2021-02-01 23:12:49.065494100 +0300
@@ -0,0 +1,152 @@
+/* BFD back-end for Amiga style m68k a.out binaries.
+   Copyright (C) 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Contributed by Stephan Thesing.
+
+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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#define TARGETNAME "a.out-amiga"
+#define MACHTYPE_OK(m) ((m)==M_UNKNOWN || (m)==M_68010 || (m)==M_68020)
+#define TARGET_IS_BIG_ENDIAN_P
+#define TARGET_PAGE_SIZE 0x2000
+#define N_HEADER_IN_TEXT(x) 0
+#define N_SHARED_LIB(x) 0
+#define TEXT_START_ADDR 0
+
+/* Do not "beautify" the CONCAT* macro args.  Traditional C will not
+   remove whitespace added here, and thus will fail to concatenate
+   the tokens.  */
+#define MY(OP) CONCAT2 (aout_amiga_,OP)
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "libaout.h"
+#include "aout/aout64.h"
+
+bfd_boolean
+MY(final_link) PARAMS ((bfd *, struct bfd_link_info *));
+
+bfd_boolean
+amiga_final_link PARAMS ((bfd *, struct bfd_link_info *));
+#define MY_bfd_final_link amiga_final_link
+
+bfd_byte *
+get_relocated_section_contents PARAMS ((bfd *, struct bfd_link_info *,
+	struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **));
+#define MY_bfd_get_relocated_section_contents get_relocated_section_contents
+
+static unsigned long MY(get_mach) PARAMS ((enum machine_type));
+static bfd_boolean MY(write_object_contents) PARAMS ((bfd *));
+static bfd_boolean MY(set_sizes) PARAMS ((bfd *));
+static bfd_boolean MY(link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *));
+#define MY_bfd_link_add_symbols aout_amiga_link_add_symbols
+
+static unsigned long
+MY(get_mach) (machtype)
+     enum machine_type machtype;
+{
+  unsigned long machine;
+  switch (machtype)
+    {
+    default:
+    case M_UNKNOWN:
+      /* Some Sun3s make magic numbers without cpu types in them, so
+	 we'll default to the 68000. */
+      machine = bfd_mach_m68000;
+      break;
+
+    case M_68010:
+      machine = bfd_mach_m68010;
+      break;
+
+    case M_68020:
+      machine = bfd_mach_m68020;
+      break;
+    }
+  return machine;
+}
+#define SET_ARCH_MACH(ABFD, EXEC) \
+  bfd_set_arch_mach (ABFD, bfd_arch_m68k, MY(get_mach) (N_MACHTYPE (EXEC)))
+
+static bfd_boolean
+MY(write_object_contents) (abfd)
+     bfd *abfd;
+{
+  struct external_exec exec_bytes;
+  struct internal_exec *execp = exec_hdr (abfd);
+
+  /* Magic number, maestro, please!  */
+  switch (bfd_get_arch (abfd))
+    {
+    case bfd_arch_m68k:
+      switch (bfd_get_mach (abfd))
+	{
+	case bfd_mach_m68000:
+	  N_SET_MACHTYPE (*execp, M_UNKNOWN);
+	  break;
+	case bfd_mach_m68010:
+	  N_SET_MACHTYPE (*execp, M_68010);
+	  break;
+	default:
+	case bfd_mach_m68020:
+	  N_SET_MACHTYPE (*execp, M_68020);
+	  break;
+	}
+      break;
+    default:
+      N_SET_MACHTYPE (*execp, M_UNKNOWN);
+    }
+
+  WRITE_HEADERS (abfd, execp);
+
+  return TRUE;
+}
+#define MY_write_object_contents MY(write_object_contents)
+
+static bfd_boolean
+MY(set_sizes) (abfd)
+     bfd *abfd;
+{
+  adata (abfd).page_size = TARGET_PAGE_SIZE;
+  adata (abfd).segment_size = TARGET_PAGE_SIZE;
+  adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE;
+  return TRUE;
+}
+#define MY_set_sizes MY(set_sizes)
+
+/* Include the usual a.out support.  */
+#include "aout-target.h"
+
+/* Add symbols from an object file to the global hash table.  */
+static bfd_boolean
+MY(link_add_symbols) (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  if (info->hash->creator->flavour == bfd_target_amiga_flavour)
+    return _bfd_generic_link_add_symbols (abfd, info);
+  return NAME(aout,link_add_symbols) (abfd, info);
+}
+
+/* Public final_link routine.  */
+bfd_boolean
+MY(final_link) (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  return NAME(aout,final_link) (abfd, info, MY_final_link_callback);
+}
diff -ru --new-file a/bfd/aoutx.h b/bfd/aoutx.h
--- a/bfd/aoutx.h	2013-11-04 19:33:37.000000000 +0400
+++ b/bfd/aoutx.h	2022-02-16 22:34:04.544915300 +0300
@@ -130,6 +130,10 @@
 #include "aout/stab_gnu.h"
 #include "aout/ar.h"
 
+/*Amiga hack - used in amigaos.c, must be global */
+/*static*/ bfd_boolean translate_to_native_sym_flags
+  PARAMS ((bfd *, asymbol *, struct external_nlist *));
+
 /*
 SUBSECTION
 	Relocations
@@ -1553,7 +1557,7 @@
 
 /* Set the fields of SYM_POINTER according to CACHE_PTR.  */
 
-static bfd_boolean
+bfd_boolean
 translate_to_native_sym_flags (bfd *abfd,
 			       asymbol *cache_ptr,
 			       struct external_nlist *sym_pointer)
@@ -1949,10 +1953,26 @@
 
   r_length = g->howto->size ;	/* Size as a power of two.  */
   r_pcrel  = (int) g->howto->pc_relative; /* Relative to PC?  */
+#if 1
+  /* FIXME! "#if 1" is the wrong way to select this Amiga specific code.  */
+  switch (bfd_asymbol_flavour(sym))
+    {
+    case bfd_target_amiga_flavour:
+    case bfd_target_aout_flavour:
+      r_baserel = (g->howto->type & 8) != 0;
+      r_jmptable = (g->howto->type & 16) != 0;
+      r_relative = (g->howto->type & 32) != 0;
+      break;
+    default:
+      r_baserel=r_jmptable=r_relative=0;
+      break;
+    }
+#else
   /* XXX This relies on relocs coming from a.out files.  */
   r_baserel = (g->howto->type & 8) != 0;
   r_jmptable = (g->howto->type & 16) != 0;
   r_relative = (g->howto->type & 32) != 0;
+#endif
 
   /* Name was clobbered by aout_write_syms to be symbol index.  */
 
@@ -2254,9 +2274,12 @@
   /* Base relative relocs are always against the symbol table,
      regardless of the setting of r_extern.  r_extern just reflects
      whether the symbol the reloc is against is local or global.  */
+#if 0
+  /* FIXME! "#if 0" is the wrong way to disable this code.  See comment
+     earlier in file. */
   if (r_baserel)
     r_extern = 1;
-
+#endif
   if (r_extern && r_index > symcount)
     {
       /* We could arrange to return an error, but it might be useful
diff -ru --new-file a/bfd/bfd.c b/bfd/bfd.c
--- a/bfd/bfd.c	2013-11-04 19:33:37.000000000 +0400
+++ b/bfd/bfd.c	2022-02-16 22:37:04.303729800 +0300
@@ -265,6 +265,7 @@
 .      struct bfd_pef_data_struct *pef_data;
 .      struct bfd_pef_xlib_data_struct *pef_xlib_data;
 .      struct bfd_sym_data_struct *sym_data;
+.      struct amiga_data_struct *amiga_data;
 .      void *any;
 .    }
 .  tdata;
diff -ru --new-file a/bfd/bfd-in2.h b/bfd/bfd-in2.h
--- a/bfd/bfd-in2.h	2013-11-18 12:40:15.000000000 +0400
+++ b/bfd/bfd-in2.h	2022-02-16 22:36:34.529218100 +0300
@@ -3183,6 +3183,10 @@
   BFD_RELOC_PPC_EMB_RELST_HA,
   BFD_RELOC_PPC_EMB_BIT_FLD,
   BFD_RELOC_PPC_EMB_RELSDA,
+  BFD_RELOC_PPC_MORPHOS_DREL,
+  BFD_RELOC_PPC_MORPHOS_DREL_LO,
+  BFD_RELOC_PPC_MORPHOS_DREL_HI,
+  BFD_RELOC_PPC_MORPHOS_DREL_HA,
   BFD_RELOC_PPC_VLE_REL8,
   BFD_RELOC_PPC_VLE_REL15,
   BFD_RELOC_PPC_VLE_REL24,
@@ -3273,6 +3277,12 @@
   BFD_RELOC_PPC64_TPREL16_HIGHA,
   BFD_RELOC_PPC64_DTPREL16_HIGH,
   BFD_RELOC_PPC64_DTPREL16_HIGHA,
+  
+/* AmigaOS4 specific relocations */
+  BFD_RELOC_PPC_AMIGAOS_BREL,
+  BFD_RELOC_PPC_AMIGAOS_BREL_LO,
+  BFD_RELOC_PPC_AMIGAOS_BREL_HI,
+  BFD_RELOC_PPC_AMIGAOS_BREL_HA,
 
 /* IBM 370/390 relocations  */
   BFD_RELOC_I370_D12,
@@ -6189,6 +6199,7 @@
       struct bfd_pef_data_struct *pef_data;
       struct bfd_pef_xlib_data_struct *pef_xlib_data;
       struct bfd_sym_data_struct *sym_data;
+      struct amiga_data_struct *amiga_data;
       void *any;
     }
   tdata;
@@ -6483,6 +6494,7 @@
 enum bfd_flavour
 {
   bfd_target_unknown_flavour,
+  bfd_target_amiga_flavour,
   bfd_target_aout_flavour,
   bfd_target_coff_flavour,
   bfd_target_ecoff_flavour,
diff -ru --new-file a/bfd/bfdio.c b/bfd/bfdio.c
--- a/bfd/bfdio.c	2013-11-04 19:33:37.000000000 +0400
+++ b/bfd/bfdio.c	2022-02-16 22:37:53.281487600 +0300
@@ -325,6 +325,31 @@
     result = abfd->iovec->bseek (abfd, file_position, direction);
   else
     result = -1;
+/* FIXME: The following code was previously used on AmigaOS. It pads the output file */
+#if 0
+  {
+    struct stat stat_buf;
+    if (direction == SEEK_CUR)
+      file_position += ftell (f);
+    fflush (f);
+    if (!(result = fstat (fileno (f), &stat_buf)) &&
+	file_position > stat_buf.st_size &&
+	!(result = fseek (f, stat_buf.st_size, SEEK_SET))) {
+      int zeroes = file_position - stat_buf.st_size;
+      char *buf = calloc (4096, 1);
+      if (buf) {
+	while (zeroes > 0) {
+	  int r, x = (zeroes > 4096? 4096 : zeroes);
+	  if ((r = write (fileno (f), buf, x))<=0)
+	    break;
+	  zeroes -= r;
+	}
+	free (buf);
+      }
+    }
+    result = fseek (f, file_position, SEEK_SET);
+  }
+#endif
 
   if (result != 0)
     {
diff -ru --new-file a/bfd/config.bfd b/bfd/config.bfd
--- a/bfd/config.bfd	2013-11-04 19:33:37.000000000 +0400
+++ b/bfd/config.bfd	2022-02-16 22:40:50.310382000 +0300
@@ -98,9 +98,11 @@
 crisv32)	 targ_archs=bfd_cris_arch ;;
 crx*)		 targ_archs=bfd_crx_arch ;;
 dlx*)		 targ_archs=bfd_dlx_arch ;;
+i[3456]86*)      targ_archs=bfd_i386_arch ;;
+i370)            targ_archs=bfd_i370_arch ;;
 fido*)		 targ_archs=bfd_m68k_arch ;;
 hppa*)		 targ_archs=bfd_hppa_arch ;;
-i[3-7]86)	 targ_archs=bfd_i386_arch ;;
+i[3-7]86*)	 targ_archs=bfd_i386_arch ;;
 i370)		 targ_archs=bfd_i370_arch ;;
 lm32)	         targ_archs=bfd_lm32_arch ;;
 m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;;
@@ -744,6 +746,11 @@
     targ_defvec=bfd_elf32_i386_vec
     targ_selfvecs=i386chaos_vec
     ;;
+	
+  i[3456]86be-*-amithlon*)
+    targ_defvec=bfd_elf32_i386be_amithlon_vec
+    targ_selvecs="bfd_elf32_i386_vec bfd_elf32_i386be_amithlon_vec"
+    ;;
 
   i860-*-mach3* | i860-*-osf1* | i860-*-coff*)
     targ_defvec=i860coff_vec
@@ -826,6 +833,11 @@
   m68*-motorola-sysv*)
     targ_defvec=m68ksysvcoff_vec
     ;;
+  m68*-*-amigaos*)
+    targ_defvec=amiga_vec
+    targ_selvecs="aout_amiga_vec amiga_vec"
+    targ_underscore=yes
+    ;;
   m68*-hp-bsd*)
     targ_defvec=hp300bsd_vec
     targ_underscore=yes
@@ -897,7 +909,7 @@
     targ_selvecs="m68kcoff_vec versados_vec tekhex_vec"
     targ_underscore=yes
     ;;
-  m68*-cbm-*)
+  m68*-cbm-amix)
     targ_defvec=bfd_elf32_m68k_vec
     targ_selvecs=m68kcoff_vec
     ;;
@@ -1209,6 +1221,18 @@
 	targ_cflags=-DSMALL_ARCHIVE;;
     esac
     ;;
+  powerpc-*-amigaoshunk*)
+    targ_defvec=amiga_vec
+    targ_selvecs="bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec aout_amiga_vec"
+    ;;
+  powerpc-*-amiga*)
+    targ_defvec=bfd_elf32_amigaos_vec
+    targ_selvecs="bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec"
+    ;;
+  powerpc-*-morphos*)
+    targ_defvec=bfd_elf32_morphos_vec
+    targ_selvecs="bfd_elf32_morphos_vec"
+    ;;
 #ifdef BFD64
   powerpc64-*-aix*)
     targ_defvec=rs6000coff64_vec
diff -ru --new-file a/bfd/configure b/bfd/configure
--- a/bfd/configure	2013-12-02 13:30:30.000000000 +0400
+++ b/bfd/configure	2022-02-16 22:42:17.185952500 +0300
@@ -15198,7 +15198,9 @@
     # use one entry per line, even though this leads to long lines.
     a_out_adobe_vec)		tb="$tb aout-adobe.lo aout32.lo" ;;
     aix5coff64_vec)		tb="$tb coff64-rs6000.lo xcofflink.lo aix5ppc-core.lo"; target_size=64 ;;
+    amiga_vec)			tb="$tb amigaos.lo amigaoslink.lo" ;;
     aout0_big_vec)		tb="$tb aout0.lo aout32.lo" ;;
+    aout_amiga_vec)		tb="$tb aout-amiga.lo aout32.lo";;
     aout_arm_big_vec)		tb="$tb aout-arm.lo aout32.lo" ;;
     aout_arm_little_vec)	tb="$tb aout-arm.lo aout32.lo" ;;
     apollocoff_vec)		tb="$tb coff-apollo.lo" ;;
@@ -15221,6 +15223,7 @@
     b_out_vec_little_host)	tb="$tb bout.lo aout32.lo" ;;
     bfd_pei_ia64_vec)		tb="$tb pei-ia64.lo pepigen.lo cofflink.lo"; target_size=64 ;;
     bfd_elf32_am33lin_vec)	tb="$tb elf32-am33lin.lo elf32.lo $elf" ;;
+    bfd_elf32_amigaos_vec)	tb="$tb elf32-amigaos.lo elf32.lo $elf" ;;
     bfd_elf32_avr_vec)		tb="$tb elf32-avr.lo elf32.lo $elf" ;;
     bfd_elf32_bfin_vec)		tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
     bfd_elf32_bfinfdpic_vec)	tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
@@ -15258,6 +15261,7 @@
     bfd_elf32_i386_nacl_vec)	tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;;
     bfd_elf32_i386_vxworks_vec)	tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;;
     bfd_elf32_i386_vec)		tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;;
+    bfd_elf32_i386be_amithlon_vec) tb="$tb elf32-i386-amithlon.lo elf32.lo $elf" ;;
     bfd_elf32_i860_little_vec)	tb="$tb elf32-i860.lo elf32.lo $elf" ;;
     bfd_elf32_i860_vec)		tb="$tb elf32-i860.lo elf32.lo $elf" ;;
     bfd_elf32_i960_vec)		tb="$tb elf32-i960.lo elf32.lo $elf" ;;
@@ -15298,6 +15302,7 @@
     bfd_elf32_microblaze_vec)	tb="$tb elf32-microblaze.lo elf32.lo $elf" ;;
     bfd_elf32_mn10200_vec)	tb="$tb elf-m10200.lo elf32.lo $elf" ;;
     bfd_elf32_mn10300_vec)	tb="$tb elf-m10300.lo elf32.lo $elf" ;;
+    bfd_elf32_morphos_vec)      tb="$tb elf32-morphos.lo elf32.lo $elf";;
     bfd_elf32_mt_vec)           tb="$tb elf32-mt.lo elf32.lo $elf" ;;
     bfd_elf32_msp430_vec)	tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
     bfd_elf32_msp430_ti_vec)	tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
diff -ru --new-file a/bfd/configure.host b/bfd/configure.host
--- a/bfd/configure.host	2013-11-04 19:33:37.000000000 +0400
+++ b/bfd/configure.host	2022-02-16 22:42:39.856040000 +0300
@@ -73,6 +73,7 @@
 mips*-*-riscos*)	HDEFINES="-G 4" ;;
 
 m68*-hp-hpux*)		HDEFINES=-DHOST_HP300HPUX ;;
+m68*-*-amigaos*)	HDEFINES=-mstackextend ;;
 
 # Some Solaris systems (osol0906 at least) have a libc that doesn't recognise
 # the "MS-ANSI" code page name, so we define an override for CP_ACP (sets the
diff -ru --new-file a/bfd/configure.in b/bfd/configure.in
--- a/bfd/configure.in	2013-12-02 13:30:28.000000000 +0400
+++ b/bfd/configure.in	2022-02-16 22:44:02.425039000 +0300
@@ -687,7 +687,9 @@
     # use one entry per line, even though this leads to long lines.
     a_out_adobe_vec)		tb="$tb aout-adobe.lo aout32.lo" ;;
     aix5coff64_vec)		tb="$tb coff64-rs6000.lo xcofflink.lo aix5ppc-core.lo"; target_size=64 ;;
+    amiga_vec)			tb="$tb amigaos.lo amigaoslink.lo" ;;
     aout0_big_vec)		tb="$tb aout0.lo aout32.lo" ;;
+    aout_amiga_vec)		tb="$tb aout-amiga.lo aout32.lo";;
     aout_arm_big_vec)		tb="$tb aout-arm.lo aout32.lo" ;;
     aout_arm_little_vec)	tb="$tb aout-arm.lo aout32.lo" ;;
     apollocoff_vec)		tb="$tb coff-apollo.lo" ;;
@@ -710,6 +712,7 @@
     b_out_vec_little_host)	tb="$tb bout.lo aout32.lo" ;;
     bfd_pei_ia64_vec)		tb="$tb pei-ia64.lo pepigen.lo cofflink.lo"; target_size=64 ;;
     bfd_elf32_am33lin_vec)	tb="$tb elf32-am33lin.lo elf32.lo $elf" ;;
+    bfd_elf32_amigaos_vec)	tb="$tb elf32-amigaos.lo elf32.lo $elf" ;;
     bfd_elf32_avr_vec)		tb="$tb elf32-avr.lo elf32.lo $elf" ;;
     bfd_elf32_bfin_vec)		tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
     bfd_elf32_bfinfdpic_vec)	tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
@@ -747,6 +750,7 @@
     bfd_elf32_i386_nacl_vec)	tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;;
     bfd_elf32_i386_vxworks_vec)	tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;;
     bfd_elf32_i386_vec)		tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;;
+    bfd_elf32_i386be_amithlon_vec) tb="$tb elf32-i386-amithlon.lo elf32.lo $elf" ;;
     bfd_elf32_i860_little_vec)	tb="$tb elf32-i860.lo elf32.lo $elf" ;;
     bfd_elf32_i860_vec)		tb="$tb elf32-i860.lo elf32.lo $elf" ;;
     bfd_elf32_i960_vec)		tb="$tb elf32-i960.lo elf32.lo $elf" ;;
@@ -787,6 +791,7 @@
     bfd_elf32_microblaze_vec)	tb="$tb elf32-microblaze.lo elf32.lo $elf" ;;
     bfd_elf32_mn10200_vec)	tb="$tb elf-m10200.lo elf32.lo $elf" ;;
     bfd_elf32_mn10300_vec)	tb="$tb elf-m10300.lo elf32.lo $elf" ;;
+    bfd_elf32_morphos_vec)      tb="$tb elf32-morphos.lo elf32.lo $elf";;
     bfd_elf32_mt_vec)           tb="$tb elf32-mt.lo elf32.lo $elf" ;;
     bfd_elf32_msp430_vec)	tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
     bfd_elf32_msp430_ti_vec)	tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
diff -ru --new-file a/bfd/doc/bfd.texinfo b/bfd/doc/bfd.texinfo
--- a/bfd/doc/bfd.texinfo	2013-11-04 19:33:37.000000000 +0400
+++ b/bfd/doc/bfd.texinfo	2022-02-16 22:49:49.450972700 +0300
@@ -291,6 +291,7 @@
 * aout ::	a.out backends
 * coff ::	coff backends
 * elf  ::	elf backends
+* amiga ::      amigaos backend
 * mmo  ::	mmo backend
 @ignore
 * oasys ::	oasys backends
@@ -308,12 +309,16 @@
 @node coff, elf, aout, BFD back ends
 @include  coffcode.texi
 
-@node elf, mmo, coff, BFD back ends
+@node elf, amiga, coff, BFD back ends
 @include  elf.texi
 @c Leave this out until the file has some actual contents...
 @c @include  elfcode.texi
 
-@node mmo,  , elf, BFD back ends
+@node amiga, mmo, elf, BFD back ends
+@include amiga.texi
+@include amigalink.texi
+
+@node mmo, , amiga, BFD back ends
 @include  mmo.texi
 
 @node GNU Free Documentation License, BFD Index, BFD back ends, Top
diff -ru --new-file a/bfd/doc/Makefile.am b/bfd/doc/Makefile.am
--- a/bfd/doc/Makefile.am	2013-11-04 19:33:37.000000000 +0400
+++ b/bfd/doc/Makefile.am	2022-02-16 22:46:39.559275000 +0300
@@ -19,7 +19,7 @@
 
 AUTOMAKE_OPTIONS = 1.9 cygnus
 
-DOCFILES = aoutx.texi  archive.texi archures.texi \
+DOCFILES = amiga.texi amigalink.texi aoutx.texi  archive.texi archures.texi \
 	bfdt.texi  cache.texi coffcode.texi \
 	core.texi elf.texi elfcode.texi  format.texi \
 	libbfd.texi bfdwin.texi bfdio.texi \
@@ -46,6 +46,7 @@
 	$(srcdir)/../cache.c $(srcdir)/../coffcode.h \
 	$(srcdir)/../corefile.c $(srcdir)/../elf.c \
 	$(srcdir)/../elfcode.h  $(srcdir)/../format.c \
+	$(srcdir)/../amigaos.c $(srcdir)/../amigaoslink.c \
 	$(srcdir)/../libbfd.c $(srcdir)/../opncls.c \
 	$(srcdir)/../reloc.c  $(srcdir)/../section.c \
 	$(srcdir)/../syms.c  $(srcdir)/../targets.c \
@@ -203,6 +204,18 @@
 	./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../linker.c >linker.tmp
 	$(SHELL) $(srcdir)/../../move-if-change linker.tmp linker.texi
 
+s-amiga: $(MKDOC) $(srcdir)/../amigaos.c $(srcdir)/doc.str
+	./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaos.c >amiga.tmp
+	$(srcdir)/../../move-if-change amiga.tmp amiga.texi
+	touch s-amiga
+amiga.texi: s-amiga
+
+s-amigalink: $(MKDOC) $(srcdir)/../amigaoslink.c $(srcdir)/doc.str
+	./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaoslink.c >amigalink.tmp
+	$(srcdir)/../../move-if-change amigalink.tmp amigalink.texi
+	touch s-amigalink
+amigalink.texi: s-amigalink
+
 LIBBFD_H_DEP = \
 	$(srcdir)/../libbfd-in.h	\
 	$(srcdir)/../init.c		\
diff -ru --new-file a/bfd/doc/Makefile.in b/bfd/doc/Makefile.in
--- a/bfd/doc/Makefile.in	2013-12-02 13:30:30.000000000 +0400
+++ b/bfd/doc/Makefile.in	2022-02-16 22:48:14.941782600 +0300
@@ -290,7 +290,7 @@
 top_srcdir = @top_srcdir@
 wordsize = @wordsize@
 AUTOMAKE_OPTIONS = 1.9 cygnus
-DOCFILES = aoutx.texi  archive.texi archures.texi \
+DOCFILES = amiga.texi amigalink.texi aoutx.texi  archive.texi archures.texi \
 	bfdt.texi  cache.texi coffcode.texi \
 	core.texi elf.texi elfcode.texi  format.texi \
 	libbfd.texi bfdwin.texi bfdio.texi \
@@ -317,6 +317,7 @@
 	$(srcdir)/../cache.c $(srcdir)/../coffcode.h \
 	$(srcdir)/../corefile.c $(srcdir)/../elf.c \
 	$(srcdir)/../elfcode.h  $(srcdir)/../format.c \
+	$(srcdir)/../amigaos.c $(srcdir)/../amigaoslink.c \
 	$(srcdir)/../libbfd.c $(srcdir)/../opncls.c \
 	$(srcdir)/../reloc.c  $(srcdir)/../section.c \
 	$(srcdir)/../syms.c  $(srcdir)/../targets.c \
@@ -902,6 +903,18 @@
 	./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../linker.c >linker.tmp
 	$(SHELL) $(srcdir)/../../move-if-change linker.tmp linker.texi
 
+s-amiga: $(MKDOC) $(srcdir)/../amigaos.c $(srcdir)/doc.str
+	./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaos.c >amiga.tmp
+	$(srcdir)/../../move-if-change amiga.tmp amiga.texi
+	touch s-amiga
+amiga.texi: s-amiga
+
+s-amigalink: $(MKDOC) $(srcdir)/../amigaoslink.c $(srcdir)/doc.str
+	./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaoslink.c >amigalink.tmp
+	$(srcdir)/../../move-if-change amigalink.tmp amigalink.texi
+	touch s-amigalink
+amigalink.texi: s-amigalink
+
 libbfd.h: $(LIBBFD_H_DEP)
 	echo "$(LIBBFD_H_DEP)" | sed -f $(srcdir)/header.sed > $@
 	for file in $(LIBBFD_H_DEP); do \
diff -ru --new-file a/bfd/elf32-amiga.c b/bfd/elf32-amiga.c
--- a/bfd/elf32-amiga.c	1970-01-01 03:00:00.000000000 +0300
+++ b/bfd/elf32-amiga.c	2021-02-01 23:12:49.099584800 +0300
@@ -0,0 +1,3844 @@
+/* PowerPC-specific support for 32-bit ELF
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "elf/ppc.h"
+
+#define USE_RELA		/* we want RELA relocations, not REL */
+
+static reloc_howto_type *ppc_elf_reloc_type_lookup
+  PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
+static void ppc_elf_info_to_howto
+  PARAMS ((bfd *abfd, arelent *cache_ptr, Elf32_Internal_Rela *dst));
+static void ppc_elf_howto_init PARAMS ((void));
+static int ppc_elf_sort_rela PARAMS ((const PTR, const PTR));
+static boolean ppc_elf_relax_section
+  PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *));
+static bfd_reloc_status_type ppc_elf_addr16_ha_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static boolean ppc_elf_object_p PARAMS ((bfd *));
+static boolean ppc_elf_set_private_flags PARAMS ((bfd *, flagword));
+static boolean ppc_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
+
+static int ppc_elf_additional_program_headers PARAMS ((bfd *));
+static boolean ppc_elf_modify_segment_map PARAMS ((bfd *));
+
+static asection *ppc_elf_create_got
+  PARAMS ((bfd *, struct bfd_link_info *));
+static boolean ppc_elf_create_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+static boolean ppc_elf_section_from_shdr PARAMS ((bfd *,
+						  Elf32_Internal_Shdr *,
+						  const char *));
+static boolean ppc_elf_fake_sections
+  PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
+
+static elf_linker_section_t *ppc_elf_create_linker_section
+  PARAMS ((bfd *abfd,
+	   struct bfd_link_info *info,
+	   enum elf_linker_section_enum));
+
+static boolean ppc_elf_check_relocs PARAMS ((bfd *,
+					     struct bfd_link_info *,
+					     asection *,
+					     const Elf_Internal_Rela *));
+
+static asection * ppc_elf_gc_mark_hook PARAMS ((asection *sec,
+						struct bfd_link_info *info,
+						Elf_Internal_Rela *rel,
+						struct elf_link_hash_entry *h,
+						Elf_Internal_Sym *sym));
+
+static boolean ppc_elf_gc_sweep_hook PARAMS ((bfd *abfd,
+					      struct bfd_link_info *info,
+					      asection *sec,
+					      const Elf_Internal_Rela *relocs));
+
+static boolean ppc_elf_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *,
+						      struct elf_link_hash_entry *));
+
+static boolean ppc_elf_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));
+
+static boolean ppc_elf_relocate_section PARAMS ((bfd *,
+						 struct bfd_link_info *info,
+						 bfd *,
+						 asection *,
+						 bfd_byte *,
+						 Elf_Internal_Rela *relocs,
+						 Elf_Internal_Sym *local_syms,
+						 asection **));
+
+static boolean ppc_elf_add_symbol_hook  PARAMS ((bfd *,
+						 struct bfd_link_info *,
+						 const Elf_Internal_Sym *,
+						 const char **,
+						 flagword *,
+						 asection **,
+						 bfd_vma *));
+
+static boolean ppc_elf_finish_dynamic_symbol PARAMS ((bfd *,
+						      struct bfd_link_info *,
+						      struct elf_link_hash_entry *,
+						      Elf_Internal_Sym *));
+
+static boolean ppc_elf_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));
+static enum elf_reloc_type_class ppc_elf_reloc_type_class
+  PARAMS ((const Elf_Internal_Rela *));
+static boolean ppc_elf_grok_prstatus
+  PARAMS ((bfd *abfd, Elf_Internal_Note *note));
+static boolean ppc_elf_grok_psinfo
+  PARAMS ((bfd *abfd, Elf_Internal_Note *note));
+
+#define BRANCH_PREDICT_BIT 0x200000		/* branch prediction bit for branch taken relocs */
+#define RA_REGISTER_MASK 0x001f0000		/* mask to set RA in memory instructions */
+#define RA_REGISTER_SHIFT 16			/* value to shift register by to insert RA */
+
+/* The name of the dynamic interpreter.  This is put in the .interp
+   section.  */
+
+#define ELF_DYNAMIC_INTERPRETER "sys:libs/runtime-linker"
+
+/* The size in bytes of an entry in the procedure linkage table.  */
+#define PLT_ENTRY_SIZE 12
+/* The initial size of the plt reserved for the dynamic linker.  */
+#define PLT_INITIAL_ENTRY_SIZE 72
+/* The size of the gap between entries in the PLT.  */
+#define PLT_SLOT_SIZE 8
+/* The number of single-slot PLT entries (the rest use two slots).  */
+#define PLT_NUM_SINGLE_ENTRIES 8192
+
+/* Will references to this symbol always reference the symbol
+   in this object?  */
+#define SYMBOL_REFERENCES_LOCAL(INFO, H)				\
+  ((! INFO->shared							\
+    || INFO->symbolic							\
+    || H->dynindx == -1							\
+    || ELF_ST_VISIBILITY (H->other) == STV_INTERNAL			\
+    || ELF_ST_VISIBILITY (H->other) == STV_HIDDEN)			\
+   && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+
+/* Will _calls_ to this symbol always call the version in this object?  */
+#define SYMBOL_CALLS_LOCAL(INFO, H)				\
+  ((! INFO->shared							\
+    || INFO->symbolic							\
+    || H->dynindx == -1							\
+    || ELF_ST_VISIBILITY (H->other) != STV_DEFAULT)			\
+   && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+
+static reloc_howto_type *ppc_elf_howto_table[(int) 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 */
+
+  /* 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_bitfield, /* 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_bitfield, /* 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 */
+
+  /* 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 */
+	 true,			/* 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 */
+
+  /* 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 ()
+{
+  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;
+      BFD_ASSERT (type < sizeof (ppc_elf_howto_table) / sizeof (ppc_elf_howto_table[0]));
+      ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i];
+    }
+}
+
+/* This function handles relaxing for the PPC with option --mpc860c0[=<n>].
+
+   The MPC860, revision C0 or earlier contains a bug in the die.
+   If all of the following conditions are true, the next instruction
+   to be executed *may* be treated as a no-op.
+   1/ A forward branch is executed.
+   2/ The branch is predicted as not taken.
+   3/ The branch is taken.
+   4/ The branch is located in the last 5 words of a page.
+      (The EOP limit is 5 by default but may be specified as any value from 1-10.)
+
+   Our software solution is to detect these problematic branches in a
+   linker pass and modify them as follows:
+   1/ Unconditional branches - Since these are always predicted taken,
+      there is no problem and no action is required.
+   2/ Conditional backward branches - No problem, no action required.
+   3/ Conditional forward branches - Ensure that the "inverse prediction
+      bit" is set (ensure it is predicted taken).
+   4/ Conditional register branches - Ensure that the "y bit" is set
+      (ensure it is predicted taken).
+*/
+
+/* Sort sections by address.  */
+
+static int
+ppc_elf_sort_rela (arg1, arg2)
+     const PTR arg1;
+     const PTR arg2;
+{
+  const Elf_Internal_Rela **rela1 = (const Elf_Internal_Rela**) arg1;
+  const Elf_Internal_Rela **rela2 = (const Elf_Internal_Rela**) arg2;
+
+  /* Sort by offset.  */
+  return ((*rela1)->r_offset - (*rela2)->r_offset);
+}
+
+static boolean
+ppc_elf_relax_section (abfd, isec, link_info, again)
+     bfd *abfd;
+     asection *isec;
+     struct bfd_link_info *link_info;
+     boolean *again;
+{
+#define PAGESIZE 0x1000
+
+  bfd_byte *contents = NULL;
+  bfd_byte *free_contents = NULL;
+  Elf_Internal_Rela *internal_relocs = NULL;
+  Elf_Internal_Rela *free_relocs = NULL;
+  Elf_Internal_Rela **rela_comb = NULL;
+  int comb_curr, comb_count;
+
+  /* We never have to do this more than once per input section.  */
+  *again = false;
+
+  /* If needed, initialize this section's cooked size.  */
+  if (isec->_cooked_size == 0)
+      isec->_cooked_size = isec->_raw_size;
+
+  /* We're only interested in text sections which overlap the
+     troublesome area at the end of a page.  */
+  if (link_info->mpc860c0 && (isec->flags & SEC_CODE) && isec->_cooked_size)
+    {
+      bfd_vma dot, end_page, end_section;
+      boolean section_modified;
+
+      /* Get the section contents.  */
+      /* 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.  */
+	  contents = (bfd_byte *) bfd_malloc (isec->_raw_size);
+	  if (contents == NULL)
+	    goto error_return;
+	  free_contents = contents;
+
+	  if (! bfd_get_section_contents (abfd, isec, contents,
+					  (file_ptr) 0, isec->_raw_size))
+	    goto error_return;
+	}
+
+      comb_curr = 0;
+      comb_count = 0;
+      if (isec->reloc_count)
+	{
+          unsigned n;
+	  bfd_size_type amt;
+
+          /* Get a copy of the native relocations.  */
+          internal_relocs = _bfd_elf32_link_read_relocs (
+    	    abfd, isec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+    	    link_info->keep_memory);
+          if (internal_relocs == NULL)
+    	      goto error_return;
+          if (! link_info->keep_memory)
+    	      free_relocs = internal_relocs;
+
+          /* Setup a faster access method for the reloc info we need.  */
+	  amt = isec->reloc_count;
+	  amt *= sizeof (Elf_Internal_Rela*);
+          rela_comb = (Elf_Internal_Rela**) bfd_malloc (amt);
+          if (rela_comb == NULL)
+              goto error_return;
+          for (n = 0; n < isec->reloc_count; ++n)
+            {
+              long r_type;
+
+              r_type = ELF32_R_TYPE (internal_relocs[n].r_info);
+              if (r_type < 0 || r_type >= (int) R_PPC_max)
+                  goto error_return;
+
+              /* Prologue constants are sometimes present in the ".text"
+              sections and they can be identified by their associated relocation.
+              We don't want to process those words and some others which
+              can also be identified by their relocations.  However, not all
+              conditional branches will have a relocation so we will
+              only ignore words that 1) have a reloc, and 2) the reloc
+              is not applicable to a conditional branch.
+              The array rela_comb is built here for use in the EOP scan loop.  */
+              switch (r_type)
+                {
+                case R_PPC_ADDR14_BRNTAKEN:     /* absolute, predicted not taken */
+                case R_PPC_REL14:               /* relative cond. br.  */
+                case R_PPC_REL14_BRNTAKEN:      /* rel. cond. br., predicted not taken */
+                  /* We should check the instruction.  */
+                  break;
+                default:
+                  /* The word is not a conditional branch - ignore it.  */
+                  rela_comb[comb_count++] = &internal_relocs[n];
+                  break;
+                }
+            }
+          if (comb_count > 1)
+	    qsort (rela_comb, (size_t) comb_count, sizeof (int), ppc_elf_sort_rela);
+	}
+
+      /* Enumerate each EOP region that overlaps this section.  */
+      end_section = isec->vma + isec->_cooked_size;
+      dot = end_page = (isec->vma | (PAGESIZE - 1)) + 1;
+      dot -= link_info->mpc860c0;
+      section_modified = false;
+      if (dot < isec->vma)      /* Increment the start position if this section */
+          dot = isec->vma;      /* begins in the middle of its first EOP region.  */
+      for (;
+           dot < end_section;
+           dot += PAGESIZE, end_page += PAGESIZE)
+        {
+
+          /* Check each word in this EOP region.  */
+          for (; dot < end_page; dot += 4)
+            {
+              bfd_vma isec_offset;
+              unsigned long insn;
+              boolean skip, modified;
+
+              /* Don't process this word if there is a relocation for it and
+              the relocation indicates the word is not a conditional branch.  */
+              skip = false;
+              isec_offset = dot - isec->vma;
+              for (; comb_curr<comb_count; ++comb_curr)
+                {
+                  bfd_vma r_offset;
+
+                  r_offset = rela_comb[comb_curr]->r_offset;
+                  if (r_offset >= isec_offset)
+                    {
+                      if (r_offset == isec_offset) skip = true;
+                      break;
+                    }
+                }
+              if (skip) continue;
+
+              /* Check the current word for a problematic conditional branch.  */
+#define BO0(insn) ((insn) & 0x02000000)
+#define BO2(insn) ((insn) & 0x00800000)
+#define BO4(insn) ((insn) & 0x00200000)
+              insn = (unsigned long) bfd_get_32 (abfd, contents + isec_offset);
+              modified = false;
+              if ((insn & 0xFc000000) == 0x40000000)
+                {
+                  /* Instruction is BCx */
+                  if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
+                    {
+                      bfd_vma target;
+                      /* This branch is predicted as "normal".
+                      If this is a forward branch, it is problematic.  */
+
+                      target = insn & 0x0000Fffc;               /*extract*/
+                      target = (target ^ 0x8000) - 0x8000;      /*sign extend*/
+                      if ((insn & 0x00000002) == 0)
+                          target += dot;                        /*convert to abs*/
+                      if (target > dot)
+                        {
+                          insn |= 0x00200000;   /* set the prediction bit */
+                          modified = true;
+                        }
+                    }
+                }
+              else if ((insn & 0xFc00Fffe) == 0x4c000420)
+                {
+                  /* Instruction is BCCTRx */
+                  if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
+		    {
+		      /* This branch is predicted as not-taken.
+		      If this is a forward branch, it is problematic.
+                      Since we can't tell statically if it will branch forward,
+                      always set the prediction bit.  */
+                      insn |= 0x00200000;   /* set the prediction bit */
+                      modified = true;
+		    }
+                }
+              else if ((insn & 0xFc00Fffe) == 0x4c000020)
+                {
+                  /* Instruction is BCLRx */
+                  if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
+		    {
+		      /* This branch is predicted as not-taken.
+		      If this is a forward branch, it is problematic.
+                      Since we can't tell statically if it will branch forward,
+                      always set the prediction bit.  */
+                      insn |= 0x00200000;   /* set the prediction bit */
+                      modified = true;
+		    }
+                }
+#undef BO0
+#undef BO2
+#undef BO4
+              if (modified)
+	        {
+                  bfd_put_32 (abfd, (bfd_vma) insn, contents + isec_offset);
+		  section_modified = true;
+	        }
+            }
+        }
+      if (section_modified)
+	{
+	  elf_section_data (isec)->this_hdr.contents = contents;
+	  free_contents = NULL;
+	}
+    }
+
+  if (rela_comb != NULL)
+    {
+      free (rela_comb);
+      rela_comb = NULL;
+    }
+
+  if (free_relocs != NULL)
+    {
+      free (free_relocs);
+      free_relocs = NULL;
+    }
+
+  if (free_contents != NULL)
+    {
+      if (! link_info->keep_memory)
+	free (free_contents);
+      else
+	{
+	  /* Cache the section contents for elf_link_input_bfd.  */
+	  elf_section_data (isec)->this_hdr.contents = contents;
+	}
+      free_contents = NULL;
+    }
+
+  return true;
+
+error_return:
+  if (rela_comb != NULL)
+    free (rela_comb);
+  if (free_relocs != NULL)
+    free (free_relocs);
+  if (free_contents != NULL)
+    free (free_contents);
+  return false;
+}
+
+static reloc_howto_type *
+ppc_elf_reloc_type_lookup (abfd, code)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     bfd_reloc_code_real_type code;
+{
+  enum elf_ppc_reloc_type ppc_reloc = R_PPC_NONE;
+
+  if (!ppc_elf_howto_table[R_PPC_ADDR32])
+    /* Initialize howto table if needed.  */
+    ppc_elf_howto_init ();
+
+  switch ((int) code)
+    {
+    default:
+      return (reloc_howto_type *) NULL;
+
+    case BFD_RELOC_NONE:		ppc_reloc = R_PPC_NONE;			break;
+    case BFD_RELOC_32:			ppc_reloc = R_PPC_ADDR32;		break;
+    case BFD_RELOC_PPC_BA26:		ppc_reloc = R_PPC_ADDR24;		break;
+    case BFD_RELOC_16:			ppc_reloc = R_PPC_ADDR16;		break;
+    case BFD_RELOC_LO16:		ppc_reloc = R_PPC_ADDR16_LO;		break;
+    case BFD_RELOC_HI16:		ppc_reloc = R_PPC_ADDR16_HI;		break;
+    case BFD_RELOC_HI16_S:		ppc_reloc = R_PPC_ADDR16_HA;		break;
+    case BFD_RELOC_PPC_BA16:		ppc_reloc = R_PPC_ADDR14;		break;
+    case BFD_RELOC_PPC_BA16_BRTAKEN:	ppc_reloc = R_PPC_ADDR14_BRTAKEN;	break;
+    case BFD_RELOC_PPC_BA16_BRNTAKEN:	ppc_reloc = R_PPC_ADDR14_BRNTAKEN;	break;
+    case BFD_RELOC_PPC_B26:		ppc_reloc = R_PPC_REL24;		break;
+    case BFD_RELOC_PPC_B16:		ppc_reloc = R_PPC_REL14;		break;
+    case BFD_RELOC_PPC_B16_BRTAKEN:	ppc_reloc = R_PPC_REL14_BRTAKEN;	break;
+    case BFD_RELOC_PPC_B16_BRNTAKEN:	ppc_reloc = R_PPC_REL14_BRNTAKEN;	break;
+    case BFD_RELOC_16_GOTOFF:		ppc_reloc = R_PPC_GOT16;		break;
+    case BFD_RELOC_LO16_GOTOFF:		ppc_reloc = R_PPC_GOT16_LO;		break;
+    case BFD_RELOC_HI16_GOTOFF:		ppc_reloc = R_PPC_GOT16_HI;		break;
+    case BFD_RELOC_HI16_S_GOTOFF:	ppc_reloc = R_PPC_GOT16_HA;		break;
+    case BFD_RELOC_24_PLT_PCREL:	ppc_reloc = R_PPC_PLTREL24;		break;
+    case BFD_RELOC_PPC_COPY:		ppc_reloc = R_PPC_COPY;			break;
+    case BFD_RELOC_PPC_GLOB_DAT:	ppc_reloc = R_PPC_GLOB_DAT;		break;
+    case BFD_RELOC_PPC_LOCAL24PC:	ppc_reloc = R_PPC_LOCAL24PC;		break;
+    case BFD_RELOC_32_PCREL:		ppc_reloc = R_PPC_REL32;		break;
+    case BFD_RELOC_32_PLTOFF:		ppc_reloc = R_PPC_PLT32;		break;
+    case BFD_RELOC_32_PLT_PCREL:	ppc_reloc = R_PPC_PLTREL32;		break;
+    case BFD_RELOC_LO16_PLTOFF:		ppc_reloc = R_PPC_PLT16_LO;		break;
+    case BFD_RELOC_HI16_PLTOFF:		ppc_reloc = R_PPC_PLT16_HI;		break;
+    case BFD_RELOC_HI16_S_PLTOFF:	ppc_reloc = R_PPC_PLT16_HA;		break;
+    case BFD_RELOC_GPREL16:		ppc_reloc = R_PPC_SDAREL16;		break;
+    case BFD_RELOC_16_BASEREL:		ppc_reloc = R_PPC_SECTOFF;		break;
+    case BFD_RELOC_LO16_BASEREL:	ppc_reloc = R_PPC_SECTOFF_LO;		break;
+    case BFD_RELOC_HI16_BASEREL:	ppc_reloc = R_PPC_SECTOFF_HI;		break;
+    case BFD_RELOC_HI16_S_BASEREL:	ppc_reloc = R_PPC_SECTOFF_HA;		break;
+    case BFD_RELOC_CTOR:		ppc_reloc = R_PPC_ADDR32;		break;
+    case BFD_RELOC_PPC_TOC16:		ppc_reloc = R_PPC_TOC16;		break;
+    case BFD_RELOC_PPC_EMB_NADDR32:	ppc_reloc = R_PPC_EMB_NADDR32;		break;
+    case BFD_RELOC_PPC_EMB_NADDR16:	ppc_reloc = R_PPC_EMB_NADDR16;		break;
+    case BFD_RELOC_PPC_EMB_NADDR16_LO:	ppc_reloc = R_PPC_EMB_NADDR16_LO;	break;
+    case BFD_RELOC_PPC_EMB_NADDR16_HI:	ppc_reloc = R_PPC_EMB_NADDR16_HI;	break;
+    case BFD_RELOC_PPC_EMB_NADDR16_HA:	ppc_reloc = R_PPC_EMB_NADDR16_HA;	break;
+    case BFD_RELOC_PPC_EMB_SDAI16:	ppc_reloc = R_PPC_EMB_SDAI16;		break;
+    case BFD_RELOC_PPC_EMB_SDA2I16:	ppc_reloc = R_PPC_EMB_SDA2I16;		break;
+    case BFD_RELOC_PPC_EMB_SDA2REL:	ppc_reloc = R_PPC_EMB_SDA2REL;		break;
+    case BFD_RELOC_PPC_EMB_SDA21:	ppc_reloc = R_PPC_EMB_SDA21;		break;
+    case BFD_RELOC_PPC_EMB_MRKREF:	ppc_reloc = R_PPC_EMB_MRKREF;		break;
+    case BFD_RELOC_PPC_EMB_RELSEC16:	ppc_reloc = R_PPC_EMB_RELSEC16;		break;
+    case BFD_RELOC_PPC_EMB_RELST_LO:	ppc_reloc = R_PPC_EMB_RELST_LO;		break;
+    case BFD_RELOC_PPC_EMB_RELST_HI:	ppc_reloc = R_PPC_EMB_RELST_HI;		break;
+    case BFD_RELOC_PPC_EMB_RELST_HA:	ppc_reloc = R_PPC_EMB_RELST_HA;		break;
+    case BFD_RELOC_PPC_EMB_BIT_FLD:	ppc_reloc = R_PPC_EMB_BIT_FLD;		break;
+    case BFD_RELOC_PPC_EMB_RELSDA:	ppc_reloc = R_PPC_EMB_RELSDA;		break;
+    case BFD_RELOC_VTABLE_INHERIT:	ppc_reloc = R_PPC_GNU_VTINHERIT;	break;
+    case BFD_RELOC_VTABLE_ENTRY:	ppc_reloc = R_PPC_GNU_VTENTRY;		break;
+    }
+
+  return ppc_elf_howto_table[(int) ppc_reloc];
+};
+
+/* Set the howto pointer for a PowerPC ELF reloc.  */
+
+static void
+ppc_elf_info_to_howto (abfd, cache_ptr, dst)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *cache_ptr;
+     Elf32_Internal_Rela *dst;
+{
+  if (!ppc_elf_howto_table[R_PPC_ADDR32])
+    /* Initialize howto table if needed.  */
+    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)];
+}
+
+/* Handle the R_PPC_ADDR16_HA reloc.  */
+
+static bfd_reloc_status_type
+ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section,
+			 output_bfd, error_message)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR 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 > input_section->_cooked_size)
+    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;
+
+  reloc_entry->addend += (relocation & 0x8000) << 1;
+
+  return bfd_reloc_continue;
+}
+
+/* Fix bad default arch selected for a 32 bit input bfd when the
+   default is 64 bit.  */
+
+static boolean
+ppc_elf_object_p (abfd)
+     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 boolean
+ppc_elf_set_private_flags (abfd, 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;
+}
+
+/* Merge backend specific data from an object file to the output
+   object file when linking */
+static boolean
+ppc_elf_merge_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  flagword old_flags;
+  flagword new_flags;
+  boolean error;
+
+  /* Check if we have the same endianess */
+  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+    return false;
+
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return true;
+
+  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;
+    }
+
+  else if (new_flags == old_flags)	/* Compatible flags are ok */
+    ;
+
+  else					/* Incompatible flags */
+    {
+      /* Warn about -mrelocatable mismatch.  Allow -mrelocatable-lib to be linked
+         with either.  */
+      error = false;
+      if ((new_flags & EF_PPC_RELOCATABLE) != 0
+	  && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
+	{
+	  error = true;
+	  (*_bfd_error_handler)
+	    (_("%s: compiled with -mrelocatable and linked with modules compiled normally"),
+	     bfd_archive_filename (ibfd));
+	}
+      else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0
+	       && (old_flags & EF_PPC_RELOCATABLE) != 0)
+	{
+	  error = true;
+	  (*_bfd_error_handler)
+	    (_("%s: compiled normally and linked with modules compiled with -mrelocatable"),
+	     bfd_archive_filename (ibfd));
+	}
+
+      /* 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)
+	    (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
+	     bfd_archive_filename (ibfd), (long) new_flags, (long) old_flags);
+	}
+
+      if (error)
+	{
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
+    }
+
+  return true;
+}
+
+/* Handle a PowerPC specific section when reading an object file.  This
+   is called when elfcode.h finds a section with an unknown type.  */
+
+static boolean
+ppc_elf_section_from_shdr (abfd, hdr, name)
+     bfd *abfd;
+     Elf32_Internal_Shdr *hdr;
+     const char *name;
+{
+  asection *newsect;
+  flagword flags;
+
+  if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
+    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 boolean
+ppc_elf_fake_sections (abfd, shdr, asect)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     Elf32_Internal_Shdr *shdr;
+     asection *asect;
+{
+  if ((asect->flags & SEC_EXCLUDE) != 0)
+    shdr->sh_flags |= SHF_EXCLUDE;
+
+  if ((asect->flags & SEC_SORT_ENTRIES) != 0)
+    shdr->sh_type = SHT_ORDERED;
+
+  return true;
+}
+
+/* Create a special linker section */
+static elf_linker_section_t *
+ppc_elf_create_linker_section (abfd, info, which)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     enum elf_linker_section_enum which;
+{
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  elf_linker_section_t *lsect;
+
+  /* Record the first bfd section that needs the special section */
+  if (!dynobj)
+    dynobj = elf_hash_table (info)->dynobj = abfd;
+
+  /* If this is the first time, create the section */
+  lsect = elf_linker_section (dynobj, which);
+  if (!lsect)
+    {
+      elf_linker_section_t defaults;
+      static elf_linker_section_t zero_section;
+
+      defaults = zero_section;
+      defaults.which = which;
+      defaults.hole_written_p = false;
+      defaults.alignment = 2;
+
+      /* Both of these sections are (technically) created by the user
+	 putting data in them, so they shouldn't be marked
+	 SEC_LINKER_CREATED.
+
+	 The linker creates them so it has somewhere to attach their
+	 respective symbols. In fact, if they were empty it would
+	 be OK to leave the symbol set to 0 (or any random number), because
+	 the appropriate register should never be used.  */
+      defaults.flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+			| SEC_IN_MEMORY);
+
+      switch (which)
+	{
+	default:
+	  (*_bfd_error_handler) (_("%s: Unknown special linker type %d"),
+				 bfd_get_filename (abfd),
+				 (int) which);
+
+	  bfd_set_error (bfd_error_bad_value);
+	  return (elf_linker_section_t *) 0;
+
+	case LINKER_SECTION_SDATA:	/* .sdata/.sbss section */
+	  defaults.name		  = ".sdata";
+	  defaults.rel_name	  = ".rela.sdata";
+	  defaults.bss_name	  = ".sbss";
+	  defaults.sym_name	  = "_SDA_BASE_";
+	  defaults.sym_offset	  = 32768;
+	  break;
+
+	case LINKER_SECTION_SDATA2:	/* .sdata2/.sbss2 section */
+	  defaults.name		  = ".sdata2";
+	  defaults.rel_name	  = ".rela.sdata2";
+	  defaults.bss_name	  = ".sbss2";
+	  defaults.sym_name	  = "_SDA2_BASE_";
+	  defaults.sym_offset	  = 32768;
+	  defaults.flags	 |= SEC_READONLY;
+	  break;
+	}
+
+      lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults);
+    }
+
+  return lsect;
+}
+
+/* If we have a non-zero sized .sbss2 or .PPC.EMB.sbss0 sections, we
+   need to bump up the number of section headers.  */
+
+static int
+ppc_elf_additional_program_headers (abfd)
+     bfd *abfd;
+{
+  asection *s;
+  int ret;
+
+  ret = 0;
+
+  s = bfd_get_section_by_name (abfd, ".interp");
+  if (s != NULL)
+    ++ret;
+
+  s = bfd_get_section_by_name (abfd, ".sbss2");
+  if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0)
+    ++ret;
+
+  s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0");
+  if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0)
+    ++ret;
+
+  return ret;
+}
+
+/* Modify the segment map if needed.  */
+
+static boolean
+ppc_elf_modify_segment_map (abfd)
+     bfd *abfd ATTRIBUTE_UNUSED;
+{
+  return true;
+}
+
+/* The powerpc .got has a blrl instruction in it.  Mark it executable.  */
+
+static asection *
+ppc_elf_create_got (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  register asection *s;
+  flagword flags;
+
+  if (!_bfd_elf_create_got_section (abfd, info))
+    return NULL;
+
+  s = bfd_get_section_by_name (abfd, ".got");
+  if (s == NULL)
+    abort ();
+
+  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 NULL;
+  return s;
+}
+
+/* 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 boolean
+ppc_elf_create_dynamic_sections (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  register asection *s;
+  flagword flags;
+
+  if (!ppc_elf_create_got (abfd, info))
+    return false;
+
+  if (!_bfd_elf_create_dynamic_sections (abfd, info))
+    return false;
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+	   | SEC_LINKER_CREATED);
+
+  s = bfd_make_section (abfd, ".dynsbss");
+  if (s == NULL
+      || ! bfd_set_section_flags (abfd, s, SEC_ALLOC))
+    return false;
+
+  if (! info->shared)
+    {
+      s = bfd_make_section (abfd, ".rela.sbss");
+      if (s == NULL
+	  || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+	  || ! bfd_set_section_alignment (abfd, s, 2))
+	return false;
+    }
+
+  s = bfd_get_section_by_name (abfd, ".plt");
+  if (s == NULL)
+    abort ();
+
+  flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED;
+  return bfd_set_section_flags (abfd, s, flags);
+}
+
+/* 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 boolean
+ppc_elf_adjust_dynamic_symbol (info, h)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+{
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  asection *s;
+  unsigned int power_of_two;
+  bfd_vma plt_offset;
+
+#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.  */
+  BFD_ASSERT (dynobj != NULL
+	      && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
+		  || h->weakdef != NULL
+		  || ((h->elf_link_hash_flags
+		       & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+		      && (h->elf_link_hash_flags
+			  & ELF_LINK_HASH_REF_REGULAR) != 0
+		      && (h->elf_link_hash_flags
+			  & ELF_LINK_HASH_DEF_REGULAR) == 0)));
+
+  /* If this is a function, put it in the procedure linkage table.  We
+     will fill in the contents of the procedure linkage table later,
+     when we know the address of the .got section.  */
+  if (h->type == STT_FUNC
+      || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+    {
+      if (! elf_hash_table (info)->dynamic_sections_created
+ 	  || SYMBOL_CALLS_LOCAL (info, h)
+	  || (info->shared && h->plt.refcount <= 0))
+	{
+	  /* 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.
+
+	     2. We know for certain that a call to this symbol
+	     will go to this object.
+
+	     3. GC has rendered the entry unused.
+	     Note, however, that in an executable all references to the
+	     symbol go to the PLT, so we can't turn it off in that case.
+	     ??? The correct thing to do here is to reference count
+	     all uses of the symbol, not just those to the GOT or PLT.  */
+	  h->plt.offset = (bfd_vma) -1;
+	  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+	  return true;
+	}
+
+      /* Make sure this symbol is output as a dynamic symbol.  */
+      if (h->dynindx == -1)
+	{
+	  if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+	    return false;
+	}
+      BFD_ASSERT (h->dynindx != -1);
+
+      s = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (s != NULL);
+
+      /* If this is the first .plt entry, make room for the special
+	 first entry.  */
+      if (s->_raw_size == 0)
+	s->_raw_size += 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 = (PLT_INITIAL_ENTRY_SIZE
+		    + (PLT_SLOT_SIZE
+		       * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE)
+			  / 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 required to make function
+	 pointers compare as equal between the normal executable and
+	 the shared library.  */
+      if (! info->shared
+	  && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+	{
+	  h->root.u.def.section = s;
+	  h->root.u.def.value = plt_offset;
+	}
+
+      h->plt.offset = plt_offset;
+
+      /* Make room for this entry.  After the 8192nd entry, room
+         for two entries is allocated.  */
+      if ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
+	  >= PLT_NUM_SINGLE_ENTRIES)
+	s->_raw_size += 2 * PLT_ENTRY_SIZE;
+      else
+	s->_raw_size += PLT_ENTRY_SIZE;
+
+      /* We also need to make an entry in the .rela.plt section.  */
+      s = bfd_get_section_by_name (dynobj, ".rela.plt");
+      BFD_ASSERT (s != NULL);
+      s->_raw_size += sizeof (Elf32_External_Rela);
+
+      return true;
+    }
+  else
+    h->plt.offset = (bfd_vma) -1;
+
+  /* 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->weakdef != NULL)
+    {
+      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+		  || h->weakdef->root.type == bfd_link_hash_defweak);
+      h->root.u.def.section = h->weakdef->root.u.def.section;
+      h->root.u.def.value = h->weakdef->root.u.def.value;
+      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;
+
+  /* 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 sufficiently small, we must instead
+     allocate it in .sbss.  FIXME: It would be better to do this if and
+     only if there were actually SDAREL relocs for that symbol.  */
+
+  if (h->size <= elf_gp_size (dynobj))
+    s = bfd_get_section_by_name (dynobj, ".dynsbss");
+  else
+    s = bfd_get_section_by_name (dynobj, ".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)
+    {
+      asection *srel;
+
+      if (h->size <= elf_gp_size (dynobj))
+	srel = bfd_get_section_by_name (dynobj, ".rela.sbss");
+      else
+	srel = bfd_get_section_by_name (dynobj, ".rela.bss");
+      BFD_ASSERT (srel != NULL);
+      srel->_raw_size += sizeof (Elf32_External_Rela);
+      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+    }
+
+  /* We need to figure out the alignment required for this symbol.  I
+     have no idea how ELF linkers handle this.  */
+  power_of_two = bfd_log2 (h->size);
+  if (power_of_two > 4)
+    power_of_two = 4;
+
+  /* Apply the required alignment.  */
+  s->_raw_size = BFD_ALIGN (s->_raw_size,
+			    (bfd_size_type) (1 << power_of_two));
+  if (power_of_two > bfd_get_section_alignment (dynobj, s))
+    {
+      if (! bfd_set_section_alignment (dynobj, s, power_of_two))
+	return false;
+    }
+
+  /* Define the symbol as being at this point in the section.  */
+  h->root.u.def.section = s;
+  h->root.u.def.value = s->_raw_size;
+
+  /* Increment the section size to make room for the symbol.  */
+  s->_raw_size += h->size;
+
+  return true;
+}
+
+/* Set the sizes of the dynamic sections.  */
+
+static boolean
+ppc_elf_size_dynamic_sections (output_bfd, info)
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info;
+{
+  bfd *dynobj;
+  asection *s;
+  boolean plt;
+  boolean relocs;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_size_dynamic_sections called\n");
+#endif
+
+  dynobj = elf_hash_table (info)->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      /* Set the contents of the .interp section to the interpreter.  */
+      if (! info->shared)
+	{
+	  s = bfd_get_section_by_name (dynobj, ".interp");
+	  BFD_ASSERT (s != NULL);
+	  s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
+	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+	}
+    }
+  else
+    {
+      /* We may have created entries in the .rela.got, .rela.sdata, and
+	 .rela.sdata2 sections.  However, if we are not creating the
+	 dynamic sections, we will not actually use these entries.  Reset
+	 the size of .rela.got, et al, which will cause it to get
+	 stripped from the output file below.  */
+      static char *rela_sections[] = { ".rela.got", ".rela.sdata",
+				       ".rela.sdata2", ".rela.sbss",
+				       (char *) 0 };
+      char **p;
+
+      for (p = rela_sections; *p != (char *) 0; p++)
+	{
+	  s = bfd_get_section_by_name (dynobj, *p);
+	  if (s != NULL)
+	    s->_raw_size = 0;
+	}
+    }
+
+  /* The check_relocs and adjust_dynamic_symbol entry points have
+     determined the sizes of the various dynamic sections.  Allocate
+     memory for them.  */
+  plt = false;
+  relocs = false;
+  for (s = dynobj->sections; s != NULL; s = s->next)
+    {
+      const char *name;
+      boolean strip;
+
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
+	continue;
+
+      /* It's OK to base decisions on the section name, because none
+	 of the dynobj section names depend upon the input files.  */
+      name = bfd_get_section_name (dynobj, s);
+
+      strip = false;
+
+      if (strcmp (name, ".plt") == 0)
+	{
+	  if (s->_raw_size == 0)
+	    {
+	      /* Strip this section if we don't need it; see the
+                 comment below.  */
+	      strip = true;
+	    }
+	  else
+	    {
+	      /* Remember whether there is a PLT.  */
+	      plt = true;
+	    }
+	}
+      else if (strncmp (name, ".rela", 5) == 0)
+	{
+	  if (s->_raw_size == 0)
+	    {
+	      /* 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.  */
+	      strip = true;
+	    }
+	  else
+	    {
+	      /* 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 if (strcmp (name, ".got") != 0
+	       && strcmp (name, ".sdata") != 0
+	       && strcmp (name, ".sdata2") != 0)
+	{
+	  /* It's not one of our sections, so don't allocate space.  */
+	  continue;
+	}
+
+      if (strip)
+	{
+	  _bfd_strip_section_from_output (info, s);
+	  continue;
+	}
+
+      /* Allocate memory for the section contents.  */
+      s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
+      if (s->contents == NULL && s->_raw_size != 0)
+	return false;
+    }
+
+  if (elf_hash_table (info)->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_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
+      if (!info->shared)
+	{
+	  if (!add_dynamic_entry (DT_DEBUG, 0))
+	    return false;
+	}
+
+      if (plt)
+	{
+	  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 (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 ((info->flags & DF_TEXTREL) != 0)
+	{
+	  if (!add_dynamic_entry (DT_TEXTREL, 0))
+	    return false;
+	  info->flags |= DF_TEXTREL;
+	}
+    }
+#undef add_dynamic_entry
+
+  return true;
+}
+
+/* Look through the relocs for a section during the first phase, and
+   allocate space in the global offset table or procedure linkage
+   table.  */
+
+static boolean
+ppc_elf_check_relocs (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+  bfd *dynobj;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+  bfd_signed_vma *local_got_refcounts;
+  elf_linker_section_t *sdata;
+  elf_linker_section_t *sdata2;
+  asection *sreloc;
+  asection *sgot = NULL;
+  asection *srelgot = NULL;
+
+  if (info->relocateable)
+    return true;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_check_relocs called for section %s in %s\n",
+	   bfd_get_section_name (abfd, sec),
+	   bfd_archive_filename (abfd));
+#endif
+
+  /* Create the linker generated sections all the time so that the
+     special symbols are created.  */
+
+  if ((sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA)) == NULL)
+    {
+      sdata = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA);
+      if (!sdata)
+	return false;
+    }
+
+  if ((sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2)) == NULL)
+    {
+      sdata2 = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA2);
+      if (!sdata2)
+	return false;
+    }
+
+  dynobj = elf_hash_table (info)->dynobj;
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  sym_hashes = elf_sym_hashes (abfd);
+  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
+  if (!elf_bad_symtab (abfd))
+    sym_hashes_end -= symtab_hdr->sh_info;
+
+  sreloc = NULL;
+
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      unsigned long r_symndx;
+      struct elf_link_hash_entry *h;
+
+      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];
+
+      /* 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 && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+	{
+	  if (sgot == NULL)
+	    {
+	      if (dynobj == NULL)
+		elf_hash_table (info)->dynobj = dynobj = abfd;
+	      sgot = ppc_elf_create_got (dynobj, info);
+	      if (sgot == NULL)
+		return false;
+	    }
+	}
+
+      switch (ELF32_R_TYPE (rel->r_info))
+	{
+	/* 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 (sgot == NULL)
+	    {
+	      if (dynobj == NULL)
+		elf_hash_table (info)->dynobj = dynobj = abfd;
+	      sgot = ppc_elf_create_got (dynobj, info);
+	      if (sgot == NULL)
+		return false;
+	    }
+
+	  if (srelgot == NULL
+	      && (h != NULL || info->shared))
+	    {
+	      srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+	      if (srelgot == NULL)
+		{
+		  srelgot = bfd_make_section (dynobj, ".rela.got");
+		  if (srelgot == NULL
+		      || ! bfd_set_section_flags (dynobj, srelgot,
+						  (SEC_ALLOC
+						   | SEC_LOAD
+						   | SEC_HAS_CONTENTS
+						   | SEC_IN_MEMORY
+						   | SEC_LINKER_CREATED
+						   | SEC_READONLY))
+		      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
+		    return false;
+		}
+	    }
+
+	  if (h != NULL)
+	    {
+	      if (h->got.refcount == 0)
+		{
+		  /* Make sure this symbol is output as a dynamic symbol.  */
+		  if (h->dynindx == -1)
+		    if (!bfd_elf32_link_record_dynamic_symbol (info, h))
+		      return false;
+
+		  /* Allocate space in the .got.  */
+		  sgot->_raw_size += 4;
+		  /* Allocate relocation space.  */
+		  srelgot->_raw_size += sizeof (Elf32_External_Rela);
+		}
+	      h->got.refcount++;
+	    }
+	  else
+	    {
+	      /* This is a global offset table entry for a local symbol.  */
+	      if (local_got_refcounts == NULL)
+		{
+		  bfd_size_type size;
+
+		  size = symtab_hdr->sh_info;
+		  size *= sizeof (bfd_signed_vma);
+		  local_got_refcounts
+		    = (bfd_signed_vma *) bfd_zalloc (abfd, size);
+		  if (local_got_refcounts == NULL)
+		    return false;
+		  elf_local_got_refcounts (abfd) = local_got_refcounts;
+		}
+	      if (local_got_refcounts[r_symndx] == 0)
+		{
+		  sgot->_raw_size += 4;
+
+		  /* If we are generating a shared object, we need to
+                     output a R_PPC_RELATIVE reloc so that the
+                     dynamic linker can adjust this GOT entry.  */
+		  if (info->shared)
+		    srelgot->_raw_size += sizeof (Elf32_External_Rela);
+		}
+	      local_got_refcounts[r_symndx]++;
+	    }
+	  break;
+
+	/* Indirect .sdata relocation */
+	case R_PPC_EMB_SDAI16:
+	  if (info->shared)
+	    {
+	      ((*_bfd_error_handler)
+	       (_("%s: relocation %s cannot be used when making a shared object"),
+		bfd_archive_filename (abfd), "R_PPC_EMB_SDAI16"));
+	      return false;
+	    }
+
+	  if (srelgot == NULL && (h != NULL || info->shared))
+	    {
+	      srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+	      if (srelgot == NULL)
+		{
+		  srelgot = bfd_make_section (dynobj, ".rela.got");
+		  if (srelgot == NULL
+		      || ! bfd_set_section_flags (dynobj, srelgot,
+						  (SEC_ALLOC
+						   | SEC_LOAD
+						   | SEC_HAS_CONTENTS
+						   | SEC_IN_MEMORY
+						   | SEC_LINKER_CREATED
+						   | SEC_READONLY))
+		      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
+		    return false;
+		}
+	    }
+
+	  if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata, h, rel))
+	    return false;
+
+	  break;
+
+	/* Indirect .sdata2 relocation */
+	case R_PPC_EMB_SDA2I16:
+	  if (info->shared)
+	    {
+	      ((*_bfd_error_handler)
+	       (_("%s: relocation %s cannot be used when making a shared object"),
+		bfd_archive_filename (abfd), "R_PPC_EMB_SDA2I16"));
+	      return false;
+	    }
+
+	  if (srelgot == NULL && (h != NULL || info->shared))
+	    {
+	      srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+	      if (srelgot == NULL)
+		{
+		  srelgot = bfd_make_section (dynobj, ".rela.got");
+		  if (srelgot == NULL
+		      || ! bfd_set_section_flags (dynobj, srelgot,
+						  (SEC_ALLOC
+						   | SEC_LOAD
+						   | SEC_HAS_CONTENTS
+						   | SEC_IN_MEMORY
+						   | SEC_LINKER_CREATED
+						   | SEC_READONLY))
+		      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
+		    return false;
+		}
+	    }
+
+	  if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata2, h, rel))
+	    return false;
+
+	  break;
+
+	case R_PPC_SDAREL16:
+	case R_PPC_EMB_SDA2REL:
+	case R_PPC_EMB_SDA21:
+	  if (info->shared)
+	    {
+	      ((*_bfd_error_handler)
+	       (_("%s: relocation %s cannot be used when making a shared object"),
+		bfd_archive_filename (abfd),
+		ppc_elf_howto_table[(int) ELF32_R_TYPE (rel->r_info)]->name));
+	      return false;
+	    }
+	  break;
+
+	case R_PPC_PLT32:
+	case R_PPC_PLTREL24:
+	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 adjust_dynamic_symbol,
+             because this might be a case of linking PIC code without
+             linking in any dynamic objects, in which case we don't
+             need to generate a procedure linkage table after all.  */
+
+	  if (h == NULL)
+	    {
+	      /* It does not make sense to have a procedure linkage
+                 table entry for a local symbol.  */
+	      bfd_set_error (bfd_error_bad_value);
+	      return false;
+	    }
+
+	  /* Make sure this symbol is output as a dynamic symbol.  */
+	  if (h->dynindx == -1)
+	    {
+	      if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+		return false;
+	    }
+	  h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+	  h->plt.refcount++;
+	  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:
+	  break;
+
+	  /* This refers only to functions defined in the shared library */
+	case R_PPC_LOCAL24PC:
+	  break;
+
+	  /* This relocation describes the C++ object vtable hierarchy.
+	     Reconstruct it for later use during GC.  */
+	case R_PPC_GNU_VTINHERIT:
+	  if (!_bfd_elf32_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:
+	  if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+	    return false;
+	  break;
+
+	  /* When creating a shared object, we must copy these
+	     relocs into the output file.  We create a reloc
+	     section in dynobj and make room for the reloc.  */
+	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
+	      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+	      || SYMBOL_REFERENCES_LOCAL (info, h))
+	    break;
+	  /* fall through */
+
+	default:
+	  if (info->shared)
+	    {
+#ifdef DEBUG
+	      fprintf (stderr, "ppc_elf_check_relocs need to create relocation for %s\n",
+		       (h && h->root.root.string) ? h->root.root.string : "<unknown>");
+#endif
+	      if (sreloc == NULL)
+		{
+		  const char *name;
+
+		  name = (bfd_elf_string_from_elf_section
+			  (abfd,
+			   elf_elfheader (abfd)->e_shstrndx,
+			   elf_section_data (sec)->rel_hdr.sh_name));
+		  if (name == NULL)
+		    return false;
+
+		  BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+			      && strcmp (bfd_get_section_name (abfd, sec),
+					 name + 5) == 0);
+
+		  sreloc = bfd_get_section_by_name (dynobj, name);
+		  if (sreloc == NULL)
+		    {
+		      flagword flags;
+
+		      sreloc = bfd_make_section (dynobj, name);
+		      flags = (SEC_HAS_CONTENTS | SEC_READONLY
+			       | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+		      if ((sec->flags & SEC_ALLOC) != 0)
+			flags |= SEC_ALLOC | SEC_LOAD;
+		      if (sreloc == NULL
+			  || ! bfd_set_section_flags (dynobj, sreloc, flags)
+			  || ! bfd_set_section_alignment (dynobj, sreloc, 2))
+			return false;
+		    }
+		  if (sec->flags & SEC_READONLY)
+		    info->flags |= DF_TEXTREL;
+		}
+
+	      sreloc->_raw_size += sizeof (Elf32_External_Rela);
+
+	      /* FIXME: We should here do what the m68k and i386
+		 backends do: if the reloc is pc-relative, record it
+		 in case it turns out that the reloc is unnecessary
+		 because the symbol is forced local by versioning or
+		 we are linking with -Bdynamic.  Fortunately this
+		 case is not frequent.  */
+	    }
+
+	  break;
+	}
+    }
+
+  return true;
+}
+
+/* Return the section that should be marked against GC for a given
+   relocation.  */
+
+static asection *
+ppc_elf_gc_mark_hook (sec, info, rel, h, sym)
+     asection *sec;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     Elf_Internal_Rela *rel;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  if (h != NULL)
+    {
+      switch (ELF32_R_TYPE (rel->r_info))
+	{
+	case R_PPC_GNU_VTINHERIT:
+	case R_PPC_GNU_VTENTRY:
+	  break;
+
+	default:
+	  switch (h->root.type)
+	    {
+	    case bfd_link_hash_defined:
+	    case bfd_link_hash_defweak:
+	      return h->root.u.def.section;
+
+	    case bfd_link_hash_common:
+	      return h->root.u.c.p->section;
+
+	    default:
+	      break;
+	    }
+	}
+    }
+  else
+    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+
+  return NULL;
+}
+
+/* Update the got entry reference counts for the section being removed.  */
+
+static boolean
+ppc_elf_gc_sweep_hook (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_signed_vma *local_got_refcounts;
+  const Elf_Internal_Rela *rel, *relend;
+  unsigned long r_symndx;
+  struct elf_link_hash_entry *h;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  relend = relocs + sec->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
+    switch (ELF32_R_TYPE (rel->r_info))
+      {
+      case R_PPC_GOT16:
+      case R_PPC_GOT16_LO:
+      case R_PPC_GOT16_HI:
+      case R_PPC_GOT16_HA:
+	r_symndx = ELF32_R_SYM (rel->r_info);
+	if (r_symndx >= symtab_hdr->sh_info)
+	  {
+	    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	    if (h->got.refcount > 0)
+	      h->got.refcount--;
+	  }
+	else if (local_got_refcounts != NULL)
+	  {
+	    if (local_got_refcounts[r_symndx] > 0)
+	      local_got_refcounts[r_symndx]--;
+	  }
+        break;
+
+      case R_PPC_PLT32:
+      case R_PPC_PLTREL24:
+      case R_PPC_PLT16_LO:
+      case R_PPC_PLT16_HI:
+      case R_PPC_PLT16_HA:
+	r_symndx = ELF32_R_SYM (rel->r_info);
+	if (r_symndx >= symtab_hdr->sh_info)
+	  {
+	    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	    if (h->plt.refcount > 0)
+	      h->plt.refcount--;
+	  }
+	break;
+
+      default:
+	break;
+      }
+
+  return true;
+}
+
+/* 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 boolean
+ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     const 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->relocateable
+      && sym->st_size <= elf_gp_size (abfd)
+      && info->hash->creator->flavour == bfd_target_elf_flavour)
+    {
+      /* Common symbols less than or equal to -G nn bytes are automatically
+	 put into .sdata.  */
+      elf_linker_section_t *sdata
+	= ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA);
+
+      if (!sdata->bss_section)
+	{
+	  bfd_size_type amt;
+
+	  /* We don't go through bfd_make_section, because we don't
+             want to attach this common section to DYNOBJ.  The linker
+             will move the symbols to the appropriate output section
+             when it defines common symbols.  */
+	  amt = sizeof (asection);
+	  sdata->bss_section = (asection *) bfd_zalloc (abfd, amt);
+	  if (sdata->bss_section == NULL)
+	    return false;
+	  sdata->bss_section->name = sdata->bss_name;
+	  sdata->bss_section->flags = SEC_IS_COMMON;
+	  sdata->bss_section->output_section = sdata->bss_section;
+	  amt = sizeof (asymbol);
+	  sdata->bss_section->symbol = (asymbol *) bfd_zalloc (abfd, amt);
+	  amt = sizeof (asymbol *);
+	  sdata->bss_section->symbol_ptr_ptr =
+	    (asymbol **) bfd_zalloc (abfd, amt);
+	  if (sdata->bss_section->symbol == NULL
+	      || sdata->bss_section->symbol_ptr_ptr == NULL)
+	    return false;
+	  sdata->bss_section->symbol->name = sdata->bss_name;
+	  sdata->bss_section->symbol->flags = BSF_SECTION_SYM;
+	  sdata->bss_section->symbol->section = sdata->bss_section;
+	  *sdata->bss_section->symbol_ptr_ptr = sdata->bss_section->symbol;
+	}
+
+      *secp = sdata->bss_section;
+      *valp = sym->st_size;
+    }
+
+  return true;
+}
+
+/* Finish up dynamic symbol handling.  We set the contents of various
+   dynamic sections here.  */
+
+static boolean
+ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  bfd *dynobj;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
+	   h->root.root.string);
+#endif
+
+  dynobj = elf_hash_table (info)->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+
+  if (h->plt.offset != (bfd_vma) -1)
+    {
+      asection *splt;
+      asection *srela;
+      Elf_Internal_Rela rela;
+      bfd_vma reloc_index;
+
+#ifdef DEBUG
+      fprintf (stderr, ", plt_offset = %d", h->plt.offset);
+#endif
+
+      /* This symbol has an entry in the procedure linkage table.  Set
+         it up.  */
+
+      BFD_ASSERT (h->dynindx != -1);
+
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      srela = bfd_get_section_by_name (dynobj, ".rela.plt");
+      BFD_ASSERT (splt != NULL && srela != NULL);
+
+      /* We don't need to fill in the .plt.  The ppc dynamic linker
+	 will fill it in.  */
+
+      /* Fill in the entry in the .rela.plt section.  */
+      rela.r_offset = (splt->output_section->vma
+		       + splt->output_offset
+		       + h->plt.offset);
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
+      rela.r_addend = 0;
+
+      reloc_index = (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_SLOT_SIZE;
+      if (reloc_index > PLT_NUM_SINGLE_ENTRIES)
+	reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+				 ((Elf32_External_Rela *) srela->contents
+				  + reloc_index));
+
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+	{
+	  /* Mark the symbol as undefined, rather than as defined in
+	     the .plt section.  Leave the value alone.  */
+	  sym->st_shndx = SHN_UNDEF;
+	  /* If the symbol is weak, we do need to clear the value.
+	     Otherwise, the PLT entry would provide a definition for
+	     the symbol even if the symbol wasn't defined anywhere,
+	     and so the symbol would never be NULL.  */
+	  if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK)
+	      == 0)
+	    sym->st_value = 0;
+	}
+    }
+
+  if (h->got.offset != (bfd_vma) -1)
+    {
+      asection *sgot;
+      asection *srela;
+      Elf_Internal_Rela rela;
+
+      /* This symbol has an entry in the global offset table.  Set it
+         up.  */
+
+      sgot = bfd_get_section_by_name (dynobj, ".got");
+      srela = bfd_get_section_by_name (dynobj, ".rela.got");
+      BFD_ASSERT (sgot != NULL && srela != NULL);
+
+      rela.r_offset = (sgot->output_section->vma
+		       + sgot->output_offset
+		       + (h->got.offset &~ (bfd_vma) 1));
+
+      /* If this is a -Bsymbolic link, and the symbol is defined
+	 locally, we just want to emit a RELATIVE reloc.  The entry in
+	 the global offset table will already have been initialized in
+	 the relocate_section function.  */
+      if (info->shared
+	  && SYMBOL_REFERENCES_LOCAL (info, h))
+	{
+	  rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+	  rela.r_addend = (h->root.u.def.value
+			   + h->root.u.def.section->output_section->vma
+			   + h->root.u.def.section->output_offset);
+	}
+      else
+	{
+	  BFD_ASSERT ((h->got.offset & 1) == 0);
+	  rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_GLOB_DAT);
+	  rela.r_addend = 0;
+	}
+
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+				 ((Elf32_External_Rela *) srela->contents
+				  + srela->reloc_count));
+      ++srela->reloc_count;
+    }
+
+  if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
+    {
+      asection *s;
+      Elf_Internal_Rela rela;
+
+      /* This symbols needs a copy reloc.  Set it up.  */
+
+#ifdef DEBUG
+      fprintf (stderr, ", copy");
+#endif
+
+      BFD_ASSERT (h->dynindx != -1);
+
+      if (h->size <= elf_gp_size (dynobj))
+	s = bfd_get_section_by_name (h->root.u.def.section->owner,
+				     ".rela.sbss");
+      else
+	s = bfd_get_section_by_name (h->root.u.def.section->owner,
+				     ".rela.bss");
+      BFD_ASSERT (s != NULL);
+
+      rela.r_offset = (h->root.u.def.value
+		       + h->root.u.def.section->output_section->vma
+		       + h->root.u.def.section->output_offset);
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY);
+      rela.r_addend = 0;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+				 ((Elf32_External_Rela *) s->contents
+				  + s->reloc_count));
+      ++s->reloc_count;
+    }
+
+#ifdef DEBUG
+  fprintf (stderr, "\n");
+#endif
+
+  /* Mark some specially defined symbols as absolute.  */
+  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+      || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+    sym->st_shndx = SHN_ABS;
+
+  return true;
+}
+
+/* Finish up the dynamic sections.  */
+
+static boolean
+ppc_elf_finish_dynamic_sections (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  asection *sdyn;
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  asection *sgot = bfd_get_section_by_name (dynobj, ".got");
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n");
+#endif
+
+  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      asection *splt;
+      Elf32_External_Dyn *dyncon, *dynconend;
+
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (splt != NULL && sdyn != NULL);
+
+      dyncon = (Elf32_External_Dyn *) sdyn->contents;
+      dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
+      for (; dyncon < dynconend; dyncon++)
+	{
+	  Elf_Internal_Dyn dyn;
+	  const char *name;
+	  boolean size;
+
+	  bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+
+	  switch (dyn.d_tag)
+	    {
+	    case DT_PLTGOT:   name = ".plt";	  size = false; break;
+	    case DT_PLTRELSZ: name = ".rela.plt"; size = true;  break;
+	    case DT_JMPREL:   name = ".rela.plt"; size = false; break;
+	    default:	      name = NULL;	  size = false; break;
+	    }
+
+	  if (name != NULL)
+	    {
+	      asection *s;
+
+	      s = bfd_get_section_by_name (output_bfd, name);
+	      if (s == NULL)
+		dyn.d_un.d_val = 0;
+	      else
+		{
+		  if (! size)
+		    dyn.d_un.d_ptr = s->vma;
+		  else
+		    {
+		      if (s->_cooked_size != 0)
+			dyn.d_un.d_val = s->_cooked_size;
+		      else
+			dyn.d_un.d_val = s->_raw_size;
+		    }
+		}
+	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+	    }
+	}
+    }
+
+  /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can
+     easily find the address of the _GLOBAL_OFFSET_TABLE_.  */
+  if (sgot)
+    {
+      unsigned char *contents = sgot->contents;
+      bfd_put_32 (output_bfd, (bfd_vma) 0x4e800021 /* blrl */, contents);
+
+      if (sdyn == NULL)
+	bfd_put_32 (output_bfd, (bfd_vma) 0, contents+4);
+      else
+	bfd_put_32 (output_bfd,
+		    sdyn->output_section->vma + sdyn->output_offset,
+		    contents+4);
+
+      elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+    }
+
+  return true;
+}
+
+/* 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
+   relocateable 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 relocateable 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 boolean
+ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
+			  contents, relocs, local_syms, local_sections)
+     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		  = &elf_tdata (input_bfd)->symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
+  bfd *dynobj				  = elf_hash_table (info)->dynobj;
+  elf_linker_section_t *sdata		  = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA)  : NULL;
+  elf_linker_section_t *sdata2		  = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA2) : NULL;
+  Elf_Internal_Rela *rel		  = relocs;
+  Elf_Internal_Rela *relend		  = relocs + input_section->reloc_count;
+  asection *sreloc			  = NULL;
+  asection *splt;
+  asection *sgot;
+  bfd_vma *local_got_offsets;
+  boolean ret				  = true;
+  long insn;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_relocate_section called for %s section %s, %ld relocations%s\n",
+	   bfd_archive_filename (input_bfd),
+	   bfd_section_name(input_bfd, input_section),
+	   (long) input_section->reloc_count,
+	   (info->relocateable) ? " (relocatable)" : "");
+#endif
+
+  if (info->relocateable)
+    return true;
+
+  if (!ppc_elf_howto_table[R_PPC_ADDR32])
+    /* Initialize howto table if needed.  */
+    ppc_elf_howto_init ();
+
+  local_got_offsets = elf_local_got_offsets (input_bfd);
+
+  splt = sgot = NULL;
+  if (dynobj != NULL)
+    {
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      sgot = bfd_get_section_by_name (dynobj, ".got");
+    }
+
+  for (; rel < relend; rel++)
+    {
+      enum elf_ppc_reloc_type r_type	= (enum elf_ppc_reloc_type)ELF32_R_TYPE (rel->r_info);
+      bfd_vma offset			= rel->r_offset;
+      bfd_vma addend			= rel->r_addend;
+      bfd_reloc_status_type r		= bfd_reloc_other;
+      Elf_Internal_Sym *sym		= (Elf_Internal_Sym *) 0;
+      asection *sec			= (asection *) 0;
+      struct elf_link_hash_entry *h	= (struct elf_link_hash_entry *) 0;
+      const char *sym_name		= (const char *) 0;
+      reloc_howto_type *howto;
+      unsigned long r_symndx;
+      bfd_vma relocation;
+      int will_become_local;
+
+      /* Unknown relocation handling */
+      if ((unsigned) r_type >= (unsigned) R_PPC_max
+	  || !ppc_elf_howto_table[(int) r_type])
+	{
+	  (*_bfd_error_handler) (_("%s: unknown relocation type %d"),
+				 bfd_archive_filename (input_bfd),
+				 (int) r_type);
+
+	  bfd_set_error (bfd_error_bad_value);
+	  ret = false;
+	  continue;
+	}
+
+      howto = ppc_elf_howto_table[(int) r_type];
+      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 = "<local symbol>";
+
+	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+	  addend = rel->r_addend;
+	  /* Relocs to local symbols are always resolved.  */
+	  will_become_local = 1;
+	}
+      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;
+	  sym_name = h->root.root.string;
+
+	  /* Can this relocation be resolved immediately?  */
+	  will_become_local = SYMBOL_REFERENCES_LOCAL (info, h);
+
+	  if (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak)
+	    {
+	      sec = h->root.u.def.section;
+	      if (((r_type == R_PPC_PLT32
+		    || r_type == R_PPC_PLTREL24)
+		   && splt != NULL
+		   && h->plt.offset != (bfd_vma) -1)
+		  || (r_type == R_PPC_LOCAL24PC
+		      && sec->output_section == NULL)
+		  || ((r_type == R_PPC_GOT16
+		       || r_type == R_PPC_GOT16_LO
+		       || r_type == R_PPC_GOT16_HI
+		       || r_type == R_PPC_GOT16_HA)
+		      && elf_hash_table (info)->dynamic_sections_created
+		      && (! info->shared || ! will_become_local))
+		  || (info->shared
+ 		      && ! will_become_local
+		      && ((input_section->flags & SEC_ALLOC) != 0
+			  /* Testing SEC_DEBUGGING here may be wrong.
+                             It's here to avoid a crash when
+                             generating a shared library with DWARF
+                             debugging information.  */
+			  || ((input_section->flags & SEC_DEBUGGING) != 0
+			      && (h->elf_link_hash_flags
+				  & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
+		      && (r_type == R_PPC_ADDR32
+			  || r_type == R_PPC_ADDR24
+			  || r_type == R_PPC_ADDR16
+			  || r_type == R_PPC_ADDR16_LO
+			  || r_type == R_PPC_ADDR16_HI
+			  || r_type == R_PPC_ADDR16_HA
+			  || r_type == R_PPC_ADDR14
+			  || r_type == R_PPC_ADDR14_BRTAKEN
+			  || r_type == R_PPC_ADDR14_BRNTAKEN
+			  || r_type == R_PPC_COPY
+			  || r_type == R_PPC_GLOB_DAT
+			  || r_type == R_PPC_JMP_SLOT
+			  || r_type == R_PPC_UADDR32
+			  || r_type == R_PPC_UADDR16
+			  || r_type == R_PPC_SDAREL16
+			  || r_type == R_PPC_EMB_NADDR32
+			  || r_type == R_PPC_EMB_NADDR16
+			  || r_type == R_PPC_EMB_NADDR16_LO
+			  || r_type == R_PPC_EMB_NADDR16_HI
+			  || r_type == R_PPC_EMB_NADDR16_HA
+			  || r_type == R_PPC_EMB_SDAI16
+			  || r_type == R_PPC_EMB_SDA2I16
+			  || r_type == R_PPC_EMB_SDA2REL
+			  || r_type == R_PPC_EMB_SDA21
+			  || r_type == R_PPC_EMB_MRKREF
+			  || r_type == R_PPC_EMB_BIT_FLD
+			  || r_type == R_PPC_EMB_RELSDA
+			  || ((r_type == R_PPC_REL24
+			       || r_type == R_PPC_REL32
+			       || r_type == R_PPC_REL14
+			       || r_type == R_PPC_REL14_BRTAKEN
+			       || r_type == R_PPC_REL14_BRNTAKEN
+			       || r_type == R_PPC_RELATIVE)
+			      && strcmp (h->root.root.string,
+					 "_GLOBAL_OFFSET_TABLE_") != 0))))
+		{
+		  /* In these cases, we don't need the relocation
+                     value.  We check specially because in some
+                     obscure cases sec->output_section will be NULL.  */
+		  relocation = 0;
+		}
+	      else if (sec->output_section == NULL)
+		{
+                  (*_bfd_error_handler)
+                    (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
+                     bfd_archive_filename (input_bfd), h->root.root.string,
+                     bfd_get_section_name (input_bfd, input_section));
+		  relocation = 0;
+		}
+	      else
+		relocation = (h->root.u.def.value
+			      + sec->output_section->vma
+			      + sec->output_offset);
+	    }
+	  else if (h->root.type == bfd_link_hash_undefweak)
+	    relocation = 0;
+	  else if (info->shared
+		   && (!info->symbolic || info->allow_shlib_undefined)
+		   && !info->no_undefined
+		   && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+	    relocation = 0;
+	  else
+	    {
+	      if (! (*info->callbacks->undefined_symbol) (info,
+							 h->root.root.string,
+							 input_bfd,
+							 input_section,
+							 rel->r_offset,
+							 (!info->shared
+							  || info->no_undefined
+							  || ELF_ST_VISIBILITY (h->other))))
+		return false;
+	      relocation = 0;
+	    }
+	}
+
+      switch ((int) r_type)
+	{
+	default:
+	  (*_bfd_error_handler) (_("%s: unknown relocation type %d for symbol %s"),
+				 bfd_archive_filename (input_bfd),
+				 (int) r_type, sym_name);
+
+	  bfd_set_error (bfd_error_bad_value);
+	  ret = false;
+	  continue;
+
+	case (int) R_PPC_NONE:
+	  continue;
+
+	/* Relocations that need no special processing.  */
+	case (int) R_PPC_LOCAL24PC:
+	  /* It makes no sense to point a local relocation
+	     at a symbol not in this object.  */
+	  if (h != NULL
+	      && (h->root.type == bfd_link_hash_defined
+		  || h->root.type == bfd_link_hash_defweak)
+	      && sec->output_section == NULL)
+	    {
+	      if (! (*info->callbacks->undefined_symbol) (info,
+							  h->root.root.string,
+							  input_bfd,
+							  input_section,
+							  rel->r_offset,
+							  true))
+		return false;
+	      continue;
+	    }
+	  break;
+
+	/* Relocations that may need to be propagated if this is a shared
+           object.  */
+	case (int) R_PPC_REL24:
+	case (int) R_PPC_REL32:
+	case (int) R_PPC_REL14:
+	  /* If these relocations are not to a named symbol, they can be
+	     handled right here, no need to bother the dynamic linker.  */
+	  if (h == NULL
+	      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+	      || SYMBOL_REFERENCES_LOCAL (info, h))
+	    break;
+	/* fall through */
+
+	/* Relocations that always need to be propagated if this is a shared
+           object.  */
+	case (int) R_PPC_ADDR32:
+	case (int) R_PPC_ADDR24:
+	case (int) R_PPC_ADDR16:
+	case (int) R_PPC_ADDR16_LO:
+	case (int) R_PPC_ADDR16_HI:
+	case (int) R_PPC_ADDR16_HA:
+	case (int) R_PPC_ADDR14:
+	case (int) R_PPC_UADDR32:
+	case (int) R_PPC_UADDR16:
+	  if (info->shared && r_symndx != 0)
+	    {
+	      Elf_Internal_Rela outrel;
+	      int skip;
+
+#ifdef DEBUG
+	      fprintf (stderr, "ppc_elf_relocate_section need 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)
+		{
+		  const char *name;
+
+		  name = (bfd_elf_string_from_elf_section
+			  (input_bfd,
+			   elf_elfheader (input_bfd)->e_shstrndx,
+			   elf_section_data (input_section)->rel_hdr.sh_name));
+		  if (name == NULL)
+		    return false;
+
+		  BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+			      && strcmp (bfd_get_section_name (input_bfd,
+							       input_section),
+					 name + 5) == 0);
+
+		  sreloc = bfd_get_section_by_name (dynobj, name);
+		  BFD_ASSERT (sreloc != NULL);
+		}
+
+	      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);
+	      /* h->dynindx may be -1 if this symbol was marked to
+                 become local.  */
+	      else if (! will_become_local)
+		{
+		  outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+		  outrel.r_addend = rel->r_addend;
+		}
+	      else
+		{
+		  if (r_type == R_PPC_ADDR32)
+		    {
+		      outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+		      outrel.r_addend = relocation + rel->r_addend;
+		    }
+		  else
+		    {
+		      long indx;
+
+		      if (h == NULL)
+			sec = local_sections[r_symndx];
+		      else
+			{
+			  BFD_ASSERT (h->root.type == bfd_link_hash_defined
+				      || (h->root.type
+					  == bfd_link_hash_defweak));
+			  sec = h->root.u.def.section;
+			}
+		      if (sec != NULL && bfd_is_abs_section (sec))
+			indx = 0;
+		      else if (sec == NULL || sec->owner == NULL)
+			{
+			  bfd_set_error (bfd_error_bad_value);
+			  return false;
+			}
+		      else
+			{
+			  asection *osec;
+
+			  osec = sec->output_section;
+			  indx = elf_section_data (osec)->dynindx;
+			  BFD_ASSERT (indx > 0);
+#ifdef DEBUG
+			  if (indx <= 0)
+			    {
+			      printf ("indx=%d 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);
+		      outrel.r_addend = relocation + rel->r_addend;
+		    }
+		}
+
+	      bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+					 (((Elf32_External_Rela *)
+					   sreloc->contents)
+					  + sreloc->reloc_count));
+	      ++sreloc->reloc_count;
+
+	      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;
+		}
+	    }
+
+	  /* Arithmetic adjust relocations that aren't going into a
+	     shared object.  */
+	  if (r_type == R_PPC_ADDR16_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).  */
+	      && sec != NULL)
+	    {
+	      addend += ((relocation + addend) & 0x8000) << 1;
+	    }
+	  break;
+
+	/* branch taken prediction relocations */
+	case (int) R_PPC_ADDR14_BRTAKEN:
+	case (int) R_PPC_REL14_BRTAKEN:
+	  insn = bfd_get_32 (output_bfd, contents + offset);
+	  if ((relocation - offset) & 0x8000)
+	    insn &= ~BRANCH_PREDICT_BIT;
+	  else
+	    insn |= BRANCH_PREDICT_BIT;
+	  bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
+	  break;
+
+	/* branch not taken predicition relocations */
+	case (int) R_PPC_ADDR14_BRNTAKEN:
+	case (int) R_PPC_REL14_BRNTAKEN:
+	  insn = bfd_get_32 (output_bfd, contents + offset);
+	  if ((relocation - offset) & 0x8000)
+	    insn |= BRANCH_PREDICT_BIT;
+	  else
+	    insn &= ~BRANCH_PREDICT_BIT;
+	  bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
+	  break;
+
+	/* GOT16 relocations */
+	case (int) R_PPC_GOT16:
+	case (int) R_PPC_GOT16_LO:
+	case (int) R_PPC_GOT16_HI:
+	case (int) R_PPC_GOT16_HA:
+	  /* Relocation is to the entry for this symbol in the global
+             offset table.  */
+	  BFD_ASSERT (sgot != NULL);
+
+	  if (h != NULL)
+	    {
+	      bfd_vma off;
+
+	      off = h->got.offset;
+	      BFD_ASSERT (off != (bfd_vma) -1);
+
+	      if (! elf_hash_table (info)->dynamic_sections_created
+		  || (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.  We must initialize this entry in the
+                     global offset table.  Since the offset must
+                     always be a multiple of 4, we use the least
+                     significant bit to record whether we have
+                     initialized it already.
+
+		     When doing a dynamic link, we create a .rela.got
+		     relocation entry to initialize the value.  This
+		     is done in the finish_dynamic_symbol routine.  */
+		  if ((off & 1) != 0)
+		    off &= ~1;
+		  else
+		    {
+		      bfd_put_32 (output_bfd, relocation,
+				  sgot->contents + off);
+		      h->got.offset |= 1;
+		    }
+		}
+
+	      relocation = sgot->output_offset + off - 4;
+	    }
+	  else
+	    {
+	      bfd_vma off;
+
+	      BFD_ASSERT (local_got_offsets != NULL
+			  && local_got_offsets[r_symndx] != (bfd_vma) -1);
+
+	      off = 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.  */
+	      if ((off & 1) != 0)
+		off &= ~1;
+	      else
+		{
+
+		  if (info->shared)
+		    {
+		      asection *srelgot;
+		      Elf_Internal_Rela outrel;
+
+		      /* We need to generate a R_PPC_RELATIVE reloc
+			 for the dynamic linker.  */
+		      srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+		      BFD_ASSERT (srelgot != NULL);
+
+		      outrel.r_offset = (sgot->output_section->vma
+					 + sgot->output_offset
+					 + off);
+		      outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+		      outrel.r_addend = relocation;
+		      bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+						 (((Elf32_External_Rela *)
+						   srelgot->contents)
+						  + srelgot->reloc_count));
+		      ++srelgot->reloc_count;
+		      relocation = 0;
+		    }
+
+		  bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+		  local_got_offsets[r_symndx] |= 1;
+		}
+
+	      relocation = sgot->output_offset + off - 4;
+	    }
+	  break;
+
+	/* Indirect .sdata relocation */
+	case (int) R_PPC_EMB_SDAI16:
+	  BFD_ASSERT (sdata != NULL);
+	  relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info,
+								sdata, h, relocation, rel,
+								R_PPC_RELATIVE);
+	  break;
+
+	/* Indirect .sdata2 relocation */
+	case (int) R_PPC_EMB_SDA2I16:
+	  BFD_ASSERT (sdata2 != NULL);
+	  relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info,
+								sdata2, h, relocation, rel,
+								R_PPC_RELATIVE);
+	  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 (int) R_PPC_TOC16:			/* phony GOT16 relocations */
+	  BFD_ASSERT (sec != (asection *) 0);
+	  BFD_ASSERT (bfd_is_und_section (sec)
+		      || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0
+		      || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0)
+
+	  addend -= sec->output_section->vma + sec->output_offset + 0x8000;
+	  break;
+
+	case (int) R_PPC_PLTREL24:
+	  /* Relocation is to the entry for this symbol in the
+             procedure linkage table.  */
+	  BFD_ASSERT (h != NULL);
+
+	  if (h->plt.offset == (bfd_vma) -1
+	      || splt == NULL)
+	    {
+	      /* We didn't make a PLT entry for this symbol.  This
+                 happens when statically linking PIC code, or when
+                 using -Bsymbolic.  */
+	      break;
+	    }
+
+	  relocation = (splt->output_section->vma
+			+ splt->output_offset
+			+ h->plt.offset);
+	  break;
+
+	/* relocate against _SDA_BASE_ */
+	case (int) R_PPC_SDAREL16:
+	  {
+	    const char *name;
+
+	    BFD_ASSERT (sec != (asection *) 0);
+	    name = bfd_get_section_name (abfd, sec->output_section);
+	    if (strcmp (name, ".sdata") != 0
+		&& strcmp (name, ".sbss") != 0)
+	      {
+		(*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+				       bfd_archive_filename (input_bfd),
+				       sym_name,
+				       ppc_elf_howto_table[(int) r_type]->name,
+				       name);
+	      }
+	    addend -= (sdata->sym_hash->root.u.def.value
+		       + sdata->sym_hash->root.u.def.section->output_section->vma
+		       + sdata->sym_hash->root.u.def.section->output_offset);
+	  }
+	  break;
+
+	/* relocate against _SDA2_BASE_ */
+	case (int) R_PPC_EMB_SDA2REL:
+	  {
+	    const char *name;
+
+	    BFD_ASSERT (sec != (asection *) 0);
+	    name = bfd_get_section_name (abfd, sec->output_section);
+	    if (strcmp (name, ".sdata2") != 0 && strcmp (name, ".sbss2") != 0)
+	      {
+		(*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+				       bfd_archive_filename (input_bfd),
+				       sym_name,
+				       ppc_elf_howto_table[(int) r_type]->name,
+				       name);
+
+		bfd_set_error (bfd_error_bad_value);
+		ret = false;
+		continue;
+	      }
+	    addend -= (sdata2->sym_hash->root.u.def.value
+		       + sdata2->sym_hash->root.u.def.section->output_section->vma
+		       + sdata2->sym_hash->root.u.def.section->output_offset);
+	  }
+	  break;
+
+	/* relocate against either _SDA_BASE_, _SDA2_BASE_, or 0 */
+	case (int) R_PPC_EMB_SDA21:
+	case (int) R_PPC_EMB_RELSDA:
+	  {
+	    const char *name;
+	    int reg;
+
+	    BFD_ASSERT (sec != (asection *) 0);
+	    name = bfd_get_section_name (abfd, sec->output_section);
+	    if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0)
+	      {
+		reg = 13;
+		addend -= (sdata->sym_hash->root.u.def.value
+			   + sdata->sym_hash->root.u.def.section->output_section->vma
+			   + sdata->sym_hash->root.u.def.section->output_offset);
+	      }
+
+	    else if (strcmp (name, ".sdata2") == 0
+		     || strcmp (name, ".sbss2") == 0)
+	      {
+		reg = 2;
+		addend -= (sdata2->sym_hash->root.u.def.value
+			   + sdata2->sym_hash->root.u.def.section->output_section->vma
+			   + sdata2->sym_hash->root.u.def.section->output_offset);
+	      }
+
+	    else if (strcmp (name, ".PPC.EMB.sdata0") == 0
+		     || strcmp (name, ".PPC.EMB.sbss0") == 0)
+	      {
+		reg = 0;
+	      }
+
+	    else
+	      {
+		(*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+				       bfd_archive_filename (input_bfd),
+				       sym_name,
+				       ppc_elf_howto_table[(int) r_type]->name,
+				       name);
+
+		bfd_set_error (bfd_error_bad_value);
+		ret = false;
+		continue;
+	      }
+
+	    if (r_type == R_PPC_EMB_SDA21)
+	      {			/* fill in register field */
+		insn = bfd_get_32 (output_bfd, contents + offset);
+		insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
+		bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
+	      }
+	  }
+	  break;
+
+	/* Relocate against the beginning of the section */
+	case (int) R_PPC_SECTOFF:
+	case (int) R_PPC_SECTOFF_LO:
+	case (int) R_PPC_SECTOFF_HI:
+	  BFD_ASSERT (sec != (asection *) 0);
+	  addend -= sec->output_section->vma;
+	  break;
+
+	case (int) R_PPC_SECTOFF_HA:
+	  BFD_ASSERT (sec != (asection *) 0);
+	  addend -= sec->output_section->vma;
+	  addend += ((relocation + addend) & 0x8000) << 1;
+	  break;
+
+	/* Negative relocations */
+	case (int) R_PPC_EMB_NADDR32:
+	case (int) R_PPC_EMB_NADDR16:
+	case (int) R_PPC_EMB_NADDR16_LO:
+	case (int) R_PPC_EMB_NADDR16_HI:
+	  addend -= 2 * relocation;
+	  break;
+
+	case (int) R_PPC_EMB_NADDR16_HA:
+	  addend -= 2 * relocation;
+	  addend += ((relocation + addend) & 0x8000) << 1;
+	  break;
+
+	/* NOP relocation that prevents garbage collecting linkers from omitting a
+	   reference.  */
+	case (int) R_PPC_EMB_MRKREF:
+	  continue;
+
+	case (int) R_PPC_COPY:
+	case (int) R_PPC_GLOB_DAT:
+	case (int) R_PPC_JMP_SLOT:
+	case (int) R_PPC_RELATIVE:
+	case (int) R_PPC_PLT32:
+	case (int) R_PPC_PLTREL32:
+	case (int) R_PPC_PLT16_LO:
+	case (int) R_PPC_PLT16_HI:
+	case (int) R_PPC_PLT16_HA:
+	case (int) R_PPC_EMB_RELSEC16:
+	case (int) R_PPC_EMB_RELST_LO:
+	case (int) R_PPC_EMB_RELST_HI:
+	case (int) R_PPC_EMB_RELST_HA:
+	case (int) R_PPC_EMB_BIT_FLD:
+	  (*_bfd_error_handler) (_("%s: Relocation %s is not yet supported for symbol %s."),
+				 bfd_archive_filename (input_bfd),
+				 ppc_elf_howto_table[(int) r_type]->name,
+				 sym_name);
+
+	  bfd_set_error (bfd_error_invalid_operation);
+	  ret = false;
+	  continue;
+
+	case (int) R_PPC_GNU_VTINHERIT:
+	case (int) R_PPC_GNU_VTENTRY:
+	  /* These are no-ops in the end.  */
+	  continue;
+	}
+
+#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) offset,
+	       (long) addend);
+#endif
+
+      r = _bfd_final_link_relocate (howto,
+				    input_bfd,
+				    input_section,
+				    contents,
+				    offset,
+				    relocation,
+				    addend);
+
+      if (r == bfd_reloc_ok)
+	;
+      else if (r == bfd_reloc_overflow)
+	{
+	  const char *name;
+
+	  if (h != NULL)
+	    {
+	      if (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;
+		}
+
+	      name = h->root.root.string;
+	    }
+	  else
+	    {
+	      name = bfd_elf_string_from_elf_section (input_bfd,
+						      symtab_hdr->sh_link,
+						      sym->st_name);
+	      if (name == NULL)
+		continue;
+	      if (*name == '\0')
+		name = bfd_section_name (input_bfd, sec);
+	    }
+
+	  if (! (*info->callbacks->reloc_overflow) (info,
+						   name,
+						   howto->name,
+						   (bfd_vma) 0,
+						   input_bfd,
+						   input_section,
+						   offset))
+	    return false;
+	}
+      else
+	ret = false;
+    }
+
+#ifdef DEBUG
+  fprintf (stderr, "\n");
+#endif
+
+  return ret;
+}
+
+static enum elf_reloc_type_class
+ppc_elf_reloc_type_class (rela)
+     const Elf_Internal_Rela *rela;
+{
+  switch ((int) 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;
+    }
+}
+
+/* Support for core dump NOTE sections */
+static boolean
+ppc_elf_grok_prstatus (abfd, note)
+     bfd *abfd;
+     Elf_Internal_Note *note;
+{
+  int offset;
+  unsigned int raw_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_pid = bfd_get_32 (abfd, note->descdata + 24);
+
+	/* pr_reg */
+	offset = 72;
+	raw_size = 192;
+
+	break;
+    }
+
+  /* Make a ".reg/999" section.  */
+  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+					  raw_size, note->descpos + offset);
+}
+
+static boolean
+ppc_elf_grok_psinfo (abfd, note)
+     bfd *abfd;
+     Elf_Internal_Note *note;
+{
+  switch (note->descsz)
+    {
+      default:
+	return false;
+
+      case 128:		/* Linux/PPC elf_prpsinfo */
+	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;
+}
+
+#define TARGET_BIG_SYM		bfd_elf32_amiga_vec
+#define TARGET_BIG_NAME		"elf32-amiga"
+#define ELF_ARCH		bfd_arch_powerpc
+#define ELF_MACHINE_CODE	EM_PPC
+#define ELF_MAXPAGESIZE		0x10000
+#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_got_symbol_offset	4
+#define elf_backend_can_gc_sections	1
+#define elf_backend_can_refcount	1
+#define elf_backend_got_header_size	12
+#define elf_backend_plt_header_size	PLT_INITIAL_ENTRY_SIZE
+#define elf_backend_rela_normal		1
+
+#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_set_private_flags		ppc_elf_set_private_flags
+#define bfd_elf32_bfd_final_link		_bfd_elf32_gc_common_final_link
+
+#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_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_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_modify_segment_map
+#define elf_backend_grok_prstatus		ppc_elf_grok_prstatus
+#define elf_backend_grok_psinfo			ppc_elf_grok_psinfo
+#define elf_backend_reloc_type_class		ppc_elf_reloc_type_class
+
+#include "elf32-target.h"
diff -ru --new-file a/bfd/elf32-amigaos.c b/bfd/elf32-amigaos.c
--- a/bfd/elf32-amigaos.c	1970-01-01 03:00:00.000000000 +0300
+++ b/bfd/elf32-amigaos.c	2022-02-17 16:11:02.130121700 +0300
@@ -0,0 +1,10093 @@
+/* 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"
+#include "elf-linux-psinfo.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 */
+};
+
+/* External 32-bit PPC structure for PRPSINFO.  This structure is
+   ABI-defined, thus we choose to use char arrays here in order to
+   avoid dealing with different types in different architectures.
+
+   The PPC 32-bit structure uses int for `pr_uid' and `pr_gid' while
+   most non-PPC architectures use `short int'.
+
+   This structure will ultimately be written in the corefile's note
+   section, as the PRPSINFO.  */
+
+struct elf_external_ppc_linux_prpsinfo32
+  {
+    char pr_state;			/* Numeric process state.  */
+    char pr_sname;			/* Char for pr_state.  */
+    char pr_zomb;			/* Zombie.  */
+    char pr_nice;			/* Nice val.  */
+    char pr_flag[4];			/* Flags.  */
+    char pr_uid[4];
+    char pr_gid[4];
+    char pr_pid[4];
+    char pr_ppid[4];
+    char pr_pgrp[4];
+    char pr_sid[4];
+    char pr_fname[16];			/* Filename of executable.  */
+    char pr_psargs[80];			/* Initial part of arg list.  */
+  };
+
+/* Helper macro to swap (properly handling endianess) things from the
+   `elf_internal_prpsinfo' structure to the `elf_external_ppc_prpsinfo32'
+   structure.
+
+   Note that FROM should be a pointer, and TO should be the explicit type.  */
+
+#define PPC_LINUX_PRPSINFO32_SWAP_FIELDS(abfd, from, to)	      \
+  do								      \
+    {								      \
+      H_PUT_8 (abfd, from->pr_state, &to.pr_state);		      \
+      H_PUT_8 (abfd, from->pr_sname, &to.pr_sname);		      \
+      H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb);		      \
+      H_PUT_8 (abfd, from->pr_nice, &to.pr_nice);		      \
+      H_PUT_32 (abfd, from->pr_flag, to.pr_flag);		      \
+      H_PUT_32 (abfd, from->pr_uid, to.pr_uid);			      \
+      H_PUT_32 (abfd, from->pr_gid, to.pr_gid);			      \
+      H_PUT_32 (abfd, from->pr_pid, to.pr_pid);			      \
+      H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid);		      \
+      H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp);		      \
+      H_PUT_32 (abfd, from->pr_sid, to.pr_sid);			      \
+      strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname));    \
+      strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \
+    } while (0)
+
+
+/* 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;
+}
+
+#if 0
+char *
+elfcore_write_ppc_linux_prpsinfo32 (bfd *abfd, char *buf, int *bufsiz,
+				      const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+  struct elf_external_ppc_linux_prpsinfo32 data;
+
+  memset (&data, 0, sizeof (data));
+  PPC_LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data);
+
+  return elfcore_write_note (abfd, buf, bufsiz,
+			     "CORE", NT_PRPSINFO, &data, sizeof (data));
+}
+#endif
+
+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_seg_map (abfd); 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
+
+/* Used to track dynamic relocations for local symbols.  */
+struct ppc_dyn_relocs
+{
+  struct ppc_dyn_relocs *next;
+
+  /* The input section of the reloc.  */
+  asection *sec;
+
+  /* Total number of relocs copied for the input section.  */
+  unsigned int count : 31;
+
+  /* Whether this entry is for STT_GNU_IFUNC symbols.  */
+  unsigned int ifunc : 1;
+};
+
+/* 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;
+
+	  /* PR15323, ref flags aren't set for references in the same
+	     object.  */
+	  h->root.non_ir_ref = 1;
+	}
+
+      /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
+	 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)
+	    {
+	      struct plt_entry **ifunc;
+
+	      /* Set PLT_IFUNC flag for this sym, no GOT entry yet.  */
+	      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.  */
+	      if (!info->shared
+		  || is_branch_reloc (r_type))
+		{
+		  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;
+		    }
+		  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
+		       && (!SYMBOLIC_BIND (info, h)
+			   || 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)))
+	    {
+#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)
+		{
+		  struct elf_dyn_relocs *p;
+		  struct elf_dyn_relocs **rel_head;
+
+		  rel_head = &ppc_elf_hash_entry (h)->dyn_relocs;
+		  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;
+		}
+	      else
+		{
+		  /* Track dynamic relocs needed for local syms too.
+		     We really need local syms available to do this
+		     easily.  Oh well.  */
+		  struct ppc_dyn_relocs *p;
+		  struct ppc_dyn_relocs **rel_head;
+		  bfd_boolean is_ifunc;
+		  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 ppc_dyn_relocs **) vpp;
+		  is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC;
+		  p = *rel_head;
+		  if (p != NULL && p->sec == sec && p->ifunc != is_ifunc)
+		    p = p->next;
+		  if (p == NULL || p->sec != sec || p->ifunc != is_ifunc)
+		    {
+		      p = bfd_alloc (htab->elf.dynobj, sizeof *p);
+		      if (p == NULL)
+			return FALSE;
+		      p->next = *rel_head;
+		      *rel_head = p;
+		      p->sec = sec;
+		      p->ifunc = is_ifunc;
+		      p->count = 0;
+		    }
+		  p->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;
+
+	      if (eh->elf.type == STT_GNU_IFUNC)
+		rsec = htab->reliplt;
+	      /* 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 (eh->elf.type == STT_GNU_IFUNC)
+	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 ppc_dyn_relocs *p;
+
+	  for (p = ((struct ppc_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 (p->ifunc)
+		    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)
+		  {
+		    asection *srel = htab->relgot;
+		    if ((*lgot_masks & PLT_IFUNC) != 0)
+		      srel = htab->reliplt;
+		    srel->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_OPT, PPC_OPT_TLS))
+	    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;
+  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;
+
+			if (ifunc != NULL)
+			  rsec = htab->reliplt;
+			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;
+	      asection *sreloc;
+#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.  */
+	      sreloc = elf_section_data (input_section)->sreloc;
+	      if (ifunc)
+		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 struct bfd_link_info *info,
+			  const asection *rel_sec,
+			  const Elf_Internal_Rela *rela)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+
+  if (rel_sec == htab->reliplt)
+    return reloc_class_ifunc;
+
+  switch (ELF32_R_TYPE (rela->r_info))
+    {
+    case R_PPC_RELATIVE:
+      return reloc_class_relative;
+    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_section_processing
+
+#include "elf32-target.h"
\ No newline at end of file
diff -ru --new-file a/bfd/elf32-i386.c b/bfd/elf32-i386.c
--- a/bfd/elf32-i386.c	2013-11-08 14:13:48.000000000 +0400
+++ b/bfd/elf32-i386.c	2022-02-16 23:10:19.537743900 +0300
@@ -32,6 +32,11 @@
 #include "hashtab.h"
 #include "dwarf2.h"
 
+#ifndef ELF32_I386_RELOCATABLE_EXECUTABLES
+#define ELF32_I386_RELOCATABLE_EXECUTABLES 0
+#endif
+
+
 /* 386 uses REL relocations instead of RELA.  */
 #define USE_REL	1
 
@@ -1720,7 +1725,7 @@
 	     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
+	  if (((ELF32_I386_RELOCATABLE_EXECUTABLES || info->shared)
 	       && (sec->flags & SEC_ALLOC) != 0
 	       && (r_type != R_386_PC32
 		   || (h != NULL
@@ -2354,7 +2359,7 @@
      space for pc-relative relocs that have become local due to symbol
      visibility changes.  */
 
-  if (info->shared)
+  if (ELF32_I386_RELOCATABLE_EXECUTABLES || info->shared)
     {
       /* The only reloc that uses pc_count is R_386_PC32, which will
 	 appear on a call or on something like ".long foo - .".  We
@@ -3689,7 +3694,7 @@
 	      || is_vxworks_tls)
 	    break;
 
-	  if ((info->shared
+	  if (((ELF32_I386_RELOCATABLE_EXECUTABLES || info->shared)
 	       && (h == NULL
 		   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
 		   || h->root.type != bfd_link_hash_undefweak)
@@ -3730,6 +3735,7 @@
 		memset (&outrel, 0, sizeof outrel);
 	      else if (h != NULL
 		       && h->dynindx != -1
+		       && !(ELF32_I386_RELOCATABLE_EXECUTABLES && !info->shared)			   
 		       && (r_type == R_386_PC32
 			   || !info->shared
 			   || !SYMBOLIC_BIND (info, h)
@@ -5052,14 +5058,20 @@
 #define elf_backend_copy_indirect_symbol      elf_i386_copy_indirect_symbol
 #define elf_backend_create_dynamic_sections   elf_i386_create_dynamic_sections
 #define elf_backend_fake_sections	      elf_i386_fake_sections
+#ifndef elf_backend_finish_dynamic_sections
 #define elf_backend_finish_dynamic_sections   elf_i386_finish_dynamic_sections
+#endif
+#ifndef elf_backend_finish_dynamic_symbol
 #define elf_backend_finish_dynamic_symbol     elf_i386_finish_dynamic_symbol
+#endif
 #define elf_backend_gc_mark_hook	      elf_i386_gc_mark_hook
 #define elf_backend_gc_sweep_hook	      elf_i386_gc_sweep_hook
 #define elf_backend_grok_prstatus	      elf_i386_grok_prstatus
 #define elf_backend_grok_psinfo		      elf_i386_grok_psinfo
 #define elf_backend_reloc_type_class	      elf_i386_reloc_type_class
+#ifndef elf_backend_relocate_section
 #define elf_backend_relocate_section	      elf_i386_relocate_section
+#endif
 #define elf_backend_size_dynamic_sections     elf_i386_size_dynamic_sections
 #define elf_backend_always_size_sections      elf_i386_always_size_sections
 #define elf_backend_omit_section_dynsym \
diff -ru --new-file a/bfd/elf32-i386-amithlon.c b/bfd/elf32-i386-amithlon.c
--- a/bfd/elf32-i386-amithlon.c	1970-01-01 03:00:00.000000000 +0300
+++ b/bfd/elf32-i386-amithlon.c	2021-02-01 23:12:49.109611400 +0300
@@ -0,0 +1,198 @@
+/* Intel IA-32 specific support for 32-bit big endian ELF on Amithlon.
+   Copyright 2002 Free Software Foundation, Inc.
+   Written by Martin Blom.
+
+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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define TARGET_LITTLE_SYM		bfd_elf32_i386_amithlon_vec
+#define TARGET_LITTLE_NAME		"elf32-i386-amithlon"
+#define TARGET_BIG_SYM			bfd_elf32_i386be_amithlon_vec
+#define TARGET_BIG_NAME			"elf32-i386be-amithlon"
+#define ELF_ARCH			bfd_arch_i386
+#define ELF_MACHINE_CODE		EM_386
+#define ELF_MAXPAGESIZE			32  //0x1000
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "elf-bfd.h"
+
+/* Forward declarations */
+extern const bfd_target bfd_elf32_i386_amithlon_vec;
+extern const bfd_target bfd_elf32_i386be_amithlon_vec;
+
+static boolean elf_i386_relocate_section
+  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+	   Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+
+static boolean elf_i386_finish_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+static boolean elf_i386_finish_dynamic_symbol
+  PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+	   Elf_Internal_Sym *));
+
+boolean elf_link_output_relocs
+  PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *));
+
+#define swap_xvec(xvec,c)                                   \
+do {                                                        \
+  xvec->bfd_getx64         = bfd_get ## c ## 64;            \
+  xvec->bfd_getx_signed_64 = bfd_get ## c ## _signed_64;    \
+  xvec->bfd_putx64         = bfd_put ## c ## 64;            \
+  xvec->bfd_getx32         = bfd_get ## c ## 32;            \
+  xvec->bfd_getx_signed_32 = bfd_get ## c ## _signed_32;    \
+  xvec->bfd_putx32         = bfd_put ## c ## 32;            \
+  xvec->bfd_getx16         = bfd_get ## c ## 16;            \
+  xvec->bfd_getx_signed_16 = bfd_get ## c ## _signed_16;    \
+  xvec->bfd_putx16         = bfd_put ## c ## 16;            \
+} while(0)
+
+/* Relocate a big endian i386 ELF section.  */
+
+static boolean
+amithlon_relocate_section (output_bfd, info, input_bfd, input_section,
+			   contents, relocs, local_syms, local_sections)
+     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;
+{
+  boolean switched_input  = false;
+  boolean switched_output = false;
+  boolean rc;
+
+  /* Since code sections are actually little endian, no matter what
+     endian mode we're operating in, this rather dirty hack is used to
+     make sure the correct data access routines are used. */
+
+  if ((bfd_get_section_flags (input_bfd, input_section) & SEC_CODE))
+  {
+    if (input_bfd->xvec == &bfd_elf32_i386be_amithlon_vec)
+    {
+      switched_input = true;
+
+      swap_xvec(input_bfd->xvec,l);
+    }
+    
+    if (output_bfd->xvec == &bfd_elf32_i386be_amithlon_vec)
+    {
+      switched_output = true;
+
+      swap_xvec(output_bfd->xvec,l);
+    }
+  }
+
+  rc = elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
+				  contents, relocs,
+				  local_syms, local_sections);
+  
+  if (switched_input)
+  {
+    swap_xvec(input_bfd->xvec,b);
+  }
+
+  if (switched_output)
+  {
+    swap_xvec(output_bfd->xvec,b);
+  }
+  
+  return rc;
+}  
+
+static boolean
+amithlon_finish_dynamic_sections (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  boolean switched_output = false;
+  boolean rc;
+
+  /* Since code sections are actually little endian, no matter what
+     endian mode we're operating in, this rather dirty hack is used to
+     make sure the correct data access routines are used. */
+
+  if (output_bfd->xvec == &bfd_elf32_i386be_amithlon_vec)
+  {
+    switched_output = true;
+
+    swap_xvec(output_bfd->xvec,l);
+  }
+
+  rc = elf_i386_finish_dynamic_sections (output_bfd, info);
+
+  if (switched_output)
+  {
+    swap_xvec(output_bfd->xvec,b);
+  }
+  
+  return rc;
+}
+
+static boolean
+amithlon_finish_dynamic_symbol (output_bfd, info, h, sym)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  boolean switched_output = false;
+  boolean rc;
+
+  /* Since code sections are actually little endian, no matter what
+     endian mode we're operating in, this rather dirty hack is used to
+     make sure the correct data access routines are used. */
+
+  if (output_bfd->xvec == &bfd_elf32_i386be_amithlon_vec)
+  {
+    switched_output = true;
+
+    swap_xvec(output_bfd->xvec,l);
+  }
+
+  rc = elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym);
+
+  if (switched_output)
+  {
+    swap_xvec(output_bfd->xvec,b);
+  }
+  
+  return rc;
+}
+
+static bfd_size_type
+amithlon_additional_program_headers (abfd)
+     bfd *abfd;
+{
+//  printf("big: %x little: %x\n",
+//	 &bfd_elf32_i386be_amithlon_vec,
+//	 &bfd_elf32_i386_amithlon_vec);
+  // headers, text, rodata, data+bss
+  return -2+4;
+}
+
+#define elf_backend_relocate_section	        amithlon_relocate_section
+#define elf_backend_finish_dynamic_sections     amithlon_finish_dynamic_sections
+#define elf_backend_finish_dynamic_symbol       amithlon_finish_dynamic_symbol
+#define elf_backend_additional_program_headers  amithlon_additional_program_headers
+
+#define ELF32_I386_RELOCATABLE_EXECUTABLES 1
+
+#include "elf32-i386.c"
diff -ru --new-file a/bfd/elf32-morphos.c b/bfd/elf32-morphos.c
--- a/bfd/elf32-morphos.c	1970-01-01 03:00:00.000000000 +0300
+++ b/bfd/elf32-morphos.c	2021-02-01 23:12:49.114624200 +0300
@@ -0,0 +1,7137 @@
+/* PowerPC-specific support for 32-bit ELF
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.  */
+
+#define ARCH_SIZE		32
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "genlink.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "elf/ppc.h"
+
+#define USE_RELA		/* we want RELA relocations, not REL */
+
+/* Renaming structures, typedefs, macros and functions to be size-specific.  */
+#define Elf_External_Ehdr	NAME(Elf,External_Ehdr)
+#define Elf_External_Sym	NAME(Elf,External_Sym)
+#define Elf_External_Shdr	NAME(Elf,External_Shdr)
+#define Elf_External_Phdr	NAME(Elf,External_Phdr)
+#define Elf_External_Rel	NAME(Elf,External_Rel)
+#define Elf_External_Rela	NAME(Elf,External_Rela)
+#define Elf_External_Dyn	NAME(Elf,External_Dyn)
+
+#define elf_core_file_failing_command	NAME(bfd_elf,core_file_failing_command)
+#define elf_core_file_failing_signal	NAME(bfd_elf,core_file_failing_signal)
+#define elf_core_file_matches_executable_p \
+  NAME(bfd_elf,core_file_matches_executable_p)
+#define elf_object_p			NAME(bfd_elf,object_p)
+#define elf_core_file_p			NAME(bfd_elf,core_file_p)
+#define elf_get_symtab_upper_bound	NAME(bfd_elf,get_symtab_upper_bound)
+#define elf_get_dynamic_symtab_upper_bound \
+  NAME(bfd_elf,get_dynamic_symtab_upper_bound)
+#define elf_swap_reloc_in		NAME(bfd_elf,swap_reloc_in)
+#define elf_swap_reloca_in		NAME(bfd_elf,swap_reloca_in)
+#define elf_swap_reloc_out		NAME(bfd_elf,swap_reloc_out)
+#define elf_swap_reloca_out		NAME(bfd_elf,swap_reloca_out)
+#define elf_swap_symbol_in		NAME(bfd_elf,swap_symbol_in)
+#define elf_swap_symbol_out		NAME(bfd_elf,swap_symbol_out)
+#define elf_swap_phdr_in		NAME(bfd_elf,swap_phdr_in)
+#define elf_swap_phdr_out		NAME(bfd_elf,swap_phdr_out)
+#define elf_swap_dyn_in			NAME(bfd_elf,swap_dyn_in)
+#define elf_swap_dyn_out		NAME(bfd_elf,swap_dyn_out)
+#define elf_get_reloc_upper_bound	NAME(bfd_elf,get_reloc_upper_bound)
+#define elf_canonicalize_reloc		NAME(bfd_elf,canonicalize_reloc)
+#define elf_slurp_symbol_table		NAME(bfd_elf,slurp_symbol_table)
+#define elf_get_symtab			NAME(bfd_elf,get_symtab)
+#define elf_canonicalize_dynamic_symtab \
+  NAME(bfd_elf,canonicalize_dynamic_symtab)
+#define elf_make_empty_symbol		NAME(bfd_elf,make_empty_symbol)
+#define elf_get_symbol_info		NAME(bfd_elf,get_symbol_info)
+#define elf_get_lineno			NAME(bfd_elf,get_lineno)
+#define elf_set_arch_mach		NAME(bfd_elf,set_arch_mach)
+#define elf_find_nearest_line		NAME(bfd_elf,find_nearest_line)
+#define elf_sizeof_headers		NAME(bfd_elf,sizeof_headers)
+#define elf_set_section_contents	NAME(bfd_elf,set_section_contents)
+#define elf_no_info_to_howto		NAME(bfd_elf,no_info_to_howto)
+#define elf_no_info_to_howto_rel	NAME(bfd_elf,no_info_to_howto_rel)
+#define elf_find_section		NAME(bfd_elf,find_section)
+#define elf_bfd_link_add_symbols	NAME(bfd_elf,bfd_link_add_symbols)
+#define elf_add_dynamic_entry		NAME(bfd_elf,add_dynamic_entry)
+#define elf_write_shdrs_and_ehdr	NAME(bfd_elf,write_shdrs_and_ehdr)
+#define elf_write_out_phdrs		NAME(bfd_elf,write_out_phdrs)
+#define elf_write_relocs		NAME(bfd_elf,write_relocs)
+#define elf_slurp_reloc_table		NAME(bfd_elf,slurp_reloc_table)
+#define elf_link_create_dynamic_sections \
+  NAME(bfd_elf,link_create_dynamic_sections)
+#define elf_bfd_discard_info		NAME(bfd_elf,discard_info)
+#define elf_reloc_symbol_deleted_p	NAME(_bfd_elf,reloc_symbol_deleted_p)
+#define elf_link_record_dynamic_symbol  _bfd_elf_link_record_dynamic_symbol
+#define elf_bfd_final_link		NAME(bfd_elf,bfd_final_link)
+#define elf_create_pointer_linker_section NAME(bfd_elf,create_pointer_linker_section)
+#define elf_finish_pointer_linker_section NAME(bfd_elf,finish_pointer_linker_section)
+#define elf_gc_sections			NAME(_bfd_elf,gc_sections)
+#define elf_gc_common_finalize_got_offsets \
+  NAME(_bfd_elf,gc_common_finalize_got_offsets)
+#define elf_gc_common_final_link	NAME(_bfd_elf,gc_common_final_link)
+#define elf_gc_record_vtinherit		NAME(_bfd_elf,gc_record_vtinherit)
+#define elf_gc_record_vtentry		NAME(_bfd_elf,gc_record_vtentry)
+#define elf_link_record_local_dynamic_symbol \
+  NAME(_bfd_elf,link_record_local_dynamic_symbol)
+
+#define ELF_R_INFO(X,Y)	ELF32_R_INFO(X,Y)
+#define ELF_R_SYM(X)	ELF32_R_SYM(X)
+#define ELF_R_TYPE(X)	ELF32_R_TYPE(X)
+#define ELFCLASS	ELFCLASS32
+#define FILE_ALIGN	4
+#define LOG_FILE_ALIGN	2
+
+#define H_PUT_WORD		H_PUT_32
+#define H_PUT_SIGNED_WORD	H_PUT_S32
+#define H_GET_WORD		H_GET_32
+#define H_GET_SIGNED_WORD	H_GET_S32
+
+#define elf_stringtab_init _bfd_elf_stringtab_init
+
+#define section_from_elf_index bfd_section_from_elf_index
+
+static int ddr_count;
+static unsigned *ddr_ptr;
+
+static reloc_howto_type *ppc_elf_reloc_type_lookup
+  PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
+static void ppc_elf_info_to_howto
+  PARAMS ((bfd *abfd, arelent *cache_ptr, Elf32_Internal_Rela *dst));
+static void ppc_elf_howto_init PARAMS ((void));
+static int ppc_elf_sort_rela PARAMS ((const PTR, const PTR));
+static boolean ppc_elf_relax_section
+  PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *));
+static bfd_reloc_status_type ppc_elf_addr16_ha_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static boolean ppc_elf_object_p PARAMS ((bfd *));
+static boolean ppc_elf_set_private_flags PARAMS ((bfd *, flagword));
+static boolean ppc_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
+
+static int ppc_elf_additional_program_headers PARAMS ((bfd *));
+static boolean ppc_elf_modify_segment_map PARAMS ((bfd *));
+
+static asection *ppc_elf_create_got
+  PARAMS ((bfd *, struct bfd_link_info *));
+static boolean ppc_elf_create_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+static boolean ppc_elf_section_from_shdr PARAMS ((bfd *,
+						  Elf32_Internal_Shdr *,
+						  const char *));
+static boolean ppc_elf_fake_sections
+  PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
+
+static elf_linker_section_t *ppc_elf_create_linker_section
+  PARAMS ((bfd *abfd,
+	   struct bfd_link_info *info,
+	   enum elf_linker_section_enum));
+
+static boolean ppc_elf_check_relocs PARAMS ((bfd *,
+					     struct bfd_link_info *,
+					     asection *,
+					     const Elf_Internal_Rela *));
+
+static asection * ppc_elf_gc_mark_hook PARAMS ((asection *sec,
+						struct bfd_link_info *info,
+						Elf_Internal_Rela *rel,
+						struct elf_link_hash_entry *h,
+						Elf_Internal_Sym *sym));
+
+static boolean ppc_elf_gc_sweep_hook PARAMS ((bfd *abfd,
+					      struct bfd_link_info *info,
+					      asection *sec,
+					      const Elf_Internal_Rela *relocs));
+
+static boolean ppc_elf_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *,
+						      struct elf_link_hash_entry *));
+
+static boolean ppc_elf_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));
+
+static boolean ppc_elf_relocate_section PARAMS ((bfd *,
+						 struct bfd_link_info *info,
+						 bfd *,
+						 asection *,
+						 bfd_byte *,
+						 Elf_Internal_Rela *relocs,
+						 Elf_Internal_Sym *local_syms,
+						 asection **));
+
+static boolean ppc_elf_add_symbol_hook  PARAMS ((bfd *,
+						 struct bfd_link_info *,
+						 const Elf_Internal_Sym *,
+						 const char **,
+						 flagword *,
+						 asection **,
+						 bfd_vma *));
+
+static boolean ppc_elf_finish_dynamic_symbol PARAMS ((bfd *,
+						      struct bfd_link_info *,
+						      struct elf_link_hash_entry *,
+						      Elf_Internal_Sym *));
+
+static boolean ppc_elf_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));
+static enum elf_reloc_type_class ppc_elf_reloc_type_class
+  PARAMS ((const Elf_Internal_Rela *));
+static boolean ppc_elf_grok_prstatus
+  PARAMS ((bfd *abfd, Elf_Internal_Note *note));
+static boolean ppc_elf_grok_psinfo
+  PARAMS ((bfd *abfd, Elf_Internal_Note *note));
+
+#define BRANCH_PREDICT_BIT 0x200000		/* branch prediction bit for branch taken relocs */
+#define RA_REGISTER_MASK 0x001f0000		/* mask to set RA in memory instructions */
+#define RA_REGISTER_SHIFT 16			/* value to shift register by to insert RA */
+
+/* The name of the dynamic interpreter.  This is put in the .interp
+   section.  */
+
+#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
+
+/* The size in bytes of an entry in the procedure linkage table.  */
+#define PLT_ENTRY_SIZE 12
+/* The initial size of the plt reserved for the dynamic linker.  */
+#define PLT_INITIAL_ENTRY_SIZE 72
+/* The size of the gap between entries in the PLT.  */
+#define PLT_SLOT_SIZE 8
+/* The number of single-slot PLT entries (the rest use two slots).  */
+#define PLT_NUM_SINGLE_ENTRIES 8192
+
+/* Will references to this symbol always reference the symbol
+   in this object?  */
+#define SYMBOL_REFERENCES_LOCAL(INFO, H)				\
+  ((! INFO->shared							\
+    || INFO->symbolic							\
+    || H->dynindx == -1							\
+    || ELF_ST_VISIBILITY (H->other) == STV_INTERNAL			\
+    || ELF_ST_VISIBILITY (H->other) == STV_HIDDEN)			\
+   && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+
+/* Will _calls_ to this symbol always call the version in this object?  */
+#define SYMBOL_CALLS_LOCAL(INFO, H)				\
+  ((! INFO->shared							\
+    || INFO->symbolic							\
+    || H->dynindx == -1							\
+    || ELF_ST_VISIBILITY (H->other) != STV_DEFAULT)			\
+   && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+
+static reloc_howto_type *ppc_elf_howto_table[(int) 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 */
+
+  /* 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_bitfield, /* 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_bitfield, /* 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 */
+
+  /* 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 */
+	 true,			/* 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 */
+
+  /* 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 */
+
+  /* 32-bit relocation relative to _SDA_BASE_ */
+  HOWTO (R_PPC_MORPHOS_DREL,	/* 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_MORPHOS_DREL",	/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Lower 16 bits of a relocation relative to _SDA_BASE */
+  HOWTO (R_PPC_MORPHOS_DREL_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 */
+	 /*complain_overflow_bitfield,*/ /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_PPC_MORPHOS_DREL_LO",/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 false),		/* pcrel_offset */
+
+  /* Upper 16 bits of a relocation relative to _SDA_BASE */
+  HOWTO (R_PPC_MORPHOS_DREL_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 */
+	 /*complain_overflow_bitfield,*/ /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_PPC_MORPHOS_DREL_HI",/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 false),		 /* pcrel_offset */
+
+  /* Upper 16 bits of a relocation relative to _SDA_BASE */
+  HOWTO (R_PPC_MORPHOS_DREL_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 */
+	 /*complain_overflow_bitfield,*/ /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_PPC_MORPHOS_DREL_HA",/* 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 ()
+{
+  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;
+      BFD_ASSERT (type < sizeof (ppc_elf_howto_table) / sizeof (ppc_elf_howto_table[0]));
+      ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i];
+    }
+}
+
+/* This function handles relaxing for the PPC with option --mpc860c0[=<n>].
+
+   The MPC860, revision C0 or earlier contains a bug in the die.
+   If all of the following conditions are true, the next instruction
+   to be executed *may* be treated as a no-op.
+   1/ A forward branch is executed.
+   2/ The branch is predicted as not taken.
+   3/ The branch is taken.
+   4/ The branch is located in the last 5 words of a page.
+      (The EOP limit is 5 by default but may be specified as any value from 1-10.)
+
+   Our software solution is to detect these problematic branches in a
+   linker pass and modify them as follows:
+   1/ Unconditional branches - Since these are always predicted taken,
+      there is no problem and no action is required.
+   2/ Conditional backward branches - No problem, no action required.
+   3/ Conditional forward branches - Ensure that the "inverse prediction
+      bit" is set (ensure it is predicted taken).
+   4/ Conditional register branches - Ensure that the "y bit" is set
+      (ensure it is predicted taken).
+*/
+
+/* Sort sections by address.  */
+
+static int
+ppc_elf_sort_rela (arg1, arg2)
+     const PTR arg1;
+     const PTR arg2;
+{
+  const Elf_Internal_Rela **rela1 = (const Elf_Internal_Rela**) arg1;
+  const Elf_Internal_Rela **rela2 = (const Elf_Internal_Rela**) arg2;
+
+  /* Sort by offset.  */
+  return ((*rela1)->r_offset - (*rela2)->r_offset);
+}
+
+static boolean
+ppc_elf_relax_section (abfd, isec, link_info, again)
+     bfd *abfd;
+     asection *isec;
+     struct bfd_link_info *link_info;
+     boolean *again;
+{
+#define PAGESIZE 0x1000
+
+  bfd_byte *contents = NULL;
+  bfd_byte *free_contents = NULL;
+  Elf_Internal_Rela *internal_relocs = NULL;
+  Elf_Internal_Rela *free_relocs = NULL;
+  Elf_Internal_Rela **rela_comb = NULL;
+  int comb_curr, comb_count;
+
+  /* We never have to do this more than once per input section.  */
+  *again = false;
+
+  /* If needed, initialize this section's cooked size.  */
+  if (isec->_cooked_size == 0)
+      isec->_cooked_size = isec->_raw_size;
+
+  /* We're only interested in text sections which overlap the
+     troublesome area at the end of a page.  */
+  if (link_info->mpc860c0 && (isec->flags & SEC_CODE) && isec->_cooked_size)
+    {
+      bfd_vma dot, end_page, end_section;
+      boolean section_modified;
+
+      /* Get the section contents.  */
+      /* 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.  */
+	  contents = (bfd_byte *) bfd_malloc (isec->_raw_size);
+	  if (contents == NULL)
+	    goto error_return;
+	  free_contents = contents;
+
+	  if (! bfd_get_section_contents (abfd, isec, contents,
+					  (file_ptr) 0, isec->_raw_size))
+	    goto error_return;
+	}
+
+      comb_curr = 0;
+      comb_count = 0;
+      if (isec->reloc_count)
+	{
+          unsigned n;
+	  bfd_size_type amt;
+
+          /* Get a copy of the native relocations.  */
+          internal_relocs = _bfd_elf32_link_read_relocs (
+    	    abfd, isec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+    	    link_info->keep_memory);
+          if (internal_relocs == NULL)
+    	      goto error_return;
+          if (! link_info->keep_memory)
+    	      free_relocs = internal_relocs;
+
+          /* Setup a faster access method for the reloc info we need.  */
+	  amt = isec->reloc_count;
+	  amt *= sizeof (Elf_Internal_Rela*);
+          rela_comb = (Elf_Internal_Rela**) bfd_malloc (amt);
+          if (rela_comb == NULL)
+              goto error_return;
+          for (n = 0; n < isec->reloc_count; ++n)
+            {
+              long r_type;
+
+              r_type = ELF32_R_TYPE (internal_relocs[n].r_info);
+              if (r_type < 0 || r_type >= (int) R_PPC_max)
+                  goto error_return;
+
+              /* Prologue constants are sometimes present in the ".text"
+              sections and they can be identified by their associated relocation.
+              We don't want to process those words and some others which
+              can also be identified by their relocations.  However, not all
+              conditional branches will have a relocation so we will
+              only ignore words that 1) have a reloc, and 2) the reloc
+              is not applicable to a conditional branch.
+              The array rela_comb is built here for use in the EOP scan loop.  */
+              switch (r_type)
+                {
+                case R_PPC_ADDR14_BRNTAKEN:     /* absolute, predicted not taken */
+                case R_PPC_REL14:               /* relative cond. br.  */
+                case R_PPC_REL14_BRNTAKEN:      /* rel. cond. br., predicted not taken */
+                  /* We should check the instruction.  */
+                  break;
+                default:
+                  /* The word is not a conditional branch - ignore it.  */
+                  rela_comb[comb_count++] = &internal_relocs[n];
+                  break;
+                }
+            }
+          if (comb_count > 1)
+	    qsort (rela_comb, (size_t) comb_count, sizeof (int), ppc_elf_sort_rela);
+	}
+
+      /* Enumerate each EOP region that overlaps this section.  */
+      end_section = isec->vma + isec->_cooked_size;
+      dot = end_page = (isec->vma | (PAGESIZE - 1)) + 1;
+      dot -= link_info->mpc860c0;
+      section_modified = false;
+      if (dot < isec->vma)      /* Increment the start position if this section */
+          dot = isec->vma;      /* begins in the middle of its first EOP region.  */
+      for (;
+           dot < end_section;
+           dot += PAGESIZE, end_page += PAGESIZE)
+        {
+
+          /* Check each word in this EOP region.  */
+          for (; dot < end_page; dot += 4)
+            {
+              bfd_vma isec_offset;
+              unsigned long insn;
+              boolean skip, modified;
+
+              /* Don't process this word if there is a relocation for it and
+              the relocation indicates the word is not a conditional branch.  */
+              skip = false;
+              isec_offset = dot - isec->vma;
+              for (; comb_curr<comb_count; ++comb_curr)
+                {
+                  bfd_vma r_offset;
+
+                  r_offset = rela_comb[comb_curr]->r_offset;
+                  if (r_offset >= isec_offset)
+                    {
+                      if (r_offset == isec_offset) skip = true;
+                      break;
+                    }
+                }
+              if (skip) continue;
+
+              /* Check the current word for a problematic conditional branch.  */
+#define BO0(insn) ((insn) & 0x02000000)
+#define BO2(insn) ((insn) & 0x00800000)
+#define BO4(insn) ((insn) & 0x00200000)
+              insn = (unsigned long) bfd_get_32 (abfd, contents + isec_offset);
+              modified = false;
+              if ((insn & 0xFc000000) == 0x40000000)
+                {
+                  /* Instruction is BCx */
+                  if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
+                    {
+                      bfd_vma target;
+                      /* This branch is predicted as "normal".
+                      If this is a forward branch, it is problematic.  */
+
+                      target = insn & 0x0000Fffc;               /*extract*/
+                      target = (target ^ 0x8000) - 0x8000;      /*sign extend*/
+                      if ((insn & 0x00000002) == 0)
+                          target += dot;                        /*convert to abs*/
+                      if (target > dot)
+                        {
+                          insn |= 0x00200000;   /* set the prediction bit */
+                          modified = true;
+                        }
+                    }
+                }
+              else if ((insn & 0xFc00Fffe) == 0x4c000420)
+                {
+                  /* Instruction is BCCTRx */
+                  if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
+		    {
+		      /* This branch is predicted as not-taken.
+		      If this is a forward branch, it is problematic.
+                      Since we can't tell statically if it will branch forward,
+                      always set the prediction bit.  */
+                      insn |= 0x00200000;   /* set the prediction bit */
+                      modified = true;
+		    }
+                }
+              else if ((insn & 0xFc00Fffe) == 0x4c000020)
+                {
+                  /* Instruction is BCLRx */
+                  if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
+		    {
+		      /* This branch is predicted as not-taken.
+		      If this is a forward branch, it is problematic.
+                      Since we can't tell statically if it will branch forward,
+                      always set the prediction bit.  */
+                      insn |= 0x00200000;   /* set the prediction bit */
+                      modified = true;
+		    }
+                }
+#undef BO0
+#undef BO2
+#undef BO4
+              if (modified)
+	        {
+                  bfd_put_32 (abfd, (bfd_vma) insn, contents + isec_offset);
+		  section_modified = true;
+	        }
+            }
+        }
+      if (section_modified)
+	{
+	  elf_section_data (isec)->this_hdr.contents = contents;
+	  free_contents = NULL;
+	}
+    }
+
+  if (rela_comb != NULL)
+    {
+      free (rela_comb);
+      rela_comb = NULL;
+    }
+
+  if (free_relocs != NULL)
+    {
+      free (free_relocs);
+      free_relocs = NULL;
+    }
+
+  if (free_contents != NULL)
+    {
+      if (! link_info->keep_memory)
+	free (free_contents);
+      else
+	{
+	  /* Cache the section contents for elf_link_input_bfd.  */
+	  elf_section_data (isec)->this_hdr.contents = contents;
+	}
+      free_contents = NULL;
+    }
+
+  return true;
+
+error_return:
+  if (rela_comb != NULL)
+    free (rela_comb);
+  if (free_relocs != NULL)
+    free (free_relocs);
+  if (free_contents != NULL)
+    free (free_contents);
+  return false;
+}
+
+static reloc_howto_type *
+ppc_elf_reloc_type_lookup (abfd, code)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     bfd_reloc_code_real_type code;
+{
+  enum elf_ppc_reloc_type ppc_reloc = R_PPC_NONE;
+
+  if (!ppc_elf_howto_table[R_PPC_ADDR32])
+    /* Initialize howto table if needed.  */
+    ppc_elf_howto_init ();
+
+  switch ((int) code)
+    {
+    default:
+      return (reloc_howto_type *) NULL;
+
+    case BFD_RELOC_NONE:		ppc_reloc = R_PPC_NONE;			break;
+    case BFD_RELOC_32:			ppc_reloc = R_PPC_ADDR32;		break;
+    case BFD_RELOC_PPC_BA26:		ppc_reloc = R_PPC_ADDR24;		break;
+    case BFD_RELOC_16:			ppc_reloc = R_PPC_ADDR16;		break;
+    case BFD_RELOC_LO16:		ppc_reloc = R_PPC_ADDR16_LO;		break;
+    case BFD_RELOC_HI16:		ppc_reloc = R_PPC_ADDR16_HI;		break;
+    case BFD_RELOC_HI16_S:		ppc_reloc = R_PPC_ADDR16_HA;		break;
+    case BFD_RELOC_PPC_BA16:		ppc_reloc = R_PPC_ADDR14;		break;
+    case BFD_RELOC_PPC_BA16_BRTAKEN:	ppc_reloc = R_PPC_ADDR14_BRTAKEN;	break;
+    case BFD_RELOC_PPC_BA16_BRNTAKEN:	ppc_reloc = R_PPC_ADDR14_BRNTAKEN;	break;
+    case BFD_RELOC_PPC_B26:		ppc_reloc = R_PPC_REL24;		break;
+    case BFD_RELOC_PPC_B16:		ppc_reloc = R_PPC_REL14;		break;
+    case BFD_RELOC_PPC_B16_BRTAKEN:	ppc_reloc = R_PPC_REL14_BRTAKEN;	break;
+    case BFD_RELOC_PPC_B16_BRNTAKEN:	ppc_reloc = R_PPC_REL14_BRNTAKEN;	break;
+    case BFD_RELOC_16_GOTOFF:		ppc_reloc = R_PPC_GOT16;		break;
+    case BFD_RELOC_LO16_GOTOFF:		ppc_reloc = R_PPC_GOT16_LO;		break;
+    case BFD_RELOC_HI16_GOTOFF:		ppc_reloc = R_PPC_GOT16_HI;		break;
+    case BFD_RELOC_HI16_S_GOTOFF:	ppc_reloc = R_PPC_GOT16_HA;		break;
+    case BFD_RELOC_24_PLT_PCREL:	ppc_reloc = R_PPC_PLTREL24;		break;
+    case BFD_RELOC_PPC_COPY:		ppc_reloc = R_PPC_COPY;			break;
+    case BFD_RELOC_PPC_GLOB_DAT:	ppc_reloc = R_PPC_GLOB_DAT;		break;
+    case BFD_RELOC_PPC_LOCAL24PC:	ppc_reloc = R_PPC_LOCAL24PC;		break;
+    case BFD_RELOC_32_PCREL:		ppc_reloc = R_PPC_REL32;		break;
+    case BFD_RELOC_32_PLTOFF:		ppc_reloc = R_PPC_PLT32;		break;
+    case BFD_RELOC_32_PLT_PCREL:	ppc_reloc = R_PPC_PLTREL32;		break;
+    case BFD_RELOC_LO16_PLTOFF:		ppc_reloc = R_PPC_PLT16_LO;		break;
+    case BFD_RELOC_HI16_PLTOFF:		ppc_reloc = R_PPC_PLT16_HI;		break;
+    case BFD_RELOC_HI16_S_PLTOFF:	ppc_reloc = R_PPC_PLT16_HA;		break;
+    case BFD_RELOC_GPREL16:		ppc_reloc = R_PPC_SDAREL16;		break;
+    case BFD_RELOC_16_BASEREL:		ppc_reloc = R_PPC_SECTOFF;		break;
+    case BFD_RELOC_LO16_BASEREL:	ppc_reloc = R_PPC_SECTOFF_LO;		break;
+    case BFD_RELOC_HI16_BASEREL:	ppc_reloc = R_PPC_SECTOFF_HI;		break;
+    case BFD_RELOC_HI16_S_BASEREL:	ppc_reloc = R_PPC_SECTOFF_HA;		break;
+    case BFD_RELOC_CTOR:		ppc_reloc = R_PPC_ADDR32;		break;
+    case BFD_RELOC_PPC_TOC16:		ppc_reloc = R_PPC_TOC16;		break;
+    case BFD_RELOC_PPC_EMB_NADDR32:	ppc_reloc = R_PPC_EMB_NADDR32;		break;
+    case BFD_RELOC_PPC_EMB_NADDR16:	ppc_reloc = R_PPC_EMB_NADDR16;		break;
+    case BFD_RELOC_PPC_EMB_NADDR16_LO:	ppc_reloc = R_PPC_EMB_NADDR16_LO;	break;
+    case BFD_RELOC_PPC_EMB_NADDR16_HI:	ppc_reloc = R_PPC_EMB_NADDR16_HI;	break;
+    case BFD_RELOC_PPC_EMB_NADDR16_HA:	ppc_reloc = R_PPC_EMB_NADDR16_HA;	break;
+    case BFD_RELOC_PPC_EMB_SDAI16:	ppc_reloc = R_PPC_EMB_SDAI16;		break;
+    case BFD_RELOC_PPC_EMB_SDA2I16:	ppc_reloc = R_PPC_EMB_SDA2I16;		break;
+    case BFD_RELOC_PPC_EMB_SDA2REL:	ppc_reloc = R_PPC_EMB_SDA2REL;		break;
+    case BFD_RELOC_PPC_EMB_SDA21:	ppc_reloc = R_PPC_EMB_SDA21;		break;
+    case BFD_RELOC_PPC_EMB_MRKREF:	ppc_reloc = R_PPC_EMB_MRKREF;		break;
+    case BFD_RELOC_PPC_EMB_RELSEC16:	ppc_reloc = R_PPC_EMB_RELSEC16;		break;
+    case BFD_RELOC_PPC_EMB_RELST_LO:	ppc_reloc = R_PPC_EMB_RELST_LO;		break;
+    case BFD_RELOC_PPC_EMB_RELST_HI:	ppc_reloc = R_PPC_EMB_RELST_HI;		break;
+    case BFD_RELOC_PPC_EMB_RELST_HA:	ppc_reloc = R_PPC_EMB_RELST_HA;		break;
+    case BFD_RELOC_PPC_EMB_BIT_FLD:	ppc_reloc = R_PPC_EMB_BIT_FLD;		break;
+    case BFD_RELOC_PPC_EMB_RELSDA:	ppc_reloc = R_PPC_EMB_RELSDA;		break;
+    case BFD_RELOC_PPC_MORPHOS_DREL:	ppc_reloc = R_PPC_MORPHOS_DREL;		break;
+    case BFD_RELOC_PPC_MORPHOS_DREL_LO:	ppc_reloc = R_PPC_MORPHOS_DREL_LO;	break;
+    case BFD_RELOC_PPC_MORPHOS_DREL_HI:	ppc_reloc = R_PPC_MORPHOS_DREL_HI;	break;
+    case BFD_RELOC_PPC_MORPHOS_DREL_HA:	ppc_reloc = R_PPC_MORPHOS_DREL_HA;	break;
+    case BFD_RELOC_VTABLE_INHERIT:	ppc_reloc = R_PPC_GNU_VTINHERIT;	break;
+    case BFD_RELOC_VTABLE_ENTRY:	ppc_reloc = R_PPC_GNU_VTENTRY;		break;
+    }
+
+  return ppc_elf_howto_table[(int) ppc_reloc];
+};
+
+/* Set the howto pointer for a PowerPC ELF reloc.  */
+
+static void
+ppc_elf_info_to_howto (abfd, cache_ptr, dst)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *cache_ptr;
+     Elf32_Internal_Rela *dst;
+{
+  if (!ppc_elf_howto_table[R_PPC_ADDR32])
+    /* Initialize howto table if needed.  */
+    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)];
+}
+
+/* Handle the R_PPC_ADDR16_HA reloc.  */
+
+static bfd_reloc_status_type
+ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section,
+			 output_bfd, error_message)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR 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;
+    }
+  else
+    {
+      reloc_entry->address += input_section->output_offset;
+      input_section->output_section->orelocation[input_section->output_section->reloc_count++]=reloc_entry;
+      return bfd_reloc_ok;
+    }
+
+  /*if (reloc_entry->address > input_section->_cooked_size)
+    return bfd_reloc_outofrange;
+
+  if (bfd_is_com_section (symbol->section))
+    relocation = 0;
+  else
+    relocation = symbol->value;
+
+  relocation += symbol->section->output_section->vma;
+  relocation += symbol->section->output_offset;
+  relocation += reloc_entry->addend;
+
+  reloc_entry->addend += (relocation & 0x8000) << 1;
+
+  return bfd_reloc_continue;*/
+}
+
+/* Fix bad default arch selected for a 32 bit input bfd when the
+   default is 64 bit.  */
+
+static boolean
+ppc_elf_object_p (abfd)
+     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 boolean
+ppc_elf_set_private_flags (abfd, 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;
+}
+
+/* Merge backend specific data from an object file to the output
+   object file when linking */
+static boolean
+ppc_elf_merge_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  flagword old_flags;
+  flagword new_flags;
+  boolean error;
+
+  /* Check if we have the same endianess */
+  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+    return false;
+
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return true;
+
+  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;
+    }
+
+  else if (new_flags == old_flags)	/* Compatible flags are ok */
+    ;
+
+  else					/* Incompatible flags */
+    {
+      /* Warn about -mrelocatable mismatch.  Allow -mrelocatable-lib to be linked
+         with either.  */
+      error = false;
+      if ((new_flags & EF_PPC_RELOCATABLE) != 0
+	  && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
+	{
+	  error = true;
+	  (*_bfd_error_handler)
+	    (_("%s: compiled with -mrelocatable and linked with modules compiled normally"),
+	     bfd_archive_filename (ibfd));
+	}
+      else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0
+	       && (old_flags & EF_PPC_RELOCATABLE) != 0)
+	{
+	  error = true;
+	  (*_bfd_error_handler)
+	    (_("%s: compiled normally and linked with modules compiled with -mrelocatable"),
+	     bfd_archive_filename (ibfd));
+	}
+
+      /* 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)
+	    (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
+	     bfd_archive_filename (ibfd), (long) new_flags, (long) old_flags);
+	}
+
+      if (error)
+	{
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
+    }
+
+  return true;
+}
+
+/* Handle a PowerPC specific section when reading an object file.  This
+   is called when elfcode.h finds a section with an unknown type.  */
+
+static boolean
+ppc_elf_section_from_shdr (abfd, hdr, name)
+     bfd *abfd;
+     Elf32_Internal_Shdr *hdr;
+     const char *name;
+{
+  asection *newsect;
+  flagword flags;
+
+  if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
+    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 boolean
+ppc_elf_fake_sections (abfd, shdr, asect)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     Elf32_Internal_Shdr *shdr;
+     asection *asect;
+{
+  if ((asect->flags & SEC_EXCLUDE) != 0)
+    shdr->sh_flags |= SHF_EXCLUDE;
+
+  if ((asect->flags & SEC_SORT_ENTRIES) != 0)
+    shdr->sh_type = SHT_ORDERED;
+
+  return true;
+}
+
+/* Create a special linker section */
+static elf_linker_section_t *
+ppc_elf_create_linker_section (abfd, info, which)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     enum elf_linker_section_enum which;
+{
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  elf_linker_section_t *lsect;
+
+  /* Record the first bfd section that needs the special section */
+  if (!dynobj)
+    dynobj = elf_hash_table (info)->dynobj = abfd;
+
+  /* If this is the first time, create the section */
+  lsect = elf_linker_section (dynobj, which);
+  if (!lsect)
+    {
+      elf_linker_section_t defaults;
+      static elf_linker_section_t zero_section;
+
+      defaults = zero_section;
+      defaults.which = which;
+      defaults.hole_written_p = false;
+      defaults.alignment = 2;
+
+      /* Both of these sections are (technically) created by the user
+	 putting data in them, so they shouldn't be marked
+	 SEC_LINKER_CREATED.
+
+	 The linker creates them so it has somewhere to attach their
+	 respective symbols. In fact, if they were empty it would
+	 be OK to leave the symbol set to 0 (or any random number), because
+	 the appropriate register should never be used.  */
+      defaults.flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+			| SEC_IN_MEMORY);
+
+      switch (which)
+	{
+	default:
+	  (*_bfd_error_handler) (_("%s: Unknown special linker type %d"),
+				 bfd_get_filename (abfd),
+				 (int) which);
+
+	  bfd_set_error (bfd_error_bad_value);
+	  return (elf_linker_section_t *) 0;
+
+	case LINKER_SECTION_SDATA:	/* .sdata/.sbss section */
+	  defaults.name		  = ".sdata";
+	  defaults.rel_name	  = ".rela.sdata";
+	  defaults.bss_name	  = ".sbss";
+	  defaults.sym_name	  = "_SDA_BASE_";
+	  defaults.sym_offset	  = 32768;
+	  break;
+
+	case LINKER_SECTION_SDATA2:	/* .sdata2/.sbss2 section */
+	  defaults.name		  = ".sdata2";
+	  defaults.rel_name	  = ".rela.sdata2";
+	  defaults.bss_name	  = ".sbss2";
+	  defaults.sym_name	  = "_SDA2_BASE_";
+	  defaults.sym_offset	  = 32768;
+	  defaults.flags	 |= SEC_READONLY;
+	  break;
+	}
+
+      lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults);
+    }
+
+  return lsect;
+}
+
+/* If we have a non-zero sized .sbss2 or .PPC.EMB.sbss0 sections, we
+   need to bump up the number of section headers.  */
+
+static int
+ppc_elf_additional_program_headers (abfd)
+     bfd *abfd;
+{
+  asection *s;
+  int ret;
+
+  ret = 0;
+
+  s = bfd_get_section_by_name (abfd, ".interp");
+  if (s != NULL)
+    ++ret;
+
+  s = bfd_get_section_by_name (abfd, ".sbss2");
+  if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0)
+    ++ret;
+
+  s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0");
+  if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0)
+    ++ret;
+
+  return ret;
+}
+
+/* Modify the segment map if needed.  */
+
+static boolean
+ppc_elf_modify_segment_map (abfd)
+     bfd *abfd ATTRIBUTE_UNUSED;
+{
+  return true;
+}
+
+/* The powerpc .got has a blrl instruction in it.  Mark it executable.  */
+
+static asection *
+ppc_elf_create_got (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  register asection *s;
+  flagword flags;
+
+  if (!_bfd_elf_create_got_section (abfd, info))
+    return NULL;
+
+  s = bfd_get_section_by_name (abfd, ".got");
+  if (s == NULL)
+    abort ();
+
+  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 NULL;
+  return s;
+}
+
+/* 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 boolean
+ppc_elf_create_dynamic_sections (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  register asection *s;
+  flagword flags;
+
+  if (!ppc_elf_create_got (abfd, info))
+    return false;
+
+  if (!_bfd_elf_create_dynamic_sections (abfd, info))
+    return false;
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+	   | SEC_LINKER_CREATED);
+
+  s = bfd_make_section (abfd, ".dynsbss");
+  if (s == NULL
+      || ! bfd_set_section_flags (abfd, s, SEC_ALLOC))
+    return false;
+
+  if (! info->shared)
+    {
+      s = bfd_make_section (abfd, ".rela.sbss");
+      if (s == NULL
+	  || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+	  || ! bfd_set_section_alignment (abfd, s, 2))
+	return false;
+    }
+
+  s = bfd_get_section_by_name (abfd, ".plt");
+  if (s == NULL)
+    abort ();
+
+  flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED;
+  return bfd_set_section_flags (abfd, s, flags);
+}
+
+/* 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 boolean
+ppc_elf_adjust_dynamic_symbol (info, h)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+{
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  asection *s;
+  unsigned int power_of_two;
+  bfd_vma plt_offset;
+
+#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.  */
+  BFD_ASSERT (dynobj != NULL
+	      && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
+		  || h->weakdef != NULL
+		  || ((h->elf_link_hash_flags
+		       & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+		      && (h->elf_link_hash_flags
+			  & ELF_LINK_HASH_REF_REGULAR) != 0
+		      && (h->elf_link_hash_flags
+			  & ELF_LINK_HASH_DEF_REGULAR) == 0)));
+
+  /* If this is a function, put it in the procedure linkage table.  We
+     will fill in the contents of the procedure linkage table later,
+     when we know the address of the .got section.  */
+  if (h->type == STT_FUNC
+      || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+    {
+      if (! elf_hash_table (info)->dynamic_sections_created
+ 	  || SYMBOL_CALLS_LOCAL (info, h)
+	  || (info->shared && h->plt.refcount <= 0))
+	{
+	  /* 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.
+
+	     2. We know for certain that a call to this symbol
+	     will go to this object.
+
+	     3. GC has rendered the entry unused.
+	     Note, however, that in an executable all references to the
+	     symbol go to the PLT, so we can't turn it off in that case.
+	     ??? The correct thing to do here is to reference count
+	     all uses of the symbol, not just those to the GOT or PLT.  */
+	  h->plt.offset = (bfd_vma) -1;
+	  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+	  return true;
+	}
+
+      /* Make sure this symbol is output as a dynamic symbol.  */
+      if (h->dynindx == -1)
+	{
+	  if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+	    return false;
+	}
+      BFD_ASSERT (h->dynindx != -1);
+
+      s = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (s != NULL);
+
+      /* If this is the first .plt entry, make room for the special
+	 first entry.  */
+      if (s->_raw_size == 0)
+	s->_raw_size += 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 = (PLT_INITIAL_ENTRY_SIZE
+		    + (PLT_SLOT_SIZE
+		       * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE)
+			  / 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 required to make function
+	 pointers compare as equal between the normal executable and
+	 the shared library.  */
+      if (! info->shared
+	  && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+	{
+	  h->root.u.def.section = s;
+	  h->root.u.def.value = plt_offset;
+	}
+
+      h->plt.offset = plt_offset;
+
+      /* Make room for this entry.  After the 8192nd entry, room
+         for two entries is allocated.  */
+      if ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
+	  >= PLT_NUM_SINGLE_ENTRIES)
+	s->_raw_size += 2 * PLT_ENTRY_SIZE;
+      else
+	s->_raw_size += PLT_ENTRY_SIZE;
+
+      /* We also need to make an entry in the .rela.plt section.  */
+      s = bfd_get_section_by_name (dynobj, ".rela.plt");
+      BFD_ASSERT (s != NULL);
+      s->_raw_size += sizeof (Elf32_External_Rela);
+
+      return true;
+    }
+  else
+    h->plt.offset = (bfd_vma) -1;
+
+  /* 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->weakdef != NULL)
+    {
+      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+		  || h->weakdef->root.type == bfd_link_hash_defweak);
+      h->root.u.def.section = h->weakdef->root.u.def.section;
+      h->root.u.def.value = h->weakdef->root.u.def.value;
+      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;
+
+  /* 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 sufficiently small, we must instead
+     allocate it in .sbss.  FIXME: It would be better to do this if and
+     only if there were actually SDAREL relocs for that symbol.  */
+
+  if (h->size <= elf_gp_size (dynobj))
+    s = bfd_get_section_by_name (dynobj, ".dynsbss");
+  else
+    s = bfd_get_section_by_name (dynobj, ".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)
+    {
+      asection *srel;
+
+      if (h->size <= elf_gp_size (dynobj))
+	srel = bfd_get_section_by_name (dynobj, ".rela.sbss");
+      else
+	srel = bfd_get_section_by_name (dynobj, ".rela.bss");
+      BFD_ASSERT (srel != NULL);
+      srel->_raw_size += sizeof (Elf32_External_Rela);
+      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+    }
+
+  /* We need to figure out the alignment required for this symbol.  I
+     have no idea how ELF linkers handle this.  */
+  power_of_two = bfd_log2 (h->size);
+  if (power_of_two > 4)
+    power_of_two = 4;
+
+  /* Apply the required alignment.  */
+  s->_raw_size = BFD_ALIGN (s->_raw_size,
+			    (bfd_size_type) (1 << power_of_two));
+  if (power_of_two > bfd_get_section_alignment (dynobj, s))
+    {
+      if (! bfd_set_section_alignment (dynobj, s, power_of_two))
+	return false;
+    }
+
+  /* Define the symbol as being at this point in the section.  */
+  h->root.u.def.section = s;
+  h->root.u.def.value = s->_raw_size;
+
+  /* Increment the section size to make room for the symbol.  */
+  s->_raw_size += h->size;
+
+  return true;
+}
+
+/* Set the sizes of the dynamic sections.  */
+
+static boolean
+ppc_elf_size_dynamic_sections (output_bfd, info)
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info;
+{
+  bfd *dynobj;
+  asection *s;
+  boolean plt;
+  boolean relocs;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_size_dynamic_sections called\n");
+#endif
+
+  dynobj = elf_hash_table (info)->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      /* Set the contents of the .interp section to the interpreter.  */
+      if (! info->shared)
+	{
+	  s = bfd_get_section_by_name (dynobj, ".interp");
+	  BFD_ASSERT (s != NULL);
+	  s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
+	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+	}
+    }
+  else
+    {
+      /* We may have created entries in the .rela.got, .rela.sdata, and
+	 .rela.sdata2 sections.  However, if we are not creating the
+	 dynamic sections, we will not actually use these entries.  Reset
+	 the size of .rela.got, et al, which will cause it to get
+	 stripped from the output file below.  */
+      static char *rela_sections[] = { ".rela.got", ".rela.sdata",
+				       ".rela.sdata2", ".rela.sbss",
+				       (char *) 0 };
+      char **p;
+
+      for (p = rela_sections; *p != (char *) 0; p++)
+	{
+	  s = bfd_get_section_by_name (dynobj, *p);
+	  if (s != NULL)
+	    s->_raw_size = 0;
+	}
+    }
+
+  /* The check_relocs and adjust_dynamic_symbol entry points have
+     determined the sizes of the various dynamic sections.  Allocate
+     memory for them.  */
+  plt = false;
+  relocs = false;
+  for (s = dynobj->sections; s != NULL; s = s->next)
+    {
+      const char *name;
+      boolean strip;
+
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
+	continue;
+
+      /* It's OK to base decisions on the section name, because none
+	 of the dynobj section names depend upon the input files.  */
+      name = bfd_get_section_name (dynobj, s);
+
+      strip = false;
+
+      if (strcmp (name, ".plt") == 0)
+	{
+	  if (s->_raw_size == 0)
+	    {
+	      /* Strip this section if we don't need it; see the
+                 comment below.  */
+	      strip = true;
+	    }
+	  else
+	    {
+	      /* Remember whether there is a PLT.  */
+	      plt = true;
+	    }
+	}
+      else if (strncmp (name, ".rela", 5) == 0)
+	{
+	  if (s->_raw_size == 0)
+	    {
+	      /* 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.  */
+	      strip = true;
+	    }
+	  else
+	    {
+	      /* 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 if (strcmp (name, ".got") != 0
+	       && strcmp (name, ".sdata") != 0
+	       && strcmp (name, ".sdata2") != 0)
+	{
+	  /* It's not one of our sections, so don't allocate space.  */
+	  continue;
+	}
+
+      if (strip)
+	{
+	  _bfd_strip_section_from_output (info, s);
+	  continue;
+	}
+
+      /* Allocate memory for the section contents.  */
+      s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
+      if (s->contents == NULL && s->_raw_size != 0)
+	return false;
+    }
+
+  if (elf_hash_table (info)->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_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
+      if (!info->shared)
+	{
+	  if (!add_dynamic_entry (DT_DEBUG, 0))
+	    return false;
+	}
+
+      if (plt)
+	{
+	  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 (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 ((info->flags & DF_TEXTREL) != 0)
+	{
+	  if (!add_dynamic_entry (DT_TEXTREL, 0))
+	    return false;
+	  info->flags |= DF_TEXTREL;
+	}
+    }
+#undef add_dynamic_entry
+
+  return true;
+}
+
+/* Look through the relocs for a section during the first phase, and
+   allocate space in the global offset table or procedure linkage
+   table.  */
+
+static boolean
+ppc_elf_check_relocs (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+  bfd *dynobj;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+  bfd_signed_vma *local_got_refcounts;
+  elf_linker_section_t *sdata;
+  elf_linker_section_t *sdata2;
+  asection *sreloc;
+  asection *sgot = NULL;
+  asection *srelgot = NULL;
+
+  if (info->relocateable)
+    return true;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_check_relocs called for section %s in %s\n",
+	   bfd_get_section_name (abfd, sec),
+	   bfd_archive_filename (abfd));
+#endif
+
+  /* Create the linker generated sections all the time so that the
+     special symbols are created.  */
+
+  if ((sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA)) == NULL)
+    {
+      sdata = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA);
+      if (!sdata)
+	return false;
+    }
+
+  if ((sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2)) == NULL)
+    {
+      sdata2 = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA2);
+      if (!sdata2)
+	return false;
+    }
+
+  dynobj = elf_hash_table (info)->dynobj;
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  sym_hashes = elf_sym_hashes (abfd);
+  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
+  if (!elf_bad_symtab (abfd))
+    sym_hashes_end -= symtab_hdr->sh_info;
+
+  sreloc = NULL;
+
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      unsigned long r_symndx;
+      struct elf_link_hash_entry *h;
+
+      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];
+
+      /* 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 && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+	{
+	  if (sgot == NULL)
+	    {
+	      if (dynobj == NULL)
+		elf_hash_table (info)->dynobj = dynobj = abfd;
+	      sgot = ppc_elf_create_got (dynobj, info);
+	      if (sgot == NULL)
+		return false;
+	    }
+	}
+
+      switch (ELF32_R_TYPE (rel->r_info))
+	{
+	/* 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 (sgot == NULL)
+	    {
+	      if (dynobj == NULL)
+		elf_hash_table (info)->dynobj = dynobj = abfd;
+	      sgot = ppc_elf_create_got (dynobj, info);
+	      if (sgot == NULL)
+		return false;
+	    }
+
+	  if (srelgot == NULL
+	      && (h != NULL || info->shared))
+	    {
+	      srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+	      if (srelgot == NULL)
+		{
+		  srelgot = bfd_make_section (dynobj, ".rela.got");
+		  if (srelgot == NULL
+		      || ! bfd_set_section_flags (dynobj, srelgot,
+						  (SEC_ALLOC
+						   | SEC_LOAD
+						   | SEC_HAS_CONTENTS
+						   | SEC_IN_MEMORY
+						   | SEC_LINKER_CREATED
+						   | SEC_READONLY))
+		      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
+		    return false;
+		}
+	    }
+
+	  if (h != NULL)
+	    {
+	      if (h->got.refcount == 0)
+		{
+		  /* Make sure this symbol is output as a dynamic symbol.  */
+		  if (h->dynindx == -1)
+		    if (!bfd_elf32_link_record_dynamic_symbol (info, h))
+		      return false;
+
+		  /* Allocate space in the .got.  */
+		  sgot->_raw_size += 4;
+		  /* Allocate relocation space.  */
+		  srelgot->_raw_size += sizeof (Elf32_External_Rela);
+		}
+	      h->got.refcount++;
+	    }
+	  else
+	    {
+	      /* This is a global offset table entry for a local symbol.  */
+	      if (local_got_refcounts == NULL)
+		{
+		  bfd_size_type size;
+
+		  size = symtab_hdr->sh_info;
+		  size *= sizeof (bfd_signed_vma);
+		  local_got_refcounts
+		    = (bfd_signed_vma *) bfd_zalloc (abfd, size);
+		  if (local_got_refcounts == NULL)
+		    return false;
+		  elf_local_got_refcounts (abfd) = local_got_refcounts;
+		}
+	      if (local_got_refcounts[r_symndx] == 0)
+		{
+		  sgot->_raw_size += 4;
+
+		  /* If we are generating a shared object, we need to
+                     output a R_PPC_RELATIVE reloc so that the
+                     dynamic linker can adjust this GOT entry.  */
+		  if (info->shared)
+		    srelgot->_raw_size += sizeof (Elf32_External_Rela);
+		}
+	      local_got_refcounts[r_symndx]++;
+	    }
+	  break;
+
+	/* Indirect .sdata relocation */
+	case R_PPC_EMB_SDAI16:
+	  if (info->shared)
+	    {
+	      ((*_bfd_error_handler)
+	       (_("%s: relocation %s cannot be used when making a shared object"),
+		bfd_archive_filename (abfd), "R_PPC_EMB_SDAI16"));
+	      return false;
+	    }
+
+	  if (srelgot == NULL && (h != NULL || info->shared))
+	    {
+	      srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+	      if (srelgot == NULL)
+		{
+		  srelgot = bfd_make_section (dynobj, ".rela.got");
+		  if (srelgot == NULL
+		      || ! bfd_set_section_flags (dynobj, srelgot,
+						  (SEC_ALLOC
+						   | SEC_LOAD
+						   | SEC_HAS_CONTENTS
+						   | SEC_IN_MEMORY
+						   | SEC_LINKER_CREATED
+						   | SEC_READONLY))
+		      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
+		    return false;
+		}
+	    }
+
+	  if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata, h, rel))
+	    return false;
+
+	  break;
+
+	/* Indirect .sdata2 relocation */
+	case R_PPC_EMB_SDA2I16:
+	  if (info->shared)
+	    {
+	      ((*_bfd_error_handler)
+	       (_("%s: relocation %s cannot be used when making a shared object"),
+		bfd_archive_filename (abfd), "R_PPC_EMB_SDA2I16"));
+	      return false;
+	    }
+
+	  if (srelgot == NULL && (h != NULL || info->shared))
+	    {
+	      srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+	      if (srelgot == NULL)
+		{
+		  srelgot = bfd_make_section (dynobj, ".rela.got");
+		  if (srelgot == NULL
+		      || ! bfd_set_section_flags (dynobj, srelgot,
+						  (SEC_ALLOC
+						   | SEC_LOAD
+						   | SEC_HAS_CONTENTS
+						   | SEC_IN_MEMORY
+						   | SEC_LINKER_CREATED
+						   | SEC_READONLY))
+		      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
+		    return false;
+		}
+	    }
+
+	  if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata2, h, rel))
+	    return false;
+
+	  break;
+
+	case R_PPC_SDAREL16:
+	case R_PPC_EMB_SDA2REL:
+	case R_PPC_EMB_SDA21:
+	  if (info->shared)
+	    {
+	      ((*_bfd_error_handler)
+	       (_("%s: relocation %s cannot be used when making a shared object"),
+		bfd_archive_filename (abfd),
+		ppc_elf_howto_table[(int) ELF32_R_TYPE (rel->r_info)]->name));
+	      return false;
+	    }
+	  break;
+
+	case R_PPC_PLT32:
+	case R_PPC_PLTREL24:
+	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 adjust_dynamic_symbol,
+             because this might be a case of linking PIC code without
+             linking in any dynamic objects, in which case we don't
+             need to generate a procedure linkage table after all.  */
+
+	  if (h == NULL)
+	    {
+	      /* It does not make sense to have a procedure linkage
+                 table entry for a local symbol.  */
+	      bfd_set_error (bfd_error_bad_value);
+	      return false;
+	    }
+
+	  /* Make sure this symbol is output as a dynamic symbol.  */
+	  if (h->dynindx == -1)
+	    {
+	      if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+		return false;
+	    }
+	  h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+	  h->plt.refcount++;
+	  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:
+	  break;
+
+	  /* This refers only to functions defined in the shared library */
+	case R_PPC_LOCAL24PC:
+	  break;
+
+	  /* This relocation describes the C++ object vtable hierarchy.
+	     Reconstruct it for later use during GC.  */
+	case R_PPC_GNU_VTINHERIT:
+	  if (!_bfd_elf32_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:
+	  if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+	    return false;
+	  break;
+
+	  /* When creating a shared object, we must copy these
+	     relocs into the output file.  We create a reloc
+	     section in dynobj and make room for the reloc.  */
+	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
+	      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+	      || SYMBOL_REFERENCES_LOCAL (info, h))
+	    break;
+	  /* fall through */
+
+	default:
+	  if (info->shared)
+	    {
+#ifdef DEBUG
+	      fprintf (stderr, "ppc_elf_check_relocs need to create relocation for %s\n",
+		       (h && h->root.root.string) ? h->root.root.string : "<unknown>");
+#endif
+	      if (sreloc == NULL)
+		{
+		  const char *name;
+
+		  name = (bfd_elf_string_from_elf_section
+			  (abfd,
+			   elf_elfheader (abfd)->e_shstrndx,
+			   elf_section_data (sec)->rel_hdr.sh_name));
+		  if (name == NULL)
+		    return false;
+
+		  BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+			      && strcmp (bfd_get_section_name (abfd, sec),
+					 name + 5) == 0);
+
+		  sreloc = bfd_get_section_by_name (dynobj, name);
+		  if (sreloc == NULL)
+		    {
+		      flagword flags;
+
+		      sreloc = bfd_make_section (dynobj, name);
+		      flags = (SEC_HAS_CONTENTS | SEC_READONLY
+			       | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+		      if ((sec->flags & SEC_ALLOC) != 0)
+			flags |= SEC_ALLOC | SEC_LOAD;
+		      if (sreloc == NULL
+			  || ! bfd_set_section_flags (dynobj, sreloc, flags)
+			  || ! bfd_set_section_alignment (dynobj, sreloc, 2))
+			return false;
+		    }
+		  if (sec->flags & SEC_READONLY)
+		    info->flags |= DF_TEXTREL;
+		}
+
+	      sreloc->_raw_size += sizeof (Elf32_External_Rela);
+
+	      /* FIXME: We should here do what the m68k and i386
+		 backends do: if the reloc is pc-relative, record it
+		 in case it turns out that the reloc is unnecessary
+		 because the symbol is forced local by versioning or
+		 we are linking with -Bdynamic.  Fortunately this
+		 case is not frequent.  */
+	    }
+
+	  break;
+	}
+    }
+
+  return true;
+}
+
+/* Return the section that should be marked against GC for a given
+   relocation.  */
+
+static asection *
+ppc_elf_gc_mark_hook (sec, info, rel, h, sym)
+     asection *sec;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     Elf_Internal_Rela *rel;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  if (h != NULL)
+    {
+      switch (ELF32_R_TYPE (rel->r_info))
+	{
+	case R_PPC_GNU_VTINHERIT:
+	case R_PPC_GNU_VTENTRY:
+	  break;
+
+	default:
+	  switch (h->root.type)
+	    {
+	    case bfd_link_hash_defined:
+	    case bfd_link_hash_defweak:
+	      return h->root.u.def.section;
+
+	    case bfd_link_hash_common:
+	      return h->root.u.c.p->section;
+
+	    default:
+	      break;
+	    }
+	}
+    }
+  else
+    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+
+  return NULL;
+}
+
+/* Update the got entry reference counts for the section being removed.  */
+
+static boolean
+ppc_elf_gc_sweep_hook (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_signed_vma *local_got_refcounts;
+  const Elf_Internal_Rela *rel, *relend;
+  unsigned long r_symndx;
+  struct elf_link_hash_entry *h;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  relend = relocs + sec->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
+    switch (ELF32_R_TYPE (rel->r_info))
+      {
+      case R_PPC_GOT16:
+      case R_PPC_GOT16_LO:
+      case R_PPC_GOT16_HI:
+      case R_PPC_GOT16_HA:
+	r_symndx = ELF32_R_SYM (rel->r_info);
+	if (r_symndx >= symtab_hdr->sh_info)
+	  {
+	    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	    if (h->got.refcount > 0)
+	      h->got.refcount--;
+	  }
+	else if (local_got_refcounts != NULL)
+	  {
+	    if (local_got_refcounts[r_symndx] > 0)
+	      local_got_refcounts[r_symndx]--;
+	  }
+        break;
+
+      case R_PPC_PLT32:
+      case R_PPC_PLTREL24:
+      case R_PPC_PLT16_LO:
+      case R_PPC_PLT16_HI:
+      case R_PPC_PLT16_HA:
+	r_symndx = ELF32_R_SYM (rel->r_info);
+	if (r_symndx >= symtab_hdr->sh_info)
+	  {
+	    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	    if (h->plt.refcount > 0)
+	      h->plt.refcount--;
+	  }
+	break;
+
+      default:
+	break;
+      }
+
+  return true;
+}
+
+/* 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 boolean
+ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     const 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->relocateable
+      && sym->st_size <= elf_gp_size (abfd)
+      && info->hash->creator->flavour == bfd_target_elf_flavour)
+    {
+      /* Common symbols less than or equal to -G nn bytes are automatically
+	 put into .sdata.  */
+      elf_linker_section_t *sdata
+	= ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA);
+
+      if (!sdata->bss_section)
+	{
+	  bfd_size_type amt;
+
+	  /* We don't go through bfd_make_section, because we don't
+             want to attach this common section to DYNOBJ.  The linker
+             will move the symbols to the appropriate output section
+             when it defines common symbols.  */
+	  amt = sizeof (asection);
+	  sdata->bss_section = (asection *) bfd_zalloc (abfd, amt);
+	  if (sdata->bss_section == NULL)
+	    return false;
+	  sdata->bss_section->name = sdata->bss_name;
+	  sdata->bss_section->flags = SEC_IS_COMMON;
+	  sdata->bss_section->output_section = sdata->bss_section;
+	  amt = sizeof (asymbol);
+	  sdata->bss_section->symbol = (asymbol *) bfd_zalloc (abfd, amt);
+	  amt = sizeof (asymbol *);
+	  sdata->bss_section->symbol_ptr_ptr =
+	    (asymbol **) bfd_zalloc (abfd, amt);
+	  if (sdata->bss_section->symbol == NULL
+	      || sdata->bss_section->symbol_ptr_ptr == NULL)
+	    return false;
+	  sdata->bss_section->symbol->name = sdata->bss_name;
+	  sdata->bss_section->symbol->flags = BSF_SECTION_SYM;
+	  sdata->bss_section->symbol->section = sdata->bss_section;
+	  *sdata->bss_section->symbol_ptr_ptr = sdata->bss_section->symbol;
+	}
+
+      *secp = sdata->bss_section;
+      *valp = sym->st_size;
+    }
+
+  return true;
+}
+
+/* Finish up dynamic symbol handling.  We set the contents of various
+   dynamic sections here.  */
+
+static boolean
+ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  bfd *dynobj;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
+	   h->root.root.string);
+#endif
+
+  dynobj = elf_hash_table (info)->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+
+  if (h->plt.offset != (bfd_vma) -1)
+    {
+      asection *splt;
+      asection *srela;
+      Elf_Internal_Rela rela;
+      bfd_vma reloc_index;
+
+#ifdef DEBUG
+      fprintf (stderr, ", plt_offset = %d", h->plt.offset);
+#endif
+
+      /* This symbol has an entry in the procedure linkage table.  Set
+         it up.  */
+
+      BFD_ASSERT (h->dynindx != -1);
+
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      srela = bfd_get_section_by_name (dynobj, ".rela.plt");
+      BFD_ASSERT (splt != NULL && srela != NULL);
+
+      /* We don't need to fill in the .plt.  The ppc dynamic linker
+	 will fill it in.  */
+
+      /* Fill in the entry in the .rela.plt section.  */
+      rela.r_offset = (splt->output_section->vma
+		       + splt->output_offset
+		       + h->plt.offset);
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
+      rela.r_addend = 0;
+
+      reloc_index = (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_SLOT_SIZE;
+      if (reloc_index > PLT_NUM_SINGLE_ENTRIES)
+	reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+				 ((Elf32_External_Rela *) srela->contents
+				  + reloc_index));
+
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+	{
+	  /* Mark the symbol as undefined, rather than as defined in
+	     the .plt section.  Leave the value alone.  */
+	  sym->st_shndx = SHN_UNDEF;
+	  /* If the symbol is weak, we do need to clear the value.
+	     Otherwise, the PLT entry would provide a definition for
+	     the symbol even if the symbol wasn't defined anywhere,
+	     and so the symbol would never be NULL.  */
+	  if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK)
+	      == 0)
+	    sym->st_value = 0;
+	}
+    }
+
+  if (h->got.offset != (bfd_vma) -1)
+    {
+      asection *sgot;
+      asection *srela;
+      Elf_Internal_Rela rela;
+
+      /* This symbol has an entry in the global offset table.  Set it
+         up.  */
+
+      sgot = bfd_get_section_by_name (dynobj, ".got");
+      srela = bfd_get_section_by_name (dynobj, ".rela.got");
+      BFD_ASSERT (sgot != NULL && srela != NULL);
+
+      rela.r_offset = (sgot->output_section->vma
+		       + sgot->output_offset
+		       + (h->got.offset &~ (bfd_vma) 1));
+
+      /* If this is a -Bsymbolic link, and the symbol is defined
+	 locally, we just want to emit a RELATIVE reloc.  The entry in
+	 the global offset table will already have been initialized in
+	 the relocate_section function.  */
+      if (info->shared
+	  && SYMBOL_REFERENCES_LOCAL (info, h))
+	{
+	  rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+	  rela.r_addend = (h->root.u.def.value
+			   + h->root.u.def.section->output_section->vma
+			   + h->root.u.def.section->output_offset);
+	}
+      else
+	{
+	  BFD_ASSERT ((h->got.offset & 1) == 0);
+	  rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_GLOB_DAT);
+	  rela.r_addend = 0;
+	}
+
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+				 ((Elf32_External_Rela *) srela->contents
+				  + srela->reloc_count));
+      ++srela->reloc_count;
+    }
+
+  if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
+    {
+      asection *s;
+      Elf_Internal_Rela rela;
+
+      /* This symbols needs a copy reloc.  Set it up.  */
+
+#ifdef DEBUG
+      fprintf (stderr, ", copy");
+#endif
+
+      BFD_ASSERT (h->dynindx != -1);
+
+      if (h->size <= elf_gp_size (dynobj))
+	s = bfd_get_section_by_name (h->root.u.def.section->owner,
+				     ".rela.sbss");
+      else
+	s = bfd_get_section_by_name (h->root.u.def.section->owner,
+				     ".rela.bss");
+      BFD_ASSERT (s != NULL);
+
+      rela.r_offset = (h->root.u.def.value
+		       + h->root.u.def.section->output_section->vma
+		       + h->root.u.def.section->output_offset);
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY);
+      rela.r_addend = 0;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+				 ((Elf32_External_Rela *) s->contents
+				  + s->reloc_count));
+      ++s->reloc_count;
+    }
+
+#ifdef DEBUG
+  fprintf (stderr, "\n");
+#endif
+
+  /* Mark some specially defined symbols as absolute.  */
+  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+      || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+    sym->st_shndx = SHN_ABS;
+
+  return true;
+}
+
+/* Finish up the dynamic sections.  */
+
+static boolean
+ppc_elf_finish_dynamic_sections (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  asection *sdyn;
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  asection *sgot = bfd_get_section_by_name (dynobj, ".got");
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n");
+#endif
+
+  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      asection *splt;
+      Elf32_External_Dyn *dyncon, *dynconend;
+
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (splt != NULL && sdyn != NULL);
+
+      dyncon = (Elf32_External_Dyn *) sdyn->contents;
+      dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
+      for (; dyncon < dynconend; dyncon++)
+	{
+	  Elf_Internal_Dyn dyn;
+	  const char *name;
+	  boolean size;
+
+	  bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+
+	  switch (dyn.d_tag)
+	    {
+	    case DT_PLTGOT:   name = ".plt";	  size = false; break;
+	    case DT_PLTRELSZ: name = ".rela.plt"; size = true;  break;
+	    case DT_JMPREL:   name = ".rela.plt"; size = false; break;
+	    default:	      name = NULL;	  size = false; break;
+	    }
+
+	  if (name != NULL)
+	    {
+	      asection *s;
+
+	      s = bfd_get_section_by_name (output_bfd, name);
+	      if (s == NULL)
+		dyn.d_un.d_val = 0;
+	      else
+		{
+		  if (! size)
+		    dyn.d_un.d_ptr = s->vma;
+		  else
+		    {
+		      if (s->_cooked_size != 0)
+			dyn.d_un.d_val = s->_cooked_size;
+		      else
+			dyn.d_un.d_val = s->_raw_size;
+		    }
+		}
+	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+	    }
+	}
+    }
+
+  /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can
+     easily find the address of the _GLOBAL_OFFSET_TABLE_.  */
+  if (sgot)
+    {
+      unsigned char *contents = sgot->contents;
+      bfd_put_32 (output_bfd, (bfd_vma) 0x4e800021 /* blrl */, contents);
+
+      if (sdyn == NULL)
+	bfd_put_32 (output_bfd, (bfd_vma) 0, contents+4);
+      else
+	bfd_put_32 (output_bfd,
+		    sdyn->output_section->vma + sdyn->output_offset,
+		    contents+4);
+
+      elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+    }
+
+  return true;
+}
+
+/* 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
+   relocateable 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 relocateable 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 boolean
+ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
+			  contents, relocs, local_syms, local_sections)
+     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		  = &elf_tdata (input_bfd)->symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
+  bfd *dynobj				  = elf_hash_table (info)->dynobj;
+  elf_linker_section_t *sdata		  = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA)  : NULL;
+  elf_linker_section_t *sdata2		  = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA2) : NULL;
+  Elf_Internal_Rela *rel		  = relocs;
+  Elf_Internal_Rela *relend		  = relocs + input_section->reloc_count;
+  asection *sreloc			  = NULL;
+  asection *splt;
+  asection *sgot;
+  bfd_vma *local_got_offsets;
+  boolean ret				  = true;
+  long insn;
+  asection *sdata_sec                     = NULL;
+  asection *sbss_sec                     = NULL;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_relocate_section called for %s section %s, %ld relocations%s\n",
+	   bfd_archive_filename (input_bfd),
+	   bfd_section_name(input_bfd, input_section),
+	   (long) input_section->reloc_count,
+	   (info->relocateable) ? " (relocatable)" : "");
+#endif
+
+  if (info->relocateable)
+    return true;
+
+  if (!ppc_elf_howto_table[R_PPC_ADDR32])
+    /* Initialize howto table if needed.  */
+    ppc_elf_howto_init ();
+
+  if (!strcmp(bfd_section_name(output_bfd, input_section), ".sdata") ||
+      !strcmp(bfd_section_name(output_bfd, input_section), ".sbss"))
+  {
+    sdata_sec = bfd_get_section_by_name(output_bfd, ".sdata");
+    if (sdata_sec)
+      sdata_sec = sdata_sec->output_section;
+    sbss_sec = bfd_get_section_by_name(output_bfd, ".sbss");
+    if (sbss_sec)
+      sbss_sec = sbss_sec->output_section;
+  }
+ 
+  local_got_offsets = elf_local_got_offsets (input_bfd);
+
+  splt = sgot = NULL;
+  if (dynobj != NULL)
+    {
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      sgot = bfd_get_section_by_name (dynobj, ".got");
+    }
+
+  for (; rel < relend; rel++)
+    {
+      enum elf_ppc_reloc_type r_type	= (enum elf_ppc_reloc_type)ELF32_R_TYPE (rel->r_info);
+      bfd_vma offset			= rel->r_offset;
+      bfd_vma addend			= rel->r_addend;
+      bfd_reloc_status_type r		= bfd_reloc_other;
+      Elf_Internal_Sym *sym		= (Elf_Internal_Sym *) 0;
+      asection *sec			= (asection *) 0;
+      struct elf_link_hash_entry *h	= (struct elf_link_hash_entry *) 0;
+      const char *sym_name		= (const char *) 0;
+      boolean copy                      = false;
+      reloc_howto_type *howto;
+      unsigned long r_symndx;
+      bfd_vma relocation;
+      int will_become_local;
+
+      /* Unknown relocation handling */
+      if ((unsigned) r_type >= (unsigned) R_PPC_max
+	  || !ppc_elf_howto_table[(int) r_type])
+	{
+	  (*_bfd_error_handler) (_("%s: unknown relocation type %d"),
+				 bfd_archive_filename (input_bfd),
+				 (int) r_type);
+
+	  bfd_set_error (bfd_error_bad_value);
+	  ret = false;
+	  continue;
+	}
+
+      howto = ppc_elf_howto_table[(int) r_type];
+      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 = "<local symbol>";
+
+	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+	  addend = rel->r_addend;
+	  /* Relocs to local symbols are always resolved.  */
+	  will_become_local = 1;
+	}
+      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;
+	  sym_name = h->root.root.string;
+
+	  /* Can this relocation be resolved immediately?  */
+	  will_become_local = SYMBOL_REFERENCES_LOCAL (info, h);
+
+	  if (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak)
+	    {
+	      sec = h->root.u.def.section;
+	      if (((r_type == R_PPC_PLT32
+		    || r_type == R_PPC_PLTREL24)
+		   && splt != NULL
+		   && h->plt.offset != (bfd_vma) -1)
+		  || (r_type == R_PPC_LOCAL24PC
+		      && sec->output_section == NULL)
+		  || ((r_type == R_PPC_GOT16
+		       || r_type == R_PPC_GOT16_LO
+		       || r_type == R_PPC_GOT16_HI
+		       || r_type == R_PPC_GOT16_HA)
+		      && elf_hash_table (info)->dynamic_sections_created
+		      && (! info->shared || ! will_become_local))
+		  || (info->shared
+ 		      && ! will_become_local
+		      && ((input_section->flags & SEC_ALLOC) != 0
+			  /* Testing SEC_DEBUGGING here may be wrong.
+                             It's here to avoid a crash when
+                             generating a shared library with DWARF
+                             debugging information.  */
+			  || ((input_section->flags & SEC_DEBUGGING) != 0
+			      && (h->elf_link_hash_flags
+				  & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
+		      && (r_type == R_PPC_ADDR32
+			  || r_type == R_PPC_ADDR24
+			  || r_type == R_PPC_ADDR16
+			  || r_type == R_PPC_ADDR16_LO
+			  || r_type == R_PPC_ADDR16_HI
+			  || r_type == R_PPC_ADDR16_HA
+			  || r_type == R_PPC_ADDR14
+			  || r_type == R_PPC_ADDR14_BRTAKEN
+			  || r_type == R_PPC_ADDR14_BRNTAKEN
+			  || r_type == R_PPC_COPY
+			  || r_type == R_PPC_GLOB_DAT
+			  || r_type == R_PPC_JMP_SLOT
+			  || r_type == R_PPC_UADDR32
+			  || r_type == R_PPC_UADDR16
+			  || r_type == R_PPC_SDAREL16
+			  || r_type == R_PPC_EMB_NADDR32
+			  || r_type == R_PPC_EMB_NADDR16
+			  || r_type == R_PPC_EMB_NADDR16_LO
+			  || r_type == R_PPC_EMB_NADDR16_HI
+			  || r_type == R_PPC_EMB_NADDR16_HA
+			  || r_type == R_PPC_EMB_SDAI16
+			  || r_type == R_PPC_EMB_SDA2I16
+			  || r_type == R_PPC_EMB_SDA2REL
+			  || r_type == R_PPC_EMB_SDA21
+			  || r_type == R_PPC_EMB_MRKREF
+			  || r_type == R_PPC_EMB_BIT_FLD
+			  || r_type == R_PPC_EMB_RELSDA
+			  || ((r_type == R_PPC_REL24
+			       || r_type == R_PPC_REL32
+			       || r_type == R_PPC_REL14
+			       || r_type == R_PPC_REL14_BRTAKEN
+			       || r_type == R_PPC_REL14_BRNTAKEN
+			       || r_type == R_PPC_RELATIVE)
+			      && strcmp (h->root.root.string,
+					 "_GLOBAL_OFFSET_TABLE_") != 0))))
+		{
+		  /* In these cases, we don't need the relocation
+                     value.  We check specially because in some
+                     obscure cases sec->output_section will be NULL.  */
+		  relocation = 0;
+		}
+	      else if (sec->output_section == NULL)
+		{
+                  (*_bfd_error_handler)
+                    (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
+                     bfd_archive_filename (input_bfd), h->root.root.string,
+                     bfd_get_section_name (input_bfd, input_section));
+		  relocation = 0;
+		}
+	      else
+		relocation = (h->root.u.def.value
+			      + sec->output_section->vma
+			      + sec->output_offset);
+	    }
+	  else if (h->root.type == bfd_link_hash_undefweak)
+	    relocation = 0;
+	  else if (info->shared
+		   && (!info->symbolic || info->allow_shlib_undefined)
+		   && !info->no_undefined
+		   && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+	    relocation = 0;
+	  else
+	    {
+	      if (! (*info->callbacks->undefined_symbol) (info,
+							 h->root.root.string,
+							 input_bfd,
+							 input_section,
+							 rel->r_offset,
+							 (!info->shared
+							  || info->no_undefined
+							  || ELF_ST_VISIBILITY (h->other))))
+		return false;
+	      relocation = 0;
+	    }
+	}
+
+      switch ((int) r_type)
+	{
+	default:
+	  (*_bfd_error_handler) (_("%s: unknown relocation type %d for symbol %s"),
+				 bfd_archive_filename (input_bfd),
+				 (int) r_type, sym_name);
+
+	  bfd_set_error (bfd_error_bad_value);
+	  ret = false;
+	  continue;
+
+	case (int) R_PPC_NONE:
+	  continue;
+
+	/* Relocations that need no special processing.  */
+	case (int) R_PPC_LOCAL24PC:
+	  /* It makes no sense to point a local relocation
+	     at a symbol not in this object.  */
+	  if (h != NULL
+	      && (h->root.type == bfd_link_hash_defined
+		  || h->root.type == bfd_link_hash_defweak)
+	      && sec->output_section == NULL)
+	    {
+	      if (! (*info->callbacks->undefined_symbol) (info,
+							  h->root.root.string,
+							  input_bfd,
+							  input_section,
+							  rel->r_offset,
+							  true))
+		return false;
+	      continue;
+	    }
+	  break;
+
+	/* Relocations that may need to be propagated if this is a shared
+           object.  */
+	case (int) R_PPC_REL24:
+	case (int) R_PPC_REL32:
+	case (int) R_PPC_REL14:
+	  /* If these relocations are not to a named symbol, they can be
+	     handled right here, no need to bother the dynamic linker.  */
+	  if (info->shared && (h == NULL
+	      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+              || SYMBOL_REFERENCES_LOCAL (info, h)))
+	    break;
+	/* fall through */
+
+	/* Relocations that always need to be propagated if this is a shared
+           object.  */
+	case (int) R_PPC_ADDR32:
+	case (int) R_PPC_ADDR24:
+	case (int) R_PPC_ADDR16:
+	case (int) R_PPC_ADDR16_LO:
+	case (int) R_PPC_ADDR16_HI:
+	case (int) R_PPC_ADDR16_HA:
+	case (int) R_PPC_ADDR14:
+	case (int) R_PPC_UADDR32:
+	case (int) R_PPC_UADDR16:
+	  if (info->shared && r_symndx != 0)
+	    {
+	      Elf_Internal_Rela outrel;
+	      int skip;
+
+#ifdef DEBUG
+	      fprintf (stderr, "ppc_elf_relocate_section need 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)
+		{
+		  const char *name;
+
+		  name = (bfd_elf_string_from_elf_section
+			  (input_bfd,
+			   elf_elfheader (input_bfd)->e_shstrndx,
+			   elf_section_data (input_section)->rel_hdr.sh_name));
+		  if (name == NULL)
+		    return false;
+
+		  BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+			      && strcmp (bfd_get_section_name (input_bfd,
+							       input_section),
+					 name + 5) == 0);
+
+		  sreloc = bfd_get_section_by_name (dynobj, name);
+		  BFD_ASSERT (sreloc != NULL);
+		}
+
+	      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);
+	      /* h->dynindx may be -1 if this symbol was marked to
+                 become local.  */
+	      else if (! will_become_local)
+		{
+		  outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+		  outrel.r_addend = rel->r_addend;
+		}
+	      else
+		{
+		  if (r_type == R_PPC_ADDR32)
+		    {
+		      outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+		      outrel.r_addend = relocation + rel->r_addend;
+		    }
+		  else
+		    {
+		      long indx;
+
+		      if (h == NULL)
+			sec = local_sections[r_symndx];
+		      else
+			{
+			  BFD_ASSERT (h->root.type == bfd_link_hash_defined
+				      || (h->root.type
+					  == bfd_link_hash_defweak));
+			  sec = h->root.u.def.section;
+			}
+		      if (sec != NULL && bfd_is_abs_section (sec))
+			indx = 0;
+		      else if (sec == NULL || sec->owner == NULL)
+			{
+			  bfd_set_error (bfd_error_bad_value);
+			  return false;
+			}
+		      else
+			{
+			  asection *osec;
+
+			  osec = sec->output_section;
+			  indx = elf_section_data (osec)->dynindx;
+			  BFD_ASSERT (indx > 0);
+#ifdef DEBUG
+			  if (indx <= 0)
+			    {
+			      printf ("indx=%d 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);
+		      outrel.r_addend = relocation + rel->r_addend;
+		    }
+		}
+
+	      bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+					 (((Elf32_External_Rela *)
+					   sreloc->contents)
+					  + sreloc->reloc_count));
+	      ++sreloc->reloc_count;
+
+	      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;
+		}
+	    }
+	  else if (r_type == R_PPC_REL24 || r_type == R_PPC_REL14)
+	    {
+	      if (sec->output_section != input_section->output_section)
+		{
+		  (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)",
+					 bfd_get_filename (input_bfd),
+					 sym_name,
+					 ppc_elf_howto_table[ (int)r_type ]->name,
+					 bfd_get_section_name (abfd, sec));
+		  bfd_set_error (bfd_error_bad_value);
+		  ret = false;
+		  continue;	 
+		}
+	      break;
+	    }
+	  else if (r_type == R_PPC_REL32)
+	    {
+	      if (sec->output_section != input_section->output_section)
+		copy = true;
+	      else
+		break;
+	    }
+	  else if (ddr_ptr && sec && r_type == R_PPC_ADDR32 && 
+		   (sec->output_section == sdata_sec ||
+		    sec->output_section == sbss_sec ||
+		    !strcmp(bfd_get_section_name(abfd, sec), "COMMON") ||
+		    !strcmp(bfd_get_section_name(abfd, sec), ".data") ||
+		    !strcmp(bfd_get_section_name(abfd, sec), ".bss")) &&
+		   (input_section->output_section == sdata_sec ||
+		    input_section->output_section == sbss_sec ||
+		    !strcmp(bfd_get_section_name(abfd, input_section), "COMMON") ||
+		    !strcmp(bfd_get_section_name(abfd, input_section), ".data") ||
+		    !strcmp(bfd_get_section_name(abfd, input_section), ".bss")))
+	    {
+	      ++ddr_count;
+	      *ddr_ptr++ = input_section->output_offset + offset;
+	      copy = true;
+	      break;
+	    }
+	  else if (sec && !bfd_is_abs_section(sec))
+	    {
+	      copy = true;
+	      break;
+	    }
+
+	  if (copy && ddr_ptr && sec &&
+	      (sec->output_section == sdata_sec ||
+	       sec->output_section == sbss_sec ||
+	       !strcmp(bfd_get_section_name(abfd, sec), "COMMON") ||
+	       !strcmp(bfd_get_section_name(abfd, sec), ".data") ||
+	       !strcmp(bfd_get_section_name(abfd, sec), ".bss")) /*&&
+	      (r_type != R_PPC_ADDR32 ||
+	       !(input_section->output_section == sdata_sec->output_section ||
+		 input_section->output_section == sbss_sec->output_section ||
+		 !strcmp(bfd_get_section_name(abfd, input_section), "COMMON") ||
+		 !strcmp(bfd_get_section_name(abfd, input_section), ".data") ||
+		 !strcmp(bfd_get_section_name(abfd, input_section), ".bss")))*/)
+	    {
+	      (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)",
+				     bfd_get_filename (input_bfd),
+				     sym_name,
+				     ppc_elf_howto_table[ (int)r_type ]->name,
+				     bfd_get_section_name (abfd, sec));
+	      bfd_set_error (bfd_error_bad_value);
+	      ret = false;
+	      continue;	    
+	    }
+
+	  /* Arithmetic adjust relocations that aren't going into a
+	     shared object.  */
+	  if (r_type == R_PPC_ADDR16_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).  */
+	      && sec != NULL)
+	    {
+	      addend += ((relocation + addend) & 0x8000) << 1;
+	    }
+	  break;
+
+	/* branch taken prediction relocations */
+	case (int) R_PPC_ADDR14_BRTAKEN:
+	case (int) R_PPC_REL14_BRTAKEN:
+	  insn = bfd_get_32 (output_bfd, contents + offset);
+	  if ((relocation - offset) & 0x8000)
+	    insn &= ~BRANCH_PREDICT_BIT;
+	  else
+	    insn |= BRANCH_PREDICT_BIT;
+	  bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
+	  break;
+
+	/* branch not taken predicition relocations */
+	case (int) R_PPC_ADDR14_BRNTAKEN:
+	case (int) R_PPC_REL14_BRNTAKEN:
+	  insn = bfd_get_32 (output_bfd, contents + offset);
+	  if ((relocation - offset) & 0x8000)
+	    insn |= BRANCH_PREDICT_BIT;
+	  else
+	    insn &= ~BRANCH_PREDICT_BIT;
+	  bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
+	  break;
+
+	/* GOT16 relocations */
+	case (int) R_PPC_GOT16:
+	case (int) R_PPC_GOT16_LO:
+	case (int) R_PPC_GOT16_HI:
+	case (int) R_PPC_GOT16_HA:
+	  /* Relocation is to the entry for this symbol in the global
+             offset table.  */
+	  BFD_ASSERT (sgot != NULL);
+
+	  if (h != NULL)
+	    {
+	      bfd_vma off;
+
+	      off = h->got.offset;
+	      BFD_ASSERT (off != (bfd_vma) -1);
+
+	      if (! elf_hash_table (info)->dynamic_sections_created
+		  || (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.  We must initialize this entry in the
+                     global offset table.  Since the offset must
+                     always be a multiple of 4, we use the least
+                     significant bit to record whether we have
+                     initialized it already.
+
+		     When doing a dynamic link, we create a .rela.got
+		     relocation entry to initialize the value.  This
+		     is done in the finish_dynamic_symbol routine.  */
+		  if ((off & 1) != 0)
+		    off &= ~1;
+		  else
+		    {
+		      bfd_put_32 (output_bfd, relocation,
+				  sgot->contents + off);
+		      h->got.offset |= 1;
+		    }
+		}
+
+	      relocation = sgot->output_offset + off - 4;
+	    }
+	  else
+	    {
+	      bfd_vma off;
+
+	      BFD_ASSERT (local_got_offsets != NULL
+			  && local_got_offsets[r_symndx] != (bfd_vma) -1);
+
+	      off = 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.  */
+	      if ((off & 1) != 0)
+		off &= ~1;
+	      else
+		{
+
+		  if (info->shared)
+		    {
+		      asection *srelgot;
+		      Elf_Internal_Rela outrel;
+
+		      /* We need to generate a R_PPC_RELATIVE reloc
+			 for the dynamic linker.  */
+		      srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+		      BFD_ASSERT (srelgot != NULL);
+
+		      outrel.r_offset = (sgot->output_section->vma
+					 + sgot->output_offset
+					 + off);
+		      outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+		      outrel.r_addend = relocation;
+		      bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+						 (((Elf32_External_Rela *)
+						   srelgot->contents)
+						  + srelgot->reloc_count));
+		      ++srelgot->reloc_count;
+		      relocation = 0;
+		    }
+
+		  bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+		  local_got_offsets[r_symndx] |= 1;
+		}
+
+	      relocation = sgot->output_offset + off - 4;
+	    }
+	  break;
+
+	/* Indirect .sdata relocation */
+	case (int) R_PPC_EMB_SDAI16:
+	  BFD_ASSERT (sdata != NULL);
+	  relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info,
+								sdata, h, relocation, rel,
+								R_PPC_RELATIVE);
+	  break;
+
+	/* Indirect .sdata2 relocation */
+	case (int) R_PPC_EMB_SDA2I16:
+	  BFD_ASSERT (sdata2 != NULL);
+	  relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info,
+								sdata2, h, relocation, rel,
+								R_PPC_RELATIVE);
+	  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 (int) R_PPC_TOC16:			/* phony GOT16 relocations */
+	  BFD_ASSERT (sec != (asection *) 0);
+	  BFD_ASSERT (bfd_is_und_section (sec)
+		      || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0
+		      || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0)
+
+	  addend -= sec->output_section->vma + sec->output_offset + 0x8000;
+	  break;
+
+	case (int) R_PPC_PLTREL24:
+	  /* Relocation is to the entry for this symbol in the
+             procedure linkage table.  */
+	  BFD_ASSERT (h != NULL);
+
+	  if (h->plt.offset == (bfd_vma) -1
+	      || splt == NULL)
+	    {
+	      /* We didn't make a PLT entry for this symbol.  This
+                 happens when statically linking PIC code, or when
+                 using -Bsymbolic.  */
+	      break;
+	    }
+
+	  relocation = (splt->output_section->vma
+			+ splt->output_offset
+			+ h->plt.offset);
+	  break;
+
+	/* relocate against _SDA_BASE_ */
+	case (int) R_PPC_SDAREL16:
+	  {
+	    const char *name;
+
+	    BFD_ASSERT (sec != (asection *) 0);
+	    name = bfd_get_section_name (abfd, sec->output_section);
+	    if (strcmp (name, ".sdata") != 0
+		&& strcmp (name, ".sbss") != 0)
+	      {
+		(*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+				       bfd_archive_filename (input_bfd),
+				       sym_name,
+				       ppc_elf_howto_table[(int) r_type]->name,
+				       name);
+	      }
+	    addend -= (sdata->sym_hash->root.u.def.value
+		       + sdata->sym_hash->root.u.def.section->output_section->vma
+		       /*+ sdata->sym_hash->root.u.def.section->output_offset*/);
+	  }
+	  break;
+
+	/* relocate against _SDA_BASE_, in large data mode */
+	case (int)R_PPC_MORPHOS_DREL:
+	case (int)R_PPC_MORPHOS_DREL_LO:
+	case (int)R_PPC_MORPHOS_DREL_HI:
+	case (int)R_PPC_MORPHOS_DREL_HA:
+	  BFD_ASSERT (sec != (asection *)0);
+	  if (strcmp (bfd_get_section_name (abfd, sec), ".sdata") != 0
+	      && strcmp (bfd_get_section_name (abfd, sec), ".data") != 0
+	      && strcmp (bfd_get_section_name (abfd, sec), ".bss") != 0
+	      && strcmp (bfd_get_section_name (abfd, sec), ".sbss") != 0
+	      && strcmp (bfd_get_section_name (abfd, sec), "COMMON") != 0)
+	    {
+	      (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)",
+				     bfd_get_filename (input_bfd),
+				     sym_name,
+				     ppc_elf_howto_table[ (int)r_type ]->name,
+				     bfd_get_section_name (abfd, sec));
+
+	      bfd_set_error (bfd_error_bad_value);
+	      ret = false;
+	      continue;
+	    }
+	  /*printf("DREL: addend = %x, sdata->val = %x, vma = %x, output_offset = %x\n",
+		 addend, sdata->sym_hash->root.u.def.value,
+		 sdata->sym_hash->root.u.def.section->output_section->vma,
+		 sdata->sym_hash->root.u.def.section->output_offset);*/
+	  addend -= (sdata->sym_hash->root.u.def.value
+		     + sdata->sym_hash->root.u.def.section->output_section->vma
+		     /*+ sdata->sym_hash->root.u.def.section->output_offset*/);
+	  if (r_type == R_PPC_MORPHOS_DREL_HA)
+	    addend += ((relocation + addend) & 0x8000) << 1;
+	  break;
+	  
+	/* relocate against _SDA2_BASE_ */
+	case (int) R_PPC_EMB_SDA2REL:
+	  {
+	    const char *name;
+
+	    BFD_ASSERT (sec != (asection *) 0);
+	    name = bfd_get_section_name (abfd, sec->output_section);
+	    if (strcmp (name, ".sdata2") != 0 && strcmp (name, ".sbss2") != 0)
+	      {
+		(*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+				       bfd_archive_filename (input_bfd),
+				       sym_name,
+				       ppc_elf_howto_table[(int) r_type]->name,
+				       name);
+
+		bfd_set_error (bfd_error_bad_value);
+		ret = false;
+		continue;
+	      }
+	    addend -= (sdata2->sym_hash->root.u.def.value
+		       + sdata2->sym_hash->root.u.def.section->output_section->vma
+		       + sdata2->sym_hash->root.u.def.section->output_offset);
+	  }
+	  break;
+
+	/* relocate against either _SDA_BASE_, _SDA2_BASE_, or 0 */
+	case (int) R_PPC_EMB_SDA21:
+	case (int) R_PPC_EMB_RELSDA:
+	  {
+	    const char *name;
+	    int reg;
+
+	    BFD_ASSERT (sec != (asection *) 0);
+	    name = bfd_get_section_name (abfd, sec->output_section);
+	    if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0)
+	      {
+		reg = 13;
+		addend -= (sdata->sym_hash->root.u.def.value
+			   + sdata->sym_hash->root.u.def.section->output_section->vma
+			   + sdata->sym_hash->root.u.def.section->output_offset);
+	      }
+
+	    else if (strcmp (name, ".sdata2") == 0
+		     || strcmp (name, ".sbss2") == 0)
+	      {
+		reg = 2;
+		addend -= (sdata2->sym_hash->root.u.def.value
+			   + sdata2->sym_hash->root.u.def.section->output_section->vma
+			   + sdata2->sym_hash->root.u.def.section->output_offset);
+	      }
+
+	    else if (strcmp (name, ".PPC.EMB.sdata0") == 0
+		     || strcmp (name, ".PPC.EMB.sbss0") == 0)
+	      {
+		reg = 0;
+	      }
+
+	    else
+	      {
+		(*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+				       bfd_archive_filename (input_bfd),
+				       sym_name,
+				       ppc_elf_howto_table[(int) r_type]->name,
+				       name);
+
+		bfd_set_error (bfd_error_bad_value);
+		ret = false;
+		continue;
+	      }
+
+	    if (r_type == R_PPC_EMB_SDA21)
+	      {			/* fill in register field */
+		insn = bfd_get_32 (output_bfd, contents + offset);
+		insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
+		bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
+	      }
+	  }
+	  break;
+
+	/* Relocate against the beginning of the section */
+	case (int) R_PPC_SECTOFF:
+	case (int) R_PPC_SECTOFF_LO:
+	case (int) R_PPC_SECTOFF_HI:
+	  BFD_ASSERT (sec != (asection *) 0);
+	  addend -= sec->output_section->vma;
+	  break;
+
+	case (int) R_PPC_SECTOFF_HA:
+	  BFD_ASSERT (sec != (asection *) 0);
+	  addend -= sec->output_section->vma;
+	  addend += ((relocation + addend) & 0x8000) << 1;
+	  break;
+
+	/* Negative relocations */
+	case (int) R_PPC_EMB_NADDR32:
+	case (int) R_PPC_EMB_NADDR16:
+	case (int) R_PPC_EMB_NADDR16_LO:
+	case (int) R_PPC_EMB_NADDR16_HI:
+	  addend -= 2 * relocation;
+	  break;
+
+	case (int) R_PPC_EMB_NADDR16_HA:
+	  addend -= 2 * relocation;
+	  addend += ((relocation + addend) & 0x8000) << 1;
+	  break;
+
+	/* NOP relocation that prevents garbage collecting linkers from omitting a
+	   reference.  */
+	case (int) R_PPC_EMB_MRKREF:
+	  continue;
+
+	case (int) R_PPC_COPY:
+	case (int) R_PPC_GLOB_DAT:
+	case (int) R_PPC_JMP_SLOT:
+	case (int) R_PPC_RELATIVE:
+	case (int) R_PPC_PLT32:
+	case (int) R_PPC_PLTREL32:
+	case (int) R_PPC_PLT16_LO:
+	case (int) R_PPC_PLT16_HI:
+	case (int) R_PPC_PLT16_HA:
+	case (int) R_PPC_EMB_RELSEC16:
+	case (int) R_PPC_EMB_RELST_LO:
+	case (int) R_PPC_EMB_RELST_HI:
+	case (int) R_PPC_EMB_RELST_HA:
+	case (int) R_PPC_EMB_BIT_FLD:
+	  (*_bfd_error_handler) (_("%s: Relocation %s is not yet supported for symbol %s."),
+				 bfd_archive_filename (input_bfd),
+				 ppc_elf_howto_table[(int) r_type]->name,
+				 sym_name);
+
+	  bfd_set_error (bfd_error_invalid_operation);
+	  ret = false;
+	  continue;
+
+	case (int) R_PPC_GNU_VTINHERIT:
+	case (int) R_PPC_GNU_VTENTRY:
+	  /* These are no-ops in the end.  */
+	  continue;
+	}
+
+#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) offset,
+	       (long) addend);
+#endif
+      if (copy) 
+	{
+	  Elf_Internal_Rela outrel;
+
+	  if (sec == NULL) /* Don't know if it is possible... */ 
+	    abort(); 
+
+	  /*printf("copying reloc %d, addend=%x, rel=%x, indx=%d, offset=%x, sec_vma=%x\n",
+		 r_type,addend,relocation,sec->output_section->target_index,
+		 sec->output_offset,sec->output_section->vma);*/
+
+	  outrel.r_info = ELF32_R_INFO(sec->output_section->target_index, r_type);
+	  outrel.r_addend = relocation + addend - sec->output_section->vma;
+	  outrel.r_offset = input_section->output_offset + offset;
+
+ 	  bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+				     (((Elf32_External_Rela *)
+				       elf_section_data(input_section->output_section)->
+				       rel_hdr.contents)
+				      + input_section->output_section->reloc_count));
+	  ++input_section->output_section->reloc_count;
+	}
+      else
+	{
+	  /*printf("applying reloc %d, sym=%s addend=%x, rel=%x, indx=%d, offset=%x, sec_vma=%x\n",
+		 r_type,sym_name,addend,relocation,sec->output_section->target_index,
+		 sec->output_offset,sec->output_section->vma);*/
+
+      r = _bfd_final_link_relocate (howto,
+				    input_bfd,
+				    input_section,
+				    contents,
+				    offset,
+				    relocation,
+				    addend);
+
+      if (r == bfd_reloc_ok)
+	;
+      else if (r == bfd_reloc_overflow)
+	{
+	  const char *name;
+
+	  if (h != NULL)
+	    {
+	      if (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;
+		}
+
+	      name = h->root.root.string;
+	    }
+	  else
+	    {
+	      name = bfd_elf_string_from_elf_section (input_bfd,
+						      symtab_hdr->sh_link,
+						      sym->st_name);
+	      if (name == NULL)
+		continue;
+	      if (*name == '\0')
+		name = bfd_section_name (input_bfd, sec);
+	    }
+
+	  if (! (*info->callbacks->reloc_overflow) (info,
+						   name,
+						   howto->name,
+						   (bfd_vma) 0,
+						   input_bfd,
+						   input_section,
+						   offset))
+	    return false;
+	}
+      else
+	ret = false;
+    }
+    }
+
+#ifdef DEBUG
+  fprintf (stderr, "\n");
+#endif
+
+  return ret;
+}
+
+static enum elf_reloc_type_class
+ppc_elf_reloc_type_class (rela)
+     const Elf_Internal_Rela *rela;
+{
+  switch ((int) 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;
+    }
+}
+
+/* Support for core dump NOTE sections */
+static boolean
+ppc_elf_grok_prstatus (abfd, note)
+     bfd *abfd;
+     Elf_Internal_Note *note;
+{
+  int offset;
+  unsigned int raw_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_pid = bfd_get_32 (abfd, note->descdata + 24);
+
+	/* pr_reg */
+	offset = 72;
+	raw_size = 192;
+
+	break;
+    }
+
+  /* Make a ".reg/999" section.  */
+  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+					  raw_size, note->descpos + offset);
+}
+
+static boolean
+ppc_elf_grok_psinfo (abfd, note)
+     bfd *abfd;
+     Elf_Internal_Note *note;
+{
+  switch (note->descsz)
+    {
+      default:
+	return false;
+
+      case 128:		/* Linux/PPC elf_prpsinfo */
+	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;
+}
+
+/* Special MorphOS final link routine.  */
+/* This is almost the same as the elf one, except for the hanling of relocations */
+
+/* A structure we use to avoid passing large numbers of arguments.  */
+
+struct elf_final_link_info
+{
+  /* General link information.  */
+  struct bfd_link_info *info;
+  /* Output BFD.  */
+  bfd *output_bfd;
+  /* Symbol string table.  */
+  struct bfd_strtab_hash *symstrtab;
+  /* .dynsym section.  */
+  asection *dynsym_sec;
+  /* .hash section.  */
+  asection *hash_sec;
+  /* symbol version section (.gnu.version).  */
+  asection *symver_sec;
+  /* first SHF_TLS section (if any).  */
+  asection *first_tls_sec;
+  /* Buffer large enough to hold contents of any section.  */
+  bfd_byte *contents;
+  /* Buffer large enough to hold external relocs of any section.  */
+  PTR external_relocs;
+  /* Buffer large enough to hold internal relocs of any section.  */
+  Elf_Internal_Rela *internal_relocs;
+  /* Buffer large enough to hold external local symbols of any input
+     BFD.  */
+  Elf_External_Sym *external_syms;
+  /* And a buffer for symbol section indices.  */
+  Elf_External_Sym_Shndx *locsym_shndx;
+  /* Buffer large enough to hold internal local symbols of any input
+     BFD.  */
+  Elf_Internal_Sym *internal_syms;
+  /* Array large enough to hold a symbol index for each local symbol
+     of any input BFD.  */
+  long *indices;
+  /* Array large enough to hold a section pointer for each local
+     symbol of any input BFD.  */
+  asection **sections;
+  /* Buffer to hold swapped out symbols.  */
+  Elf_External_Sym *symbuf;
+  /* And one for symbol section indices.  */
+  Elf_External_Sym_Shndx *symshndxbuf;
+  /* Number of swapped out symbols in buffer.  */
+  size_t symbuf_count;
+  /* Number of symbols which fit in symbuf.  */
+  size_t symbuf_size;
+};
+
+static boolean elf_link_output_sym
+  PARAMS ((struct elf_final_link_info *, const char *,
+	   Elf_Internal_Sym *, asection *));
+static boolean elf_link_flush_output_syms
+  PARAMS ((struct elf_final_link_info *));
+static boolean elf_link_output_extsym
+  PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_link_sec_merge_syms
+  PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_link_check_versioned_symbol
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static boolean elf_link_input_bfd
+  PARAMS ((struct elf_final_link_info *, bfd *));
+static boolean elf_reloc_link_order
+  PARAMS ((bfd *, struct bfd_link_info *, asection *,
+	   struct bfd_link_order *));
+
+static boolean elf_section_ignore_discarded_relocs
+  PARAMS ((asection *));
+
+/* This struct is used to pass information to elf_link_output_extsym.  */
+
+struct elf_outext_info
+{
+  boolean failed;
+  boolean localsyms;
+  struct elf_final_link_info *finfo;
+};
+
+/* Compute the size of, and allocate space for, REL_HDR which is the
+   section header for a section containing relocations for O.  */
+
+static boolean
+elf_link_size_reloc_section (abfd, rel_hdr, o)
+     bfd *abfd;
+     Elf_Internal_Shdr *rel_hdr;
+     asection *o;
+{
+  bfd_size_type reloc_count;
+  bfd_size_type num_rel_hashes;
+
+  /* Figure out how many relocations there will be.  */
+  if (rel_hdr == &elf_section_data (o)->rel_hdr)
+    reloc_count = elf_section_data (o)->rel_count;
+  else
+    reloc_count = elf_section_data (o)->rel_count2;
+
+  num_rel_hashes = o->reloc_count;
+  if (num_rel_hashes < reloc_count)
+    num_rel_hashes = reloc_count;
+
+  /* That allows us to calculate the size of the section.  */
+  rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count;
+
+  /* The contents field must last into write_object_contents, so we
+     allocate it with bfd_alloc rather than malloc.  Also since we
+     cannot be sure that the contents will actually be filled in,
+     we zero the allocated space.  */
+  rel_hdr->contents = (PTR) bfd_zalloc (abfd, rel_hdr->sh_size);
+  if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
+    return false;
+
+  /* We only allocate one set of hash entries, so we only do it the
+     first time we are called.  */
+  if (elf_section_data (o)->rel_hashes == NULL
+      && num_rel_hashes)
+    {
+      struct elf_link_hash_entry **p;
+
+      p = ((struct elf_link_hash_entry **)
+	   bfd_zmalloc (num_rel_hashes
+			* sizeof (struct elf_link_hash_entry *)));
+      if (p == NULL)
+	return false;
+
+      elf_section_data (o)->rel_hashes = p;
+    }
+
+  return true;
+}
+
+/* When performing a relocateable link, the input relocations are
+   preserved.  But, if they reference global symbols, the indices
+   referenced must be updated.  Update all the relocations in
+   REL_HDR (there are COUNT of them), using the data in REL_HASH.  */
+
+static void
+elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
+     bfd *abfd;
+     Elf_Internal_Shdr *rel_hdr;
+     unsigned int count;
+     struct elf_link_hash_entry **rel_hash;
+{
+  unsigned int i;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  Elf_Internal_Rel *irel;
+  Elf_Internal_Rela *irela;
+  bfd_size_type amt = sizeof (Elf_Internal_Rel) * bed->s->int_rels_per_ext_rel;
+
+  irel = (Elf_Internal_Rel *) bfd_zmalloc (amt);
+  if (irel == NULL)
+    {
+      (*_bfd_error_handler) (_("Error: out of memory"));
+      abort ();
+    }
+
+  amt = sizeof (Elf_Internal_Rela) * bed->s->int_rels_per_ext_rel;
+  irela = (Elf_Internal_Rela *) bfd_zmalloc (amt);
+  if (irela == NULL)
+    {
+      (*_bfd_error_handler) (_("Error: out of memory"));
+      abort ();
+    }
+
+  for (i = 0; i < count; i++, rel_hash++)
+    {
+      if (*rel_hash == NULL)
+	continue;
+
+      BFD_ASSERT ((*rel_hash)->indx >= 0);
+
+      if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+	{
+	  Elf_External_Rel *erel;
+	  unsigned int j;
+
+	  erel = (Elf_External_Rel *) rel_hdr->contents + i;
+	  if (bed->s->swap_reloc_in)
+	    (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, irel);
+	  else
+	    elf_swap_reloc_in (abfd, erel, irel);
+
+	  for (j = 0; j < bed->s->int_rels_per_ext_rel; j++)
+	    irel[j].r_info = ELF_R_INFO ((*rel_hash)->indx,
+					 ELF_R_TYPE (irel[j].r_info));
+
+	  if (bed->s->swap_reloc_out)
+	    (*bed->s->swap_reloc_out) (abfd, irel, (bfd_byte *) erel);
+	  else
+	    elf_swap_reloc_out (abfd, irel, erel);
+	}
+      else
+	{
+	  Elf_External_Rela *erela;
+	  unsigned int j;
+
+	  BFD_ASSERT (rel_hdr->sh_entsize
+		      == sizeof (Elf_External_Rela));
+
+	  erela = (Elf_External_Rela *) rel_hdr->contents + i;
+	  if (bed->s->swap_reloca_in)
+	    (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, irela);
+	  else
+	    elf_swap_reloca_in (abfd, erela, irela);
+
+	  for (j = 0; j < bed->s->int_rels_per_ext_rel; j++)
+	    irela[j].r_info = ELF_R_INFO ((*rel_hash)->indx,
+					  ELF_R_TYPE (irela[j].r_info));
+
+	  if (bed->s->swap_reloca_out)
+	    (*bed->s->swap_reloca_out) (abfd, irela, (bfd_byte *) erela);
+	  else
+	    elf_swap_reloca_out (abfd, irela, erela);
+	}
+    }
+
+  free (irel);
+  free (irela);
+}
+
+struct elf_link_sort_rela
+{
+  bfd_vma offset;
+  enum elf_reloc_type_class type;
+  union
+  {
+    Elf_Internal_Rel rel;
+    Elf_Internal_Rela rela;
+  } u;
+};
+
+static int
+elf_link_sort_cmp1 (A, B)
+     const PTR A;
+     const PTR B;
+{
+  struct elf_link_sort_rela *a = (struct elf_link_sort_rela *) A;
+  struct elf_link_sort_rela *b = (struct elf_link_sort_rela *) B;
+  int relativea, relativeb;
+
+  relativea = a->type == reloc_class_relative;
+  relativeb = b->type == reloc_class_relative;
+
+  if (relativea < relativeb)
+    return 1;
+  if (relativea > relativeb)
+    return -1;
+  if (ELF_R_SYM (a->u.rel.r_info) < ELF_R_SYM (b->u.rel.r_info))
+    return -1;
+  if (ELF_R_SYM (a->u.rel.r_info) > ELF_R_SYM (b->u.rel.r_info))
+    return 1;
+  if (a->u.rel.r_offset < b->u.rel.r_offset)
+    return -1;
+  if (a->u.rel.r_offset > b->u.rel.r_offset)
+    return 1;
+  return 0;
+}
+
+static int
+elf_link_sort_cmp2 (A, B)
+     const PTR A;
+     const PTR B;
+{
+  struct elf_link_sort_rela *a = (struct elf_link_sort_rela *) A;
+  struct elf_link_sort_rela *b = (struct elf_link_sort_rela *) B;
+  int copya, copyb;
+
+  if (a->offset < b->offset)
+    return -1;
+  if (a->offset > b->offset)
+    return 1;
+  copya = (a->type == reloc_class_copy) * 2 + (a->type == reloc_class_plt);
+  copyb = (b->type == reloc_class_copy) * 2 + (b->type == reloc_class_plt);
+  if (copya < copyb)
+    return -1;
+  if (copya > copyb)
+    return 1;
+  if (a->u.rel.r_offset < b->u.rel.r_offset)
+    return -1;
+  if (a->u.rel.r_offset > b->u.rel.r_offset)
+    return 1;
+  return 0;
+}
+
+static size_t
+elf_link_sort_relocs (abfd, info, psec)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection **psec;
+{
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  asection *reldyn, *o;
+  boolean rel = false;
+  bfd_size_type count, size;
+  size_t i, j, ret;
+  struct elf_link_sort_rela *rela;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+  reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
+  if (reldyn == NULL || reldyn->_raw_size == 0)
+    {
+      reldyn = bfd_get_section_by_name (abfd, ".rel.dyn");
+      if (reldyn == NULL || reldyn->_raw_size == 0)
+	return 0;
+      rel = true;
+      count = reldyn->_raw_size / sizeof (Elf_External_Rel);
+    }
+  else
+    count = reldyn->_raw_size / sizeof (Elf_External_Rela);
+
+  size = 0;
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+	== (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+	&& o->output_section == reldyn)
+      size += o->_raw_size;
+
+  if (size != reldyn->_raw_size)
+    return 0;
+
+  rela = (struct elf_link_sort_rela *) bfd_zmalloc (sizeof (*rela) * count);
+  if (rela == NULL)
+    {
+      (*info->callbacks->warning)
+	(info, _("Not enough memory to sort relocations"), 0, abfd, 0,
+	 (bfd_vma) 0);
+      return 0;
+    }
+
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+	== (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+	&& o->output_section == reldyn)
+      {
+	if (rel)
+	  {
+	    Elf_External_Rel *erel, *erelend;
+	    struct elf_link_sort_rela *s;
+
+	    erel = (Elf_External_Rel *) o->contents;
+	    erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
+	    s = rela + o->output_offset / sizeof (Elf_External_Rel);
+	    for (; erel < erelend; erel++, s++)
+	      {
+		if (bed->s->swap_reloc_in)
+		  (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &s->u.rel);
+		else
+		  elf_swap_reloc_in (abfd, erel, &s->u.rel);
+
+		s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+	      }
+	  }
+	else
+	  {
+	    Elf_External_Rela *erela, *erelaend;
+	    struct elf_link_sort_rela *s;
+
+	    erela = (Elf_External_Rela *) o->contents;
+	    erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
+	    s = rela + o->output_offset / sizeof (Elf_External_Rela);
+	    for (; erela < erelaend; erela++, s++)
+	      {
+		if (bed->s->swap_reloca_in)
+		  (*bed->s->swap_reloca_in) (dynobj, (bfd_byte *) erela,
+					     &s->u.rela);
+		else
+		  elf_swap_reloca_in (dynobj, erela, &s->u.rela);
+
+		s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+	      }
+	  }
+      }
+
+  qsort (rela, (size_t) count, sizeof (*rela), elf_link_sort_cmp1);
+  for (ret = 0; ret < count && rela[ret].type == reloc_class_relative; ret++)
+    ;
+  for (i = ret, j = ret; i < count; i++)
+    {
+      if (ELF_R_SYM (rela[i].u.rel.r_info) != ELF_R_SYM (rela[j].u.rel.r_info))
+	j = i;
+      rela[i].offset = rela[j].u.rel.r_offset;
+    }
+  qsort (rela + ret, (size_t) count - ret, sizeof (*rela), elf_link_sort_cmp2);
+
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+	== (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+	&& o->output_section == reldyn)
+      {
+	if (rel)
+	  {
+	    Elf_External_Rel *erel, *erelend;
+	    struct elf_link_sort_rela *s;
+
+	    erel = (Elf_External_Rel *) o->contents;
+	    erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
+	    s = rela + o->output_offset / sizeof (Elf_External_Rel);
+	    for (; erel < erelend; erel++, s++)
+	      {
+		if (bed->s->swap_reloc_out)
+		  (*bed->s->swap_reloc_out) (abfd, &s->u.rel,
+					     (bfd_byte *) erel);
+		else
+		  elf_swap_reloc_out (abfd, &s->u.rel, erel);
+	      }
+	  }
+	else
+	  {
+	    Elf_External_Rela *erela, *erelaend;
+	    struct elf_link_sort_rela *s;
+
+	    erela = (Elf_External_Rela *) o->contents;
+	    erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
+	    s = rela + o->output_offset / sizeof (Elf_External_Rela);
+	    for (; erela < erelaend; erela++, s++)
+	      {
+		if (bed->s->swap_reloca_out)
+		  (*bed->s->swap_reloca_out) (dynobj, &s->u.rela,
+					      (bfd_byte *) erela);
+		else
+		  elf_swap_reloca_out (dynobj, &s->u.rela, erela);
+	      }
+	  }
+      }
+
+  free (rela);
+  *psec = reldyn;
+  return ret;
+}
+
+/* Do the final step of an ELF link.  */
+
+boolean
+ppc_elf_final_link (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  boolean dynamic;
+  boolean emit_relocs;
+  bfd *dynobj;
+  struct elf_final_link_info finfo;
+  register asection *o;
+  register struct bfd_link_order *p;
+  register bfd *sub;
+  bfd_size_type max_contents_size;
+  bfd_size_type max_external_reloc_size;
+  bfd_size_type max_internal_reloc_count;
+  bfd_size_type max_sym_count;
+  bfd_size_type max_sym_shndx_count;
+  bfd_size_type max_datadata_reloc_count;
+  file_ptr off;
+  Elf_Internal_Sym elfsym;
+  unsigned int i;
+  Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *symstrtab_hdr;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct elf_outext_info eoinfo;
+  boolean merged;
+  size_t relativecount = 0;
+  asection *reldyn = 0;
+  bfd_size_type amt;
+  asection *ddr_sec;
+  asection *sdata_sec = NULL;
+  asection *sbss_sec = NULL;
+
+  if (! is_elf_hash_table (info))
+    return false;
+
+  if (info->shared)
+    abfd->flags |= DYNAMIC;
+
+  bfd_set_start_address(abfd, 0);
+
+  dynamic = elf_hash_table (info)->dynamic_sections_created;
+  dynobj = elf_hash_table (info)->dynobj;
+
+  emit_relocs = (info->relocateable
+		 || info->emitrelocations
+		 || bed->elf_backend_emit_relocs);
+
+  finfo.info = info;
+  finfo.output_bfd = abfd;
+  finfo.symstrtab = elf_stringtab_init ();
+  if (finfo.symstrtab == NULL)
+    return false;
+
+  if (! dynamic)
+    {
+      finfo.dynsym_sec = NULL;
+      finfo.hash_sec = NULL;
+      finfo.symver_sec = NULL;
+    }
+  else
+    {
+      finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym");
+      finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash");
+      BFD_ASSERT (finfo.dynsym_sec != NULL && finfo.hash_sec != NULL);
+      finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version");
+      /* Note that it is OK if symver_sec is NULL.  */
+    }
+
+  finfo.contents = NULL;
+  finfo.external_relocs = NULL;
+  finfo.internal_relocs = NULL;
+  finfo.external_syms = NULL;
+  finfo.locsym_shndx = NULL;
+  finfo.internal_syms = NULL;
+  finfo.indices = NULL;
+  finfo.sections = NULL;
+  finfo.symbuf = NULL;
+  finfo.symshndxbuf = NULL;
+  finfo.symbuf_count = 0;
+  finfo.first_tls_sec = NULL;
+  for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+    if ((o->flags & SEC_THREAD_LOCAL) != 0
+	&& (o->flags & SEC_LOAD) != 0)
+      {
+	finfo.first_tls_sec = o;
+	break;
+      }
+
+  ddr_sec = bfd_get_section_by_name(abfd, "ddrelocs");
+  
+  /* Count up the number of relocations we will output for each output
+     section, so that we know the sizes of the reloc sections.  We
+     also figure out some maximum sizes.  */
+  max_contents_size = 0;
+  max_external_reloc_size = 0;
+  max_internal_reloc_count = 0;
+  max_sym_count = 0;
+  max_sym_shndx_count = 0;
+  max_datadata_reloc_count = 0;
+  merged = false;
+  for (o = abfd->sections; o != (asection *) NULL; o = o->next)
+    {
+      o->reloc_count = 0;
+
+      for (p = o->link_order_head; p != NULL; p = p->next)
+	{
+	  if (p->type == bfd_section_reloc_link_order
+	      || p->type == bfd_symbol_reloc_link_order)
+	    ++o->reloc_count;
+	  else if (p->type == bfd_indirect_link_order)
+	    {
+	      asection *sec;
+
+	      sec = p->u.indirect.section;
+
+	      /* Mark all sections which are to be included in the
+		 link.  This will normally be every section.  We need
+		 to do this so that we can identify any sections which
+		 the linker has decided to not include.  */
+	      sec->linker_mark = true;
+
+	      if (sec->flags & SEC_MERGE)
+		merged = true;
+
+	      /* Maximum number of relocations */
+	      if (1 || info->relocateable || info->emitrelocations)
+		o->reloc_count += sec->reloc_count;
+	      else if (bed->elf_backend_count_relocs)
+		{
+		  Elf_Internal_Rela * relocs;
+
+		  relocs = (NAME(_bfd_elf,link_read_relocs)
+			    (abfd, sec, (PTR) NULL,
+			     (Elf_Internal_Rela *) NULL, info->keep_memory));
+
+		  o->reloc_count
+		    += (*bed->elf_backend_count_relocs) (sec, relocs);
+
+		  if (elf_section_data (o)->relocs != relocs)
+		    free (relocs);
+		}
+
+	      if (sec->_raw_size > max_contents_size)
+		max_contents_size = sec->_raw_size;
+	      if (sec->_cooked_size > max_contents_size)
+		max_contents_size = sec->_cooked_size;
+
+	      /* We are interested in just local symbols, not all
+		 symbols.  */
+	      if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour
+		  && (sec->owner->flags & DYNAMIC) == 0)
+		{
+		  size_t sym_count;
+
+		  if (elf_bad_symtab (sec->owner))
+		    sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size
+				 / sizeof (Elf_External_Sym));
+		  else
+		    sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info;
+
+		  if (sym_count > max_sym_count)
+		    max_sym_count = sym_count;
+
+		  if (sym_count > max_sym_shndx_count
+		      && elf_symtab_shndx (sec->owner) != 0)
+		    max_sym_shndx_count = sym_count;
+
+		  if ((sec->flags & SEC_RELOC) != 0)
+		    {
+		      size_t ext_size;
+
+		      ext_size = elf_section_data (sec)->rel_hdr.sh_size;
+		      if (ext_size > max_external_reloc_size)
+			max_external_reloc_size = ext_size;
+		      if (sec->reloc_count > max_internal_reloc_count)
+			max_internal_reloc_count = sec->reloc_count;
+		    }
+		}
+	    }
+	}
+
+      if (!strcmp(bfd_section_name(abfd, o), ".sdata"))
+	sdata_sec = o;
+      else if(!strcmp(bfd_section_name(abfd, o), ".sbss"))
+	sbss_sec = o;
+      else
+	bfd_set_section_vma(abfd, o, 0);
+
+      if (o->reloc_count > 0)
+        {
+	  o->flags |= SEC_RELOC;
+	  if (o == sdata_sec || o == sbss_sec)
+	    max_datadata_reloc_count += o->reloc_count;
+	}
+      else
+	{
+	  /* Explicitly clear the SEC_RELOC flag.  The linker tends to
+	     set it (this is probably a bug) and if it is set
+	     assign_section_numbers will create a reloc section.  */
+	  o->flags &=~ SEC_RELOC;
+	}
+
+      /* If the SEC_ALLOC flag is not set, force the section VMA to
+	 zero.  This is done in elf_fake_sections as well, but forcing
+	 the VMA to 0 here will ensure that relocs against these
+	 sections are handled correctly.  */
+      if ((o->flags & SEC_ALLOC) == 0
+	  && ! o->user_set_vma)
+	o->vma = 0;
+    }
+
+  if (sdata_sec)
+    {
+      if (sbss_sec)
+	bfd_set_section_vma(abfd, sbss_sec, sbss_sec->vma - sdata_sec->vma);
+      bfd_set_section_vma(abfd, sdata_sec, 0);
+    }
+  
+  if (! info->relocateable && merged)
+    elf_link_hash_traverse (elf_hash_table (info),
+			    elf_link_sec_merge_syms, (PTR) abfd);
+
+  /* Figure out the file positions for everything but the symbol table
+     and the relocs.  We set symcount to force assign_section_numbers
+     to create a symbol table.  */
+  bfd_get_symcount (abfd) = 1;
+  BFD_ASSERT (! abfd->output_has_begun);
+  if (! _bfd_elf_compute_section_file_positions (abfd, info))
+    goto error_return;
+
+  /* Figure out how many relocations we will have in each section.
+     Just using RELOC_COUNT isn't good enough since that doesn't
+     maintain a separate value for REL vs. RELA relocations.  */
+  if (emit_relocs)
+    for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+      for (o = sub->sections; o != NULL; o = o->next)
+	{
+	  asection *output_section;
+
+	  if (! o->linker_mark)
+	    {
+	      /* This section was omitted from the link.  */
+	      continue;
+	    }
+
+	  output_section = o->output_section;
+
+	  if (output_section != NULL
+	      && (o->flags & SEC_RELOC) != 0)
+	    {
+	      struct bfd_elf_section_data *esdi
+		= elf_section_data (o);
+	      struct bfd_elf_section_data *esdo
+		= elf_section_data (output_section);
+	      unsigned int *rel_count;
+	      unsigned int *rel_count2;
+	      bfd_size_type entsize;
+	      bfd_size_type entsize2;
+
+	      /* We must be careful to add the relocations from the
+		 input section to the right output count.  */
+	      entsize = esdi->rel_hdr.sh_entsize;
+	      entsize2 = esdi->rel_hdr2 ? esdi->rel_hdr2->sh_entsize : 0;
+	      BFD_ASSERT ((entsize == sizeof (Elf_External_Rel)
+			   || entsize == sizeof (Elf_External_Rela))
+			  && entsize2 != entsize
+			  && (entsize2 == 0
+			      || entsize2 == sizeof (Elf_External_Rel)
+			      || entsize2 == sizeof (Elf_External_Rela)));
+	      if (entsize == esdo->rel_hdr.sh_entsize)
+		{
+		  rel_count = &esdo->rel_count;
+		  rel_count2 = &esdo->rel_count2;
+		}
+	      else
+		{
+		  rel_count = &esdo->rel_count2;
+		  rel_count2 = &esdo->rel_count;
+		}
+
+	      *rel_count += NUM_SHDR_ENTRIES (& esdi->rel_hdr);
+	      if (esdi->rel_hdr2)
+		*rel_count2 += NUM_SHDR_ENTRIES (esdi->rel_hdr2);
+	      output_section->flags |= SEC_RELOC;
+	    }
+	}
+
+  /* That created the reloc sections.  Set their sizes, and assign
+     them file positions, and allocate some buffers.  */
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if ((o->flags & SEC_RELOC) != 0)
+	{
+	  if (!elf_link_size_reloc_section (abfd,
+					    &elf_section_data (o)->rel_hdr,
+					    o))
+	    goto error_return;
+
+	  if (elf_section_data (o)->rel_hdr2
+	      && !elf_link_size_reloc_section (abfd,
+					       elf_section_data (o)->rel_hdr2,
+					       o))
+	    goto error_return;
+	}
+
+      /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
+	 to count upwards while actually outputting the relocations.  */
+      elf_section_data (o)->rel_count = 0;
+      elf_section_data (o)->rel_count2 = 0;
+    }
+
+  /* We have now assigned file positions for all the sections except
+     relocations, .symtab, and .strtab.  We start the .symtab section
+     at the current file position, and write directly to it.  We build
+     the .strtab section in memory.  */
+  bfd_get_symcount (abfd) = 0;
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  /* sh_name is set in prep_headers.  */
+  symtab_hdr->sh_type = SHT_SYMTAB;
+  symtab_hdr->sh_flags = 0;
+  symtab_hdr->sh_addr = 0;
+  symtab_hdr->sh_size = 0;
+  symtab_hdr->sh_entsize = sizeof (Elf_External_Sym);
+  /* sh_link is set in assign_section_numbers.  */
+  /* sh_info is set below.  */
+  /* sh_offset is set just below.  */
+  symtab_hdr->sh_addralign = bed->s->file_align;
+
+  off = elf_tdata (abfd)->next_file_pos;
+  off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, true);
+
+  /* Note that at this point elf_tdata (abfd)->next_file_pos is
+     incorrect.  We do not yet know the size of the .symtab section.
+     We correct next_file_pos below, after we do know the size.  */
+
+  /* Allocate a buffer to hold swapped out symbols.  This is to avoid
+     continuously seeking to the right position in the file.  */
+  if (! info->keep_memory || max_sym_count < 20)
+    finfo.symbuf_size = 20;
+  else
+    finfo.symbuf_size = max_sym_count;
+  amt = finfo.symbuf_size;
+  amt *= sizeof (Elf_External_Sym);
+  finfo.symbuf = (Elf_External_Sym *) bfd_malloc (amt);
+  if (finfo.symbuf == NULL)
+    goto error_return;
+  if (elf_numsections (abfd) > SHN_LORESERVE)
+    {
+      amt = finfo.symbuf_size;
+      amt *= sizeof (Elf_External_Sym_Shndx);
+      finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      if (finfo.symshndxbuf == NULL)
+	goto error_return;
+    }
+
+  /* Start writing out the symbol table.  The first symbol is always a
+     dummy symbol.  */
+  elfsym.st_value = 0;
+  elfsym.st_size = 0;
+  elfsym.st_info = 0;
+  elfsym.st_other = 0;
+  elfsym.st_shndx = SHN_UNDEF;
+  if (! elf_link_output_sym (&finfo, (const char *) NULL,
+			     &elfsym, bfd_und_section_ptr))
+    goto error_return;
+
+#if 0
+  /* Some standard ELF linkers do this, but we don't because it causes
+     bootstrap comparison failures.  */
+  /* Output a file symbol for the output file as the second symbol.
+     We output this even if we are discarding local symbols, although
+     I'm not sure if this is correct.  */
+  elfsym.st_value = 0;
+  elfsym.st_size = 0;
+  elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+  elfsym.st_other = 0;
+  elfsym.st_shndx = SHN_ABS;
+  if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd),
+			     &elfsym, bfd_abs_section_ptr))
+    goto error_return;
+#endif
+
+  /* Output a symbol for each section.  We output these even if we are
+     discarding local symbols, since they are used for relocs.  These
+     symbols have no names.  We store the index of each one in the
+     index field of the section, so that we can find it again when
+     outputting relocs.  */
+  elfsym.st_size = 0;
+  elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+  elfsym.st_other = 0;
+  for (i = 1; i < elf_numsections (abfd); i++)
+    {
+      o = section_from_elf_index (abfd, i);
+      if (o != NULL)
+	o->target_index = bfd_get_symcount (abfd);
+      elfsym.st_shndx = i;
+      elfsym.st_value = 0;
+      if (! elf_link_output_sym (&finfo, (const char *) NULL,
+				 &elfsym, o))
+	goto error_return;
+      if (i == SHN_LORESERVE)
+	i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+    }
+
+  /* Allocate some memory to hold information read in from the input
+     files.  */
+  if (max_contents_size != 0)
+    {
+      finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+      if (finfo.contents == NULL)
+	goto error_return;
+    }
+
+  if (max_external_reloc_size != 0)
+    {
+      finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size);
+      if (finfo.external_relocs == NULL)
+	goto error_return;
+    }
+
+  if (max_internal_reloc_count != 0)
+    {
+      amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel;
+      amt *= sizeof (Elf_Internal_Rela);
+      finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
+      if (finfo.internal_relocs == NULL)
+	goto error_return;
+    }
+
+  if (max_sym_count != 0)
+    {
+      amt = max_sym_count * sizeof (Elf_External_Sym);
+      finfo.external_syms = (Elf_External_Sym *) bfd_malloc (amt);
+      if (finfo.external_syms == NULL)
+	goto error_return;
+
+      amt = max_sym_count * sizeof (Elf_Internal_Sym);
+      finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
+      if (finfo.internal_syms == NULL)
+	goto error_return;
+
+      amt = max_sym_count * sizeof (long);
+      finfo.indices = (long *) bfd_malloc (amt);
+      if (finfo.indices == NULL)
+	goto error_return;
+
+      amt = max_sym_count * sizeof (asection *);
+      finfo.sections = (asection **) bfd_malloc (amt);
+      if (finfo.sections == NULL)
+	goto error_return;
+    }
+
+  if (max_sym_shndx_count != 0)
+    {
+      amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx);
+      finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      if (finfo.locsym_shndx == NULL)
+	goto error_return;
+    }
+
+  if (finfo.first_tls_sec)
+    {
+      unsigned int align = 0;
+      bfd_vma base = finfo.first_tls_sec->vma, end = 0;
+      asection *sec;
+
+      for (sec = finfo.first_tls_sec;
+	   sec && (sec->flags & SEC_THREAD_LOCAL);
+	   sec = sec->next)
+	{
+	  bfd_vma size = sec->_raw_size;
+
+	  if (bfd_get_section_alignment (abfd, sec) > align)
+	    align = bfd_get_section_alignment (abfd, sec);
+	  if (sec->_raw_size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0)
+	    {
+	      struct bfd_link_order *o;
+
+	      size = 0;
+	      for (o = sec->link_order_head; o != NULL; o = o->next)
+		if (size < o->offset + o->size)
+		  size = o->offset + o->size;
+	    }
+	  end = sec->vma + size;
+	}
+      elf_hash_table (info)->tls_segment
+	= bfd_zalloc (abfd, sizeof (struct elf_link_tls_segment));
+      if (elf_hash_table (info)->tls_segment == NULL)
+	goto error_return;
+      elf_hash_table (info)->tls_segment->start = base;
+      elf_hash_table (info)->tls_segment->size = end - base;
+      elf_hash_table (info)->tls_segment->align = align;
+    }
+
+  if (ddr_sec)
+    {
+      ddr_count = 0;
+      ddr_ptr = (unsigned *)bfd_alloc(abfd, 4 * max_datadata_reloc_count + 4);
+      if (ddr_ptr)
+	++ddr_ptr;
+      else
+	goto error_return;
+    }
+  else
+    ddr_ptr = NULL;
+
+  /* Since ELF permits relocations to be against local symbols, we
+     must have the local symbols available when we do the relocations.
+     Since we would rather only read the local symbols once, and we
+     would rather not keep them in memory, we handle all the
+     relocations for a single input file at the same time.
+
+     Unfortunately, there is no way to know the total number of local
+     symbols until we have seen all of them, and the local symbol
+     indices precede the global symbol indices.  This means that when
+     we are generating relocateable output, and we see a reloc against
+     a global symbol, we can not know the symbol index until we have
+     finished examining all the local symbols to see which ones we are
+     going to output.  To deal with this, we keep the relocations in
+     memory, and don't output them until the end of the link.  This is
+     an unfortunate waste of memory, but I don't see a good way around
+     it.  Fortunately, it only happens when performing a relocateable
+     link, which is not the common case.  FIXME: If keep_memory is set
+     we could write the relocs out and then read them again; I don't
+     know how bad the memory loss will be.  */
+
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+    sub->output_has_begun = false;
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      for (p = o->link_order_head; p != NULL; p = p->next)
+	{
+	  if (p->type == bfd_indirect_link_order
+	      && (bfd_get_flavour ((sub = p->u.indirect.section->owner))
+		  == bfd_target_elf_flavour)
+	      && elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass)
+	    {
+	      if (! sub->output_has_begun)
+		{
+		  if (! elf_link_input_bfd (&finfo, sub))
+		    goto error_return;
+		  sub->output_has_begun = true;
+		}
+	    }
+	  else if (p->type == bfd_section_reloc_link_order
+		   || p->type == bfd_symbol_reloc_link_order)
+	    {
+	      if (! elf_reloc_link_order (abfd, info, o, p))
+		goto error_return;
+	    }
+	  else
+	    {
+	      if (! _bfd_default_link_order (abfd, info, o, p))
+		goto error_return;
+	    }
+	}
+    }
+
+  /* Output any global symbols that got converted to local in a
+     version script or due to symbol visibility.  We do this in a
+     separate step since ELF requires all local symbols to appear
+     prior to any global symbols.  FIXME: We should only do this if
+     some global symbols were, in fact, converted to become local.
+     FIXME: Will this work correctly with the Irix 5 linker?  */
+  eoinfo.failed = false;
+  eoinfo.finfo = &finfo;
+  eoinfo.localsyms = true;
+  elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
+			  (PTR) &eoinfo);
+  if (eoinfo.failed)
+    return false;
+
+  /* Set the vma of the sections to 0. We can't do that before, otherwise the
+     relocation doesn't work properly for .sbss. */
+  {
+    int n = elf_elfheader(abfd)->e_shnum;
+    Elf_Internal_Shdr **hdr = elf_elfsections(abfd);
+    for (i = 1; i < n; ++i, ++hdr)
+      (*hdr)->sh_addr = 0;
+  }
+  
+  /* That wrote out all the local symbols.  Finish up the symbol table
+     with the global symbols. Even if we want to strip everything we
+     can, we still need to deal with those global symbols that got
+     converted to local in a version script.  */
+
+  /* The sh_info field records the index of the first non local symbol.  */
+  symtab_hdr->sh_info = bfd_get_symcount (abfd);
+
+  if (dynamic
+      && finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
+    {
+      Elf_Internal_Sym sym;
+      Elf_External_Sym *dynsym =
+	(Elf_External_Sym *) finfo.dynsym_sec->contents;
+      long last_local = 0;
+
+      /* Write out the section symbols for the output sections.  */
+      if (info->shared)
+	{
+	  asection *s;
+
+	  sym.st_size = 0;
+	  sym.st_name = 0;
+	  sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+	  sym.st_other = 0;
+
+	  for (s = abfd->sections; s != NULL; s = s->next)
+	    {
+	      int indx;
+	      Elf_External_Sym *dest;
+
+	      indx = elf_section_data (s)->this_idx;
+	      BFD_ASSERT (indx > 0);
+	      sym.st_shndx = indx;
+	      sym.st_value = s->vma;
+	      dest = dynsym + elf_section_data (s)->dynindx;
+	      elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0);
+	    }
+
+	  last_local = bfd_count_sections (abfd);
+	}
+
+      /* Write out the local dynsyms.  */
+      if (elf_hash_table (info)->dynlocal)
+	{
+	  struct elf_link_local_dynamic_entry *e;
+	  for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
+	    {
+	      asection *s;
+	      Elf_External_Sym *dest;
+
+	      sym.st_size = e->isym.st_size;
+	      sym.st_other = e->isym.st_other;
+
+	      /* Copy the internal symbol as is.
+		 Note that we saved a word of storage and overwrote
+		 the original st_name with the dynstr_index.  */
+	      sym = e->isym;
+
+	      if (e->isym.st_shndx != SHN_UNDEF
+		  && (e->isym.st_shndx < SHN_LORESERVE
+		      || e->isym.st_shndx > SHN_HIRESERVE))
+		{
+		  s = bfd_section_from_elf_index (e->input_bfd,
+						  e->isym.st_shndx);
+
+		  sym.st_shndx =
+		    elf_section_data (s->output_section)->this_idx;
+		  sym.st_value = (s->output_section->vma
+				  + s->output_offset
+				  + e->isym.st_value);
+		}
+
+	      if (last_local < e->dynindx)
+		last_local = e->dynindx;
+
+	      dest = dynsym + e->dynindx;
+	      elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0);
+	    }
+	}
+
+      elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info =
+	last_local + 1;
+    }
+
+  /* We get the global symbols from the hash table.  */
+  eoinfo.failed = false;
+  eoinfo.localsyms = false;
+  eoinfo.finfo = &finfo;
+  elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
+			  (PTR) &eoinfo);
+  if (eoinfo.failed)
+    return false;
+
+  /* If backend needs to output some symbols not present in the hash
+     table, do it now.  */
+  if (bed->elf_backend_output_arch_syms)
+    {
+      typedef boolean (*out_sym_func) PARAMS ((PTR, const char *,
+					       Elf_Internal_Sym *,
+					       asection *));
+
+      if (! ((*bed->elf_backend_output_arch_syms)
+	     (abfd, info, (PTR) &finfo, (out_sym_func) elf_link_output_sym)))
+	return false;
+    }
+
+  /* Flush all symbols to the file.  */
+  if (! elf_link_flush_output_syms (&finfo))
+    return false;
+
+  /* Now we know the size of the symtab section.  */
+  off += symtab_hdr->sh_size;
+
+  /* Add the __datadata_relocs table. */
+  if (ddr_sec)
+    {
+      Elf_Internal_Shdr *hdr = elf_elfsections(abfd)[_bfd_elf_section_from_bfd_section(abfd, ddr_sec)];
+      ddr_sec->_cooked_size = ddr_sec->_raw_size = hdr->sh_size = 4 * ddr_count + 4;
+      hdr->sh_addralign = 2;
+      off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+      ddr_ptr -= ddr_count + 1;
+      *ddr_ptr = ddr_count ? ddr_count : -1;
+      bfd_set_section_contents(abfd, ddr_sec, ddr_ptr, 0, hdr->sh_size);
+    }
+  
+  /* Finish up and write out the symbol string table (.strtab)
+     section.  */
+  symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
+  /* sh_name was set in prep_headers.  */
+  symstrtab_hdr->sh_type = SHT_STRTAB;
+  symstrtab_hdr->sh_flags = 0;
+  symstrtab_hdr->sh_addr = 0;
+  symstrtab_hdr->sh_size = _bfd_stringtab_size (finfo.symstrtab);
+  symstrtab_hdr->sh_entsize = 0;
+  symstrtab_hdr->sh_link = 0;
+  symstrtab_hdr->sh_info = 0;
+  /* sh_offset is set just below.  */
+  symstrtab_hdr->sh_addralign = 1;
+
+  off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, true);
+  elf_tdata (abfd)->next_file_pos = off;
+
+  if (bfd_get_symcount (abfd) > 0)
+    {
+      if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
+	  || ! _bfd_stringtab_emit (abfd, finfo.symstrtab))
+	return false;
+    }
+
+  /* Adjust the relocs to have the correct symbol indices.  */
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if ((o->flags & SEC_RELOC) == 0)
+	continue;
+
+      elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr,
+			      elf_section_data (o)->rel_count,
+			      elf_section_data (o)->rel_hashes);
+      if (elf_section_data (o)->rel_hdr2 != NULL)
+	elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2,
+				elf_section_data (o)->rel_count2,
+				(elf_section_data (o)->rel_hashes
+				 + elf_section_data (o)->rel_count));
+
+      elf_section_data (o)->rel_hdr.sh_size =
+	o->reloc_count * elf_section_data (o)->rel_hdr.sh_entsize;
+      
+      /* Set the reloc_count field to 0 to prevent write_relocs from
+	 trying to swap the relocs out itself.  */
+      o->reloc_count = 0;
+    }
+
+  _bfd_elf_assign_file_positions_for_relocs (abfd);
+
+  if (dynamic && info->combreloc && dynobj != NULL)
+    relativecount = elf_link_sort_relocs (abfd, info, &reldyn);
+
+  /* If we are linking against a dynamic object, or generating a
+     shared library, finish up the dynamic linking information.  */
+  if (dynamic)
+    {
+      Elf_External_Dyn *dyncon, *dynconend;
+
+      /* Fix up .dynamic entries.  */
+      o = bfd_get_section_by_name (dynobj, ".dynamic");
+      BFD_ASSERT (o != NULL);
+
+      dyncon = (Elf_External_Dyn *) o->contents;
+      dynconend = (Elf_External_Dyn *) (o->contents + o->_raw_size);
+      for (; dyncon < dynconend; dyncon++)
+	{
+	  Elf_Internal_Dyn dyn;
+	  const char *name;
+	  unsigned int type;
+
+	  elf_swap_dyn_in (dynobj, dyncon, &dyn);
+
+	  switch (dyn.d_tag)
+	    {
+	    default:
+	      break;
+	    case DT_NULL:
+	      if (relativecount > 0 && dyncon + 1 < dynconend)
+		{
+		  switch (elf_section_data (reldyn)->this_hdr.sh_type)
+		    {
+		    case SHT_REL: dyn.d_tag = DT_RELCOUNT; break;
+		    case SHT_RELA: dyn.d_tag = DT_RELACOUNT; break;
+		    default: break;
+		    }
+		  if (dyn.d_tag != DT_NULL)
+		    {
+		      dyn.d_un.d_val = relativecount;
+		      elf_swap_dyn_out (dynobj, &dyn, dyncon);
+		      relativecount = 0;
+		    }
+		}
+	      break;
+	    case DT_INIT:
+	      name = info->init_function;
+	      goto get_sym;
+	    case DT_FINI:
+	      name = info->fini_function;
+	    get_sym:
+	      {
+		struct elf_link_hash_entry *h;
+
+		h = elf_link_hash_lookup (elf_hash_table (info), name,
+					  false, false, true);
+		if (h != NULL
+		    && (h->root.type == bfd_link_hash_defined
+			|| h->root.type == bfd_link_hash_defweak))
+		  {
+		    dyn.d_un.d_val = h->root.u.def.value;
+		    o = h->root.u.def.section;
+		    if (o->output_section != NULL)
+		      dyn.d_un.d_val += (o->output_section->vma
+					 + o->output_offset);
+		    else
+		      {
+			/* The symbol is imported from another shared
+			   library and does not apply to this one.  */
+			dyn.d_un.d_val = 0;
+		      }
+
+		    elf_swap_dyn_out (dynobj, &dyn, dyncon);
+		  }
+	      }
+	      break;
+
+	    case DT_PREINIT_ARRAYSZ:
+	      name = ".preinit_array";
+	      goto get_size;
+	    case DT_INIT_ARRAYSZ:
+	      name = ".init_array";
+	      goto get_size;
+	    case DT_FINI_ARRAYSZ:
+	      name = ".fini_array";
+	    get_size:
+	      o = bfd_get_section_by_name (abfd, name);
+	      if (o == NULL)
+		{
+		  (*_bfd_error_handler)
+		    (_("%s: could not find output section %s"),
+		     bfd_get_filename (abfd), name);
+		  goto error_return;
+		}
+	      if (o->_raw_size == 0)
+		(*_bfd_error_handler)
+		  (_("warning: %s section has zero size"), name);
+	      dyn.d_un.d_val = o->_raw_size;
+	      elf_swap_dyn_out (dynobj, &dyn, dyncon);
+	      break;
+
+	    case DT_PREINIT_ARRAY:
+	      name = ".preinit_array";
+	      goto get_vma;
+	    case DT_INIT_ARRAY:
+	      name = ".init_array";
+	      goto get_vma;
+	    case DT_FINI_ARRAY:
+	      name = ".fini_array";
+	      goto get_vma;
+
+	    case DT_HASH:
+	      name = ".hash";
+	      goto get_vma;
+	    case DT_STRTAB:
+	      name = ".dynstr";
+	      goto get_vma;
+	    case DT_SYMTAB:
+	      name = ".dynsym";
+	      goto get_vma;
+	    case DT_VERDEF:
+	      name = ".gnu.version_d";
+	      goto get_vma;
+	    case DT_VERNEED:
+	      name = ".gnu.version_r";
+	      goto get_vma;
+	    case DT_VERSYM:
+	      name = ".gnu.version";
+	    get_vma:
+	      o = bfd_get_section_by_name (abfd, name);
+	      if (o == NULL)
+		{
+		  (*_bfd_error_handler)
+		    (_("%s: could not find output section %s"),
+		     bfd_get_filename (abfd), name);
+		  goto error_return;
+		}
+	      dyn.d_un.d_ptr = o->vma;
+	      elf_swap_dyn_out (dynobj, &dyn, dyncon);
+	      break;
+
+	    case DT_REL:
+	    case DT_RELA:
+	    case DT_RELSZ:
+	    case DT_RELASZ:
+	      if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ)
+		type = SHT_REL;
+	      else
+		type = SHT_RELA;
+	      dyn.d_un.d_val = 0;
+	      for (i = 1; i < elf_numsections (abfd); i++)
+		{
+		  Elf_Internal_Shdr *hdr;
+
+		  hdr = elf_elfsections (abfd)[i];
+		  if (hdr->sh_type == type
+		      && (hdr->sh_flags & SHF_ALLOC) != 0)
+		    {
+		      if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
+			dyn.d_un.d_val += hdr->sh_size;
+		      else
+			{
+			  if (dyn.d_un.d_val == 0
+			      || hdr->sh_addr < dyn.d_un.d_val)
+			    dyn.d_un.d_val = hdr->sh_addr;
+			}
+		    }
+		}
+	      elf_swap_dyn_out (dynobj, &dyn, dyncon);
+	      break;
+	    }
+	}
+    }
+
+  /* If we have created any dynamic sections, then output them.  */
+  if (dynobj != NULL)
+    {
+      if (! (*bed->elf_backend_finish_dynamic_sections) (abfd, info))
+	goto error_return;
+
+      for (o = dynobj->sections; o != NULL; o = o->next)
+	{
+	  if ((o->flags & SEC_HAS_CONTENTS) == 0
+	      || o->_raw_size == 0
+	      || o->output_section == bfd_abs_section_ptr)
+	    continue;
+	  if ((o->flags & SEC_LINKER_CREATED) == 0)
+	    {
+	      /* At this point, we are only interested in sections
+		 created by elf_link_create_dynamic_sections.  */
+	      continue;
+	    }
+	  if ((elf_section_data (o->output_section)->this_hdr.sh_type
+	       != SHT_STRTAB)
+	      || strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)
+	    {
+	      if (! bfd_set_section_contents (abfd, o->output_section,
+					      o->contents,
+					      (file_ptr) o->output_offset,
+					      o->_raw_size))
+		goto error_return;
+	    }
+	  else
+	    {
+	      /* The contents of the .dynstr section are actually in a
+		 stringtab.  */
+	      off = elf_section_data (o->output_section)->this_hdr.sh_offset;
+	      if (bfd_seek (abfd, off, SEEK_SET) != 0
+		  || ! _bfd_elf_strtab_emit (abfd,
+					     elf_hash_table (info)->dynstr))
+		goto error_return;
+	    }
+	}
+    }
+
+  if (info->relocateable)
+    {
+      boolean failed = false;
+
+      bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed);
+      if (failed)
+	goto error_return;
+    }
+
+  /* If we have optimized stabs strings, output them.  */
+  if (elf_hash_table (info)->stab_info != NULL)
+    {
+      if (! _bfd_write_stab_strings (abfd, &elf_hash_table (info)->stab_info))
+	goto error_return;
+    }
+
+  if (info->eh_frame_hdr && elf_hash_table (info)->dynobj)
+    {
+      o = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
+				   ".eh_frame_hdr");
+      if (o
+	  && (elf_section_data (o)->sec_info_type
+	      == ELF_INFO_TYPE_EH_FRAME_HDR))
+	{
+	  if (! _bfd_elf_write_section_eh_frame_hdr (abfd, o))
+	    goto error_return;
+	}
+    }
+
+  if (finfo.symstrtab != NULL)
+    _bfd_stringtab_free (finfo.symstrtab);
+  if (finfo.contents != NULL)
+    free (finfo.contents);
+  if (finfo.external_relocs != NULL)
+    free (finfo.external_relocs);
+  if (finfo.internal_relocs != NULL)
+    free (finfo.internal_relocs);
+  if (finfo.external_syms != NULL)
+    free (finfo.external_syms);
+  if (finfo.locsym_shndx != NULL)
+    free (finfo.locsym_shndx);
+  if (finfo.internal_syms != NULL)
+    free (finfo.internal_syms);
+  if (finfo.indices != NULL)
+    free (finfo.indices);
+  if (finfo.sections != NULL)
+    free (finfo.sections);
+  if (finfo.symbuf != NULL)
+    free (finfo.symbuf);
+  if (finfo.symshndxbuf != NULL)
+    free (finfo.symbuf);
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if ((o->flags & SEC_RELOC) != 0
+	  && elf_section_data (o)->rel_hashes != NULL)
+	free (elf_section_data (o)->rel_hashes);
+    }
+
+  elf_tdata (abfd)->linker = true;
+
+  return true;
+
+ error_return:
+  if (finfo.symstrtab != NULL)
+    _bfd_stringtab_free (finfo.symstrtab);
+  if (finfo.contents != NULL)
+    free (finfo.contents);
+  if (finfo.external_relocs != NULL)
+    free (finfo.external_relocs);
+  if (finfo.internal_relocs != NULL)
+    free (finfo.internal_relocs);
+  if (finfo.external_syms != NULL)
+    free (finfo.external_syms);
+  if (finfo.locsym_shndx != NULL)
+    free (finfo.locsym_shndx);
+  if (finfo.internal_syms != NULL)
+    free (finfo.internal_syms);
+  if (finfo.indices != NULL)
+    free (finfo.indices);
+  if (finfo.sections != NULL)
+    free (finfo.sections);
+  if (finfo.symbuf != NULL)
+    free (finfo.symbuf);
+  if (finfo.symshndxbuf != NULL)
+    free (finfo.symbuf);
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if ((o->flags & SEC_RELOC) != 0
+	  && elf_section_data (o)->rel_hashes != NULL)
+	free (elf_section_data (o)->rel_hashes);
+    }
+
+  return false;
+}
+
+/* Add a symbol to the output symbol table.  */
+
+static boolean
+elf_link_output_sym (finfo, name, elfsym, input_sec)
+     struct elf_final_link_info *finfo;
+     const char *name;
+     Elf_Internal_Sym *elfsym;
+     asection *input_sec;
+{
+  Elf_External_Sym *dest;
+  Elf_External_Sym_Shndx *destshndx;
+
+  boolean (*output_symbol_hook) PARAMS ((bfd *,
+					 struct bfd_link_info *info,
+					 const char *,
+					 Elf_Internal_Sym *,
+					 asection *));
+
+  output_symbol_hook = get_elf_backend_data (finfo->output_bfd)->
+    elf_backend_link_output_symbol_hook;
+  if (output_symbol_hook != NULL)
+    {
+      if (! ((*output_symbol_hook)
+	     (finfo->output_bfd, finfo->info, name, elfsym, input_sec)))
+	return false;
+    }
+
+  if (name == (const char *) NULL || *name == '\0')
+    elfsym->st_name = 0;
+  else if (input_sec->flags & SEC_EXCLUDE)
+    elfsym->st_name = 0;
+  else
+    {
+      elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab,
+							    name, true, false);
+      if (elfsym->st_name == (unsigned long) -1)
+	return false;
+    }
+
+  if (finfo->symbuf_count >= finfo->symbuf_size)
+    {
+      if (! elf_link_flush_output_syms (finfo))
+	return false;
+    }
+
+  dest = finfo->symbuf + finfo->symbuf_count;
+  destshndx = finfo->symshndxbuf;
+  if (destshndx != NULL)
+    destshndx += finfo->symbuf_count;
+  elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx);
+  ++finfo->symbuf_count;
+
+  ++ bfd_get_symcount (finfo->output_bfd);
+
+  return true;
+}
+
+/* Flush the output symbols to the file.  */
+
+static boolean
+elf_link_flush_output_syms (finfo)
+     struct elf_final_link_info *finfo;
+{
+  if (finfo->symbuf_count > 0)
+    {
+      Elf_Internal_Shdr *hdr;
+      file_ptr pos;
+      bfd_size_type amt;
+
+      hdr = &elf_tdata (finfo->output_bfd)->symtab_hdr;
+      pos = hdr->sh_offset + hdr->sh_size;
+      amt = finfo->symbuf_count * sizeof (Elf_External_Sym);
+      if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
+	  || bfd_bwrite ((PTR) finfo->symbuf, amt, finfo->output_bfd) != amt)
+	return false;
+
+      hdr->sh_size += amt;
+
+      if (finfo->symshndxbuf != NULL)
+	{
+	  hdr = &elf_tdata (finfo->output_bfd)->symtab_shndx_hdr;
+	  pos = hdr->sh_offset + hdr->sh_size;
+	  amt = finfo->symbuf_count * sizeof (Elf_External_Sym_Shndx);
+	  if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
+	      || (bfd_bwrite ((PTR) finfo->symshndxbuf, amt, finfo->output_bfd)
+		  != amt))
+	    return false;
+
+	  hdr->sh_size += amt;
+	}
+
+      finfo->symbuf_count = 0;
+    }
+
+  return true;
+}
+
+/* Adjust all external symbols pointing into SEC_MERGE sections
+   to reflect the object merging within the sections.  */
+
+static boolean
+elf_link_sec_merge_syms (h, data)
+     struct elf_link_hash_entry *h;
+     PTR data;
+{
+  asection *sec;
+
+  if (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)
+      && ((sec = h->root.u.def.section)->flags & SEC_MERGE)
+      && elf_section_data (sec)->sec_info_type == ELF_INFO_TYPE_MERGE)
+    {
+      bfd *output_bfd = (bfd *) data;
+
+      h->root.u.def.value =
+	_bfd_merged_section_offset (output_bfd,
+				    &h->root.u.def.section,
+				    elf_section_data (sec)->sec_info,
+				    h->root.u.def.value, (bfd_vma) 0);
+    }
+
+  return true;
+}
+
+/* For DSOs loaded in via a DT_NEEDED entry, emulate ld.so in
+   allowing an unsatisfied unversioned symbol in the DSO to match a
+   versioned symbol that would normally require an explicit version.  */
+
+static boolean
+elf_link_check_versioned_symbol (info, h)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+{
+  bfd *undef_bfd = h->root.u.undef.abfd;
+  struct elf_link_loaded_list *loaded;
+
+  if ((undef_bfd->flags & DYNAMIC) == 0
+      || info->hash->creator->flavour != bfd_target_elf_flavour
+      || elf_dt_soname (h->root.u.undef.abfd) == NULL)
+    return false;
+
+  for (loaded = elf_hash_table (info)->loaded;
+       loaded != NULL;
+       loaded = loaded->next)
+    {
+      bfd *input;
+      Elf_Internal_Shdr *hdr;
+      bfd_size_type symcount;
+      bfd_size_type extsymcount;
+      bfd_size_type extsymoff;
+      Elf_Internal_Shdr *versymhdr;
+      Elf_Internal_Sym *isym;
+      Elf_Internal_Sym *isymend;
+      Elf_Internal_Sym *isymbuf;
+      Elf_External_Versym *ever;
+      Elf_External_Versym *extversym;
+
+      input = loaded->abfd;
+
+      /* We check each DSO for a possible hidden versioned definition.  */
+      if (input == undef_bfd
+	  || (input->flags & DYNAMIC) == 0
+	  || elf_dynversym (input) == 0)
+	continue;
+
+      hdr = &elf_tdata (input)->dynsymtab_hdr;
+
+      symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+      if (elf_bad_symtab (input))
+	{
+	  extsymcount = symcount;
+	  extsymoff = 0;
+	}
+      else
+	{
+	  extsymcount = symcount - hdr->sh_info;
+	  extsymoff = hdr->sh_info;
+	}
+
+      if (extsymcount == 0)
+	continue;
+
+      isymbuf = bfd_elf_get_elf_syms (input, hdr, extsymcount, extsymoff,
+				      NULL, NULL, NULL);
+      if (isymbuf == NULL)
+	return false;
+
+      /* Read in any version definitions.  */
+      versymhdr = &elf_tdata (input)->dynversym_hdr;
+      extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
+      if (extversym == NULL)
+	goto error_ret;
+
+      if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0
+	  || (bfd_bread ((PTR) extversym, versymhdr->sh_size, input)
+	      != versymhdr->sh_size))
+	{
+	  free (extversym);
+	error_ret:
+	  free (isymbuf);
+	  return false;
+	}
+
+      ever = extversym + extsymoff;
+      isymend = isymbuf + extsymcount;
+      for (isym = isymbuf; isym < isymend; isym++, ever++)
+	{
+	  const char *name;
+	  Elf_Internal_Versym iver;
+
+	  if (ELF_ST_BIND (isym->st_info) == STB_LOCAL
+	      || isym->st_shndx == SHN_UNDEF)
+	    continue;
+
+	  name = bfd_elf_string_from_elf_section (input,
+						  hdr->sh_link,
+						  isym->st_name);
+	  if (strcmp (name, h->root.root.string) != 0)
+	    continue;
+
+	  _bfd_elf_swap_versym_in (input, ever, &iver);
+
+	  if ((iver.vs_vers & VERSYM_HIDDEN) == 0)
+	    {
+	      /* If we have a non-hidden versioned sym, then it should
+		 have provided a definition for the undefined sym.  */
+	      abort ();
+	    }
+
+	  if ((iver.vs_vers & VERSYM_VERSION) == 2)
+	    {
+	      /* This is the oldest (default) sym.  We can use it.  */
+	      free (extversym);
+	      free (isymbuf);
+	      return true;
+	    }
+	}
+
+      free (extversym);
+      free (isymbuf);
+    }
+
+  return false;
+}
+
+/* Add an external symbol to the symbol table.  This is called from
+   the hash table traversal routine.  When generating a shared object,
+   we go through the symbol table twice.  The first time we output
+   anything that might have been forced to local scope in a version
+   script.  The second time we output the symbols that are still
+   global symbols.  */
+
+static boolean
+elf_link_output_extsym (h, data)
+     struct elf_link_hash_entry *h;
+     PTR data;
+{
+  struct elf_outext_info *eoinfo = (struct elf_outext_info *) data;
+  struct elf_final_link_info *finfo = eoinfo->finfo;
+  boolean strip;
+  Elf_Internal_Sym sym;
+  asection *input_sec;
+
+  if (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_new)
+	return true;
+    }
+
+  /* Decide whether to output this symbol in this pass.  */
+  if (eoinfo->localsyms)
+    {
+      if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+	return true;
+    }
+  else
+    {
+      if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+	return true;
+    }
+
+  /* If we are not creating a shared library, and this symbol is
+     referenced by a shared library but is not defined anywhere, then
+     warn that it is undefined.  If we do not do this, the runtime
+     linker will complain that the symbol is undefined when the
+     program is run.  We don't have to worry about symbols that are
+     referenced by regular files, because we will already have issued
+     warnings for them.  */
+  if (! finfo->info->relocateable
+      && ! finfo->info->allow_shlib_undefined
+      && ! finfo->info->shared
+      && h->root.type == bfd_link_hash_undefined
+      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
+      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0
+      && ! elf_link_check_versioned_symbol (finfo->info, h))
+    {
+      if (! ((*finfo->info->callbacks->undefined_symbol)
+	     (finfo->info, h->root.root.string, h->root.u.undef.abfd,
+	      (asection *) NULL, (bfd_vma) 0, true)))
+	{
+	  eoinfo->failed = true;
+	  return false;
+	}
+    }
+
+  /* We don't want to output symbols that have never been mentioned by
+     a regular file, or that we have been told to strip.  However, if
+     h->indx is set to -2, the symbol is used by a reloc and we must
+     output it.  */
+  if (h->indx == -2)
+    strip = false;
+  else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+	    || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0)
+	   && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+	   && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
+    strip = true;
+  else if (finfo->info->strip == strip_all
+	   || (finfo->info->strip == strip_some
+	       && bfd_hash_lookup (finfo->info->keep_hash,
+				   h->root.root.string,
+				   false, false) == NULL))
+    strip = true;
+  else
+    strip = false;
+
+  /* If we're stripping it, and it's not a dynamic symbol, there's
+     nothing else to do unless it is a forced local symbol.  */
+  if (strip
+      && h->dynindx == -1
+      && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+    return true;
+
+  sym.st_value = 0;
+  sym.st_size = h->size;
+  sym.st_other = h->other;
+  if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+    sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
+  else if (h->root.type == bfd_link_hash_undefweak
+	   || h->root.type == bfd_link_hash_defweak)
+    sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
+  else
+    sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
+
+  switch (h->root.type)
+    {
+    default:
+    case bfd_link_hash_new:
+    case bfd_link_hash_warning:
+      abort ();
+      return false;
+
+    case bfd_link_hash_undefined:
+    case bfd_link_hash_undefweak:
+      input_sec = bfd_und_section_ptr;
+      sym.st_shndx = SHN_UNDEF;
+      break;
+
+    case bfd_link_hash_defined:
+    case bfd_link_hash_defweak:
+      {
+	input_sec = h->root.u.def.section;
+	if (input_sec->output_section != NULL)
+	  {
+	    sym.st_shndx =
+	      _bfd_elf_section_from_bfd_section (finfo->output_bfd,
+						 input_sec->output_section);
+	    if (sym.st_shndx == SHN_BAD)
+	      {
+		(*_bfd_error_handler)
+		  (_("%s: could not find output section %s for input section %s"),
+		   bfd_get_filename (finfo->output_bfd),
+		   input_sec->output_section->name,
+		   input_sec->name);
+		eoinfo->failed = true;
+		return false;
+	      }
+
+	    /* ELF symbols in relocateable files are section relative,
+	       but in nonrelocateable files they are virtual
+	       addresses.  */
+	    sym.st_value = h->root.u.def.value + input_sec->output_offset;
+#if 0
+	    if (! finfo->info->relocateable)
+	      {
+		sym.st_value += input_sec->output_section->vma;
+		if (h->type == STT_TLS)
+		  {
+		    /* STT_TLS symbols are relative to PT_TLS segment
+		       base.  */
+		    BFD_ASSERT (finfo->first_tls_sec != NULL);
+		    sym.st_value -= finfo->first_tls_sec->vma;
+		  }
+	      }
+#endif
+	  }
+	else
+	  {
+	    BFD_ASSERT (input_sec->owner == NULL
+			|| (input_sec->owner->flags & DYNAMIC) != 0);
+	    sym.st_shndx = SHN_UNDEF;
+	    input_sec = bfd_und_section_ptr;
+	  }
+      }
+      break;
+
+    case bfd_link_hash_common:
+      input_sec = h->root.u.c.p->section;
+      sym.st_shndx = SHN_COMMON;
+      sym.st_value = 1 << h->root.u.c.p->alignment_power;
+      break;
+
+    case bfd_link_hash_indirect:
+      /* These symbols are created by symbol versioning.  They point
+	 to the decorated version of the name.  For example, if the
+	 symbol foo@@GNU_1.2 is the default, which should be used when
+	 foo is used with no version, then we add an indirect symbol
+	 foo which points to foo@@GNU_1.2.  We ignore these symbols,
+	 since the indirected symbol is already in the hash table.  */
+      return true;
+    }
+
+  /* Give the processor backend a chance to tweak the symbol value,
+     and also to finish up anything that needs to be done for this
+     symbol.  FIXME: Not calling elf_backend_finish_dynamic_symbol for
+     forced local syms when non-shared is due to a historical quirk.  */
+  if ((h->dynindx != -1
+       || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+      && (finfo->info->shared
+	  || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+      && elf_hash_table (finfo->info)->dynamic_sections_created)
+    {
+      struct elf_backend_data *bed;
+
+      bed = get_elf_backend_data (finfo->output_bfd);
+      if (! ((*bed->elf_backend_finish_dynamic_symbol)
+	     (finfo->output_bfd, finfo->info, h, &sym)))
+	{
+	  eoinfo->failed = true;
+	  return false;
+	}
+    }
+
+  /* If we are marking the symbol as undefined, and there are no
+     non-weak references to this symbol from a regular object, then
+     mark the symbol as weak undefined; if there are non-weak
+     references, mark the symbol as strong.  We can't do this earlier,
+     because it might not be marked as undefined until the
+     finish_dynamic_symbol routine gets through with it.  */
+  if (sym.st_shndx == SHN_UNDEF
+      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0
+      && (ELF_ST_BIND (sym.st_info) == STB_GLOBAL
+	  || ELF_ST_BIND (sym.st_info) == STB_WEAK))
+    {
+      int bindtype;
+
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) != 0)
+	bindtype = STB_GLOBAL;
+      else
+	bindtype = STB_WEAK;
+      sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
+    }
+
+  /* If a symbol is not defined locally, we clear the visibility
+     field.  */
+  if (! finfo->info->relocateable
+      && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+    sym.st_other ^= ELF_ST_VISIBILITY (sym.st_other);
+
+  /* If this symbol should be put in the .dynsym section, then put it
+     there now.  We already know the symbol index.  We also fill in
+     the entry in the .hash section.  */
+  if (h->dynindx != -1
+      && elf_hash_table (finfo->info)->dynamic_sections_created)
+    {
+      size_t bucketcount;
+      size_t bucket;
+      size_t hash_entry_size;
+      bfd_byte *bucketpos;
+      bfd_vma chain;
+      Elf_External_Sym *esym;
+
+      sym.st_name = h->dynstr_index;
+      esym = (Elf_External_Sym *) finfo->dynsym_sec->contents + h->dynindx;
+      elf_swap_symbol_out (finfo->output_bfd, &sym, (PTR) esym, (PTR) 0);
+
+      bucketcount = elf_hash_table (finfo->info)->bucketcount;
+      bucket = h->elf_hash_value % bucketcount;
+      hash_entry_size
+	= elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
+      bucketpos = ((bfd_byte *) finfo->hash_sec->contents
+		   + (bucket + 2) * hash_entry_size);
+      chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos);
+      bfd_put (8 * hash_entry_size, finfo->output_bfd, (bfd_vma) h->dynindx,
+	       bucketpos);
+      bfd_put (8 * hash_entry_size, finfo->output_bfd, chain,
+	       ((bfd_byte *) finfo->hash_sec->contents
+		+ (bucketcount + 2 + h->dynindx) * hash_entry_size));
+
+      if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL)
+	{
+	  Elf_Internal_Versym iversym;
+	  Elf_External_Versym *eversym;
+
+	  if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+	    {
+	      if (h->verinfo.verdef == NULL)
+		iversym.vs_vers = 0;
+	      else
+		iversym.vs_vers = h->verinfo.verdef->vd_exp_refno + 1;
+	    }
+	  else
+	    {
+	      if (h->verinfo.vertree == NULL)
+		iversym.vs_vers = 1;
+	      else
+		iversym.vs_vers = h->verinfo.vertree->vernum + 1;
+	    }
+
+	  if ((h->elf_link_hash_flags & ELF_LINK_HIDDEN) != 0)
+	    iversym.vs_vers |= VERSYM_HIDDEN;
+
+	  eversym = (Elf_External_Versym *) finfo->symver_sec->contents;
+	  eversym += h->dynindx;
+	  _bfd_elf_swap_versym_out (finfo->output_bfd, &iversym, eversym);
+	}
+    }
+
+  /* If we're stripping it, then it was just a dynamic symbol, and
+     there's nothing else to do.  */
+  if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
+    return true;
+
+  h->indx = bfd_get_symcount (finfo->output_bfd);
+
+  if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec))
+    {
+      eoinfo->failed = true;
+      return false;
+    }
+
+  return true;
+}
+
+/* Copy the relocations indicated by the INTERNAL_RELOCS (which
+   originated from the section given by INPUT_REL_HDR) to the
+   OUTPUT_BFD.  */
+
+static boolean
+elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
+			internal_relocs)
+     bfd *output_bfd;
+     asection *input_section;
+     Elf_Internal_Shdr *input_rel_hdr;
+     Elf_Internal_Rela *internal_relocs;
+{
+  Elf_Internal_Rela *irela;
+  Elf_Internal_Rela *irelaend;
+  Elf_Internal_Shdr *output_rel_hdr;
+  asection *output_section;
+  unsigned int *rel_countp = NULL;
+  struct elf_backend_data *bed;
+  bfd_size_type amt;
+
+  output_section = input_section->output_section;
+  output_rel_hdr = NULL;
+
+  if (elf_section_data (output_section)->rel_hdr.sh_entsize
+      == input_rel_hdr->sh_entsize)
+    {
+      output_rel_hdr = &elf_section_data (output_section)->rel_hdr;
+      rel_countp = &elf_section_data (output_section)->rel_count;
+    }
+  else if (elf_section_data (output_section)->rel_hdr2
+	   && (elf_section_data (output_section)->rel_hdr2->sh_entsize
+	       == input_rel_hdr->sh_entsize))
+    {
+      output_rel_hdr = elf_section_data (output_section)->rel_hdr2;
+      rel_countp = &elf_section_data (output_section)->rel_count2;
+    }
+  else
+    {
+      (*_bfd_error_handler)
+	(_("%s: relocation size mismatch in %s section %s"),
+	 bfd_get_filename (output_bfd),
+	 bfd_archive_filename (input_section->owner),
+	 input_section->name);
+      bfd_set_error (bfd_error_wrong_object_format);
+      return false;
+    }
+
+  bed = get_elf_backend_data (output_bfd);
+  irela = internal_relocs;
+  irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
+		      * bed->s->int_rels_per_ext_rel);
+
+  if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+    {
+      Elf_External_Rel *erel;
+      Elf_Internal_Rel *irel;
+
+      amt = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rel);
+      irel = (Elf_Internal_Rel *) bfd_zmalloc (amt);
+      if (irel == NULL)
+	{
+	  (*_bfd_error_handler) (_("Error: out of memory"));
+	  abort ();
+	}
+
+      erel = ((Elf_External_Rel *) output_rel_hdr->contents + *rel_countp);
+      for (; irela < irelaend; irela += bed->s->int_rels_per_ext_rel, erel++)
+	{
+	  unsigned int i;
+
+	  for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
+	    {
+	      irel[i].r_offset = irela[i].r_offset;
+	      irel[i].r_info = irela[i].r_info;
+	      BFD_ASSERT (irela[i].r_addend == 0);
+	    }
+
+	  if (bed->s->swap_reloc_out)
+	    (*bed->s->swap_reloc_out) (output_bfd, irel, (PTR) erel);
+	  else
+	    elf_swap_reloc_out (output_bfd, irel, erel);
+	}
+
+      free (irel);
+    }
+  else
+    {
+      Elf_External_Rela *erela;
+
+      BFD_ASSERT (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rela));
+
+      erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp);
+      for (; irela < irelaend; irela += bed->s->int_rels_per_ext_rel, erela++)
+	if (bed->s->swap_reloca_out)
+	  (*bed->s->swap_reloca_out) (output_bfd, irela, (PTR) erela);
+	else
+	  elf_swap_reloca_out (output_bfd, irela, erela);
+    }
+
+  /* Bump the counter, so that we know where to add the next set of
+     relocations.  */
+  *rel_countp += NUM_SHDR_ENTRIES (input_rel_hdr);
+
+  return true;
+}
+
+/* Link an input file into the linker output file.  This function
+   handles all the sections and relocations of the input file at once.
+   This is so that we only have to read the local symbols once, and
+   don't have to keep them in memory.  */
+
+static boolean
+elf_link_input_bfd (finfo, input_bfd)
+     struct elf_final_link_info *finfo;
+     bfd *input_bfd;
+{
+  boolean (*relocate_section) PARAMS ((bfd *, struct bfd_link_info *,
+				       bfd *, asection *, bfd_byte *,
+				       Elf_Internal_Rela *,
+				       Elf_Internal_Sym *, asection **));
+  bfd *output_bfd;
+  Elf_Internal_Shdr *symtab_hdr;
+  size_t locsymcount;
+  size_t extsymoff;
+  Elf_Internal_Sym *isymbuf;
+  Elf_Internal_Sym *isym;
+  Elf_Internal_Sym *isymend;
+  long *pindex;
+  asection **ppsection;
+  asection *o;
+  struct elf_backend_data *bed;
+  boolean emit_relocs;
+  struct elf_link_hash_entry **sym_hashes;
+
+  output_bfd = finfo->output_bfd;
+  bed = get_elf_backend_data (output_bfd);
+  relocate_section = bed->elf_backend_relocate_section;
+
+  /* If this is a dynamic object, we don't want to do anything here:
+     we don't want the local symbols, and we don't want the section
+     contents.  */
+  if ((input_bfd->flags & DYNAMIC) != 0)
+    return true;
+
+  emit_relocs = (finfo->info->relocateable
+		 || finfo->info->emitrelocations
+		 || bed->elf_backend_emit_relocs);
+
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  if (elf_bad_symtab (input_bfd))
+    {
+      locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+      extsymoff = 0;
+    }
+  else
+    {
+      locsymcount = symtab_hdr->sh_info;
+      extsymoff = symtab_hdr->sh_info;
+    }
+
+  /* Read the local symbols.  */
+  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (isymbuf == NULL && locsymcount != 0)
+    {
+      isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
+				      finfo->internal_syms,
+				      finfo->external_syms,
+				      finfo->locsym_shndx);
+      if (isymbuf == NULL)
+	return false;
+    }
+
+  /* Find local symbol sections and adjust values of symbols in
+     SEC_MERGE sections.  Write out those local symbols we know are
+     going into the output file.  */
+  isymend = isymbuf + locsymcount;
+  for (isym = isymbuf, pindex = finfo->indices, ppsection = finfo->sections;
+       isym < isymend;
+       isym++, pindex++, ppsection++)
+    {
+      asection *isec;
+      const char *name;
+      Elf_Internal_Sym osym;
+
+      *pindex = -1;
+
+      if (elf_bad_symtab (input_bfd))
+	{
+	  if (ELF_ST_BIND (isym->st_info) != STB_LOCAL)
+	    {
+	      *ppsection = NULL;
+	      continue;
+	    }
+	}
+
+      if (isym->st_shndx == SHN_UNDEF)
+	isec = bfd_und_section_ptr;
+      else if (isym->st_shndx < SHN_LORESERVE
+	       || isym->st_shndx > SHN_HIRESERVE)
+	{
+	  isec = section_from_elf_index (input_bfd, isym->st_shndx);
+	  if (isec
+	      && elf_section_data (isec)->sec_info_type == ELF_INFO_TYPE_MERGE
+	      && ELF_ST_TYPE (isym->st_info) != STT_SECTION)
+	    isym->st_value =
+	      _bfd_merged_section_offset (output_bfd, &isec,
+					  elf_section_data (isec)->sec_info,
+					  isym->st_value, (bfd_vma) 0);
+	}
+      else if (isym->st_shndx == SHN_ABS)
+	isec = bfd_abs_section_ptr;
+      else if (isym->st_shndx == SHN_COMMON)
+	isec = bfd_com_section_ptr;
+      else
+	{
+	  /* Who knows?  */
+	  isec = NULL;
+	}
+
+      *ppsection = isec;
+
+      /* Don't output the first, undefined, symbol.  */
+      if (ppsection == finfo->sections)
+	continue;
+
+      if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+	{
+	  /* We never output section symbols.  Instead, we use the
+	     section symbol of the corresponding section in the output
+	     file.  */
+	  continue;
+	}
+
+      /* If we are stripping all symbols, we don't want to output this
+	 one.  */
+      if (finfo->info->strip == strip_all)
+	continue;
+
+      /* If we are discarding all local symbols, we don't want to
+	 output this one.  If we are generating a relocateable output
+	 file, then some of the local symbols may be required by
+	 relocs; we output them below as we discover that they are
+	 needed.  */
+      if (finfo->info->discard == discard_all)
+	continue;
+
+      /* If this symbol is defined in a section which we are
+	 discarding, we don't need to keep it, but note that
+	 linker_mark is only reliable for sections that have contents.
+	 For the benefit of the MIPS ELF linker, we check SEC_EXCLUDE
+	 as well as linker_mark.  */
+      if ((isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
+	  && isec != NULL
+	  && ((! isec->linker_mark && (isec->flags & SEC_HAS_CONTENTS) != 0)
+	      || (! finfo->info->relocateable
+		  && (isec->flags & SEC_EXCLUDE) != 0)))
+	continue;
+
+      /* Get the name of the symbol.  */
+      name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link,
+					      isym->st_name);
+      if (name == NULL)
+	return false;
+
+      /* See if we are discarding symbols with this name.  */
+      if ((finfo->info->strip == strip_some
+	   && (bfd_hash_lookup (finfo->info->keep_hash, name, false, false)
+	       == NULL))
+	  || (((finfo->info->discard == discard_sec_merge
+		&& (isec->flags & SEC_MERGE) && ! finfo->info->relocateable)
+	       || finfo->info->discard == discard_l)
+	      && bfd_is_local_label_name (input_bfd, name)))
+	continue;
+
+      /* If we get here, we are going to output this symbol.  */
+
+      osym = *isym;
+
+      /* Adjust the section index for the output file.  */
+      osym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
+							 isec->output_section);
+      if (osym.st_shndx == SHN_BAD)
+	return false;
+
+      *pindex = bfd_get_symcount (output_bfd);
+
+      /* ELF symbols in relocateable files are section relative, but
+	 in executable files they are virtual addresses.  Note that
+	 this code assumes that all ELF sections have an associated
+	 BFD section with a reasonable value for output_offset; below
+	 we assume that they also have a reasonable value for
+	 output_section.  Any special sections must be set up to meet
+	 these requirements.  */
+      osym.st_value += isec->output_offset;
+      if (! finfo->info->relocateable)
+	{
+	  osym.st_value += isec->output_section->vma;
+	  if (ELF_ST_TYPE (osym.st_info) == STT_TLS)
+	    {
+	      /* STT_TLS symbols are relative to PT_TLS segment base.  */
+	      BFD_ASSERT (finfo->first_tls_sec != NULL);
+	      osym.st_value -= finfo->first_tls_sec->vma;
+	    }
+	}
+
+      if (! elf_link_output_sym (finfo, name, &osym, isec))
+	return false;
+    }
+
+  /* Relocate the contents of each section.  */
+  sym_hashes = elf_sym_hashes (input_bfd);
+  for (o = input_bfd->sections; o != NULL; o = o->next)
+    {
+      bfd_byte *contents;
+
+      if (! o->linker_mark)
+	{
+	  /* This section was omitted from the link.  */
+	  continue;
+	}
+
+      if ((o->flags & SEC_HAS_CONTENTS) == 0
+	  || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0))
+	continue;
+
+      if ((o->flags & SEC_LINKER_CREATED) != 0)
+	{
+	  /* Section was created by elf_link_create_dynamic_sections
+	     or somesuch.  */
+	  continue;
+	}
+
+      /* Get the contents of the section.  They have been cached by a
+	 relaxation routine.  Note that o is a section in an input
+	 file, so the contents field will not have been set by any of
+	 the routines which work on output files.  */
+      if (elf_section_data (o)->this_hdr.contents != NULL)
+	contents = elf_section_data (o)->this_hdr.contents;
+      else
+	{
+	  contents = finfo->contents;
+	  if (! bfd_get_section_contents (input_bfd, o, contents,
+					  (file_ptr) 0, o->_raw_size))
+	    return false;
+	}
+
+      if ((o->flags & SEC_RELOC) != 0)
+	{
+	  Elf_Internal_Rela *internal_relocs;
+
+	  /* Get the swapped relocs.  */
+	  internal_relocs = (NAME(_bfd_elf,link_read_relocs)
+			     (input_bfd, o, finfo->external_relocs,
+			      finfo->internal_relocs, false));
+	  if (internal_relocs == NULL
+	      && o->reloc_count > 0)
+	    return false;
+
+	  /* Run through the relocs looking for any against symbols
+	     from discarded sections and section symbols from
+	     removed link-once sections.  Complain about relocs
+	     against discarded sections.  Zero relocs against removed
+	     link-once sections.  We should really complain if
+	     anything in the final link tries to use it, but
+	     DWARF-based exception handling might have an entry in
+	     .eh_frame to describe a routine in the linkonce section,
+	     and it turns out to be hard to remove the .eh_frame
+	     entry too.  FIXME.  */
+	  if (!finfo->info->relocateable
+	      && !elf_section_ignore_discarded_relocs (o))
+	    {
+	      Elf_Internal_Rela *rel, *relend;
+
+	      rel = internal_relocs;
+	      relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
+	      for ( ; rel < relend; rel++)
+		{
+		  unsigned long r_symndx = ELF_R_SYM (rel->r_info);
+
+		  if (r_symndx >= locsymcount
+		      || (elf_bad_symtab (input_bfd)
+			  && finfo->sections[r_symndx] == NULL))
+		    {
+		      struct elf_link_hash_entry *h;
+
+		      h = sym_hashes[r_symndx - extsymoff];
+		      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;
+
+		      /* Complain if the definition comes from a
+			 discarded section.  */
+		      if ((h->root.type == bfd_link_hash_defined
+			   || h->root.type == bfd_link_hash_defweak)
+			  && elf_discarded_section (h->root.u.def.section))
+			{
+			  if ((o->flags & SEC_DEBUGGING) != 0)
+			    {
+			      BFD_ASSERT (r_symndx != 0);
+			      memset (rel, 0, sizeof (*rel));
+			    }
+			  else
+			    {
+			      if (! ((*finfo->info->callbacks->undefined_symbol)
+				     (finfo->info, h->root.root.string,
+				      input_bfd, o, rel->r_offset,
+				      true)))
+				return false;
+			    }
+			}
+		    }
+		  else
+		    {
+		      asection *sec = finfo->sections[r_symndx];
+
+		      if (sec != NULL && elf_discarded_section (sec))
+			{
+			  if ((o->flags & SEC_DEBUGGING) != 0
+			      || (sec->flags & SEC_LINK_ONCE) != 0)
+			    {
+			      BFD_ASSERT (r_symndx != 0);
+			      rel->r_info
+				= ELF_R_INFO (0, ELF_R_TYPE (rel->r_info));
+			      rel->r_addend = 0;
+			    }
+			  else
+			    {
+			      boolean ok;
+			      const char *msg
+				= _("local symbols in discarded section %s");
+			      bfd_size_type amt
+				= strlen (sec->name) + strlen (msg) - 1;
+			      char *buf = (char *) bfd_malloc (amt);
+
+			      if (buf != NULL)
+				sprintf (buf, msg, sec->name);
+			      else
+				buf = (char *) sec->name;
+			      ok = (*finfo->info->callbacks
+				    ->undefined_symbol) (finfo->info, buf,
+							 input_bfd, o,
+							 rel->r_offset,
+							 true);
+			      if (buf != sec->name)
+				free (buf);
+			      if (!ok)
+				return false;
+			    }
+			}
+		    }
+		}
+	    }
+
+	  /* Relocate the section by invoking a back end routine.
+
+	     The back end routine is responsible for adjusting the
+	     section contents as necessary, and (if using Rela relocs
+	     and generating a relocateable output file) adjusting the
+	     reloc addend as necessary.
+
+	     The back end routine does not have to worry about setting
+	     the reloc address or the reloc symbol index.
+
+	     The back end routine is given a pointer to the swapped in
+	     internal symbols, and can access the hash table entries
+	     for the external symbols via elf_sym_hashes (input_bfd).
+
+	     When generating relocateable output, the back end routine
+	     must handle STB_LOCAL/STT_SECTION symbols specially.  The
+	     output symbol is going to be a section symbol
+	     corresponding to the output section, which will require
+	     the addend to be adjusted.  */
+
+	  if (! (*relocate_section) (output_bfd, finfo->info,
+				     input_bfd, o, contents,
+				     internal_relocs,
+				     isymbuf,
+				     finfo->sections))
+	    return false;
+
+	  if (emit_relocs)
+	    {
+	      Elf_Internal_Rela *irela;
+	      Elf_Internal_Rela *irelaend;
+	      struct elf_link_hash_entry **rel_hash;
+	      Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2;
+	      unsigned int next_erel;
+	      boolean (*reloc_emitter) PARAMS ((bfd *, asection *,
+						Elf_Internal_Shdr *,
+						Elf_Internal_Rela *));
+	      boolean rela_normal;
+
+	      input_rel_hdr = &elf_section_data (o)->rel_hdr;
+	      rela_normal = (bed->rela_normal
+			     && (input_rel_hdr->sh_entsize
+				 == sizeof (Elf_External_Rela)));
+
+	      /* Adjust the reloc addresses and symbol indices.  */
+
+	      irela = internal_relocs;
+	      irelaend = irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
+	      rel_hash = (elf_section_data (o->output_section)->rel_hashes
+			  + elf_section_data (o->output_section)->rel_count
+			  + elf_section_data (o->output_section)->rel_count2);
+	      for (next_erel = 0; irela < irelaend; irela++, next_erel++)
+		{
+		  unsigned long r_symndx;
+		  asection *sec;
+		  Elf_Internal_Sym sym;
+
+		  if (next_erel == bed->s->int_rels_per_ext_rel)
+		    {
+		      rel_hash++;
+		      next_erel = 0;
+		    }
+
+		  irela->r_offset += o->output_offset;
+
+		  /* Relocs in an executable have to be virtual addresses.  */
+		  if (!finfo->info->relocateable)
+		    irela->r_offset += o->output_section->vma;
+
+		  r_symndx = ELF_R_SYM (irela->r_info);
+
+		  if (r_symndx == 0)
+		    continue;
+
+		  if (r_symndx >= locsymcount
+		      || (elf_bad_symtab (input_bfd)
+			  && finfo->sections[r_symndx] == NULL))
+		    {
+		      struct elf_link_hash_entry *rh;
+		      unsigned long indx;
+
+		      /* This is a reloc against a global symbol.  We
+			 have not yet output all the local symbols, so
+			 we do not know the symbol index of any global
+			 symbol.  We set the rel_hash entry for this
+			 reloc to point to the global hash table entry
+			 for this symbol.  The symbol index is then
+			 set at the end of elf_bfd_final_link.  */
+		      indx = r_symndx - extsymoff;
+		      rh = elf_sym_hashes (input_bfd)[indx];
+		      while (rh->root.type == bfd_link_hash_indirect
+			     || rh->root.type == bfd_link_hash_warning)
+			rh = (struct elf_link_hash_entry *) rh->root.u.i.link;
+
+		      /* Setting the index to -2 tells
+			 elf_link_output_extsym that this symbol is
+			 used by a reloc.  */
+		      BFD_ASSERT (rh->indx < 0);
+		      rh->indx = -2;
+
+		      *rel_hash = rh;
+
+		      continue;
+		    }
+
+		  /* This is a reloc against a local symbol.  */
+
+		  *rel_hash = NULL;
+		  sym = isymbuf[r_symndx];
+		  sec = finfo->sections[r_symndx];
+		  if (ELF_ST_TYPE (sym.st_info) == STT_SECTION)
+		    {
+		      /* I suppose the backend ought to fill in the
+			 section of any STT_SECTION symbol against a
+			 processor specific section.  If we have
+			 discarded a section, the output_section will
+			 be the absolute section.  */
+		      if (bfd_is_abs_section (sec)
+			  || (sec != NULL
+			      && bfd_is_abs_section (sec->output_section)))
+			r_symndx = 0;
+		      else if (sec == NULL || sec->owner == NULL)
+			{
+			  bfd_set_error (bfd_error_bad_value);
+			  return false;
+			}
+		      else
+			{
+			  r_symndx = sec->output_section->target_index;
+			  BFD_ASSERT (r_symndx != 0);
+			}
+
+		      /* Adjust the addend according to where the
+			 section winds up in the output section.  */
+		      if (rela_normal)
+			irela->r_addend += sec->output_offset;
+		    }
+		  else
+		    {
+		      if (finfo->indices[r_symndx] == -1)
+			{
+			  unsigned long shlink;
+			  const char *name;
+			  asection *osec;
+
+			  if (finfo->info->strip == strip_all)
+			    {
+			      /* You can't do ld -r -s.  */
+			      bfd_set_error (bfd_error_invalid_operation);
+			      return false;
+			    }
+
+			  /* This symbol was skipped earlier, but
+			     since it is needed by a reloc, we
+			     must output it now.  */
+			  shlink = symtab_hdr->sh_link;
+			  name = (bfd_elf_string_from_elf_section
+				  (input_bfd, shlink, sym.st_name));
+			  if (name == NULL)
+			    return false;
+
+			  osec = sec->output_section;
+			  sym.st_shndx =
+			    _bfd_elf_section_from_bfd_section (output_bfd,
+							       osec);
+			  if (sym.st_shndx == SHN_BAD)
+			    return false;
+
+			  sym.st_value += sec->output_offset;
+#if 0
+			  if (! finfo->info->relocateable)
+			    {
+			      sym.st_value += osec->vma;
+			      if (ELF_ST_TYPE (sym.st_info) == STT_TLS)
+				{
+				  /* STT_TLS symbols are relative to PT_TLS
+				     segment base.  */
+				  BFD_ASSERT (finfo->first_tls_sec != NULL);
+				  sym.st_value -= finfo->first_tls_sec->vma;
+				}
+			    }
+#endif
+
+			  finfo->indices[r_symndx]
+			    = bfd_get_symcount (output_bfd);
+
+			  if (! elf_link_output_sym (finfo, name, &sym, sec))
+			    return false;
+			}
+
+		      r_symndx = finfo->indices[r_symndx];
+		    }
+
+		  irela->r_info = ELF_R_INFO (r_symndx,
+					      ELF_R_TYPE (irela->r_info));
+		}
+
+	      /* Swap out the relocs.  */
+	      if (bed->elf_backend_emit_relocs
+		  && !(finfo->info->relocateable
+		       || finfo->info->emitrelocations))
+		reloc_emitter = bed->elf_backend_emit_relocs;
+	      else
+		reloc_emitter = elf_link_output_relocs;
+
+	      if (input_rel_hdr->sh_size != 0
+		  && ! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
+					 internal_relocs))
+		return false;
+
+	      input_rel_hdr2 = elf_section_data (o)->rel_hdr2;
+	      if (input_rel_hdr2 && input_rel_hdr2->sh_size != 0)
+		{
+		  internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr)
+				      * bed->s->int_rels_per_ext_rel);
+		  if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr2,
+					  internal_relocs))
+		    return false;
+		}
+	    }
+	}
+
+      /* Write out the modified section contents.  */
+      if (bed->elf_backend_write_section
+	  && (*bed->elf_backend_write_section) (output_bfd, o, contents))
+	{
+	  /* Section written out.  */
+	}
+      else switch (elf_section_data (o)->sec_info_type)
+	{
+	case ELF_INFO_TYPE_STABS:
+	  if (! (_bfd_write_section_stabs
+		 (output_bfd,
+		  &elf_hash_table (finfo->info)->stab_info,
+		  o, &elf_section_data (o)->sec_info, contents)))
+	    return false;
+	  break;
+	case ELF_INFO_TYPE_MERGE:
+	  if (! (_bfd_write_merged_section
+		 (output_bfd, o, elf_section_data (o)->sec_info)))
+	    return false;
+	  break;
+	case ELF_INFO_TYPE_EH_FRAME:
+	  {
+	    asection *ehdrsec;
+
+	    ehdrsec
+	      = bfd_get_section_by_name (elf_hash_table (finfo->info)->dynobj,
+					 ".eh_frame_hdr");
+	    if (! (_bfd_elf_write_section_eh_frame (output_bfd, o, ehdrsec,
+						    contents)))
+	      return false;
+	  }
+	  break;
+	default:
+	  {
+	    bfd_size_type sec_size;
+
+	    sec_size = (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size);
+	    if (! (o->flags & SEC_EXCLUDE)
+		&& ! bfd_set_section_contents (output_bfd, o->output_section,
+					       contents,
+					       (file_ptr) o->output_offset,
+					       sec_size))
+	      return false;
+	  }
+	  break;
+	}
+    }
+
+  return true;
+}
+
+/* Generate a reloc when linking an ELF file.  This is a reloc
+   requested by the linker, and does come from any input file.  This
+   is used to build constructor and destructor tables when linking
+   with -Ur.  */
+
+static boolean
+elf_reloc_link_order (output_bfd, info, output_section, link_order)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     asection *output_section;
+     struct bfd_link_order *link_order;
+{
+  reloc_howto_type *howto;
+  long indx;
+  bfd_vma offset;
+  bfd_vma addend;
+  struct elf_link_hash_entry **rel_hash_ptr;
+  Elf_Internal_Shdr *rel_hdr;
+  struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+
+  howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
+  if (howto == NULL)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      return false;
+    }
+
+  addend = link_order->u.reloc.p->addend;
+
+  /* Figure out the symbol index.  */
+  rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
+		  + elf_section_data (output_section)->rel_count
+		  + elf_section_data (output_section)->rel_count2);
+  if (link_order->type == bfd_section_reloc_link_order)
+    {
+      indx = link_order->u.reloc.p->u.section->target_index;
+      BFD_ASSERT (indx != 0);
+      *rel_hash_ptr = NULL;
+    }
+  else
+    {
+      struct elf_link_hash_entry *h;
+
+      /* Treat a reloc against a defined symbol as though it were
+	 actually against the section.  */
+      h = ((struct elf_link_hash_entry *)
+	   bfd_wrapped_link_hash_lookup (output_bfd, info,
+					 link_order->u.reloc.p->u.name,
+					 false, false, true));
+      if (h != NULL
+	  && (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak))
+	{
+	  asection *section;
+
+	  section = h->root.u.def.section;
+	  indx = section->output_section->target_index;
+	  *rel_hash_ptr = NULL;
+	  /* It seems that we ought to add the symbol value to the
+	     addend here, but in practice it has already been added
+	     because it was passed to constructor_callback.  */
+	  addend += section->output_section->vma + section->output_offset;
+	}
+      else if (h != NULL)
+	{
+	  /* Setting the index to -2 tells elf_link_output_extsym that
+	     this symbol is used by a reloc.  */
+	  h->indx = -2;
+	  *rel_hash_ptr = h;
+	  indx = 0;
+	}
+      else
+	{
+	  if (! ((*info->callbacks->unattached_reloc)
+		 (info, link_order->u.reloc.p->u.name, (bfd *) NULL,
+		  (asection *) NULL, (bfd_vma) 0)))
+	    return false;
+	  indx = 0;
+	}
+    }
+
+  /* If this is an inplace reloc, we must write the addend into the
+     object file.  */
+  if (howto->partial_inplace && addend != 0)
+    {
+      bfd_size_type size;
+      bfd_reloc_status_type rstat;
+      bfd_byte *buf;
+      boolean ok;
+      const char *sym_name;
+
+      size = bfd_get_reloc_size (howto);
+      buf = (bfd_byte *) bfd_zmalloc (size);
+      if (buf == (bfd_byte *) NULL)
+	return false;
+      rstat = _bfd_relocate_contents (howto, output_bfd, (bfd_vma) addend, buf);
+      switch (rstat)
+	{
+	case bfd_reloc_ok:
+	  break;
+
+	default:
+	case bfd_reloc_outofrange:
+	  abort ();
+
+	case bfd_reloc_overflow:
+	  if (link_order->type == bfd_section_reloc_link_order)
+	    sym_name = bfd_section_name (output_bfd,
+					 link_order->u.reloc.p->u.section);
+	  else
+	    sym_name = link_order->u.reloc.p->u.name;
+	  if (! ((*info->callbacks->reloc_overflow)
+		 (info, sym_name, howto->name, addend,
+		  (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+	    {
+	      free (buf);
+	      return false;
+	    }
+	  break;
+	}
+      ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf,
+				     (file_ptr) link_order->offset, size);
+      free (buf);
+      if (! ok)
+	return false;
+    }
+
+  /* The address of a reloc is relative to the section in a
+     relocateable file, and is a virtual address in an executable
+     file.  */
+  offset = link_order->offset;
+  if (! info->relocateable)
+    offset += output_section->vma;
+
+  rel_hdr = &elf_section_data (output_section)->rel_hdr;
+
+  if (rel_hdr->sh_type == SHT_REL)
+    {
+      bfd_size_type size;
+      Elf_Internal_Rel *irel;
+      Elf_External_Rel *erel;
+      unsigned int i;
+
+      size = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rel);
+      irel = (Elf_Internal_Rel *) bfd_zmalloc (size);
+      if (irel == NULL)
+	return false;
+
+      for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
+	irel[i].r_offset = offset;
+      irel[0].r_info = ELF_R_INFO (indx, howto->type);
+
+      erel = ((Elf_External_Rel *) rel_hdr->contents
+	      + elf_section_data (output_section)->rel_count);
+
+      if (bed->s->swap_reloc_out)
+	(*bed->s->swap_reloc_out) (output_bfd, irel, (bfd_byte *) erel);
+      else
+	elf_swap_reloc_out (output_bfd, irel, erel);
+
+      free (irel);
+    }
+  else
+    {
+      bfd_size_type size;
+      Elf_Internal_Rela *irela;
+      Elf_External_Rela *erela;
+      unsigned int i;
+
+      size = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela);
+      irela = (Elf_Internal_Rela *) bfd_zmalloc (size);
+      if (irela == NULL)
+	return false;
+
+      for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
+	irela[i].r_offset = offset;
+      irela[0].r_info = ELF_R_INFO (indx, howto->type);
+      irela[0].r_addend = addend;
+
+      erela = ((Elf_External_Rela *) rel_hdr->contents
+	       + elf_section_data (output_section)->rel_count);
+
+      if (bed->s->swap_reloca_out)
+	(*bed->s->swap_reloca_out) (output_bfd, irela, (bfd_byte *) erela);
+      else
+	elf_swap_reloca_out (output_bfd, irela, erela);
+    }
+
+  ++elf_section_data (output_section)->rel_count;
+
+  return true;
+}
+
+static boolean
+elf_section_ignore_discarded_relocs (sec)
+     asection *sec;
+{
+  struct elf_backend_data *bed;
+
+  switch (elf_section_data (sec)->sec_info_type)
+    {
+    case ELF_INFO_TYPE_STABS:
+    case ELF_INFO_TYPE_EH_FRAME:
+      return true;
+    default:
+      break;
+    }
+
+  bed = get_elf_backend_data (sec->owner);
+  if (bed->elf_backend_ignore_discarded_relocs != NULL
+      && (*bed->elf_backend_ignore_discarded_relocs) (sec))
+    return true;
+
+  return false;
+}
+
+#define TARGET_BIG_SYM		bfd_elf32_morphos_vec
+#define TARGET_BIG_NAME		"elf32-morphos"
+#define ELF_ARCH		bfd_arch_powerpc
+#define ELF_MACHINE_CODE	EM_PPC
+#define ELF_MAXPAGESIZE		0x10000
+#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_got_symbol_offset	4
+#define elf_backend_can_gc_sections	1
+#define elf_backend_can_refcount	1
+#define elf_backend_got_header_size	12
+#define elf_backend_plt_header_size	PLT_INITIAL_ENTRY_SIZE
+#define elf_backend_rela_normal		1
+
+#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_set_private_flags		ppc_elf_set_private_flags
+/*#define bfd_elf32_bfd_final_link		_bfd_elf32_gc_common_final_link*/
+#define bfd_elf32_bfd_final_link                ppc_elf_final_link
+
+#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_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_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_modify_segment_map
+#define elf_backend_grok_prstatus		ppc_elf_grok_prstatus
+#define elf_backend_grok_psinfo			ppc_elf_grok_psinfo
+#define elf_backend_reloc_type_class		ppc_elf_reloc_type_class
+
+#include "elf32-target.h"
diff -ru --new-file a/bfd/hosts/amigaos.h b/bfd/hosts/amigaos.h
--- a/bfd/hosts/amigaos.h	1970-01-01 03:00:00.000000000 +0300
+++ b/bfd/hosts/amigaos.h	2021-02-01 23:12:49.125654100 +0300
@@ -0,0 +1,5 @@
+/* Host configuration for AmigaOS */
+#ifndef hosts_amigaos_h
+#define hosts_amigaos_h
+#include "hosts/std-host.h"
+#endif /* hosts_amigaos_h */
diff -ru --new-file a/bfd/hosts/morphos.h b/bfd/hosts/morphos.h
--- a/bfd/hosts/morphos.h	1970-01-01 03:00:00.000000000 +0300
+++ b/bfd/hosts/morphos.h	2021-02-01 23:12:49.126657000 +0300
@@ -0,0 +1,5 @@
+/* Host configuration for MorphOS */
+#ifndef hosts_morphos_h
+#define hosts_morphos_h
+#include "hosts/std-host.h"
+#endif /* hosts_morphos_h */
diff -ru --new-file a/bfd/libamiga.h b/bfd/libamiga.h
--- a/bfd/libamiga.h	1970-01-01 03:00:00.000000000 +0300
+++ b/bfd/libamiga.h	2021-02-01 23:12:49.127659400 +0300
@@ -0,0 +1,187 @@
+/* BFD back-end for Commodore-Amiga AmigaOS binaries. Data structures.
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998
+   Free Software Foundation, Inc.
+   Contributed by Leonard Norrgard.
+   Extended by Stephan Thesing 11/1994.
+
+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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Hunk ID numbers.  */
+
+#define HUNK_UNIT		999
+#define HUNK_NAME		1000
+#define HUNK_CODE		1001
+#define HUNK_DATA		1002
+#define HUNK_BSS		1003
+#define HUNK_RELOC32		1004
+#define HUNK_ABSRELOC32		HUNK_RELOC32
+#define HUNK_RELOC16		1005
+#define HUNK_RELRELOC16		HUNK_RELOC16
+#define HUNK_RELOC8		1006
+#define HUNK_RELRELOC8		HUNK_RELOC8
+#define HUNK_EXT		1007
+#define HUNK_SYMBOL		1008
+#define HUNK_DEBUG		1009
+#define HUNK_END		1010
+#define HUNK_HEADER		1011
+#define HUNK_OVERLAY		1013
+#define HUNK_BREAK		1014
+#define HUNK_DREL32		1015
+#define HUNK_DREL16		1016
+#define HUNK_DREL8		1017
+#define HUNK_LIB		1018
+#define HUNK_INDEX		1019
+#define HUNK_RELOC32SHORT	1020
+#define HUNK_RELRELOC32		1021
+#define HUNK_ABSRELOC16		1022
+/* EHF extensions */
+#define HUNK_PPC_CODE		1257
+#define HUNK_RELRELOC26		1260
+
+/* The hunk ID part.  */
+
+#define HUNK_VALUE(hunk_id)	((hunk_id) & 0x3fffffff)
+
+/* Attributes of a hunk.  */
+
+#define HUNK_ATTRIBUTE(hunk_id)	((hunk_id) >> 30)
+#define HUNK_ATTR_CHIP 		0x01	/* hunk content must go into chip ram */
+#define HUNK_ATTR_FAST		0x02	/* fast */
+#define HUNK_ATTR_FOLLOWS	0x03	/* mem id follows */
+
+/* HUNK_EXT subtypes.  */
+
+#define EXT_SYMB		0
+#define EXT_DEF			1
+#define EXT_ABS			2
+#define EXT_RES			3
+#define EXT_REF32		129
+#define EXT_ABSREF32		EXT_REF32
+#define EXT_COMMON		130
+#define EXT_ABSCOMMON		EXT_COMMON
+#define EXT_REF16		131
+#define EXT_RELREF16		EXT_REF16
+#define EXT_REF8		132
+#define EXT_RELREF8		EXT_REF8
+#define EXT_DEXT32		133
+#define EXT_DEXT16		134
+#define EXT_DEXT8		135
+#define EXT_RELREF32		136
+#define EXT_RELCOMMON		137
+#define EXT_ABSREF16		138
+#define EXT_ABSREF8		139
+/* VBCC extensions */
+#define EXT_DEXT32COMMON	208
+#define EXT_DEXT16COMMON	209
+#define EXT_DEXT8COMMON		210
+/* EHF extensions */
+#define EXT_RELREF26		229
+
+/* HOWTO types almost matching aoutx.h/howto_table_std.  */
+
+enum {
+  H_ABS8=0,H_ABS16,H_ABS32,H_ABS32SHORT,H_PC8,H_PC16,H_PC32,H_PC26,H_SD8,H_SD16,H_SD32
+};
+
+/* Various structures.  */
+
+typedef struct amiga_reloc {
+  arelent relent;
+  struct amiga_reloc *next;
+  asymbol *symbol;
+} amiga_reloc_type;
+
+/* Structure layout *must* match libaout.h/struct aout_symbol.  */
+
+typedef struct amiga_symbol {
+  asymbol symbol;
+  short desc;
+  char other;
+  unsigned char type;
+  /* amiga data */
+  unsigned long index,refnum;
+} amiga_symbol_type;
+
+/* We take the address of the first element of an asymbol to ensure that the
+   macro is only ever applied to an asymbol.  */
+#define amiga_symbol(asymbol) ((amiga_symbol_type *)(&(asymbol)->the_bfd))
+
+typedef struct raw_reloc {
+  unsigned long num,pos;
+  struct raw_reloc *next;
+} raw_reloc_type;
+
+typedef struct amiga_per_section {
+  amiga_reloc_type *reloc_tail; /* last reloc, first is in section->relocation */
+  int attribute; /* Memory type required by this section */
+  unsigned long disk_size; /* Section size on disk, _raw_size may be larger than this */
+  amiga_symbol_type *amiga_symbols; /* the symbols for this section */
+  unsigned long hunk_ext_pos; /* offset of hunk_ext in the bfd file */
+  unsigned long hunk_symbol_pos; /* offset of hunk_symbol in the bfd file */
+  raw_reloc_type *relocs;
+} amiga_per_section_type;
+
+#define amiga_per_section(x) ((amiga_per_section_type *)((x)->used_by_bfd))
+
+/* Structure layout *must* match libaout.h/struct aoutdata.  */
+
+struct amiga_data {
+  char *dummy[2];
+  sec_ptr textsec;
+  sec_ptr datasec;
+  sec_ptr bsssec;
+  file_ptr sym_filepos;
+  file_ptr str_filepos;
+  /* rest intentionally omitted */
+};
+
+typedef struct amiga_data_struct {
+  struct amiga_data a;
+  unsigned long symtab_size;
+  unsigned long stringtab_size;
+  amiga_symbol_type *symbols;
+  bfd_boolean IsLoadFile; /* If true, this is a load file (for output bfd only) */
+  unsigned int nb_hunks;
+  /* The next two fields are set at final_link time (for the output bfd only) */
+  bfd_boolean baserel;/* true if there is ___init_a4 in the global hash table */
+  bfd_vma a4init;     /* cache the value for efficiency */
+} amiga_data_type;
+
+#define adata(bfd)	((bfd)->tdata.amiga_data->a)
+#define AMIGA_DATA(bfd)	((bfd)->tdata.amiga_data)
+
+#define HUNKB_ADVISORY	29
+#define HUNKB_CHIP	30
+#define HUNKB_FAST	31
+#define HUNKF_ADVISORY	(1L << HUNKB_ADVISORY)
+#define HUNKF_CHIP	(1L << HUNKB_CHIP)
+#define HUNKF_FAST	(1L << HUNKB_FAST)
+
+#ifndef MEMF_ANY
+#define MEMF_ANY	(0L)
+#define MEMF_PUBLIC	(1L << 0)
+#define MEMF_CHIP	(1L << 1)
+#define MEMF_FAST	(1L << 2)
+#define MEMF_LOCAL	(1L << 8)
+#define MEMF_24BITDMA	(1L << 9)
+#define MEMF_KICK	(1L << 10)
+#define MEMF_CLEAR	(1L << 16)
+#define MEMF_LARGEST	(1L << 17)
+#define MEMF_REVERSE	(1L << 18)
+#define MEMF_TOTAL	(1L << 19)
+#define MEMF_NO_EXPUNGE	(1L << 31)
+#endif /* MEMF_ANY */
diff -ru --new-file a/bfd/libbfd.h b/bfd/libbfd.h
--- a/bfd/libbfd.h	2013-11-18 12:40:15.000000000 +0400
+++ b/bfd/libbfd.h	2022-02-16 23:15:26.280733200 +0300
@@ -1359,6 +1359,10 @@
   "BFD_RELOC_PPC_EMB_RELST_HA",
   "BFD_RELOC_PPC_EMB_BIT_FLD",
   "BFD_RELOC_PPC_EMB_RELSDA",
+  "BFD_RELOC_PPC_MORPHOS_DREL",
+  "BFD_RELOC_PPC_MORPHOS_DREL_LO",
+  "BFD_RELOC_PPC_MORPHOS_DREL_HI",
+  "BFD_RELOC_PPC_MORPHOS_DREL_HA",
   "BFD_RELOC_PPC_VLE_REL8",
   "BFD_RELOC_PPC_VLE_REL15",
   "BFD_RELOC_PPC_VLE_REL24",
@@ -1443,6 +1447,10 @@
   "BFD_RELOC_PPC64_DTPREL16_HIGHERA",
   "BFD_RELOC_PPC64_DTPREL16_HIGHEST",
   "BFD_RELOC_PPC64_DTPREL16_HIGHESTA",
+  "BFD_RELOC_PPC_AMIGAOS_BREL",
+  "BFD_RELOC_PPC_AMIGAOS_BREL_LO",
+  "BFD_RELOC_PPC_AMIGAOS_BREL_HI",
+  "BFD_RELOC_PPC_AMIGAOS_BREL_HA",
   "BFD_RELOC_PPC64_TPREL16_HIGH",
   "BFD_RELOC_PPC64_TPREL16_HIGHA",
   "BFD_RELOC_PPC64_DTPREL16_HIGH",
diff -ru --new-file a/bfd/linker.c b/bfd/linker.c
--- a/bfd/linker.c	2013-11-04 19:33:37.000000000 +0400
+++ b/bfd/linker.c	2022-02-16 23:18:10.864019400 +0300
@@ -433,7 +433,8 @@
   (bfd *, size_t *psymalloc, asymbol *);
 static bfd_boolean default_data_link_order
   (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *);
-static bfd_boolean default_indirect_link_order
+/*Amiga hack - used in amigaoslink.c so must be global */
+/*static*/ bfd_boolean default_indirect_link_order
   (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *,
    bfd_boolean);
 
@@ -1297,6 +1298,13 @@
 	  h->u.c.size = size;
 
 	  power = bfd_log2 (size);
+	  /* For the amiga, we don't want an alignment bigger than 2**2.
+	     Doing this here is horrible kludgy, but IMHO the maximal
+	     power alignment really should be target-dependant so that
+	     we wouldn't have to do this -- daniel */
+	  if (info->output_bfd->xvec->flavour == bfd_target_amiga_flavour
+	      && power > 2)
+	    power = 2;
 	  if (power > 4)
 	    power = 4;
 	  h->u.c.p->alignment_power = power;
@@ -1749,6 +1757,13 @@
 	    unsigned int power;
 
 	    power = bfd_log2 (value);
+	    /* For the amiga, we don't want an alignment bigger than 2**2.
+	       Doing this here is horrible kludgy, but IMHO the maximal
+	       power alignment really should be target-dependant so that
+	       we wouldn't have to do this -- daniel */
+	    if (info->output_bfd->xvec->flavour == bfd_target_amiga_flavour
+		&& power > 2)
+	      power = 2;
 	    if (power > 4)
 	      power = 4;
 	    h->u.c.p->alignment_power = power;
@@ -1802,6 +1817,13 @@
 	      /* Select a default alignment based on the size.  This may
 		 be overridden by the caller.  */
 	      power = bfd_log2 (value);
+	      /* For the amiga, we don't want an alignment bigger than 2**2.
+		 Doing this here is horrible kludgy, but IMHO the maximal
+		 power alignment really should be target-dependant so that
+		 we wouldn't have to do this -- daniel */
+	      if (info->output_bfd->xvec->flavour == bfd_target_amiga_flavour
+		  && power > 2)
+		power = 2;
 	      if (power > 4)
 		power = 4;
 	      h->u.c.p->alignment_power = power;
@@ -2712,7 +2734,7 @@
 
 /* Default routine to handle a bfd_indirect_link_order.  */
 
-static bfd_boolean
+/*static*/ bfd_boolean
 default_indirect_link_order (bfd *output_bfd,
 			     struct bfd_link_info *info,
 			     asection *output_section,
diff -ru --new-file a/bfd/Makefile.am b/bfd/Makefile.am
--- a/bfd/Makefile.am	2013-12-02 13:30:28.000000000 +0400
+++ b/bfd/Makefile.am	2022-02-16 22:21:27.824518400 +0300
@@ -258,7 +258,10 @@
 # The .o files needed by all of the 32 bit vectors that are configured into
 # target_vector in targets.c if configured with --enable-targets=all.
 BFD32_BACKENDS = \
+	amigaos.lo \
+	amigaoslink.lo \
 	aout-adobe.lo \
+	aout-amiga.lo \
 	aout-arm.lo \
 	aout-cris.lo \
 	aout-ns32k.lo \
@@ -313,6 +316,7 @@
 	elf32-am33lin.lo \
 	elf32-arc.lo \
 	elf32-arm.lo \
+	elf32-amigaos.lo \
 	elf32-avr.lo \
 	elf32-bfin.lo \
 	elf32-cr16.lo \
@@ -446,7 +450,10 @@
 	xtensa-modules.lo
 
 BFD32_BACKENDS_CFILES = \
+	amigaos.c \
+	amigaoslink.c \
 	aout-adobe.c \
+	aout-amiga.c \
 	aout-arm.c \
 	aout-cris.c \
 	aout-ns32k.c \
@@ -501,6 +508,7 @@
 	elf32-am33lin.c \
 	elf32-arc.c \
 	elf32-arm.c \
+	elf32-amigaos.c \
 	elf32-avr.c \
 	elf32-bfin.c \
 	elf32-cr16.c \
@@ -649,6 +657,7 @@
 	demo64.lo \
 	elf32-ia64.lo \
 	elf32-mips.lo \
+	elf32-morphos.lo \
 	elf32-score.lo \
 	elf32-score7.lo \
 	elf64-alpha.lo \
@@ -687,6 +696,7 @@
 	coff64-rs6000.c \
 	demo64.c \
 	elf32-mips.c \
+	elf32-morphos.c \
 	elf32-score.c \
 	elf32-score7.c \
 	elf64-alpha.c \
@@ -776,7 +786,7 @@
 	aout-target.h aoutf1.h aoutx.h coffcode.h coffswap.h ecoffswap.h \
 	elf-bfd.h elf-hppa.h elf-linux-psinfo.h elf32-hppa.h \
 	elf64-hppa.h elfcode.h elfcore.h \
-	freebsd.h genlink.h go32stub.h \
+	freebsd.h genlink.h go32stub.h libamiga.h \
 	libaout.h libbfd.h libcoff.h libecoff.h libhppa.h libieee.h \
 	libnlm.h liboasys.h libpei.h libxcoff.h mach-o.h \
 	netbsd.h nlm-target.h nlmcode.h nlmswap.h ns32k.h \
@@ -1056,9 +1066,3 @@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $< $(NO_WERROR)
 
-coff-tic54x.lo: coff-tic54x.c
-@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR)
-@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $< $(NO_WERROR)
diff -ru --new-file a/bfd/Makefile.in b/bfd/Makefile.in
--- a/bfd/Makefile.in	2013-12-02 13:30:30.000000000 +0400
+++ b/bfd/Makefile.in	2022-02-16 22:25:30.312033500 +0300
@@ -560,7 +560,10 @@
 # The .o files needed by all of the 32 bit vectors that are configured into
 # target_vector in targets.c if configured with --enable-targets=all.
 BFD32_BACKENDS = \
-	aout-adobe.lo \
+	amigaos.lo \
+	amigaoslink.lo \
+ 	aout-adobe.lo \
+	aout-amiga.lo \
 	aout-arm.lo \
 	aout-cris.lo \
 	aout-ns32k.lo \
@@ -615,6 +618,7 @@
 	elf32-am33lin.lo \
 	elf32-arc.lo \
 	elf32-arm.lo \
+	elf32-amigaos.lo \
 	elf32-avr.lo \
 	elf32-bfin.lo \
 	elf32-cr16.lo \
@@ -748,7 +752,10 @@
 	xtensa-modules.lo
 
 BFD32_BACKENDS_CFILES = \
-	aout-adobe.c \
+	amigaos.c \
+	amigaoslink.c \
+ 	aout-adobe.c \
+	aout-amiga.c \
 	aout-arm.c \
 	aout-cris.c \
 	aout-ns32k.c \
@@ -803,6 +810,7 @@
 	elf32-am33lin.c \
 	elf32-arc.c \
 	elf32-arm.c \
+	elf32-amigaos.c \
 	elf32-avr.c \
 	elf32-bfin.c \
 	elf32-cr16.c \
@@ -952,6 +960,7 @@
 	demo64.lo \
 	elf32-ia64.lo \
 	elf32-mips.lo \
+	elf32-morphos.lo \
 	elf32-score.lo \
 	elf32-score7.lo \
 	elf64-alpha.lo \
@@ -990,6 +999,7 @@
 	coff64-rs6000.c \
 	demo64.c \
 	elf32-mips.c \
+	elf32-morphos.c \
 	elf32-score.c \
 	elf32-score7.c \
 	elf64-alpha.c \
@@ -1079,7 +1089,7 @@
 	aout-target.h aoutf1.h aoutx.h coffcode.h coffswap.h ecoffswap.h \
 	elf-bfd.h elf-hppa.h elf-linux-psinfo.h elf32-hppa.h \
 	elf64-hppa.h elfcode.h elfcore.h \
-	freebsd.h genlink.h go32stub.h \
+	freebsd.h genlink.h go32stub.h libamiga.h \
 	libaout.h libbfd.h libcoff.h libecoff.h libhppa.h libieee.h \
 	libnlm.h liboasys.h libpei.h libxcoff.h mach-o.h \
 	netbsd.h nlm-target.h nlmcode.h nlmswap.h ns32k.h \
@@ -1248,7 +1258,10 @@
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix386-core.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix5ppc-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amigaos.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amigaoslink.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-adobe.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-amiga.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-arm.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-cris.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-ns32k.Plo@am__quote@
@@ -1402,6 +1415,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-aarch64.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-am33lin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-amigaos.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-arc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-arm.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-avr.Plo@am__quote@
@@ -1439,6 +1453,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-metag.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-microblaze.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mips.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-morphos.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-moxie.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-msp430.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mt.Plo@am__quote@
@@ -2114,13 +2129,6 @@
 @am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR)
 @am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $< $(NO_WERROR)
-
-coff-tic54x.lo: coff-tic54x.c
-@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR)
-@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $< $(NO_WERROR)
 
diff -ru --new-file a/bfd/reloc.c b/bfd/reloc.c
--- a/bfd/reloc.c	2013-11-18 12:40:15.000000000 +0400
+++ b/bfd/reloc.c	2022-02-16 23:20:04.832771200 +0300
@@ -2816,6 +2816,14 @@
 ENUMX
   BFD_RELOC_PPC_EMB_RELSDA
 ENUMX
+  BFD_RELOC_PPC_MORPHOS_DREL
+ENUMX
+  BFD_RELOC_PPC_MORPHOS_DREL_LO
+ENUMX
+  BFD_RELOC_PPC_MORPHOS_DREL_HI
+ENUMX
+  BFD_RELOC_PPC_MORPHOS_DREL_HA
+ENUMX
   BFD_RELOC_PPC_VLE_REL8
 ENUMX
   BFD_RELOC_PPC_VLE_REL15
@@ -2998,6 +3006,17 @@
   PowerPC and PowerPC64 thread-local storage relocations.
 
 ENUM
+  BFD_RELOC_PPC_AMIGAOS_BREL
+ENUMX
+  BFD_RELOC_PPC_AMIGAOS_BREL_LO
+ENUMX
+  BFD_RELOC_PPC_AMIGAOS_BREL_HI
+ENUMX
+  BFD_RELOC_PPC_AMIGAOS_BREL_HA
+ENUMDOC
+  AmigaOS4 PowerPC specific base-relative relocations.
+
+ENUM
   BFD_RELOC_I370_D12
 ENUMDOC
   IBM 370/390 relocations
diff -ru --new-file a/bfd/targets.c b/bfd/targets.c
--- a/bfd/targets.c	2013-11-04 19:33:37.000000000 +0400
+++ b/bfd/targets.c	2022-02-16 23:22:50.528420600 +0300
@@ -145,6 +145,7 @@
 .enum bfd_flavour
 .{
 .  bfd_target_unknown_flavour,
+.  bfd_target_amiga_flavour,
 .  bfd_target_aout_flavour,
 .  bfd_target_coff_flavour,
 .  bfd_target_ecoff_flavour,
@@ -569,6 +570,8 @@
    we can't intermix extern's and initializers.  */
 extern const bfd_target a_out_adobe_vec;
 extern const bfd_target aix5coff64_vec;
+extern const bfd_target amiga_vec;
+extern const bfd_target aout_amiga_vec;
 extern const bfd_target aout0_big_vec;
 extern const bfd_target aout_arm_big_vec;
 extern const bfd_target aout_arm_little_vec;
@@ -593,6 +596,7 @@
 extern const bfd_target b_out_vec_big_host;
 extern const bfd_target b_out_vec_little_host;
 extern const bfd_target bfd_pei_ia64_vec;
+extern const bfd_target bfd_elf32_amigaos_vec;
 extern const bfd_target bfd_elf32_avr_vec;
 extern const bfd_target bfd_elf32_bfin_vec;
 extern const bfd_target bfd_elf32_bfinfdpic_vec;
@@ -627,6 +631,7 @@
 extern const bfd_target bfd_elf32_i386_sol2_vec;
 extern const bfd_target bfd_elf32_i386_vxworks_vec;
 extern const bfd_target bfd_elf32_i386_vec;
+extern const bfd_target bfd_elf32_i386be_amithlon_vec;
 extern const bfd_target bfd_elf32_i860_little_vec;
 extern const bfd_target bfd_elf32_i860_vec;
 extern const bfd_target bfd_elf32_i960_vec;
@@ -664,6 +669,7 @@
 extern const bfd_target bfd_elf32_microblaze_vec;
 extern const bfd_target bfd_elf32_mn10200_vec;
 extern const bfd_target bfd_elf32_mn10300_vec;
+extern const bfd_target bfd_elf32_morphos_vec;
 extern const bfd_target bfd_elf32_mt_vec;
 extern const bfd_target bfd_elf32_msp430_vec;
 extern const bfd_target bfd_elf32_msp430_ti_vec;
@@ -939,6 +945,8 @@
 #ifdef BFD64
 	&aix5coff64_vec,
 #endif
+	&amiga_vec,
+	&aout_amiga_vec,
 	&aout0_big_vec,
 #if 0
 	/* We have no way of distinguishing these from other a.out variants.  */
@@ -971,6 +979,7 @@
 #ifdef BFD64
 	&bfd_pei_ia64_vec,
 #endif
+	&bfd_elf32_amigaos_vec,
 	&bfd_elf32_avr_vec,
 	&bfd_elf32_bfin_vec,
 	&bfd_elf32_bfinfdpic_vec,
@@ -1011,6 +1020,7 @@
 	&bfd_elf32_i386_sol2_vec,
 	&bfd_elf32_i386_vxworks_vec,
 	&bfd_elf32_i386_vec,
+	&bfd_elf32_i386be_amithlon_vec,
 	&bfd_elf32_i860_little_vec,
 	&bfd_elf32_i860_vec,
 	&bfd_elf32_i960_vec,
@@ -1050,6 +1060,7 @@
 	&bfd_elf32_microblaze_vec,
 	&bfd_elf32_mn10200_vec,
 	&bfd_elf32_mn10300_vec,
+	&bfd_elf32_morphos_vec,
 	&bfd_elf32_mt_vec,
 	&bfd_elf32_msp430_vec,
 	&bfd_elf32_msp430_ti_vec,
diff -ru --new-file a/binutils/objcopy.c b/binutils/objcopy.c
--- a/binutils/objcopy.c	2013-11-04 19:33:37.000000000 +0400
+++ b/binutils/objcopy.c	2022-02-16 23:28:26.606291400 +0300
@@ -1177,6 +1177,11 @@
       bfd_boolean add_leading_char;
 
       undefined = bfd_is_und_section (bfd_get_section (sym));
+	  
+      if (strip_symbols == STRIP_ALL && undefined)
+        {
+          add_specific_symbol(name, keep_specific_htab);
+        }
 
       if (redefine_sym_list)
 	{
@@ -1239,7 +1244,12 @@
 	}
 
       if (strip_symbols == STRIP_ALL)
-	keep = FALSE;
+      {
+        if (strcmp(name, "_start") == 0 || strcmp(name, "__amigaos4__") == 0 || strcmp(name, "_SDA_BASE_") == 0)
+          keep = TRUE;
+        else
+          keep = FALSE;
+      }
       else if ((flags & BSF_KEEP) != 0		/* Used in relocation.  */
 	       || ((flags & BSF_SECTION_SYM) != 0
 		   && ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags
@@ -2013,7 +2023,7 @@
 	 haven't been set yet.  mark_symbols_used_in_relocations will
 	 ignore input sections which have no corresponding output
 	 section.  */
-      if (strip_symbols != STRIP_ALL)
+//      if (strip_symbols != STRIP_ALL)
 	bfd_map_over_sections (ibfd,
 			       mark_symbols_used_in_relocations,
 			       isympp);
@@ -2837,7 +2847,10 @@
 	  return;
 	}
 
-      if (strip_symbols == STRIP_ALL)
+      /* Never, ever, strip reloc data on the Amiga! */
+      if (strip_symbols == STRIP_ALL &&
+	  bfd_get_flavour(obfd) != bfd_target_amiga_flavour)
+
 	{
 	  /* Remove relocations which are not in
 	     keep_strip_specific_list.  */
@@ -2847,9 +2860,30 @@
 
 	  temp_relpp = (arelent **) xmalloc (relsize);
 	  for (i = 0; i < relcount; i++)
+	  {
+	    asection *sec;
+	    sec = bfd_get_section(*relpp[i]->sym_ptr_ptr);
+
+//	    printf("%d: %s (0x%lx + 0x%lx) value 0x%lx (in section %s)\n",
+//	    	i, bfd_asymbol_name (*relpp [i]->sym_ptr_ptr), relpp [i]->address, relpp [i]->addend,
+//		bfd_asymbol_value(*relpp [i]->sym_ptr_ptr),
+//		bfd_section_name(ibfd, sec));
+
+	    /* Keep the symbol */
 	    if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr),
 				     keep_specific_htab))
 	      temp_relpp [temp_relcount++] = relpp [i];
+	    else
+	    {
+		/* Don't keep the symbol, but keep the reloc */
+		temp_relpp [temp_relcount] = relpp[i];
+		temp_relpp [temp_relcount]->addend = bfd_asymbol_value(*relpp [i]->sym_ptr_ptr)
+							 - sec->vma
+							 + relpp[i]->addend;
+		temp_relpp [temp_relcount]->sym_ptr_ptr = sec->symbol_ptr_ptr;
+		temp_relcount++;
+	    }
+	  }
 	  relcount = temp_relcount;
 	  free (relpp);
 	  relpp = temp_relpp;
@@ -3249,7 +3283,11 @@
 
   default_deterministic ();
 
-  /* Default is to strip all symbols.  */
+  add_specific_symbol("__amigaos4__", keep_specific_htab);
+  add_specific_symbol("_start", keep_specific_htab);
+  add_specific_symbol("_SDA_BASE_", keep_specific_htab);
+
+  /* Default is to strip all unnecessary symbols.  */
   if (strip_symbols == STRIP_UNDEF
       && discard_locals == LOCALS_UNDEF
       && htab_elements (strip_specific_htab) == 0)
@@ -4092,6 +4130,11 @@
   if (interleave && copy_byte == -1)
     fatal (_("interleave start byte must be set with --byte"));
 
+  add_specific_symbol("__amigappc__", keep_specific_htab);
+  add_specific_symbol("__amigaos4__", keep_specific_htab);
+  add_specific_symbol("_start", keep_specific_htab);
+  add_specific_symbol("_SDA_BASE_", keep_specific_htab);
+
   if (copy_byte >= interleave)
     fatal (_("byte number must be less than interleave"));
 
diff -ru --new-file a/binutils/readelf.c b/binutils/readelf.c
--- a/binutils/readelf.c	2013-11-18 12:40:15.000000000 +0400
+++ b/binutils/readelf.c	2022-02-16 23:31:56.413164100 +0300
@@ -153,6 +153,7 @@
 #include "elf/xgate.h"
 #include "elf/xstormy16.h"
 #include "elf/xtensa.h"
+#include "elf/amigaos.h"
 
 #include "getopt.h"
 #include "libiberty.h"
@@ -1576,6 +1577,7 @@
     {
     case DT_PPC_GOT:    return "PPC_GOT";
     case DT_PPC_OPT:    return "PPC_OPT";
+    case DT_AMIGAOS_DYNVERSION: return "AMIGAOS_DYNVERSION";
     default:
       return NULL;
     }
@@ -1859,6 +1861,9 @@
 
 	  switch (elf_header.e_machine)
 	    {
+	    case EM_PPC:
+          result = get_ppc_dynamic_type (type);
+          break;
 	    case EM_PARISC:
 	      result = get_parisc_dynamic_type (type);
 	      break;
diff -ru --new-file a/binutils/rename.c b/binutils/rename.c
--- a/binutils/rename.c	2013-11-04 19:33:37.000000000 +0400
+++ b/binutils/rename.c	2022-02-16 23:32:40.008332000 +0300
@@ -30,7 +30,7 @@
 #endif /* HAVE_UTIMES */
 #endif /* ! HAVE_GOOD_UTIME_H */
 
-#if ! defined (_WIN32) || defined (__CYGWIN32__)
+#if ! defined (_WIN32) && !defined(__amigaos4__) || defined (__CYGWIN32__)
 static int simple_copy (const char *, const char *);
 
 /* The number of bytes to copy at once.  */
@@ -143,7 +143,7 @@
 
   exists = lstat (to, &s) == 0;
 
-#if defined (_WIN32) && !defined (__CYGWIN32__)
+#if defined (_WIN32) && !defined (__CYGWIN32__) || defined (__amigaos4__)
   /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
      fail instead.  Also, chown is not present.  */
 
diff -ru --new-file a/binutils/stabs.c b/binutils/stabs.c
--- a/binutils/stabs.c	2013-11-04 19:33:37.000000000 +0400
+++ b/binutils/stabs.c	2022-02-17 16:15:01.938661000 +0300
@@ -2697,7 +2697,7 @@
 	      ++*pp;
 	      voffset &= 0x7fffffff;
 
-	      if (**pp == ';' || *pp == '\0')
+	      if (**pp == ';' || **pp == '\0')
 		{
 		  /* Must be g++ version 1.  */
 		  context = DEBUG_TYPE_NULL;
diff -ru --new-file a/config/mh-amigaos b/config/mh-amigaos
--- a/config/mh-amigaos	1970-01-01 03:00:00.000000000 +0300
+++ b/config/mh-amigaos	2021-02-01 23:12:49.154731600 +0300
@@ -0,0 +1,13 @@
+# Host makefile fragment for Commodore Amiga running AmigaOS.
+
+# There is no standard system compiler.  Assume using GNU C.
+CC = gcc
+CFLAGS = -g -O2 -mstackextend
+
+# We have both types of links under AmigaOS with GNU
+# utils, however the links need to be made in canonical
+# AmigaOS format (foo:bar/bell/file) rather than UNIX
+# format (/foo/bar/bell/file).  When this is fixed, then
+# these can go away.
+SYMLINK = cp
+HARDLINK = cp
diff -ru --new-file a/config/mh-morphos b/config/mh-morphos
--- a/config/mh-morphos	1970-01-01 03:00:00.000000000 +0300
+++ b/config/mh-morphos	2021-02-01 23:12:49.155734100 +0300
@@ -0,0 +1,13 @@
+# Host makefile fragment for Commodore Amiga running AmigaOS.
+
+# There is no standard system compiler.  Assume using GNU C.
+CC = gcc
+CFLAGS = -g -O2
+
+# We have both types of links under AmigaOS with GNU
+# utils, however the links need to be made in canonical
+# AmigaOS format (foo:bar/bell/file) rather than UNIX
+# format (/foo/bar/bell/file).  When this is fixed, then
+# these can go away.
+SYMLINK = cp
+HARDLINK = cp
diff -ru --new-file a/config.sub b/config.sub
--- a/config.sub	2013-11-26 15:37:33.000000000 +0400
+++ b/config.sub	2022-02-16 23:33:52.478744200 +0300
@@ -353,7 +353,7 @@
 	# We use `pc' rather than `unknown'
 	# because (1) that's what they normally are, and
 	# (2) the word "unknown" tends to confuse beginning users.
-	i*86 | x86_64)
+	i*86 | i*86be | x86_64)
 	  basic_machine=$basic_machine-pc
 	  ;;
 	# Object if more than one company name word.
@@ -485,11 +485,8 @@
 		basic_machine=580-amdahl
 		os=-sysv
 		;;
-	amiga | amiga-*)
-		basic_machine=m68k-unknown
-		;;
-	amigaos | amigados)
-		basic_machine=m68k-unknown
+	amigaos | amigados | amiga)
+		basic_machine=powerpc-unknown
 		os=-amigaos
 		;;
 	amigaunix | amix)
@@ -1356,7 +1353,7 @@
 	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
 	      | -sym* | -kopensolaris* | -plan9* \
 	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-	      | -aos* | -aros* \
+	      | -aos* | -amithlon* | -aros* \
 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
 	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
 	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
diff -ru --new-file a/configure b/configure
--- a/configure	2013-11-08 14:13:48.000000000 +0400
+++ b/configure	2022-02-16 23:35:36.544561800 +0300
@@ -3831,6 +3831,9 @@
 host_makefile_frag=/dev/null
 if test -d ${srcdir}/config ; then
 case "${host}" in
+  m68k-*-amigaos*)
+    host_makefile_frag="config/mh-amigaos"
+    ;;
   i[3456789]86-*-msdosdjgpp*)
     host_makefile_frag="config/mh-djgpp"
     ;;
@@ -3872,6 +3875,9 @@
   *-*-darwin*)
     host_makefile_frag="config/mh-darwin"
     ;;
+  *-morphos*)
+    host_makefile_frag="config/mh-morphos"
+    ;;
   powerpc-*-aix*)
     host_makefile_frag="config/mh-ppc-aix"
     ;;
diff -ru --new-file a/configure.ac b/configure.ac
--- a/configure.ac	2013-12-02 13:32:22.000000000 +0400
+++ b/configure.ac	2022-02-16 23:36:29.009582200 +0300
@@ -1167,6 +1167,9 @@
 host_makefile_frag=/dev/null
 if test -d ${srcdir}/config ; then
 case "${host}" in
+  m68k-*-amigaos*)
+    host_makefile_frag="config/mh-amigaos"
+    ;;
   i[[3456789]]86-*-msdosdjgpp*)
     host_makefile_frag="config/mh-djgpp"
     ;;
@@ -1189,6 +1192,9 @@
   *-*-darwin*)
     host_makefile_frag="config/mh-darwin"
     ;;
+  *-morphos*)
+    host_makefile_frag="config/mh-morphos"
+    ;;
   powerpc-*-aix*)
     host_makefile_frag="config/mh-ppc-aix"
     ;;
diff -ru --new-file a/gas/as.c b/gas/as.c
--- a/gas/as.c	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/as.c	2022-02-16 23:41:47.021272500 +0300
@@ -105,6 +105,11 @@
 segT data_section;
 segT bss_section;
 
+#ifdef OBJ_AMIGAHUNK
+segT data_chip_section;
+segT bss_chip_section;
+#endif
+
 /* Name of listing file.  */
 static char *listing_filename = NULL;
 
@@ -1056,6 +1061,10 @@
   text_section = subseg_new (TEXT_SECTION_NAME, 0);
   data_section = subseg_new (DATA_SECTION_NAME, 0);
   bss_section = subseg_new (BSS_SECTION_NAME, 0);
+#ifdef OBJ_AMIGAHUNK
+  data_chip_section = subseg_new (".data_chip", 0);
+  bss_chip_section = subseg_new (".bss_chip", 0);
+#endif
   /* @@ FIXME -- we're setting the RELOC flag so that sections are assumed
      to have relocs, otherwise we don't find out in time.  */
   applicable = bfd_applicable_section_flags (stdoutput);
@@ -1066,6 +1075,11 @@
 			 applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC
 				       | SEC_DATA));
   bfd_set_section_flags (stdoutput, bss_section, applicable & SEC_ALLOC);
+#ifdef OBJ_AMIGAHUNK
+  bfd_set_section_flags (stdoutput, data_chip_section,
+			 applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC));
+  bfd_set_section_flags (stdoutput, bss_chip_section, applicable & SEC_ALLOC);
+#endif
   seg_info (bss_section)->bss = 1;
 #endif
   subseg_new (BFD_ABS_SECTION_NAME, 0);
diff -ru --new-file a/gas/config/m68k-parse.h b/gas/config/m68k-parse.h
--- a/gas/config/m68k-parse.h	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/config/m68k-parse.h	2022-02-16 23:42:23.063821300 +0300
@@ -296,6 +296,9 @@
 
   /* The expression itself.  */
   expressionS exp;
+  
+  /* base-relative? */
+  short baserel;
 };
 
 /* The operand modes.  */
diff -ru --new-file a/gas/config/m68k-parse.y b/gas/config/m68k-parse.y
--- a/gas/config/m68k-parse.y	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/config/m68k-parse.y	2022-02-16 23:44:19.471075900 +0300
@@ -975,6 +975,7 @@
     }
 
   yylval.exp.size = SIZE_UNSPEC;
+  yylval.exp.baserel = 0;
   if (s <= str + 2
       || (s[-2] != '.' && s[-2] != ':'))
     tail = 0;
@@ -982,18 +983,21 @@
     {
       switch (s[-1])
 	{
+	case 'B':
+          yylval.exp.baserel = 1;
 	case 's':
 	case 'S':
 	case 'b':
-	case 'B':
 	  yylval.exp.size = SIZE_BYTE;
 	  break;
-	case 'w':
 	case 'W':
+	  yylval.exp.baserel = 1;
+	case 'w':
 	  yylval.exp.size = SIZE_WORD;
 	  break;
-	case 'l':
 	case 'L':
+	  yylval.exp.baserel = 1;
+	case 'l':
 	  yylval.exp.size = SIZE_LONG;
 	  break;
 	default:
diff -ru --new-file a/gas/config/obj-amigahunk.c b/gas/config/obj-amigahunk.c
--- a/gas/config/obj-amigahunk.c	1970-01-01 03:00:00.000000000 +0300
+++ b/gas/config/obj-amigahunk.c	2021-02-01 23:12:49.187819000 +0300
@@ -0,0 +1,212 @@
+/* AmigaOS object file format
+   Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS 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 2,
+or (at your option) any later version.
+
+GAS 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 GAS; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include "as.h"
+
+enum {
+  N_UNDF=0,
+/*N_ABS=2,*/
+/*N_TEXT=4,*/
+/*N_DATA=6,*/
+/*N_BSS=8,*/
+  N_INDR=0xa,
+/*N_COMM=0x12,*/
+  N_SETA=0x14,
+  N_SETT=0x16,
+  N_SETD=0x18,
+  N_SETB=0x1a,
+/*N_SETV=0x1c,*/
+  N_WARNING=0x1e,
+/*N_FN=0x1f*/
+  N_EXT=1,
+  N_TYPE=0x1e,
+/*N_STAB=0xe0,*/
+};
+
+static void obj_amiga_line PARAMS ((int));
+static void obj_amiga_weak PARAMS ((int));
+
+const pseudo_typeS obj_pseudo_table[] =
+{
+  {"line", obj_amiga_line, 0},	/* source code line number */
+  {"weak", obj_amiga_weak, 0},	/* mark symbol as weak.  */
+
+  /* other stuff */
+  {"ABORT", s_abort, 0},
+
+  {NULL, NULL, 0}		/* end sentinel */
+};
+
+#ifdef BFD_ASSEMBLER
+
+void
+obj_amiga_frob_symbol (sym, punt)
+     symbolS *sym;
+     int *punt ATTRIBUTE_UNUSED;
+{
+  sec_ptr sec = S_GET_SEGMENT (sym);
+  unsigned int type = amiga_symbol (symbol_get_bfdsym (sym))->type;
+
+  /* Only frob simple symbols this way right now.  */
+  if (! (type & ~ (N_TYPE | N_EXT)))
+    {
+      if (type == (N_UNDF | N_EXT)
+	  && sec == &bfd_abs_section)
+	{
+	  sec = bfd_und_section_ptr;
+	  S_SET_SEGMENT (sym, sec);
+	}
+
+      if ((type & N_TYPE) != N_INDR
+	  && (type & N_TYPE) != N_SETA
+	  && (type & N_TYPE) != N_SETT
+	  && (type & N_TYPE) != N_SETD
+	  && (type & N_TYPE) != N_SETB
+	  && type != N_WARNING
+	  && (sec == &bfd_abs_section
+	      || sec == &bfd_und_section))
+	return;
+      if (symbol_get_bfdsym (sym)->flags & BSF_EXPORT)
+	type |= N_EXT;
+
+      switch (type & N_TYPE)
+	{
+	case N_SETA:
+	case N_SETT:
+	case N_SETD:
+	case N_SETB:
+	  /* Set the debugging flag for constructor symbols so that
+	     BFD leaves them alone.  */
+	  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
+
+	  /* You can't put a common symbol in a set.  The way a set
+	     element works is that the symbol has a definition and a
+	     name, and the linker adds the definition to the set of
+	     that name.  That does not work for a common symbol,
+	     because the linker can't tell which common symbol the
+	     user means.  FIXME: Using as_bad here may be
+	     inappropriate, since the user may want to force a
+	     particular type without regard to the semantics of sets;
+	     on the other hand, we certainly don't want anybody to be
+	     mislead into thinking that their code will work.  */
+	  if (S_IS_COMMON (sym))
+	    as_bad (_("Attempt to put a common symbol into set %s"),
+		    S_GET_NAME (sym));
+	  /* Similarly, you can't put an undefined symbol in a set.  */
+	  else if (! S_IS_DEFINED (sym))
+	    as_bad (_("Attempt to put an undefined symbol into set %s"),
+		    S_GET_NAME (sym));
+
+	  break;
+	case N_INDR:
+	  /* Put indirect symbols in the indirect section.  */
+	  S_SET_SEGMENT (sym, bfd_ind_section_ptr);
+	  symbol_get_bfdsym (sym)->flags |= BSF_INDIRECT;
+	  if (type & N_EXT)
+	    {
+	      symbol_get_bfdsym (sym)->flags |= BSF_EXPORT;
+	      symbol_get_bfdsym (sym)->flags &=~ BSF_LOCAL;
+	    }
+	  break;
+	case N_WARNING:
+	  /* Mark warning symbols.  */
+	  symbol_get_bfdsym (sym)->flags |= BSF_WARNING;
+	  break;
+	}
+    }
+  else
+    {
+      symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
+    }
+
+  amiga_symbol (symbol_get_bfdsym (sym))->type = type;
+
+  /* Double check weak symbols.  */
+  if (S_IS_WEAK (sym))
+    {
+      if (S_IS_COMMON (sym))
+	as_bad (_("Symbol `%s' can not be both weak and common"),
+		S_GET_NAME (sym));
+    }
+}
+
+void
+obj_amiga_frob_file_before_fix ()
+{
+  /* Relocation processing may require knowing the VMAs of the sections.
+     Since writing to a section will cause the BFD back end to compute the
+     VMAs, fake it out here....  */
+  bfd_byte b = 0;
+  bfd_boolean x = TRUE;
+  if (bfd_section_size (stdoutput, text_section) != 0)
+    {
+      x = bfd_set_section_contents (stdoutput, text_section, &b, (file_ptr) 0,
+				    (bfd_size_type) 1);
+    }
+  else if (bfd_section_size (stdoutput, data_section) != 0)
+    {
+      x = bfd_set_section_contents (stdoutput, data_section, &b, (file_ptr) 0,
+				    (bfd_size_type) 1);
+    }
+  assert (x);
+}
+
+#endif /* BFD_ASSEMBLER */
+
+static void
+obj_amiga_line (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  /* Assume delimiter is part of expression.
+     BSD4.2 as fails with delightful bug, so we
+     are not being incompatible here.  */
+  new_logical_line ((char *) NULL, (int) (get_absolute_expression ()));
+  demand_empty_rest_of_line ();
+}				/* obj_amiga_line() */
+
+/* Handle .weak.  This is a GNU extension.  */
+
+static void
+obj_amiga_weak (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  char *name;
+  int c;
+  symbolS *symbolP;
+
+  do
+    {
+      name = input_line_pointer;
+      c = get_symbol_end ();
+      symbolP = symbol_find_or_make (name);
+      *input_line_pointer = c;
+      SKIP_WHITESPACE ();
+      S_SET_WEAK (symbolP);
+      if (c == ',')
+	{
+	  input_line_pointer++;
+	  SKIP_WHITESPACE ();
+	  if (*input_line_pointer == '\n')
+	    c = '\n';
+	}
+    }
+  while (c == ',');
+  demand_empty_rest_of_line ();
+}
diff -ru --new-file a/gas/config/obj-amigahunk.h b/gas/config/obj-amigahunk.h
--- a/gas/config/obj-amigahunk.h	1970-01-01 03:00:00.000000000 +0300
+++ b/gas/config/obj-amigahunk.h	2021-02-01 23:12:49.188822300 +0300
@@ -0,0 +1,54 @@
+/* obj-amigahunk.h, AmigaOS object file format for gas, the assembler.
+   Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS 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 2,
+   or (at your option) any later version.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA. */
+
+/* Tag to validate an amiga object file format processing */
+#define OBJ_AMIGAHUNK 1
+
+#include "targ-cpu.h"
+
+#ifdef BFD_ASSEMBLER
+
+#include "bfd/libamiga.h"
+
+#define OUTPUT_FLAVOR bfd_target_amiga_flavour
+
+/* SYMBOL TABLE */
+/* Symbol table macros and constants */
+
+#define S_SET_OTHER(S,V) (amiga_symbol (symbol_get_bfdsym (S))->other = (V))
+#define S_SET_TYPE(S,T)	 (amiga_symbol (symbol_get_bfdsym (S))->type = (T))
+#define S_SET_DESC(S,D)	 (amiga_symbol (symbol_get_bfdsym (S))->desc = (D))
+#define S_GET_TYPE(S)	 (amiga_symbol (symbol_get_bfdsym (S))->type)
+
+#define obj_frob_symbol(S,PUNT) obj_amiga_frob_symbol (S, &PUNT)
+extern void obj_amiga_frob_symbol PARAMS ((symbolS *, int *));
+
+#define obj_frob_file_before_fix() obj_amiga_frob_file_before_fix ()
+extern void obj_amiga_frob_file_before_fix PARAMS ((void));
+
+#define obj_sec_sym_ok_for_reloc(SEC)	(1)
+
+#endif /* BFD_ASSEMBLER */
+
+#define obj_read_begin_hook()		{;}
+#define obj_symbol_new_hook(s)		{;}
+#define EMIT_SECTION_SYMBOLS		(0)
+
+#define AOUT_STABS
diff -ru --new-file a/gas/config/obj-elf.c b/gas/config/obj-elf.c
--- a/gas/config/obj-elf.c	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/config/obj-elf.c	2022-02-16 23:46:09.073211400 +0300
@@ -1409,7 +1409,7 @@
   gas_assert (symbol_get_value_expression (csym)->X_op == O_constant);
   return fix_new (symbol_get_frag (csym),
 		  symbol_get_value_expression (csym)->X_add_number,
-		  0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT);
+		  0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT, 0);
 }
 
 /* This handles the .vtable_entry pseudo-op, which is used to indicate
@@ -1442,7 +1442,7 @@
   demand_empty_rest_of_line ();
 
   return fix_new (frag_now, frag_now_fix (), 0, sym, offset, 0,
-		  BFD_RELOC_VTABLE_ENTRY);
+		  BFD_RELOC_VTABLE_ENTRY, 0);
 }
 
 #define skip_whitespace(str)  do { if (*(str) == ' ') ++(str); } while (0)
diff -ru --new-file a/gas/config/tc-i386.h b/gas/config/tc-i386.h
--- a/gas/config/tc-i386.h	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/config/tc-i386.h	2022-02-16 23:47:39.622132100 +0300
@@ -27,7 +27,15 @@
 
 struct fix;
 
+/* Set the endianness we are using.  Default to little endian.  */
+#ifndef TARGET_BYTES_BIG_ENDIAN
 #define TARGET_BYTES_BIG_ENDIAN	0
+#endif
+
+#if !defined(OBJ_ELF) && TARGET_BYTES_BIG_ENDIAN == 1
+ #error Big endian i386 tested only for ELF!
+#endif
+
 
 #define TARGET_ARCH		(i386_arch ())
 #define TARGET_MACH		(i386_mach ())
@@ -67,6 +75,10 @@
 #define ELF_TARGET_FORMAT64	"elf64-x86-64-nacl"
 #endif
 
+#ifdef TE_Amithlon
+#define ELF_TARGET_FORMAT	"elf32-i386be-amithlon"
+#endif
+
 #ifdef TE_SOLARIS
 #define ELF_TARGET_FORMAT	"elf32-i386-sol2"
 #define ELF_TARGET_FORMAT64	"elf64-x86-64-sol2"
@@ -136,7 +148,7 @@
 #endif
 extern void x86_cons (expressionS *, int);
 
-#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) x86_cons_fix_new(FRAG, OFF, LEN, EXP)
+#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP,BASEREL) x86_cons_fix_new(FRAG, OFF, LEN, EXP)
 extern void x86_cons_fix_new
   (fragS *, unsigned int, unsigned int, expressionS *);
 
@@ -223,7 +235,7 @@
 extern unsigned int i386_frag_max_var (fragS *);
 #define md_frag_max_var i386_frag_max_var
 
-#define md_number_to_chars number_to_chars_littleendian
+/* #define md_number_to_chars number_to_chars_littleendian */
 
 enum processor_type
 {
diff -ru --new-file a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c
--- a/gas/config/tc-m68k.c	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/config/tc-m68k.c	2022-02-17 00:06:55.049388300 +0300
@@ -38,6 +38,16 @@
 #include "obj-coff.h"
 #endif
 
+/* FIXME: delete this #define as soon as the code that references
+   N_TEXT is changed */
+#ifdef BFD_ASSEMBLER
+#define N_TEXT 4
+#endif
+
+#ifndef OBJ_AMIGAHUNK
+#define OBJ_AMIGAHUNK 0
+#endif
+
 #ifdef OBJ_ELF
 static void m68k_elf_cons (int);
 #endif
@@ -84,6 +94,7 @@
 static int flag_short_refs;	/* -l option.  */
 static int flag_long_jumps;	/* -S option.  */
 static int flag_keep_pcrel;	/* --pcrel option.  */
+static int flag_small_code;	/* -sc option */
 
 #ifdef REGISTER_PREFIX_OPTIONAL
 int flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL;
@@ -391,6 +402,7 @@
 	 so, which.  */
       enum pic_relocation pic_reloc;
 #endif
+      char baserel;
     }
   reloc[5];			/* Five is enough???  */
 };
@@ -441,7 +453,7 @@
 /* The numo+1 kludge is so we can hit the low order byte of the prev word.
    Blecch.  */
 static void
-add_fix (int width, struct m68k_exp *exp, int pc_rel, int pc_fix)
+add_fix (int width, struct m68k_exp *exp, int pc_rel, int pc_fix, int base_rel)
 {
   the_ins.reloc[the_ins.nrel].n = (width == 'B' || width == '3'
 				   ? the_ins.numo * 2 - 1
@@ -454,7 +466,8 @@
 #ifdef OBJ_ELF
   the_ins.reloc[the_ins.nrel].pic_reloc = exp->pic_reloc;
 #endif
-  the_ins.reloc[the_ins.nrel++].pcrel = pc_rel;
+  the_ins.reloc[the_ins.nrel].pcrel = pc_rel;
+  the_ins.reloc[the_ins.nrel++].baserel = base_rel;
 }
 
 /* Cause an extra frag to be generated here, inserting up to 10 bytes
@@ -810,6 +823,18 @@
 #define BRANCHBWPL	10      /* Branch byte, word or pair of longs
 				   */
 
+/* ABSREL (nice name;-)) is used in small-code, it might be implemented
+ * base-relative (a4), pc-relative, or base-relative with an extra add
+ * instruction to add the base-register.
+ *
+ * IMMREL is the analogous mode for immediate addressing of variables. This
+ * one can lead into situations, where a replacement is not possible:
+ *   addl #foo,a0
+ * can't be made pc-relative, if foo is in the text segment.  */
+
+#define ABSREL		11
+#define IMMREL		12
+
 /* Note that calls to frag_var need to specify the maximum expansion
    needed; this is currently 12 bytes for bne/beq pair.  */
 #define FRAG_VAR_SIZE 12
@@ -877,6 +902,17 @@
   { 32767, -32768,  2, TAB (BRANCHBWPL, LONG) },
   {     0,	0,  10, 0 },
   {     1,	1,  0, 0 },
+  
+  {   127,   -128,  0, 0 },
+  { 32767, -32768,  2, TAB (ABSREL, LONG) },
+  {     0,      0,  6, 0 },
+  {     1,      1,  0, 0 },
+
+  {   127,   -128,  0, 0 },
+  { 32767, -32768,  2, TAB (IMMREL, LONG) },
+  {     0,      0,  6, 0 },
+  {     1,      1,  0, 0 },
+  
 };
 
 /* These are the machine dependent pseudo-ops.  These are included so
@@ -1317,6 +1353,17 @@
 	    }
 	}
     }
+  else if (fixp->tc_fix_data)
+    {
+      switch (fixp->fx_size)
+	{
+	case 1: code = BFD_RELOC_8_BASEREL; break;
+	case 2: code = BFD_RELOC_16_BASEREL; break;
+	case 4: code = BFD_RELOC_32_BASEREL; break;
+	default:
+	  abort ();
+	}
+    }
   else
     {
 #define F(SZ,PCREL)		(((SZ) << 1) + (PCREL))
@@ -2511,7 +2558,18 @@
 	      else
 		nextword = get_num (&opP->disp, 0);
 	      if (isvar (&opP->disp))
-		add_fix (s[1], &opP->disp, 0, 0);
+		{
+/* This doesn't work when the symbol is N_UNDF! We ignore this for now. */
+		  if (0 && flag_small_code)
+		    {
+		      add_frag (adds (&opP->disp),
+				offs (&opP->disp),
+				TAB (IMMREL, SZ_UNDEF));
+		       break;
+		    }
+		  else
+		    add_fix(s[1], &opP->disp, 0, 0, opP->disp.baserel);
+	        }
 	      switch (s[1])
 		{
 		case 'b':
@@ -2680,7 +2738,7 @@
 			      )
 			    {
 			      addword (0x0170);
-			      add_fix ('l', &opP->disp, 1, 2);
+			      add_fix ('l', &opP->disp, 1, 2, opP->disp.baserel);
 			    }
 			  else
 			    {
@@ -2693,7 +2751,7 @@
 		      else
 			{
 			  addword (0x0170);
-			  add_fix ('l', &opP->disp, 0, 0);
+			  add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel);
 			}
 		    }
 		  else
@@ -2711,10 +2769,10 @@
 		    {
 		      if (opP->reg == PC)
 			{
-			  add_fix ('w', &opP->disp, 1, 0);
+			  add_fix ('w', &opP->disp, 1, 0, opP->disp.baserel);
 			}
 		      else
-			add_fix ('w', &opP->disp, 0, 0);
+			add_fix ('w', &opP->disp, 0, 0, opP->disp.baserel);
 		    }
 		}
 	      addword (nextword);
@@ -2824,9 +2882,9 @@
 				 fit (possible on m68000) let the
 				 fixup processing complain later.  */
 			      if (opP->reg == PC)
-				add_fix ('B', &opP->disp, 1, 1);
+				add_fix ('B', &opP->disp, 1, 1, 0);	/* FIXME? -fnf */
 			      else
-				add_fix ('B', &opP->disp, 0, 0);
+				add_fix ('B', &opP->disp, 0, 0, 0);	/* FIXME? -fnf */
 			    }
 			  else if (siz1 != SIZE_BYTE)
 			    {
@@ -2957,9 +3015,9 @@
 	      if (siz1 != SIZE_UNSPEC && isvar (&opP->disp))
 		{
 		  if (opP->reg == PC || opP->reg == ZPC)
-		    add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 1, 2);
+		    add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 1, 2, opP->disp.baserel);
 		  else
-		    add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 0, 0);
+		    add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 0, 0, opP->disp.baserel);
 		}
 	      if (siz1 == SIZE_LONG)
 		addword (baseo >> 16);
@@ -2967,7 +3025,7 @@
 		addword (baseo);
 
 	      if (siz2 != SIZE_UNSPEC && isvar (&opP->odisp))
-		add_fix (siz2 == SIZE_LONG ? 'l' : 'w', &opP->odisp, 0, 0);
+		add_fix (siz2 == SIZE_LONG ? 'l' : 'w', &opP->odisp, 0, 0, opP->disp.baserel);
 	      if (siz2 == SIZE_LONG)
 		addword (outro >> 16);
 	      if (siz2 != SIZE_UNSPEC)
@@ -3007,8 +3065,17 @@
 		    }
 		  /* Fall through into long.  */
 		case SIZE_LONG:
+/* This doesn't work when the symbol is N_UNDF! We ignore this for now. */
+		  if (0 && flag_small_code)
+		    {
+		      tmpreg=0x3A; /* 7.2 */
+		      add_frag (adds (&opP->disp),
+			        offs (&opP->disp),
+				TAB (ABSREL, SZ_UNDEF));
+		      break;
+		    }
 		  if (isvar (&opP->disp))
-		    add_fix ('l', &opP->disp, 0, 0);
+		    add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel);
 
 		  tmpreg = 0x39;/* 7.1 mode */
 		  addword (nextword >> 16);
@@ -3021,7 +3088,7 @@
 
 		case SIZE_WORD:
 		  if (isvar (&opP->disp))
-		    add_fix ('w', &opP->disp, 0, 0);
+		    add_fix ('w', &opP->disp, 0, 0, opP->disp.baserel);
 
 		  tmpreg = 0x38;/* 7.0 mode */
 		  addword (nextword);
@@ -3067,7 +3134,7 @@
 	    }
 	  tmpreg = get_num (&opP->disp, tmpreg);
 	  if (isvar (&opP->disp))
-	    add_fix (s[1], &opP->disp, 0, 0);
+	    add_fix (s[1], &opP->disp, 0, 0, opP->disp.baserel);
 	  switch (s[1])
 	    {
 	    case 'b':		/* Danger:  These do no check for
@@ -3134,16 +3201,16 @@
 	  switch (s[1])
 	    {
 	    case 'B':
-	      add_fix ('B', &opP->disp, 1, -1);
+	      add_fix ('B', &opP->disp, 1, -1, opP->disp.baserel);
 	      break;
 	    case 'W':
-	      add_fix ('w', &opP->disp, 1, 0);
+	      add_fix ('w', &opP->disp, 1, 0, opP->disp.baserel);
 	      addword (0);
 	      break;
 	    case 'L':
 	    long_branch:
 	      the_ins.opcode[0] |= 0xff;
-	      add_fix ('l', &opP->disp, 1, 0);
+	      add_fix ('l', &opP->disp, 1, 0, opP->disp.baserel);
 	      addword (0);
 	      addword (0);
 	      break;
@@ -3189,7 +3256,7 @@
 		      the_ins.opcode[0] |= 0x0006;
 		      addword (0x4EF9);
 		    }
-		  add_fix ('l', &opP->disp, 0, 0);
+		  add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel);
 		  addword (0);
 		  addword (0);
 		  break;
@@ -3240,12 +3307,12 @@
 				  TAB (DBCCABSJ, SZ_UNDEF));
 		      break;
 		    }
-		  add_fix ('w', &opP->disp, 1, 0);
+		  add_fix ('w', &opP->disp, 1, 0, opP->disp.baserel);
 		}
 	      addword (0);
 	      break;
 	    case 'C':		/* Fixed size LONG coproc branches.  */
-	      add_fix ('l', &opP->disp, 1, 0);
+	      add_fix ('l', &opP->disp, 1, 0, opP->disp.baserel);
 	      addword (0);
 	      addword (0);
 	      break;
@@ -3253,7 +3320,7 @@
 	      if (subs (&opP->disp) || (adds (&opP->disp) == 0))
 		{
 		  the_ins.opcode[the_ins.numo - 1] |= 0x40;
-		  add_fix ('l', &opP->disp, 1, 0);
+		  add_fix ('l', &opP->disp, 1, 0, opP->disp.baserel);
 		  addword (0);
 		  addword (0);
 		}
@@ -3707,7 +3774,7 @@
 	  break;
 	case '_':	/* used only for move16 absolute 32-bit address.  */
 	  if (isvar (&opP->disp))
-	    add_fix ('l', &opP->disp, 0, 0);
+	    add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel);
 	  tmpreg = get_num (&opP->disp, 90);
 	  addword (tmpreg >> 16);
 	  addword (tmpreg & 0xFFFF);
@@ -4056,6 +4123,12 @@
     int number;
   };
 
+#if defined(TE_AMIGA)
+  #define FRAME ADDR5
+#else
+  #define FRAME ADDR6
+#endif
+
 static const struct init_entry init_table[] =
 {
   { "d0", DATA0 },
@@ -4073,7 +4146,7 @@
   { "a4", ADDR4 },
   { "a5", ADDR5 },
   { "a6", ADDR6 },
-  { "fp", ADDR6 },
+  { "fp", FRAME },
   { "a7", ADDR7 },
   { "sp", ADDR7 },
   { "ssp", ADDR7 },
@@ -4444,7 +4517,8 @@
 			      &the_ins.reloc[m].exp,
 			      the_ins.reloc[m].pcrel,
 			      get_reloc_code (n, the_ins.reloc[m].pcrel,
-					      the_ins.reloc[m].pic_reloc));
+					      the_ins.reloc[m].pic_reloc),
+			      the_ins.reloc[m].baserel);
 	  fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
 	  if (the_ins.reloc[m].wid == 'B')
 	    fixP->fx_signed = 1;
@@ -4506,7 +4580,8 @@
 			      &the_ins.reloc[m].exp,
 			      the_ins.reloc[m].pcrel,
 			      get_reloc_code (wid, the_ins.reloc[m].pcrel,
-					      the_ins.reloc[m].pic_reloc));
+					      the_ins.reloc[m].pic_reloc),
+			      the_ins.reloc[m].baserel);
 	  fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
 	}
       (void) frag_var (rs_machine_dependent, FRAG_VAR_SIZE, 0,
@@ -4543,7 +4618,8 @@
 			  &the_ins.reloc[m].exp,
 			  the_ins.reloc[m].pcrel,
 			  get_reloc_code (wid, the_ins.reloc[m].pcrel,
-					  the_ins.reloc[m].pic_reloc));
+					  the_ins.reloc[m].pic_reloc),
+			  the_ins.reloc[m].baserel);
       fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
     }
 }
@@ -5059,7 +5135,7 @@
 	as_bad_where (fragP->fr_file, fragP->fr_line,
 		      _("short branch with zero offset: use :w"));
       fixP = fix_new (fragP, fragP->fr_fix - 1, 1, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC8);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC8, 0);
       fixP->fx_pcrel_adjust = -1;
       break;
     case TAB (BRANCHBWL, SHORT):
@@ -5069,13 +5145,13 @@
     case TAB (BRANCHBWPL, SHORT):
       fragP->fr_opcode[1] = 0x00;
       fixP = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC16);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC16, 0);
       fragP->fr_fix += 2;
       break;
     case TAB (BRANCHBWL, LONG):
       fragP->fr_opcode[1] = (char) 0xFF;
       fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC32);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC32, 0);
       fragP->fr_fix += 4;
       break;
     case TAB (BRANCHBWPL, LONG):
@@ -5097,6 +5173,10 @@
       fragP->fr_fix += 4;
       break;
     case TAB (BRABSJUNC, LONG):
+      if (flag_small_code)
+	{
+	  as_bad (_("Long branch in small code model, not supported."));
+	} else
       if (fragP->fr_opcode[0] == 0x61)		/* jbsr */
 	{
 	  if (flag_keep_pcrel)
@@ -5105,7 +5185,7 @@
 	  fragP->fr_opcode[0] = 0x4E;
 	  fragP->fr_opcode[1] = (char) 0xB9; /* JSR with ABSL LONG operand.  */
 	  fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-			  fragP->fr_offset, 0, RELAX_RELOC_ABS32);
+			  fragP->fr_offset, 0, RELAX_RELOC_ABS32,0);
 	  fragP->fr_fix += 4;
 	}
       else if (fragP->fr_opcode[0] == 0x60)	/* jbra */
@@ -5116,7 +5196,7 @@
 	  fragP->fr_opcode[0] = 0x4E;
 	  fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG operand.  */
 	  fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-			  fragP->fr_offset, 0, RELAX_RELOC_ABS32);
+			  fragP->fr_offset, 0, RELAX_RELOC_ABS32, 0);
 	  fragP->fr_fix += 4;
 	}
       else
@@ -5143,25 +5223,25 @@
       *buffer_address++ = (char) 0xf9;
       fragP->fr_fix += 2;	/* Account for jmp instruction.  */
       fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-		      fragP->fr_offset, 0, RELAX_RELOC_ABS32);
+		      fragP->fr_offset, 0, RELAX_RELOC_ABS32,0);
       fragP->fr_fix += 4;
       break;
     case TAB (FBRANCH, SHORT):
       know ((fragP->fr_opcode[1] & 0x40) == 0);
       fixP = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC16);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC16,0);
       fragP->fr_fix += 2;
       break;
     case TAB (FBRANCH, LONG):
       fragP->fr_opcode[1] |= 0x40;	/* Turn on LONG bit.  */
       fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC32);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC32,0);
       fragP->fr_fix += 4;
       break;
     case TAB (DBCCLBR, SHORT):
     case TAB (DBCCABSJ, SHORT):
       fixP = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC16);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC16,0);
       fragP->fr_fix += 2;
       break;
     case TAB (DBCCLBR, LONG):
@@ -5181,7 +5261,7 @@
 
       fragP->fr_fix += 6;	/* Account for bra/jmp instructions.  */
       fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC32);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC32,0);
       fragP->fr_fix += 4;
       break;
     case TAB (DBCCABSJ, LONG):
@@ -5201,14 +5281,14 @@
 
       fragP->fr_fix += 6;		/* Account for bra/jmp instructions.  */
       fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-		      fragP->fr_offset, 0, RELAX_RELOC_ABS32);
+		      fragP->fr_offset, 0, RELAX_RELOC_ABS32,0);
       fragP->fr_fix += 4;
       break;
     case TAB (PCREL1632, SHORT):
       fragP->fr_opcode[1] &= ~0x3F;
       fragP->fr_opcode[1] |= 0x3A; /* 072 - mode 7.2 */
       fixP = fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC16);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC16,0);
       fragP->fr_fix += 2;
       break;
     case TAB (PCREL1632, LONG):
@@ -5218,7 +5298,7 @@
       *buffer_address++ = 0x70;
       fragP->fr_fix += 2;
       fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC32);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC32,0);
       fixP->fx_pcrel_adjust = 2;
       fragP->fr_fix += 4;
       break;
@@ -5226,7 +5306,7 @@
       gas_assert (fragP->fr_fix >= 2);
       buffer_address[-2] &= ~1;
       fixP = fix_new (fragP, fragP->fr_fix - 1, 1, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC8);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC8,0);
       fixP->fx_pcrel_adjust = 1;
       break;
     case TAB (PCINDEX, SHORT):
@@ -5234,7 +5314,7 @@
       buffer_address[-2] |= 0x1;
       buffer_address[-1] = 0x20;
       fixP = fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC16);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC16,0);
       fixP->fx_pcrel_adjust = 2;
       fragP->fr_fix += 2;
       break;
@@ -5243,13 +5323,13 @@
       buffer_address[-2] |= 0x1;
       buffer_address[-1] = 0x30;
       fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC32);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC32,0);
       fixP->fx_pcrel_adjust = 2;
       fragP->fr_fix += 4;
       break;
     case TAB (ABSTOPCREL, SHORT):
       fixP = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-		      fragP->fr_offset, 1, RELAX_RELOC_PC16);
+		      fragP->fr_offset, 1, RELAX_RELOC_PC16,0);
       fragP->fr_fix += 2;
       break;
     case TAB (ABSTOPCREL, LONG):
@@ -5263,9 +5343,81 @@
       fragP->fr_opcode[1] &= ~0x3F;
       fragP->fr_opcode[1] |= 0x39;	/* Mode 7.1 */
       fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-		      fragP->fr_offset, 0, RELAX_RELOC_ABS32);
+		      fragP->fr_offset, 0, RELAX_RELOC_ABS32,0);
       fragP->fr_fix += 4;
       break;
+    case TAB (ABSREL, BYTE):
+      as_bad (_("ABSREL_BYTE: how the ** does this look??"));
+      break;
+    case TAB (ABSREL, SHORT):
+      fragP->fr_opcode[1] &= ~0x3f;
+      fragP->fr_fix += 2;
+      if (S_GET_TYPE (fragP->fr_symbol) == N_TEXT)
+	{
+	  /* so this is really a pc-relative address */
+	  fragP->fr_opcode[1] |= 0x3a;
+	  fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, 1, NO_RELOC, 0);
+	  break;
+	}
+      /* in that case we have to generate base-relative code
+       * (note: if we're in N_UNDF, this could as well be pc-relative, but the linker
+       *        will have to do the final patch in that case) */
+      fragP->fr_opcode[1] |= 0x2c;  /* (a4) */
+      fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 1);
+      break;
+    case TAB (ABSREL, LONG):
+      as_bad (_("ABSREL_LONG: sorry, not supported."));
+      break;
+    case TAB (IMMREL, BYTE):
+      as_bad (_("IMMREL_BYTE: how the ** does this look??"));
+      break;
+    case TAB (IMMREL, SHORT):
+      if (S_GET_TYPE (fragP->fr_symbol) == N_TEXT)
+	{
+	/* we can only fix operations on data registers, not on <ea> */
+	if ((fragP->fr_opcode[1] & 0x38) != 0)
+	  {
+	    /* use the normal reloc32, sigh... */
+	    fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 0);
+	    fragP->fr_fix += 4;
+	    break;
+	  }
+
+	  /* so this is really a pc-relative address
+	   * What we have to do now is a VERY UGLY AND BIG KLUDGE. Basically do the
+	   * following thing:
+	   *   turn
+	   *     addl #foo,d0      (foo is N_TEXT)
+	   *   into
+	   *     pea  foo(pc)
+	   *     addl (sp)+,d0
+	   */
+	  *buffer_address++ = fragP->fr_opcode[0]; /* save the original command */
+	  *buffer_address++ = fragP->fr_opcode[1];
+	  fragP->fr_opcode[0] = 0x48; 	/* PEA */
+	  fragP->fr_opcode[1] = 0x7a;
+	  fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, 1, NO_RELOC, 0);
+
+	  *buffer_address++ = 0x9f;	/* sp@+ */
+	  fragP->fr_fix += 4;	/* two byte fix, two byte code extension */
+	  break;
+	}
+      /* in that case we have to generate base-relative code
+       * (note: if we're in N_UNDF, this could as well be pc-relative, but the linker
+       *        will have to do the final patch in that case) */
+
+      /* analogous (more or less;-)) to above, the following conversion is done
+       *   turn
+       *     addl #bar,d0		(bar is N_DATA)
+       *   into
+       *	   addl #<bar>,d0	where <bar> is a baserel-reloc
+       *     addl a4,d0
+       */
+
+      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 1);
+      *buffer_address++ = 0xd0;
+      *buffer_address++ = 0x8c;
+      break;
     }
   if (fixP)
     {
@@ -5301,7 +5453,7 @@
 	  {
 	    fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
 	  }
-	else if (flag_short_refs)
+	else if (flag_short_refs || (0 && flag_small_code))
 	  {
 	    /* Symbol is undefined and we want short ref.  */
 	    fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
@@ -5372,6 +5524,21 @@
 	  }
 	break;
       }
+	  
+   case TAB (ABSREL, SZ_UNDEF):
+     {
+	if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
+	     && relaxable_symbol (fragP->fr_symbol))
+	    || flag_short_refs || (0 && flag_small_code))
+	  {
+	    fragP->fr_subtype = TAB (ABSREL, SHORT);
+	  }
+	else
+	  {
+	    fragP->fr_subtype = TAB (ABSREL, LONG);
+	  }
+	break;
+     }
 
     default:
       break;
@@ -5435,10 +5602,46 @@
   the_bytes[6] =  ri->r_symbolnum        & 0x0ff;
   the_bytes[7] = (((ri->r_pcrel << 7) & 0x80)
 		  | ((ri->r_length << 5) & 0x60)
-		  | ((ri->r_extern << 4) & 0x10));
+		  | ((ri->r_extern << 4) & 0x10)
+		  | ((ri->r_baserel << 3) & 0x08));
 }
 
+#endif /* comment */
+
+#if 0 /* FIXME: sba */
+#ifndef BFD_ASSEMBLER
+void
+tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
+     char *where;
+     fixS *fixP;
+     relax_addressT segment_address_in_file;
+{
+  /*
+   * In: length of relocation (or of address) in chars: 1, 2 or 4.
+   * Out: GNU LD relocation length code: 0, 1, or 2.
+   */
+
+  static const unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2};
+  long r_symbolnum;
+
+  know (fixP->fx_addsy != NULL);
+
+  md_number_to_chars (where,
+       fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+		      4);
+
+  r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
+		 ? S_GET_TYPE (fixP->fx_addsy)
+		 : fixP->fx_addsy->sy_number);
+
+  where[4] = (r_symbolnum >> 16) & 0x0ff;
+  where[5] = (r_symbolnum >> 8) & 0x0ff;
+  where[6] = r_symbolnum & 0x0ff;
+  where[7] = (((fixP->fx_pcrel << 7) & 0x80) | ((nbytes_r_length[fixP->fx_size] << 5) & 0x60) |
+	      (((!S_IS_DEFINED (fixP->fx_addsy)) << 4) & 0x10) | ((fixP->tc_fix_data << 3) & 0x08));
+}
 #endif
+#endif /* 0 */
 
 #endif /* OBJ_AOUT or OBJ_BOUT */
 
@@ -5473,7 +5676,7 @@
       md_number_to_chars (ptr, (valueT) 0x4EF9, 2);
       md_number_to_chars (ptr + 2, (valueT) offset, 4);
       fix_new (frag, (ptr + 2) - frag->fr_literal, 4, to_symbol, (offsetT) 0,
-	       0, NO_RELOC);
+	       0, NO_RELOC,0);
     }
   else
     {
@@ -7520,7 +7723,7 @@
 #ifdef OBJ_ELF
 const char *md_shortopts = "lSA:m:kQ:V";
 #else
-const char *md_shortopts = "lSA:m:k";
+const char *md_shortopts = "lSA:m:s:k";
 #endif
 
 struct option md_longopts[] = {
@@ -7565,6 +7768,13 @@
       flag_keep_pcrel = 1;
       break;
 
+    case 's':
+      if (!strcmp(arg, "c") || !strcmp(arg, "mallcode"))
+	flag_small_code = 1;
+      else
+	return 0;
+      break;
+
     case OPTION_PIC:
     case 'k':
       flag_want_pic = 1;
@@ -7748,6 +7958,7 @@
 -l			use 1 word for refs to undefined symbols [default 2]\n\
 -pic, -k		generate position independent code\n\
 -S			turn jbsr into jsr\n\
+-smallcode, -sc		small code model\n\
 --pcrel                 never turn PC-relative branches into absolute jumps\n\
 --register-prefix-optional\n\
 			recognize register names without prefix character\n\
@@ -7912,6 +8123,8 @@
   adjust = fixP->fx_pcrel_adjust;
   if (adjust == 64)
     adjust = -1;
+  if (OBJ_AMIGAHUNK)
+    return -adjust;
   return fixP->fx_where + fixP->fx_frag->fr_address - adjust;
 }
 
diff -ru --new-file a/gas/config/tc-m68k.h b/gas/config/tc-m68k.h
--- a/gas/config/tc-m68k.h	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/config/tc-m68k.h	2022-02-17 00:08:26.078988700 +0300
@@ -33,6 +33,9 @@
 #ifdef TE_NetBSD
 #define TARGET_FORMAT "a.out-m68k-netbsd"
 #endif
+#ifdef TE_AMIGA
+#define TARGET_FORMAT "a.out-amiga"
+#endif
 #ifdef TE_LINUX
 #define TARGET_FORMAT "a.out-m68k-linux"
 #endif
@@ -41,6 +44,10 @@
 #endif
 #endif
 
+#ifdef OBJ_AMIGAHUNK
+#define TARGET_FORMAT "amiga"
+#endif
+
 #ifdef OBJ_ELF
 #define TARGET_FORMAT "elf32-m68k"
 #endif
@@ -63,6 +70,11 @@
 #endif
 #define TARGET_ARCH bfd_arch_m68k
 
+// FIXME: This was in binutils 2.14
+//#ifdef TE_AMIGA
+//#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (OMAGIC);	/* Magic byte for file header */
+//#endif
+
 #define tc_comment_chars m68k_comment_chars
 extern const char *m68k_comment_chars;
 
@@ -155,6 +167,9 @@
 extern struct relax_type md_relax_table[];
 #define TC_GENERIC_RELAX_TABLE md_relax_table
 
+#define TC_FIX_TYPE char
+#define TC_INIT_FIX_DATA(p)
+
 /* We can't do a byte jump to the next instruction, so in that case
    force word mode by faking AIM.  */
 #define md_prepare_relax_scan(fragP, address, aim, this_state, this_type) \
diff -ru --new-file a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
--- a/gas/config/tc-ppc.c	2013-11-18 12:40:15.000000000 +0400
+++ b/gas/config/tc-ppc.c	2022-02-17 13:28:50.320708400 +0300
@@ -1412,6 +1412,11 @@
 #endif
 #endif
 #ifdef OBJ_ELF
+#ifdef TE_MORPHOS
+  return "elf32-morphos";
+#elif TE_AMIGAOS
+  return "elf32-amigaos";
+#else
 # ifdef TE_FreeBSD
   return (ppc_obj64 ? "elf64-powerpc-freebsd" : "elf32-powerpc-freebsd");
 # elif defined (TE_VXWORKS)
@@ -1422,6 +1427,7 @@
 	  : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle"));
 # endif
 #endif
+#endif
 }
 
 /* Validate one entry in powerpc_opcodes[] or vle_opcodes[].
@@ -1863,6 +1869,18 @@
 #define MAP64(str, reloc) { str, sizeof (str) - 1, 0, 1, reloc }
 
   static const struct map_bfd mapping[] = {
+    /* MorphOS specifc relocs */
+	MAP ("drel",        	BFD_RELOC_PPC_MORPHOS_DREL),
+	MAP ("drell",       	BFD_RELOC_PPC_MORPHOS_DREL_LO),
+	MAP ("drelh",       	BFD_RELOC_PPC_MORPHOS_DREL_HI),
+	MAP ("drelha",      	BFD_RELOC_PPC_MORPHOS_DREL_HA),
+
+    /* AmigaOS4 specific relocs */
+    MAP ("brel",		BFD_RELOC_PPC_AMIGAOS_BREL),
+    MAP ("brel@l",		BFD_RELOC_PPC_AMIGAOS_BREL_LO),
+    MAP ("brel@h",		BFD_RELOC_PPC_AMIGAOS_BREL_HI),
+    MAP ("brel@ha",		BFD_RELOC_PPC_AMIGAOS_BREL_HA),
+
     MAP ("l",			BFD_RELOC_LO16),
     MAP ("h",			BFD_RELOC_HI16),
     MAP ("ha",			BFD_RELOC_HI16_S),
@@ -2094,7 +2112,7 @@
 	      if (target_big_endian)
 		offset = nbytes - size;
 	      fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
-			   &exp, 0, reloc);
+			   &exp, 0, reloc,0);
 	    }
 	}
       else
@@ -3436,7 +3454,7 @@
 			      size,
 			      &fixups[i].exp,
 			      reloc_howto->pc_relative,
-			      fixups[i].reloc);
+			      fixups[i].reloc,0);
 	}
       else
 	{
@@ -3448,7 +3466,7 @@
 			      insn_length,
 			      &fixups[i].exp,
 			      (operand->flags & PPC_OPERAND_RELATIVE) != 0,
-			      BFD_RELOC_UNUSED);
+			      BFD_RELOC_UNUSED,0);
 	}
       fixP->fx_pcrel_adjust = fixups[i].opindex;
     }
@@ -6855,6 +6873,14 @@
 	  break;
 
 #ifdef OBJ_ELF
+	case BFD_RELOC_PPC_AMIGAOS_BREL:
+	case BFD_RELOC_PPC_AMIGAOS_BREL_HI:
+	case BFD_RELOC_PPC_AMIGAOS_BREL_LO:
+	case BFD_RELOC_PPC_AMIGAOS_BREL_HA:
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      value, 2);
+	  break;
+
 	  /* These can appear with @l etc. in data.  */
 	case BFD_RELOC_LO16:
 	case BFD_RELOC_LO16_PCREL:
diff -ru --new-file a/gas/config/tc-sh.c b/gas/config/tc-sh.c
--- a/gas/config/tc-sh.c	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/config/tc-sh.c	2022-02-17 13:31:43.959249000 +0300
@@ -803,7 +803,7 @@
       r_type = BFD_RELOC_UNUSED;
     }
 
-  fix_new_exp (frag, off, size, exp, 0, r_type);
+  fix_new_exp (frag, off, size, exp, 0, r_type,0);
 }
 
 /* The regular cons() function, that reads constants, doesn't support
@@ -2243,7 +2243,7 @@
 	       2,
 	       &op->immediate,
 	       pcrel,
-	       how);
+	       how,0);
 }
 
 static void
@@ -2254,7 +2254,7 @@
 	       4,
 	       & op->immediate,
 	       pcrel,
-	       how);
+	       how,0);
 }
 static void
 build_relax (sh_opcode_info *opcode, sh_operand_info *op)
@@ -2324,7 +2324,7 @@
       symbol_table_insert (end_sym);
       end_sym->sy_value = operand[1].immediate;
       end_sym->sy_value.X_add_number += 2;
-      fix_new (frag_now, frag_now_fix (), 2, end_sym, 0, 1, BFD_RELOC_SH_LABEL);
+      fix_new (frag_now, frag_now_fix (), 2, end_sym, 0, 1, BFD_RELOC_SH_LABEL,0);
     }
 
   output = frag_more (2);
@@ -2978,7 +2978,7 @@
       /* Output a CODE reloc to tell the linker that the following
          bytes are instructions, not data.  */
       fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0,
-	       BFD_RELOC_SH_CODE);
+	       BFD_RELOC_SH_CODE,0);
       seg_info (now_seg)->tc_segment_info_data.in_code = 1;
     }
 
@@ -3059,7 +3059,7 @@
       if (frag_now != last_label_frag
 	  || offset != last_label_offset)
 	{
-	  fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL);
+	  fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL,0);
 	  last_label_frag = frag_now;
 	  last_label_offset = offset;
 	}
@@ -3078,7 +3078,7 @@
       && seg_info (now_seg)->tc_segment_info_data.in_code)
     {
       fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0,
-	       BFD_RELOC_SH_DATA);
+	       BFD_RELOC_SH_DATA,0);
       seg_info (now_seg)->tc_segment_info_data.in_code = 0;
     }
 }
@@ -3119,7 +3119,7 @@
       return;
     }
 
-  fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES);
+  fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES,0);
 
   demand_empty_rest_of_line ();
 }
@@ -3518,7 +3518,7 @@
       subseg_change (sec, 0);
       fix_new (fscan->fx_frag,
 	       S_GET_VALUE (sym) - fscan->fx_frag->fr_address,
-	       4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT);
+	       4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT,0);
     }
 }
 
@@ -3559,7 +3559,7 @@
     case C (COND_JUMP_DELAY, COND8):
       subseg_change (seg, 0);
       fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
-	       1, BFD_RELOC_SH_PCDISP8BY2);
+	       1, BFD_RELOC_SH_PCDISP8BY2,0);
       fragP->fr_fix += 2;
       fragP->fr_var = 0;
       break;
@@ -3567,7 +3567,7 @@
     case C (UNCOND_JUMP, UNCOND12):
       subseg_change (seg, 0);
       fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
-	       1, BFD_RELOC_SH_PCDISP12BY2);
+	       1, BFD_RELOC_SH_PCDISP12BY2,0);
       fragP->fr_fix += 2;
       fragP->fr_var = 0;
       break;
@@ -3624,13 +3624,13 @@
 	subseg_change (seg, 0);
 	fix_new (fragP, fragP->fr_fix, 2, section_symbol (seg),
 		 fragP->fr_address + fragP->fr_fix + (delay ? 4 : 6),
-		 1, BFD_RELOC_SH_PCDISP8BY2);
+		 1, BFD_RELOC_SH_PCDISP8BY2,0);
 
 	/* Set up a jump instruction.  */
 	buffer[highbyte + 2] = 0xa0;
 	buffer[lowbyte + 2] = 0;
 	fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
-		 fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2);
+		 fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2,0);
 
 	if (delay)
 	  {
@@ -3802,7 +3802,7 @@
       && frag->fr_offset > 1
       && now_seg != bss_section)
     fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0,
-	     BFD_RELOC_SH_ALIGN);
+	     BFD_RELOC_SH_ALIGN,0);
 }
 
 /* See whether the relocation should be resolved locally.  */
diff -ru --new-file a/gas/config/te-amiga.h b/gas/config/te-amiga.h
--- a/gas/config/te-amiga.h	1970-01-01 03:00:00.000000000 +0300
+++ b/gas/config/te-amiga.h	2021-02-01 23:12:49.208608700 +0300
@@ -0,0 +1,24 @@
+/*
+ * te-amiga.h -- Amiga target environment declarations.
+ */
+
+#define TE_AMIGA 1
+
+#define LOCAL_LABELS_DOLLAR 1
+#define LOCAL_LABELS_FB 1
+
+#ifdef OBJ_HEADER
+#include OBJ_HEADER
+#else
+#include "obj-format.h"
+#endif
+
+#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR)	\
+  do {							\
+    if ((SIZE) >= 4)                                 	\
+      (P2VAR) = 2;					\
+    else if ((SIZE) >= 2)				\
+      (P2VAR) = 1;					\
+    else						\
+      (P2VAR) = 0;					\
+  } while (0)
diff -ru --new-file a/gas/config/te-amigaos.h b/gas/config/te-amigaos.h
--- a/gas/config/te-amigaos.h	1970-01-01 03:00:00.000000000 +0300
+++ b/gas/config/te-amigaos.h	2021-02-01 23:12:49.209611100 +0300
@@ -0,0 +1,14 @@
+/*
+ * te-amigaos.h -- Amiga target environment declarations.
+ */
+
+#define TE_AMIGAOS 1
+
+#define LOCAL_LABELS_DOLLAR 1
+#define LOCAL_LABELS_FB 1
+
+#ifdef OBJ_HEADER
+#include OBJ_HEADER
+#else
+#include "obj-format.h"
+#endif
diff -ru --new-file a/gas/config/te-amithlon.h b/gas/config/te-amithlon.h
--- a/gas/config/te-amithlon.h	1970-01-01 03:00:00.000000000 +0300
+++ b/gas/config/te-amithlon.h	2021-02-01 23:12:49.210613600 +0300
@@ -0,0 +1,26 @@
+/* te-amithlon.h -- Amithlon target environment declarations.
+   Copyright 2000 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS 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 2, or (at your option)
+   any later version.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#define TE_Amithlon 1
+
+#define LOCAL_LABELS_DOLLAR 1
+#define LOCAL_LABELS_FB 1
+
+#include "obj-format.h"
diff -ru --new-file a/gas/config/te-morphos.h b/gas/config/te-morphos.h
--- a/gas/config/te-morphos.h	1970-01-01 03:00:00.000000000 +0300
+++ b/gas/config/te-morphos.h	2021-02-01 23:12:49.211616100 +0300
@@ -0,0 +1,14 @@
+/*
+ * te-amiga.h -- Amiga target environment declarations.
+ */
+
+#define TE_MORPHOS 1
+
+#define LOCAL_LABELS_DOLLAR 1
+#define LOCAL_LABELS_FB 1
+
+#ifdef OBJ_HEADER
+#include OBJ_HEADER
+#else
+#include "obj-format.h"
+#endif
diff -ru --new-file a/gas/configure b/gas/configure
--- a/gas/configure	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/configure	2022-02-17 13:34:07.243706400 +0300
@@ -12492,6 +12492,12 @@
 #define DEFAULT_EMULATION "$DEFAULT_EMULATION"
 _ACEOF
 
+# FIXME: As of version 2.18 of binutils, MANY_SEGMENTS no longer exists
+#case ${primary_bfd_gas}-${target_cpu_type}-${obj_format} in
+#  yes-*-coff)	need_bfd=yes ;;
+#  no-*-coff | yes-m68k-amigahunk | no-m68k-amigahunk)	need_bfd=yes
+#		AC_DEFINE(MANY_SEGMENTS, 1, [old COFF support?]) ;;
+#esac
 
 reject_dev_configs=yes
 
@@ -12542,6 +12548,20 @@
 _ACEOF
 
 
+### begin-GG-local
+# Check for additional host specific CFLAGS.
+echo "$as_me:$LINENO: checking for host dependent CFLAGS" >&5
+echo $ECHO_N "checking for host dependent CFLAGS... $ECHO_C" >&6
+other_host_cflags=""
+case "${host}" in
+	m68k-*-amigaos*)	other_host_cflags="-mstackextend" ;;
+esac
+test -n "$other_host_cflags" && CFLAGS="$CFLAGS $other_host_cflags"
+echo "$as_me:$LINENO: result: $other_host_cflags" >&5
+echo "${ECHO_T}$other_host_cflags" >&6
+### end-GG-local
+
+
 for ac_prog in 'bison -y' byacc
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
diff -ru --new-file a/gas/configure.in b/gas/configure.in
--- a/gas/configure.in	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/configure.in	2022-02-17 13:35:06.040695100 +0300
@@ -594,6 +594,14 @@
 AC_DEFINE_UNQUOTED(DEFAULT_EMULATION, "$DEFAULT_EMULATION",
 		   [Default emulation.])
 
+# FIXME: As of version 2.18 of binutils, MANY_SEGMENTS no longer exists
+#case ${primary_bfd_gas}-${target_cpu_type}-${obj_format} in
+#  yes-*-coff)	need_bfd=yes ;;
+#  no-*-coff | yes-m68k-amigahunk | no-m68k-amigahunk)	need_bfd=yes
+#		AC_DEFINE(MANY_SEGMENTS, 1, [old COFF support?]) ;;
+#esac
+
+
 reject_dev_configs=yes
 
 case ${reject_dev_configs}-${dev} in
@@ -624,6 +632,17 @@
 AC_DEFINE_UNQUOTED(TARGET_VENDOR,	"${target_vendor}", [Target vendor.])
 AC_DEFINE_UNQUOTED(TARGET_OS,		"${target_os}",    [Target OS.])
 
+### begin-GG-local
+# Check for additional host specific CFLAGS.
+AC_MSG_CHECKING(for host dependent CFLAGS)
+other_host_cflags=""
+case "${host}" in
+	m68k-*-amigaos*)	other_host_cflags="-mstackextend" ;;
+esac
+test -n "$other_host_cflags" && CFLAGS="$CFLAGS $other_host_cflags"
+AC_MSG_RESULT($other_host_cflags)
+### end-GG-local
+
 AC_PROG_YACC
 AM_PROG_LEX
 
diff -ru --new-file a/gas/configure.tgt b/gas/configure.tgt
--- a/gas/configure.tgt	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/configure.tgt	2022-02-17 13:36:24.744812500 +0300
@@ -60,7 +60,8 @@
   epiphany*)		cpu_type=epiphany endian=little ;;
   fido)			cpu_type=m68k ;;
   hppa*)		cpu_type=hppa ;;
-  i[3-7]86)		cpu_type=i386 arch=i386;;
+  i[3-7]86)		cpu_type=i386 arch=i386 endian=little ;;
+  i[3-7]86)		cpu_type=i386 arch=i386 endian=big ;;
   ia64)			cpu_type=ia64 ;;
   ip2k)			cpu_type=ip2k endian=big ;;
   iq2000)		cpu_type=iq2000 endian=big ;;
@@ -202,6 +203,7 @@
 
   i386-ibm-aix*)			fmt=coff em=i386aix ;;
   i386-sequent-bsd*)			fmt=aout em=dynix ;;
+  i386-*-amithlon*)	    		fmt=elf em=amithlon ;;
   i386-*-beospe*)			fmt=coff em=pe ;;
   i386-*-beos*)				fmt=elf ;;
   i386-*-coff)				fmt=coff ;;
@@ -296,6 +298,8 @@
   m68hc11-*-* | m6811-*-*)		fmt=elf ;;
   m68hc12-*-* | m6812-*-*)		fmt=elf ;;
 
+  m68k-*-amigaoshunk)		fmt=amigahunk em=amiga bfd_gas=yes ;;
+  m68k-*-amigaos*)			fmt=aout em=amiga ;;
   m68k-*-aout)				fmt=aout bfd_gas=yes ;;
   m68k-*-elf*)				fmt=elf ;;
   m68k-*-sysv4*)			fmt=elf em=svr4 ;;
@@ -359,6 +363,8 @@
 
   pj*)					fmt=elf ;;
 
+  ppc-*-amigaos*)         		fmt=elf em=amigaos ;;
+  ppc-*-morphos*)			fmt=elf em=morphos ;;
   ppc-*-pe | ppc-*-cygwin*)		fmt=coff em=pe ;;
   ppc-*-winnt*)				fmt=coff em=pe ;;
   ppc-*-aix5.[01])			fmt=coff em=aix5 ;;
diff -ru --new-file a/gas/Makefile.am b/gas/Makefile.am
--- a/gas/Makefile.am	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/Makefile.am	2022-02-16 23:38:43.495889000 +0300
@@ -269,6 +269,7 @@
 # OBJ files in config
 
 OBJ_FORMAT_CFILES = \
+	config/obj-amigahunk.c \
 	config/obj-aout.c \
 	config/obj-coff.c \
 	config/obj-ecoff.c \
@@ -280,6 +281,7 @@
 	config/obj-som.c
 
 OBJ_FORMAT_HFILES = \
+	config/obj-amigahunk.h \
 	config/obj-aout.h \
 	config/obj-coff.h \
 	config/obj-ecoff.h \
@@ -295,6 +297,7 @@
 TARG_ENV_HFILES = \
 	config/te-386bsd.h \
 	config/te-aix5.h \
+	config/te-amiga.h \
 	config/te-armeabi.h \
 	config/te-armlinuxeabi.h \
 	config/te-dynix.h \
@@ -364,7 +367,7 @@
 	rl78-parse.c rl78-parse.h \
 	rx-parse.c rx-parse.h
 
-diststuff: $(EXTRA_DIST) info
+diststuff: $(EXTRA_DIST) info guide
 
 DISTCLEANFILES = targ-cpu.h obj-format.h targ-env.h itbl-cpu.h cgen-desc.h
 
diff -ru --new-file a/gas/Makefile.in b/gas/Makefile.in
--- a/gas/Makefile.in	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/Makefile.in	2022-02-17 15:52:49.811375100 +0300
@@ -538,6 +538,7 @@
 
 # OBJ files in config
 OBJ_FORMAT_CFILES = \
+	config/obj-amigahunk.c \
 	config/obj-aout.c \
 	config/obj-coff.c \
 	config/obj-ecoff.c \
@@ -549,6 +550,7 @@
 	config/obj-som.c
 
 OBJ_FORMAT_HFILES = \
+	config/obj-amigahunk.h \
 	config/obj-aout.h \
 	config/obj-coff.h \
 	config/obj-ecoff.h \
@@ -564,6 +566,7 @@
 TARG_ENV_HFILES = \
 	config/te-386bsd.h \
 	config/te-aix5.h \
+	config/te-amiga.h \
 	config/te-armeabi.h \
 	config/te-armlinuxeabi.h \
 	config/te-dynix.h \
@@ -798,6 +801,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m68k-parse.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/macro.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/messages.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-amigahunk.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-aout.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-coff.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-ecoff.Po@am__quote@
@@ -1888,6 +1892,20 @@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xtensa-relax.obj `if test -f 'config/xtensa-relax.c'; then $(CYGPATH_W) 'config/xtensa-relax.c'; else $(CYGPATH_W) '$(srcdir)/config/xtensa-relax.c'; fi`
 
+obj-amigahunk.o: config/obj-amigahunk.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obj-amigahunk.o -MD -MP -MF $(DEPDIR)/obj-amigahunk.Tpo -c -o obj-amigahunk.o `test -f 'config/obj-amigahunk.c' || echo '$(srcdir)/'`config/obj-amigahunk.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/obj-amigahunk.Tpo $(DEPDIR)/obj-amigahunk.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/obj-amigahunk.c' object='obj-amigahunk.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obj-amigahunk.o `test -f 'config/obj-amigahunk.c' || echo '$(srcdir)/'`config/obj-amigahunk.c
+
+obj-amigahunk.obj: config/obj-amigahunk.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obj-amigahunk.obj -MD -MP -MF $(DEPDIR)/obj-amigahunk.Tpo -c -o obj-amigahunk.obj `if test -f 'config/obj-amigahunk.c'; then $(CYGPATH_W) 'config/obj-amigahunk.c'; else $(CYGPATH_W) '$(srcdir)/config/obj-amigahunk.c'; fi`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/obj-amigahunk.Tpo $(DEPDIR)/obj-amigahunk.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/obj-amigahunk.c' object='obj-amigahunk.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obj-amigahunk.obj `if test -f 'config/obj-amigahunk.c'; then $(CYGPATH_W) 'config/obj-amigahunk.c'; else $(CYGPATH_W) '$(srcdir)/config/obj-amigahunk.c'; fi`
+
 obj-aout.o: config/obj-aout.c
 @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obj-aout.o -MD -MP -MF $(DEPDIR)/obj-aout.Tpo -c -o obj-aout.o `test -f 'config/obj-aout.c' || echo '$(srcdir)/'`config/obj-aout.c
 @am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/obj-aout.Tpo $(DEPDIR)/obj-aout.Po
@@ -2449,7 +2467,7 @@
 	for f in $(POTFILES); do echo $$f; done | LC_ALL=C sort > tmp \
 	  && mv tmp $(srcdir)/po/POTFILES.in
 
-diststuff: $(EXTRA_DIST) info
+diststuff: $(EXTRA_DIST) info guide
 
 check-DEJAGNU: site.exp
 	if [ -d testsuite ]; then \
diff -ru --new-file a/gas/read.c b/gas/read.c
--- a/gas/read.c	2013-11-08 14:13:48.000000000 +0400
+++ b/gas/read.c	2022-02-17 16:00:48.099916800 +0300
@@ -46,6 +46,11 @@
 #define TC_START_LABEL(x,y,z) (x == ':')
 #endif
 
+#ifdef OBJ_AMIGAHUNK
+extern segT data_chip_section, bss_chip_section;
+#endif
+
+
 /* Set by the object-format or the target.  */
 #ifndef TC_IMPLICIT_LCOMM_ALIGNMENT
 #define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR)		\
@@ -314,6 +319,9 @@
   {"common", s_mri_common, 0},
   {"common.s", s_mri_common, 1},
   {"data", s_data, 0},
+#ifdef OBJ_AMIGAHUNK
+  {"datachip", s_data_chip, 0},
+#endif
   {"dc", cons, 2},
 #ifdef TC_ADDRESS_BYTES
   {"dc.a", cons, 0},
@@ -1892,6 +1900,16 @@
   demand_empty_rest_of_line ();
 }
 
+#ifdef OBJ_AMIGAHUNK
+void
+s_data_chip (int ignore ATTRIBUTE_UNUSED)
+{
+  int temp = get_absolute_expression ();
+  subseg_set (data_chip_section, (subsegT) temp);
+  demand_empty_rest_of_line ();
+}
+#endif
+
 /* Handle the .appfile pseudo-op.  This is automatically generated by
    do_scrub_chars when a preprocessor # line comment is seen with a
    file name.  This default definition may be overridden by the object
@@ -4389,7 +4407,7 @@
   /* Generate a fixS to record the symbol value.  */
 
 #ifdef TC_CONS_FIX_NEW
-  TC_CONS_FIX_NEW (frag, p - frag->fr_literal, nbytes, exp);
+  TC_CONS_FIX_NEW (frag, p - frag->fr_literal, nbytes, exp,0);
 #else
   {
     bfd_reloc_code_real_type r;
@@ -4417,7 +4435,7 @@
 	break;
       }
     fix_new_exp (frag, p - frag->fr_literal, (int) nbytes, exp,
-		 0, r);
+		 0, r, 0);
   }
 #endif
 }
diff -ru --new-file a/gas/read.h b/gas/read.h
--- a/gas/read.h	2013-11-04 19:33:37.000000000 +0400
+++ b/gas/read.h	2022-02-17 13:39:03.489963500 +0300
@@ -133,6 +133,10 @@
 
 extern void generate_lineno_debug (void);
 
+#ifdef OBJ_AMIGAHUNK
+extern void s_data_chip (int);
+#endif
+
 extern void s_abort (int) ATTRIBUTE_NORETURN;
 extern void s_align_bytes (int arg);
 extern void s_align_ptwo (int);
diff -ru --new-file a/gas/write.c b/gas/write.c
--- a/gas/write.c	2013-11-04 19:33:38.000000000 +0400
+++ b/gas/write.c	2022-02-17 13:43:17.712899000 +0300
@@ -151,7 +151,8 @@
 		  offsetT offset,	/* X_add_number.  */
 		  int pcrel,		/* TRUE if PC-relative relocation.  */
 		  RELOC_ENUM r_type	/* Relocation type.  */,
-		  int at_beginning)	/* Add to the start of the list?  */
+		  int at_beginning,	/* Add to the start of the list?  */
+		  int baserel ATTRIBUTE_UNUSED) /* TRUE if base-relative data */
 {
   fixS *fixP;
 
@@ -191,8 +192,11 @@
 #endif
 
 #ifdef TC_FIX_TYPE
+#ifndef TC_PPC
+  fixP->tc_fix_data = baserel;
   TC_INIT_FIX_DATA (fixP);
 #endif
+#endif
 
   as_where (&fixP->fx_file, &fixP->fx_line);
 
@@ -235,10 +239,11 @@
 	 symbolS *add_symbol,	/* X_add_symbol.  */
 	 offsetT offset,		/* X_add_number.  */
 	 int pcrel,			/* TRUE if PC-relative relocation.  */
-	 RELOC_ENUM r_type		/* Relocation type.  */)
+	 RELOC_ENUM r_type,		/* Relocation type.  */
+     int baserel)		/* TRUE if base-relative data */
 {
   return fix_new_internal (frag, where, size, add_symbol,
-			   (symbolS *) NULL, offset, pcrel, r_type, FALSE);
+			   (symbolS *) NULL, offset, pcrel, r_type, FALSE,baserel);
 }
 
 /* Create a fixup for an expression.  Currently we only support fixups
@@ -251,7 +256,8 @@
 	     int size,			/* 1, 2, or 4 usually.  */
 	     expressionS *exp,		/* Expression.  */
 	     int pcrel,			/* TRUE if PC-relative relocation.  */
-	     RELOC_ENUM r_type		/* Relocation type.  */)
+	     RELOC_ENUM r_type,		/* Relocation type.  */
+	     int baserel)		/* TRUE if base-relative data */
 {
   symbolS *add = NULL;
   symbolS *sub = NULL;
@@ -277,7 +283,7 @@
 	exp->X_add_symbol = stmp;
 	exp->X_add_number = 0;
 
-	return fix_new_exp (frag, where, size, exp, pcrel, r_type);
+	return fix_new_exp (frag, where, size, exp, pcrel, r_type,baserel);
       }
 
     case O_symbol_rva:
@@ -307,7 +313,7 @@
     }
 
   return fix_new_internal (frag, where, size, add, sub, off, pcrel,
-			   r_type, FALSE);
+			   r_type, FALSE,baserel);
 }
 
 /* Create a fixup at the beginning of FRAG.  The arguments are the same
@@ -318,7 +324,7 @@
 	      offsetT offset, int pcrel, RELOC_ENUM r_type)
 {
   return fix_new_internal (frag, 0, size, add_symbol,
-			   (symbolS *) NULL, offset, pcrel, r_type, TRUE);
+			   (symbolS *) NULL, offset, pcrel, r_type, TRUE,0);
 }
 
 /* Generic function to determine whether a fixup requires a relocation.  */
@@ -894,6 +900,13 @@
    Ones that we couldn't completely handle here will be output later
    by emit_relocations.  */
 
+/* FIXME: There was following code here
+#if !defined(BFD_ASSEMBLER) && !defined(MANY_SEGMENTS)
+      if (fixP->tc_fix_data && add_number != fixP->fx_offset)
+        add_number -= text_last_frag->fr_address;
+#endif
+*/
+
 static void
 fixup_segment (fixS *fixP, segT this_segment)
 {
@@ -1885,11 +1898,11 @@
 #ifdef TC_CONS_FIX_NEW
 	  TC_CONS_FIX_NEW (lie->frag,
 			   lie->word_goes_here - lie->frag->fr_literal,
-			   2, &exp);
+			   2, &exp,0);
 #else
 	  fix_new_exp (lie->frag,
 		       lie->word_goes_here - lie->frag->fr_literal,
-		       2, &exp, 0, BFD_RELOC_16);
+		       2, &exp, 0, BFD_RELOC_16,0);
 #endif
 	  *prevP = lie->next_broken_word;
 	}
diff -ru --new-file a/gas/write.h b/gas/write.h
--- a/gas/write.h	2013-11-04 19:33:38.000000000 +0400
+++ b/gas/write.h	2022-02-17 13:45:10.200969500 +0300
@@ -179,13 +179,13 @@
 extern void number_to_chars_bigendian (char *, valueT, int);
 extern fixS *fix_new
   (fragS * frag, int where, int size, symbolS * add_symbol,
-   offsetT offset, int pcrel, bfd_reloc_code_real_type r_type);
+   offsetT offset, int pcrel, bfd_reloc_code_real_type r_type,int baserel);
 extern fixS *fix_at_start
   (fragS * frag, int size, symbolS * add_symbol,
    offsetT offset, int pcrel, bfd_reloc_code_real_type r_type);
 extern fixS *fix_new_exp
   (fragS * frag, int where, int size, expressionS *exp, int pcrel,
-   bfd_reloc_code_real_type r_type);
+   bfd_reloc_code_real_type r_type,int baserel);
 extern void write_print_statistics (FILE *);
 
 #endif /* __write_h__ */
diff -ru --new-file a/gprof/configure b/gprof/configure
--- a/gprof/configure	2013-11-04 19:33:39.000000000 +0400
+++ b/gprof/configure	2022-02-17 13:46:31.046042400 +0300
@@ -11866,7 +11866,18 @@
   ac_config_commands="$ac_config_commands default-1"
 
 
-
+### begin-GG-local
+# Check for additional host specific CFLAGS.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for host dependent CFLAGS" >&5
+$as_echo_n "checking for host dependent CFLAGS... " >&6; }
+other_host_cflags=""
+case "${host}" in
+	m68*-*-amigaos*)	other_host_cflags="-mstackextend" ;;
+esac
+test -n "$other_host_cflags" && CFLAGS="$CFLAGS $other_host_cflags"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $other_host_cflags" >&5
+$as_echo "$other_host_cflags" >&6; }
+### end-GG-local
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
 $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
diff -ru --new-file a/gprof/configure.in b/gprof/configure.in
--- a/gprof/configure.in	2013-11-04 19:33:39.000000000 +0400
+++ b/gprof/configure.in	2022-02-17 13:47:02.720239900 +0300
@@ -48,6 +48,17 @@
 ZW_GNU_GETTEXT_SISTER_DIR
 AM_PO_SUBDIRS
 
+### begin-GG-local
+# Check for additional host specific CFLAGS.
+AC_MSG_CHECKING(for host dependent CFLAGS)
+other_host_cflags=""
+case "${host}" in
+	m68*-*-amigaos*)	other_host_cflags="-mstackextend" ;;
+esac
+test -n "$other_host_cflags" && CFLAGS="$CFLAGS $other_host_cflags"
+AC_MSG_RESULT($other_host_cflags)
+### end-GG-local
+
 AM_MAINTAINER_MODE
 AM_CONDITIONAL(GENINSRC_NEVER, false)
 AC_EXEEXT
diff -ru --new-file a/gprof/gconfig.in b/gprof/gconfig.in
--- a/gprof/gconfig.in	2013-11-04 19:33:39.000000000 +0400
+++ b/gprof/gconfig.in	2022-02-17 13:47:29.161449300 +0300
@@ -1,9 +1,5 @@
 /* gconfig.in.  Generated from configure.in by autoheader.  */
 
-/* Define to 1 if translation of program messages to the user's native
-   language is requested. */
-#undef ENABLE_NLS
-
 /* Is the prototype for getopt in <unistd.h> in the expected format? */
 #undef HAVE_DECL_GETOPT
 
diff -ru --new-file a/gprof/Makefile.am b/gprof/Makefile.am
--- a/gprof/Makefile.am	2013-11-08 14:13:48.000000000 +0400
+++ b/gprof/Makefile.am	2022-02-17 13:45:40.712347000 +0300
@@ -56,7 +56,7 @@
 BUILT_SOURCES = flat_bl.c bsd_callg_bl.c fsf_callg_bl.c
 EXTRA_DIST    = $(BUILT_SOURCES) bbconv.pl $(man_MANS)
 
-diststuff: $(BUILT_SOURCES) info $(man_MANS)
+diststuff: $(BUILT_SOURCES) info guide $(man_MANS)
 
 # We extract version from bfd/configure.in, make sure to rerun configure
 # when BFD's version changes.
diff -ru --new-file a/gprof/Makefile.in b/gprof/Makefile.in
--- a/gprof/Makefile.in	2013-11-08 14:13:48.000000000 +0400
+++ b/gprof/Makefile.in	2022-02-17 13:45:57.664990400 +0300
@@ -1036,7 +1036,7 @@
 	uninstall-man1 uninstall-pdf-am uninstall-ps-am
 
 
-diststuff: $(BUILT_SOURCES) info $(man_MANS)
+diststuff: $(BUILT_SOURCES) info guide $(man_MANS)
 
 # This empty rule is a hack against gmake patched by Apple.
 %.o:%.m
diff -ru --new-file a/include/elf/amigaos.h b/include/elf/amigaos.h
--- a/include/elf/amigaos.h	1970-01-01 03:00:00.000000000 +0300
+++ b/include/elf/amigaos.h	2021-02-01 23:12:49.248749300 +0300
@@ -0,0 +1,27 @@
+/* AmigaOS ELF support for BFD.
+   Copyright 2001 Free Software Foundation, Inc.
+
+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 2 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.  */
+
+#ifndef _ELF_AMIGAOS_H
+#define _ELF_AMIGAOS_H
+
+#include "elf/common.h"
+
+#define DT_AMIGAOS_DYNVERSION	(DT_LOOS + 1)
+
+#endif /* _ELF_AMIGAOS_H */
diff -ru --new-file a/include/elf/ppc.h b/include/elf/ppc.h
--- a/include/elf/ppc.h	2013-11-18 12:40:15.000000000 +0400
+++ b/include/elf/ppc.h	2022-02-17 13:49:00.297572500 +0300
@@ -131,6 +131,19 @@
   RELOC_NUMBER (R_PPC_EMB_BIT_FLD,	115)
   RELOC_NUMBER (R_PPC_EMB_RELSDA,	116)
 
+/* Special MorphOS relocs. */
+  RELOC_NUMBER (R_PPC_MORPHOS_DREL,	200)
+  RELOC_NUMBER (R_PPC_MORPHOS_DREL_LO,	201)
+  RELOC_NUMBER (R_PPC_MORPHOS_DREL_HI,	202)
+  RELOC_NUMBER (R_PPC_MORPHOS_DREL_HA,	203)
+
+/* AmigaOS4 relocs */
+  RELOC_NUMBER (R_PPC_AMIGAOS_BREL,	210)
+  RELOC_NUMBER (R_PPC_AMIGAOS_BREL_LO,	211)
+  RELOC_NUMBER (R_PPC_AMIGAOS_BREL_HI,  212)
+  RELOC_NUMBER (R_PPC_AMIGAOS_BREL_HA,  213)
+
+
 /* PowerPC VLE relocations.  */
   RELOC_NUMBER (R_PPC_VLE_REL8,		216)
   RELOC_NUMBER (R_PPC_VLE_REL15,	217)
diff -ru --new-file a/include/libiberty.h b/include/libiberty.h
--- a/include/libiberty.h	2013-11-04 19:33:39.000000000 +0400
+++ b/include/libiberty.h	2022-02-17 13:49:42.536175300 +0300
@@ -106,7 +106,7 @@
    to find the declaration so provide a fully prototyped one.  If it
    is 1, we found it so don't provide any declaration at all.  */
 #if !HAVE_DECL_BASENAME
-#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__) || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) || defined (HAVE_DECL_BASENAME)
+#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__) || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) || defined(AMIGA) || defined (HAVE_DECL_BASENAME)
 extern char *basename (const char *);
 #else
 /* Do not allow basename to be used if there is no prototype seen.  We
diff -ru --new-file a/ld/configure.host b/ld/configure.host
--- a/ld/configure.host	2013-11-04 19:33:39.000000000 +0400
+++ b/ld/configure.host	2022-02-17 13:57:25.734410500 +0300
@@ -191,6 +191,10 @@
   HOSTING_LIBS='-L/usr/lib32 '"$HOSTING_LIBS"' `if [ -f ../gcc/crtend.o ]; then echo ../gcc/crtend.o ; else ${CC} -print-file-name=crtend.o; fi` /usr/lib32/crtn.o -init __do_global_ctors -fini __do_global_dtors'
   ;;
 
+m68*-*-amigaos*)
+  HDEFINES=-mstackextend
+  ;;
+
 m68*-motorola-sysv)
   HOSTING_CRT0='`if [ -f ../gcc/crt0.o ]; then echo ../gcc/crt0.o; elif [ -f \`${CC} -print-file-name=\`crt0.o ]; then echo \`${CC} -print-file-name=\`crt0.o; else echo /lib/crt0.o; fi`'
   HOSTING_LIBS=`sed -e 's,-lc,-lc881,' <<EOF
diff -ru --new-file a/ld/configure.tgt b/ld/configure.tgt
--- a/ld/configure.tgt	2013-11-26 15:37:33.000000000 +0400
+++ b/ld/configure.tgt	2022-02-17 13:59:00.927964900 +0300
@@ -329,6 +329,7 @@
 			targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" ;;
 i[3-7]86-*-interix*)	targ_emul=i386pe_posix;
  			targ_extra_ofiles="deffilep.o pe-dll.o" ;;
+i[3-7]86be-*-amithlon*) targ_emul=amithlon;;
 i[3-7]86-*-beospe*)	targ_emul=i386beos ;;
 i[3-7]86-*-beos*)	targ_emul=elf_i386_be ;;
 i[3-7]86-*-vxworks*)	targ_emul=elf_i386_vxworks ;;
@@ -393,6 +394,7 @@
 m68k-sony-*)		targ_emul=news ;;
 m68k-hp-bsd*)		targ_emul=hp300bsd ;;
 m68*-motorola-sysv*)	targ_emul=delta68 ;;
+m68*-*-amigaos*)	targ_emul=amiga ; targ_extra_emuls=amiga_bss;;
 m68*-*-aout)		targ_emul=m68kaout ;;
 m68*-*-coff)		targ_emul=m68kcoff ;;
 m68*-*-elf)		targ_emul=m68kelf ;;
@@ -529,6 +531,9 @@
 pjl*-*-*)	        targ_emul=pjlelf ; targ_extra_emuls="elf_i386" ;;
 pj*-*-*)	        targ_emul=pjelf
 			;;
+powerpc-*-amigaos*)	targ_emul=amigaos; targ_extra_emuls=elf32ppc ;;
+powerpc-*-amigaoshunk*)	targ_emul=ppcamiga ; targ_extra_emuls=ppcamiga_bss;;
+powerpc-*-morphos*)	targ_emul=morphos ; targ_extra_emuls=morphos_baserel;;
 powerpc-*-freebsd* | powerpc-*-kfreebsd*-gnu)
 			targ_emul=elf32ppc_fbsd
 			targ_extra_emuls="elf32ppc elf32ppcsim"
@@ -819,6 +824,10 @@
 *-*-netbsd*)
   ;;
 
+powerpc-*-amigaos*)
+  NATIVE_LIB_DIRS='/gcc/local/lib /gcc/lib'
+  ;;
+
 alpha*-*-*)
   NATIVE_LIB_DIRS='/usr/local/lib /usr/ccs/lib /lib /usr/lib'
   ;;
diff -ru --new-file a/ld/emulparams/amiga.sh b/ld/emulparams/amiga.sh
--- a/ld/emulparams/amiga.sh	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emulparams/amiga.sh	2021-02-01 23:12:49.271811900 +0300
@@ -0,0 +1,6 @@
+SCRIPT_NAME=amiga
+OUTPUT_FORMAT="amiga"
+TEXT_START_ADDR=0x0
+SEGMENT_SIZE=0x0
+TEMPLATE_NAME=amiga
+ARCH=m68k
diff -ru --new-file a/ld/emulparams/amiga_bss.sh b/ld/emulparams/amiga_bss.sh
--- a/ld/emulparams/amiga_bss.sh	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emulparams/amiga_bss.sh	2021-02-01 23:12:49.271811900 +0300
@@ -0,0 +1,6 @@
+SCRIPT_NAME=amiga_bss
+OUTPUT_FORMAT="amiga"
+TEXT_START_ADDR=0x0
+SEGMENT_SIZE=0x0
+TEMPLATE_NAME=amiga
+ARCH=m68k
diff -ru --new-file a/ld/emulparams/amigaos.sh b/ld/emulparams/amigaos.sh
--- a/ld/emulparams/amigaos.sh	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emulparams/amigaos.sh	2022-02-17 18:55:07.182603900 +0300
@@ -0,0 +1,26 @@
+#. ${srcdir}/emulparams/elf32ppccommon.sh
+TEMPLATE_NAME=amigaos
+SCRIPT_NAME=amigaos
+OUTPUT_FORMAT="elf32-amigaos"
+MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
+ALIGNMENT=16
+ARCH=powerpc
+MACHINE=
+GENERATE_SHLIB_SCRIPT=yes
+TEXT_START_ADDR=0x01000000
+SHLIB_TEXT_START_ADDR=0x10000000
+unset WRITABLE_RODATA
+DATA_START_SYMBOLS="_DATA_BASE_ = .;"
+SDATA_START_SYMBOLS="_SDA_BASE_ = . + 0x8000;"
+DATA_GOT=
+SDATA_GOT=
+TEXT_PLT=yes
+SEPARATE_GOTPLT=0
+unset BSS_PLT
+unset DATA_PLT
+GOT=".got          ${RELOCATING-0} : SPECIAL { *(.got) }"
+PLT=".plt          ${RELOCATING-0} :  { *(.plt) }"
+# GOTPLT="${PLT}"
+OTHER_TEXT_SECTIONS="*(.glink)"
+EXTRA_EM_FILE=ppc32elf
diff -ru --new-file a/ld/emulparams/amithlon.sh b/ld/emulparams/amithlon.sh
--- a/ld/emulparams/amithlon.sh	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emulparams/amithlon.sh	2021-02-01 23:12:49.274817900 +0300
@@ -0,0 +1,11 @@
+SCRIPT_NAME=amithlon
+OUTPUT_FORMAT="elf32-i386be-amithlon"
+#TEXT_START_ADDR=0x08048000
+#MAXPAGESIZE=0x1000
+MAXPAGESIZE=32
+#NONPAGED_TEXT_START_ADDR=0x08048000
+ARCH=i386
+MACHINE=
+NOP=0x9090
+TEMPLATE_NAME=amithlon
+GENERATE_SHLIB_SCRIPT=yes
diff -ru --new-file a/ld/emulparams/morphos.sh b/ld/emulparams/morphos.sh
--- a/ld/emulparams/morphos.sh	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emulparams/morphos.sh	2021-02-01 23:12:49.274817900 +0300
@@ -0,0 +1,6 @@
+TEMPLATE_NAME=morphos
+SCRIPT_NAME=morphos
+OUTPUT_FORMAT="elf32-morphos"
+MAXPAGESIZE=0x40000
+ARCH=powerpc
+MACHINE=
diff -ru --new-file a/ld/emulparams/morphos_baserel.sh b/ld/emulparams/morphos_baserel.sh
--- a/ld/emulparams/morphos_baserel.sh	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emulparams/morphos_baserel.sh	2021-02-01 23:12:49.275823000 +0300
@@ -0,0 +1,6 @@
+TEMPLATE_NAME=morphos
+SCRIPT_NAME=morphos_baserel
+OUTPUT_FORMAT="elf32-morphos"
+MAXPAGESIZE=0x40000
+ARCH=powerpc
+MACHINE=
diff -ru --new-file a/ld/emulparams/ppcamiga.sh b/ld/emulparams/ppcamiga.sh
--- a/ld/emulparams/ppcamiga.sh	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emulparams/ppcamiga.sh	2021-02-01 23:12:49.276824000 +0300
@@ -0,0 +1,8 @@
+SCRIPT_NAME=amiga
+OUTPUT_FORMAT="amiga"
+TEXT_START_ADDR=0x400
+PAGE_SIZE=0x400
+SEGMENT_SIZE=0x400
+NONPAGED_TEXT_START_ADDR=0x400
+TEMPLATE_NAME=amiga
+ARCH=powerpc
diff -ru --new-file a/ld/emulparams/ppcamiga_bss.sh b/ld/emulparams/ppcamiga_bss.sh
--- a/ld/emulparams/ppcamiga_bss.sh	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emulparams/ppcamiga_bss.sh	2021-02-01 23:12:49.277825300 +0300
@@ -0,0 +1,8 @@
+SCRIPT_NAME=amiga_bss
+OUTPUT_FORMAT="amiga"
+TEXT_START_ADDR=0x400
+PAGE_SIZE=0x400
+SEGMENT_SIZE=0x400
+NONPAGED_TEXT_START_ADDR=0x400
+TEMPLATE_NAME=amiga
+ARCH=powerpc
diff -ru --new-file a/ld/emultempl/amiga.em b/ld/emultempl/amiga.em
--- a/ld/emultempl/amiga.em	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emultempl/amiga.em	2021-02-01 23:12:49.278828500 +0300
@@ -0,0 +1,288 @@
+# This shell script emits a C file. -*- C -*-
+# It does some substitutions.
+cat >e${EMULATION_NAME}.c <<EOF
+/* This file is is generated by a shell script.  DO NOT EDIT! */
+
+/* emulate the original gld for the given ${EMULATION_NAME}
+   Copyright (C) 1991, 1993 Free Software Foundation, Inc.
+   Written by Steve Chamberlain steve@cygnus.com
+
+This file is part of GLD, the Gnu Linker.
+
+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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#define TARGET_IS_${EMULATION_NAME}
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "getopt.h"
+
+#include "ld.h"
+#include "ldmain.h"
+#include "ldmisc.h"
+#include "ldexp.h"
+#include "ldlang.h"
+#include "ldfile.h"
+#include "ldemul.h"
+#include "ldctor.h"
+
+#include "libamiga.h"
+
+/* shared functions */
+void amiga_add_options PARAMS ((int, char **, int, struct option **, int, struct option **));
+bfd_boolean amiga_handle_option PARAMS ((int));
+void amiga_after_parse PARAMS ((void));
+void amiga_after_open PARAMS ((void));
+void amiga_after_allocation PARAMS ((void));
+
+/* amigaoslink.c variables */
+
+/* 1 means, write out debug hunk, when producing a load file */
+extern int write_debug_hunk;
+
+/* This is the attribute to use for the next file */
+extern int amiga_attribute;
+
+/* generate a combined data+bss hunk */
+extern int amiga_base_relative;
+
+/* generate a resident executable */
+extern int amiga_resident;
+
+static void gld${EMULATION_NAME}_before_parse PARAMS ((void));
+static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile));
+
+#if defined(TARGET_IS_amiga)
+
+/* Handle amiga specific options */
+
+enum {
+  OPTION_IGNORE = 300,
+  OPTION_AMIGA_CHIP,
+  OPTION_AMIGA_FAST,
+  OPTION_AMIGA_ATTRIBUTE,
+  OPTION_AMIGA_DEBUG,
+  OPTION_AMIGA_DATABSS_TOGETHER,
+  OPTION_AMIGA_DATADATA_RELOC,
+  OPTION_FLAVOR
+};
+
+void
+amiga_add_options (ns, shortopts, nl, longopts, nrl, really_longopts)
+     int ns ATTRIBUTE_UNUSED;
+     char **shortopts ATTRIBUTE_UNUSED;
+     int nl;
+     struct option **longopts;
+     int nrl ATTRIBUTE_UNUSED;
+     struct option **really_longopts ATTRIBUTE_UNUSED;
+{
+  static const struct option xtra_long[] = {
+    {"flavor", required_argument, NULL, OPTION_FLAVOR},
+    {"amiga-datadata-reloc", no_argument, NULL, OPTION_AMIGA_DATADATA_RELOC},
+    {"amiga-databss-together", no_argument, NULL, OPTION_AMIGA_DATABSS_TOGETHER},
+    {"amiga-debug-hunk", no_argument, NULL, OPTION_AMIGA_DEBUG},
+    {"attribute", required_argument, NULL, OPTION_AMIGA_ATTRIBUTE},
+    {"fast", no_argument, NULL, OPTION_AMIGA_FAST},
+    {"chip", no_argument, NULL, OPTION_AMIGA_CHIP},
+    {NULL, no_argument, NULL, 0}
+  };
+
+  *longopts = (struct option *)
+    xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long));
+  memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long));
+}
+
+bfd_boolean
+amiga_handle_option (optc)
+     int optc;
+{
+  switch (optc)
+    {
+    default:
+      return FALSE;
+
+    case 0:
+      /* Long option which just sets a flag.  */
+      break;
+
+    case OPTION_AMIGA_CHIP:
+      amiga_attribute = MEMF_CHIP;
+      break;
+
+    case OPTION_AMIGA_FAST:
+      amiga_attribute = MEMF_FAST;
+      break;
+
+    case OPTION_AMIGA_ATTRIBUTE:
+      {
+	char *end;
+	amiga_attribute = strtoul (optarg, &end, 0);
+	if (*end)
+	  einfo ("%P%F: invalid number \`%s\'\n", optarg);
+      }
+      break;
+
+    case OPTION_AMIGA_DEBUG:
+      write_debug_hunk = 1; /* Write out debug hunk */
+      break;
+
+    case OPTION_AMIGA_DATABSS_TOGETHER:
+      amiga_base_relative = 1; /* Combine data and bss */
+      break;
+
+    case OPTION_AMIGA_DATADATA_RELOC:
+      amiga_resident = 1; /* Write out datadata_reloc array */
+      break;
+
+    case OPTION_FLAVOR:
+      ldfile_add_flavor (optarg);
+      break;
+    }
+
+  return TRUE;
+}
+
+void
+amiga_after_parse ()
+{
+  ldfile_sort_flavors();
+}
+
+void
+amiga_after_open ()
+{
+  ldctor_build_sets ();
+}
+
+static void
+amiga_assign_attribute (inp)
+     lang_input_statement_type *inp;
+{
+  asection *s;
+
+  if (bfd_get_flavour(inp->the_bfd)==bfd_target_amiga_flavour)
+    {
+      for (s=inp->the_bfd->sections;s!=NULL;s=s->next)
+	amiga_per_section(s)->attribute=inp->amiga_attribute;
+    }
+}
+
+void
+amiga_after_allocation ()
+{
+  if (0) /* Does not work at the moment */
+    lang_for_each_input_file (amiga_assign_attribute);
+}
+
+#endif
+
+static void
+gld${EMULATION_NAME}_before_parse ()
+{
+  write_debug_hunk = 0;
+
+#if defined(TARGET_IS_amiga_bss)
+  amiga_base_relative = 1;
+#endif
+
+#ifndef TARGET_ /* I.e., if not generic.  */
+  ldfile_output_architecture = bfd_arch_${ARCH};
+#endif /* not TARGET_ */
+}
+
+static char *
+gld${EMULATION_NAME}_get_script (isfile)
+     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"
+
+cat >>e${EMULATION_NAME}.c <<EOF
+{
+  *isfile = 0;
+
+  if (link_info.relocateable == TRUE && config.build_constructors == TRUE)
+    return
+EOF
+sed $sc ldscripts/${EMULATION_NAME}.xu                     >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.relocateable == TRUE) 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
+echo '  ; else if (!config.magic_demand_paged) return'     >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xn                     >> e${EMULATION_NAME}.c
+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.
+
+cat >>e${EMULATION_NAME}.c <<EOF
+{
+  *isfile = 1;
+
+  if (link_info.relocateable == TRUE && config.build_constructors == TRUE)
+    return "ldscripts/${EMULATION_NAME}.xu";
+  else if (link_info.relocateable == TRUE)
+    return "ldscripts/${EMULATION_NAME}.xr";
+  else if (!config.text_read_only)
+    return "ldscripts/${EMULATION_NAME}.xbn";
+  else if (!config.magic_demand_paged)
+    return "ldscripts/${EMULATION_NAME}.xn";
+  else
+    return "ldscripts/${EMULATION_NAME}.x";
+}
+EOF
+
+fi
+
+cat >>e${EMULATION_NAME}.c <<EOF
+
+struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = 
+{
+  gld${EMULATION_NAME}_before_parse,	/* before_parse */
+  syslib_default,			/* syslib */
+  hll_default,				/* hll */
+  amiga_after_parse,			/* after_parse */
+  amiga_after_open,			/* after_open */
+  amiga_after_allocation,		/* after_allocation */
+  set_output_arch_default,		/* set_output_arch */
+  ldemul_default_target,		/* choose_target */
+  before_allocation_default,		/* before_allocation */
+  gld${EMULATION_NAME}_get_script,	/* get_script */
+  "${EMULATION_NAME}",			/* emulation_name */
+  "${OUTPUT_FORMAT}",			/* target_name */
+  NULL,					/* finish */
+  NULL,					/* create_output_section_statements */
+  NULL,					/* open_dynamic_library */
+  NULL,					/* place_orphan */
+  NULL,					/* set_symbols */
+  NULL,					/* parse_args */
+  amiga_add_options,			/* add_options */
+  amiga_handle_option,			/* handle_option */
+  NULL,					/* unrecognized file */
+  NULL,					/* list_options */
+  NULL,					/* recognized_file */
+  NULL,					/* find potential_libraries */
+  NULL					/* new_vers_pattern */
+};
+EOF
diff -ru --new-file a/ld/emultempl/amigaos.em b/ld/emultempl/amigaos.em
--- a/ld/emultempl/amigaos.em	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emultempl/amigaos.em	2022-02-17 17:38:03.396125500 +0300
@@ -0,0 +1,2544 @@
+# 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, 2013
+   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 */
+
+/* Style of .note.gnu.build-id section.  */
+static const char *emit_note_gnu_build_id;
+
+/* 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: error adding 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
+id_note_section_size (bfd *abfd ATTRIBUTE_UNUSED)
+{
+  const char *style = emit_note_gnu_build_id;
+  bfd_size_type size;
+
+  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;
+}
+
+static bfd_boolean
+write_build_id (bfd *abfd)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct elf_obj_tdata *t = elf_tdata (abfd);
+  const char *style;
+  asection *asec;
+  Elf_Internal_Shdr *i_shdr;
+  unsigned char *contents, *id_bits;
+  bfd_size_type size;
+  file_ptr position;
+  Elf_External_Note *e_note;
+  typedef void (*sum_fn) (const void *, size_t, void *);
+
+  style = t->o->build_id.style;
+  asec = t->o->build_id.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 (style, "md5") == 0)
+    {
+      struct md5_ctx ctx;
+
+      md5_init_ctx (&ctx);
+      if (!bed->s->checksum_contents (abfd, (sum_fn) &md5_process_bytes, &ctx))
+	return FALSE;
+      md5_finish_ctx (&ctx, id_bits);
+    }
+  else if (strcmp (style, "sha1") == 0)
+    {
+      struct sha1_ctx ctx;
+
+      sha1_init_ctx (&ctx);
+      if (!bed->s->checksum_contents (abfd, (sum_fn) &sha1_process_bytes, &ctx))
+	return FALSE;
+      sha1_finish_ctx (&ctx, id_bits);
+    }
+  else if (strcmp (style, "uuid") == 0)
+    {
+      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 (style, "0x", 2) == 0)
+    {
+      /* ID is in string form (hex).  Convert to bits.  */
+      const char *id = 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.  */
+
+  position = i_shdr->sh_offset + asec->output_offset;
+  size = asec->size;
+  return (bfd_seek (abfd, position, SEEK_SET) == 0
+	  && bfd_bwrite (contents, size, abfd) == size);
+}
+
+/* Make .note.gnu.build-id section, and set up elf_tdata->build_id.  */
+
+static bfd_boolean
+setup_build_id (bfd *ibfd)
+{
+  asection *s;
+  bfd_size_type size;
+  flagword flags;
+
+  size = id_note_section_size (ibfd);
+  if (size == 0)
+    {
+      einfo ("%P: warning: unrecognized --build-id style ignored.\n");
+      return FALSE;
+    }
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY
+	   | SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA);
+  s = bfd_make_section_with_flags (ibfd, ".note.gnu.build-id", flags);
+  if (s != NULL && bfd_set_section_alignment (ibfd, s, 2))
+    {
+      struct elf_obj_tdata *t = elf_tdata (link_info.output_bfd);
+      t->o->build_id.after_write_object_contents = &write_build_id;
+      t->o->build_id.style = emit_note_gnu_build_id;
+      t->o->build_id.sec = s;
+      elf_section_type (s) = SHT_NOTE;
+      s->size = size;
+      return TRUE;
+    }
+
+  einfo ("%P: warning: Cannot create .note.gnu.build-id section,"
+	 " --build-id ignored.\n");
+  return FALSE;
+}
+
+/* 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 (emit_note_gnu_build_id != NULL)
+    {
+      bfd *abfd;
+
+      /* 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;
+
+      /* PR 10555: If there are no ELF input files do not try to
+	 create a .note.gnu-build-id section.  */
+      if (abfd == NULL
+	  || !setup_build_id (abfd))
+	{
+	  free ((char *) emit_note_gnu_build_id);
+	  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.  */
+      if (l->by != NULL
+	  && (bfd_elf_get_dyn_lib_class (l->by) & DYN_AS_NEEDED) != 0)
+	continue;
+
+      /* Skip the lib if --no-copy-dt-needed-entries and
+	 --allow-shlib-undefined is in effect.  */
+      if (l->by != NULL
+	  && link_info.unresolved_syms_in_shared_libs == RM_IGNORE
+	  && (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*)
+      fragment <<EOF
+	  if (gld${EMULATION_NAME}_check_ld_so_conf (l, force))
+	    break;
+
+EOF
+    # Linux
+    ;;
+  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 (is_elf_hash_table (link_info.hash))
+    {
+      _bfd_elf_tls_setup (link_info.output_bfd, &link_info);
+
+      /* Make __ehdr_start hidden if it has been referenced, to
+	 prevent the symbol from being dynamic.  */
+      if (!link_info.relocatable)
+       {
+         struct elf_link_hash_entry *h
+           = elf_link_hash_lookup (elf_hash_table (&link_info), "__ehdr_start",
+                                   FALSE, FALSE, TRUE);
+
+         /* Only adjust the export class if the symbol was referenced
+            and not defined, otherwise leave it alone.  */
+         if (h != NULL
+             && (h->root.type == bfd_link_hash_new
+                 || h->root.type == bfd_link_hash_undefined
+                 || h->root.type == bfd_link_hash_undefweak
+                 || h->root.type == bfd_link_hash_common))
+           {
+             _bfd_elf_link_hash_hide_symbol (&link_info, h, TRUE);
+             if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
+               h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
+           }
+       }
+
+      /* 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 (emit_note_gnu_build_id != NULL)
+	{
+	  free ((char *) emit_note_gnu_build_id);
+	  emit_note_gnu_build_id = NULL;
+	}
+      if (optarg == NULL)
+	optarg = DEFAULT_BUILD_ID_STYLE;
+      if (strcmp (optarg, "none"))
+	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 (CONST_STRNEQ (optarg, "stack-size="))
+	{
+	  char *end;
+	  link_info.stacksize = strtoul (optarg + 11, &end, 0);
+	  if (*end || link_info.stacksize < 0)
+	    einfo (_("%P%F: invalid stack size \`%s'\n"), optarg + 11);
+	  if (!link_info.stacksize)
+	    /* Use -1 for explicit no-stack, because zero means
+	       'default'.   */
+	    link_info.stacksize = -1;
+	}
+      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, "global") == 0)
+	link_info.flags_1 |= (bfd_vma) DF_1_GLOBAL;
+      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 global                   Make symbols in DSO available for subsequently\n\
+			       loaded objects\n"));
+  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"));
+  fprintf (file, _("\
+  -z stacksize=SIZE           Set size of stack segment\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
diff -ru --new-file a/ld/emultempl/amithlon.em b/ld/emultempl/amithlon.em
--- a/ld/emultempl/amithlon.em	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emultempl/amithlon.em	2021-02-01 23:12:49.280835000 +0300
@@ -0,0 +1,1698 @@
+# 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
+cat >e${EMULATION_NAME}.c <<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 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 GLD, the Gnu Linker.
+
+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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define TARGET_IS_${EMULATION_NAME}
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libiberty.h"
+#include "safe-ctype.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"
+
+static void gld${EMULATION_NAME}_before_parse
+  PARAMS ((void));
+static void gld${EMULATION_NAME}_vercheck
+  PARAMS ((lang_input_statement_type *));
+static void gld${EMULATION_NAME}_stat_needed
+  PARAMS ((lang_input_statement_type *));
+static boolean gld${EMULATION_NAME}_try_needed
+  PARAMS ((const char *, int));
+static boolean gld${EMULATION_NAME}_search_needed
+  PARAMS ((const char *, const char *, int));
+static void gld${EMULATION_NAME}_check_needed
+  PARAMS ((lang_input_statement_type *));
+static void gld${EMULATION_NAME}_after_open
+  PARAMS ((void));
+static void gld${EMULATION_NAME}_find_exp_assignment
+  PARAMS ((etree_type *));
+static void gld${EMULATION_NAME}_find_statement_assignment
+  PARAMS ((lang_statement_union_type *));
+static void gld${EMULATION_NAME}_before_allocation
+  PARAMS ((void));
+static boolean gld${EMULATION_NAME}_open_dynamic_archive
+  PARAMS ((const char *, search_dirs_type *, lang_input_statement_type *));
+static lang_output_section_statement_type *output_rel_find
+  PARAMS ((asection *));
+static asection *output_prev_sec_find
+  PARAMS ((lang_output_section_statement_type *));
+static boolean gld${EMULATION_NAME}_place_orphan
+  PARAMS ((lang_input_statement_type *, asection *));
+static void gld${EMULATION_NAME}_finish
+  PARAMS ((void));
+static char *gld${EMULATION_NAME}_get_script
+  PARAMS ((int *isfile));
+
+extern void ldfile_add_flavor (char*);
+
+EOF
+
+# Import any needed special functions and/or overrides.
+#
+if test -n "$EXTRA_EM_FILE" ; then
+. ${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
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static void
+gld${EMULATION_NAME}_before_parse ()
+{
+  const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}");
+  if (arch)
+    {
+      ldfile_output_architecture = arch->arch;
+      ldfile_output_machine = arch->mach;
+      ldfile_output_machine_name = arch->printable_name;
+    }
+  else
+    ldfile_output_architecture = bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`;
+  config.dynamic_link = ${DYNAMIC_LINK-true};
+  config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`;
+  sort_flavors();
+}
+
+EOF
+fi
+
+cat >>e${EMULATION_NAME}.c <<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 boolean global_found;
+static struct bfd_link_needed_list *global_vercheck_needed;
+static boolean global_vercheck_failed;
+
+
+/* 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 (s)
+     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 (strcmp (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 (strncmp (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 (s)
+     lang_input_statement_type *s;
+{
+  struct stat st;
+  const char *suffix;
+  const char *soname;
+
+  if (global_found)
+    return;
+  if (s->the_bfd == NULL)
+    return;
+
+  if (bfd_stat (s->the_bfd, &st) != 0)
+    {
+      einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd);
+      return;
+    }
+
+  if (st.st_dev == global_stat.st_dev
+      && st.st_ino == global_stat.st_ino)
+    {
+      global_found = true;
+      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 (strncmp (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);
+}
+
+
+/* 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 boolean
+gld${EMULATION_NAME}_try_needed (name, force)
+     const char *name;
+     int force;
+{
+  bfd *abfd;
+  const char *soname;
+
+  abfd = bfd_openr (name, bfd_get_target (output_bfd));
+  if (abfd == NULL)
+    return false;
+  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 != 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 *needed;
+
+      if (! bfd_elf_get_bfd_needed_list (abfd, &needed))
+	einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd);
+
+      if (needed != NULL)
+	{
+	  global_vercheck_needed = needed;
+	  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-gnu*)
+    cat >>e${EMULATION_NAME}.c <<EOF
+	  {
+	    struct bfd_link_needed_list *l;
+
+	    for (l = needed; l != NULL; l = l->next)
+	      if (strncmp (l->name, "libc.so", 7) == 0)
+		break;
+	    if (l == NULL)
+	      {
+		bfd_close (abfd);
+		return false;
+	      }
+	  }
+
+EOF
+    ;;
+esac
+cat >>e${EMULATION_NAME}.c <<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 (trace_file_tries)
+    info_msg (_("found %s at %s\n"), soname, name);
+
+  global_found = false;
+  lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed);
+  if (global_found)
+    {
+      /* Return true to indicate that we found the file, even though
+         we aren't going to do anything with it.  */
+      return true;
+    }
+
+  /* Tell the ELF backend that we don't want the output file to have a
+     DT_NEEDED entry for this file.  */
+  bfd_elf_set_dt_needed_name (abfd, "");
+
+  /* Tell the ELF backend that the output file needs a DT_NEEDED
+     entry for this file if it is used to resolve the reference in
+     a regular object.  */
+  bfd_elf_set_dt_needed_soname (abfd, soname);
+
+  /* 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 boolean
+gld${EMULATION_NAME}_search_needed (path, name, force)
+     const char *path;
+     const char *name;
+     int force;
+{
+  const char *s;
+  size_t len;
+
+  if (name[0] == '/')
+    return gld${EMULATION_NAME}_try_needed (name, force);
+
+  if (path == NULL || *path == '\0')
+    return false;
+  len = strlen (name);
+  while (1)
+    {
+      char *filename, *sset;
+
+      s = strchr (path, ':');
+      if (s == NULL)
+	s = path + strlen (path);
+
+      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);
+
+      if (gld${EMULATION_NAME}_try_needed (filename, force))
+	return true;
+
+      free (filename);
+
+      if (*s == '\0')
+	break;
+      path = s + 1;
+    }
+
+  return false;
+}
+
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+  case " ${EMULATION_LIBPATH} " in
+  *" ${EMULATION_NAME} "*)
+    case ${target} in
+      *-*-linux-gnu*)
+	cat >>e${EMULATION_NAME}.c <<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.  */
+
+static boolean gld${EMULATION_NAME}_check_ld_so_conf
+  PARAMS ((const char *, int));
+
+static boolean
+gld${EMULATION_NAME}_check_ld_so_conf (name, force)
+     const char *name;
+     int force;
+{
+  static boolean initialized;
+  static char *ld_so_conf;
+
+  if (! initialized)
+    {
+      FILE *f;
+
+      f = fopen ("/etc/ld.so.conf", FOPEN_RT);
+      if (f != NULL)
+	{
+	  char *b;
+	  size_t len, alloc;
+	  int c;
+
+	  len = 0;
+	  alloc = 100;
+	  b = (char *) xmalloc (alloc);
+
+	  while ((c = getc (f)) != EOF)
+	    {
+	      if (len + 1 >= alloc)
+		{
+		  alloc *= 2;
+		  b = (char *) xrealloc (b, alloc);
+		}
+	      if (c != ':'
+		  && c != ' '
+		  && c != '\t'
+		  && c != '\n'
+		  && c != ',')
+		{
+		  b[len] = c;
+		  ++len;
+		}
+	      else
+		{
+		  if (len > 0 && b[len - 1] != ':')
+		    {
+		      b[len] = ':';
+		      ++len;
+		    }
+		}
+	    }
+
+	  if (len > 0 && b[len - 1] == ':')
+	    --len;
+
+	  if (len > 0)
+	    b[len] = '\0';
+	  else
+	    {
+	      free (b);
+	      b = NULL;
+	    }
+
+	  fclose (f);
+
+	  ld_so_conf = b;
+	}
+
+      initialized = true;
+    }
+
+  if (ld_so_conf == NULL)
+    return false;
+
+  return gld${EMULATION_NAME}_search_needed (ld_so_conf, name, force);
+}
+
+EOF
+	# Linux
+	;;
+    esac
+  esac
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* See if an input file matches a DT_NEEDED entry by name.  */
+
+static void
+gld${EMULATION_NAME}_check_needed (s)
+     lang_input_statement_type *s;
+{
+  if (global_found)
+    return;
+
+  if (s->filename != NULL)
+    {
+      const char *f;
+
+      if (strcmp (s->filename, global_needed->name) == 0)
+	{
+	  global_found = true;
+	  return;
+	}
+
+      if (s->search_dirs_flag)
+	{
+	  f = strrchr (s->filename, '/');
+	  if (f != NULL
+	      && strcmp (f + 1, global_needed->name) == 0)
+	    {
+	      global_found = true;
+	      return;
+	    }
+	}
+    }
+
+  if (s->the_bfd != NULL)
+    {
+      const char *soname;
+
+      soname = bfd_elf_get_dt_soname (s->the_bfd);
+      if (soname != NULL
+	  && strcmp (soname, global_needed->name) == 0)
+	{
+	  global_found = true;
+	  return;
+	}
+    }
+}
+
+EOF
+
+if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* This is called after all the input files have been opened.  */
+
+static void
+gld${EMULATION_NAME}_after_open ()
+{
+  struct bfd_link_needed_list *needed, *l;
+
+  /* We only need to worry about this when doing a final link.  */
+  if (link_info.relocateable || link_info.shared)
+    return;
+
+  /* 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 (output_bfd, &link_info);
+  for (l = needed; l != NULL; l = l->next)
+    {
+      struct bfd_link_needed_list *ll;
+      int force;
+
+      /* If we've already seen this file, skip it.  */
+      for (ll = needed; ll != l; ll = ll->next)
+	if (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 = false;
+      lang_for_each_input_file (gld${EMULATION_NAME}_check_needed);
+      if (global_found)
+	continue;
+
+      if (trace_file_tries)
+	info_msg (_("%s needed by %B\n"), l->name, l->by);
+
+      /* 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${host}" = "x${target}" ] ; then
+  case " ${EMULATION_LIBPATH} " in
+  *" ${EMULATION_NAME} "*)
+cat >>e${EMULATION_NAME}.c <<EOF
+	  const char *lib_path;
+	  struct bfd_link_needed_list *rp;
+	  int found;
+EOF
+  ;;
+  esac
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
+
+	  if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
+						  l->name, force))
+	    break;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+  case " ${EMULATION_LIBPATH} " in
+  *" ${EMULATION_NAME} "*)
+cat >>e${EMULATION_NAME}.c <<EOF
+	  if (gld${EMULATION_NAME}_search_needed (command_line.rpath,
+						  l->name, force))
+	    break;
+	  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, l->name,
+						      force))
+		break;
+	    }
+	  lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
+	  if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force))
+	    break;
+
+	  found = 0;
+	  rp = bfd_elf_get_runpath_list (output_bfd, &link_info);
+	  for (; !found && rp != NULL; rp = rp->next)
+	    {
+	      found = (rp->by == l->by
+		       && gld${EMULATION_NAME}_search_needed (rp->name,
+							      l->name,
+							      force));
+	    }
+	  if (found)
+	    break;
+
+EOF
+  ;;
+  esac
+fi
+cat >>e${EMULATION_NAME}.c <<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);
+	      if (gld${EMULATION_NAME}_try_needed (filename, force))
+		break;
+	      free (filename);
+	    }
+	  if (search != NULL)
+	    break;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+  case " ${EMULATION_LIBPATH} " in
+  *" ${EMULATION_NAME} "*)
+    case ${target} in
+      *-*-linux-gnu*)
+	cat >>e${EMULATION_NAME}.c <<EOF
+	  if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force))
+	    break;
+EOF
+	# Linux
+        ;;
+    esac
+  ;;
+  esac
+fi
+cat >>e${EMULATION_NAME}.c <<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
+
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* Look through an expression for an assignment statement.  */
+
+static void
+gld${EMULATION_NAME}_find_exp_assignment (exp)
+     etree_type *exp;
+{
+  struct bfd_link_hash_entry *h;
+
+  switch (exp->type.node_class)
+    {
+    case etree_provide:
+      h = bfd_link_hash_lookup (link_info.hash, exp->assign.dst,
+				false, false, false);
+      if (h == NULL)
+	break;
+
+      /* 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.  */
+
+      /* Fall through.  */
+    case etree_assign:
+      if (strcmp (exp->assign.dst, ".") != 0)
+	{
+	  if (! (bfd_elf${ELFSIZE}_record_link_assignment
+		 (output_bfd, &link_info, exp->assign.dst,
+		  exp->type.node_class == etree_provide ? true : false)))
+	    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 (s)
+     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 = ${ELF_INTERPRETER_NAME};
+      sinterp->_raw_size = strlen (sinterp->contents) + 1;
+    }
+
+"
+  else
+    ELF_INTERPRETER_SET_DEFAULT=
+  fi
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* 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 ()
+{
+  const char *rpath;
+  asection *sinterp;
+
+  /* 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");
+  if (! (bfd_elf${ELFSIZE}_size_dynamic_sections
+         (output_bfd, command_line.soname, rpath,
+	  command_line.filter_shlib,
+	  (const char * const *) command_line.auxiliary_filters,
+	  &link_info, &sinterp, lang_elf_version_info)))
+    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->_raw_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;
+	boolean ret;
+
+	if (is->just_syms_flag)
+	  continue;
+
+	s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning");
+	if (s == NULL)
+	  continue;
+
+	sz = bfd_section_size (is->the_bfd, s);
+	msg = 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 copying the
+	   warning into the output file.  */
+	s->_raw_size = 0;
+      }
+  }
+}
+
+EOF
+fi
+
+if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then
+cat >>e${EMULATION_NAME}.c <<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 boolean
+gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry)
+     const char *arch;
+     search_dirs_type *search;
+     lang_input_statement_type *entry;
+{
+  const char *filename;
+  char *string;
+
+  if (! entry->is_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;
+    }
+
+  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->is_archive && entry->search_dirs_flag);
+
+      /* 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
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* A variant of lang_output_section_find.  Used by place_orphan.  */
+
+static lang_output_section_statement_type *
+output_rel_find (sec)
+     asection *sec;
+{
+  lang_statement_union_type *u;
+  lang_output_section_statement_type *lookup;
+  lang_output_section_statement_type *last = 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 (u = lang_output_section_statement.head; u; u = lookup->next)
+    {
+      lookup = &u->output_section_statement;
+      if (strncmp (".rel", lookup->name, 4) == 0)
+	{
+	  /* Don't place after .rel.plt as doing so results in wrong
+	     dynamic tags.  Also, place allocated reloc sections before
+	     non-allocated.  */
+	  int lookrela = lookup->name[4] == 'a';
+
+	  if (strcmp (".plt", lookup->name + 4 + lookrela) == 0
+	      || (lookup->bfd_section != NULL
+		  && (lookup->bfd_section->flags & SEC_ALLOC) == 0))
+	    break;
+	  last = lookup;
+	  if (rela == lookrela)
+	    last_rel = lookup;
+	  if (lookup->bfd_section != NULL
+	      && (lookup->bfd_section->flags & SEC_ALLOC) != 0)
+	    last_rel_alloc = lookup;
+	}
+    }
+
+  if (last_rel_alloc)
+    return last_rel_alloc;
+
+  if (last_rel)
+    return last_rel;
+
+  return last;
+}
+
+/* Find the last output section before given output statement.
+   Used by place_orphan.  */
+
+static asection *
+output_prev_sec_find (os)
+     lang_output_section_statement_type *os;
+{
+  asection *s = (asection *) NULL;
+  lang_statement_union_type *u;
+  lang_output_section_statement_type *lookup;
+
+  for (u = lang_output_section_statement.head;
+       u != (lang_statement_union_type *) NULL;
+       u = lookup->next)
+    {
+      lookup = &u->output_section_statement;
+      if (lookup == os)
+	return s;
+
+      if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
+	s = lookup->bfd_section;
+    }
+
+  return NULL;
+}
+
+/* Place an orphan section.  We use this to put random SHF_ALLOC
+   sections in the right segment.  */
+
+struct orphan_save {
+  lang_output_section_statement_type *os;
+  asection **section;
+  lang_statement_union_type **stmt;
+};
+
+static boolean
+gld${EMULATION_NAME}_place_orphan (file, s)
+     lang_input_statement_type *file;
+     asection *s;
+{
+  static struct orphan_save hold_text;
+  static struct orphan_save hold_rodata;
+  static struct orphan_save hold_data;
+  static struct orphan_save hold_bss;
+  static struct orphan_save hold_rel;
+  static struct orphan_save hold_interp;
+  static struct orphan_save hold_sdata;
+  static int count = 1;
+  struct orphan_save *place;
+  lang_statement_list_type *old;
+  lang_statement_list_type add;
+  etree_type *address;
+  const char *secname;
+  const char *ps = NULL;
+  lang_output_section_statement_type *os;
+  int isdyn = 0;
+
+  secname = bfd_get_section_name (s->owner, s);
+  if (! link_info.relocateable
+      && link_info.combreloc
+      && (s->flags & SEC_ALLOC)
+      && strncmp (secname, ".rel", 4) == 0)
+    {
+      if (secname[4] == 'a')
+	secname = ".rela.dyn";
+      else
+	secname = ".rel.dyn";
+      isdyn = 1;
+    }
+
+  if (isdyn || (!config.unique_orphan_sections && !unique_section_p (secname)))
+    {
+      /* Look through the script to see where to place this section.  */
+      os = lang_output_section_find (secname);
+
+      if (os != NULL
+	  && (os->bfd_section == NULL
+	      || ((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, if any, has compatible flags.  */
+	  lang_add_section (&os->children, s, os, file);
+	  return true;
+	}
+    }
+
+  if (hold_text.os == NULL)
+    hold_text.os = lang_output_section_find (".text");
+
+  /* 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.shared
+      && ! link_info.relocateable
+      && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
+      && hold_text.os != NULL)
+    {
+      lang_add_section (&hold_text.os->children, s, hold_text.os, file);
+      return true;
+    }
+
+  /* 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.  */
+#define HAVE_SECTION(hold, name) \
+(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
+
+  if ((s->flags & SEC_EXCLUDE) != 0 && !link_info.relocateable)
+    {
+      if (s->output_section == NULL)
+	s->output_section = bfd_abs_section_ptr;
+      return true;
+    }
+
+  place = NULL;
+  if ((s->flags & SEC_ALLOC) == 0)
+    ;
+  else if ((s->flags & SEC_LOAD) != 0
+	   && strncmp (secname, ".note", 5) == 0
+	   && HAVE_SECTION (hold_interp, ".interp"))
+    place = &hold_interp;
+  else if ((s->flags & SEC_HAS_CONTENTS) == 0
+	   && HAVE_SECTION (hold_bss, ".bss"))
+    place = &hold_bss;
+  else if ((s->flags & SEC_SMALL_DATA) != 0
+	   && HAVE_SECTION (hold_sdata, ".sdata"))
+    place = &hold_sdata;
+  else if ((s->flags & SEC_READONLY) == 0
+	   && HAVE_SECTION (hold_data, ".data"))
+    place = &hold_data;
+  else if (strncmp (secname, ".rel", 4) == 0
+	   && (s->flags & SEC_LOAD) != 0
+	   && (hold_rel.os != NULL
+	       || (hold_rel.os = output_rel_find (s)) != NULL))
+    place = &hold_rel;
+  else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
+	   && HAVE_SECTION (hold_rodata, ".rodata"))
+    place = &hold_rodata;
+  else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
+	   && hold_text.os != NULL)
+    place = &hold_text;
+
+#undef HAVE_SECTION
+
+  /* Choose a unique name for the section.  This will be needed if the
+     same section name appears in the input file with different
+     loadable or allocatable characteristics.  */
+  if (bfd_get_section_by_name (output_bfd, secname) != NULL)
+    {
+      secname = bfd_get_unique_section_name (output_bfd, secname, &count);
+      if (secname == NULL)
+	einfo ("%F%P: place_orphan failed: %E\n");
+    }
+
+  /* Start building a list of statements for this section.
+     First save the current statement pointer.  */
+  old = stat_ptr;
+
+  /* If we have found an appropriate place for the output section
+     statements for this orphan, add them to our own private list,
+     inserting them later into the global statement list.  */
+  if (place != NULL)
+    {
+      stat_ptr = &add;
+      lang_list_init (stat_ptr);
+    }
+
+  if (config.build_constructors)
+    {
+      /* If the name of the section is representable in C, then create
+	 symbols to mark the start and the end of the section.  */
+      for (ps = secname; *ps != '\0'; ps++)
+	if (! ISALNUM (*ps) && *ps != '_')
+	  break;
+      if (*ps == '\0')
+	{
+	  char *symname;
+	  etree_type *e_align;
+
+	  symname = (char *) xmalloc (ps - secname + sizeof "__start_");
+	  sprintf (symname, "__start_%s", secname);
+	  e_align = exp_unop (ALIGN_K,
+			      exp_intop ((bfd_vma) 1 << s->alignment_power));
+	  lang_add_assignment (exp_assop ('=', symname, e_align));
+	}
+    }
+
+  if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
+    address = exp_intop ((bfd_vma) 0);
+  else
+    address = NULL;
+
+  os = lang_enter_output_section_statement (secname, address, 0,
+					    (bfd_vma) 0,
+					    (etree_type *) NULL,
+					    (etree_type *) NULL,
+					    (etree_type *) NULL);
+
+  lang_add_section (&os->children, s, os, file);
+
+  lang_leave_output_section_statement
+    ((bfd_vma) 0, "*default*",
+     (struct lang_output_section_phdr_list *) NULL, NULL);
+
+  if (config.build_constructors && *ps == '\0')
+    {
+      char *symname;
+
+      /* lang_leave_ouput_section_statement resets stat_ptr.  Put
+	 stat_ptr back where we want it.  */
+      if (place != NULL)
+	stat_ptr = &add;
+
+      symname = (char *) xmalloc (ps - secname + sizeof "__stop_");
+      sprintf (symname, "__stop_%s", secname);
+      lang_add_assignment (exp_assop ('=', symname,
+				      exp_nameop (NAME, ".")));
+    }
+
+  /* Restore the global list pointer.  */
+  stat_ptr = old;
+
+  if (place != NULL && os->bfd_section != NULL)
+    {
+      asection *snew, **pps;
+
+      snew = os->bfd_section;
+
+      /* Shuffle the bfd section list to make the output file look
+	 neater.  This is really only cosmetic.  */
+      if (place->section == NULL)
+	{
+	  asection *bfd_section = place->os->bfd_section;
+
+	  /* If the output statement hasn't been used to place
+	     any input sections (and thus doesn't have an output
+	     bfd_section), look for the closest prior output statement
+	     having an output section.  */
+	  if (bfd_section == NULL)
+	    bfd_section = output_prev_sec_find (place->os);
+
+	  if (bfd_section != NULL && bfd_section != snew)
+	    place->section = &bfd_section->next;
+	}
+
+      if (place->section != NULL)
+	{
+	  /* Unlink the section.  */
+	  for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
+	    ;
+	  bfd_section_list_remove (output_bfd, pps);
+
+	  /* Now tack it on to the "place->os" section list.  */
+	  bfd_section_list_insert (output_bfd, place->section, snew);
+	}
+
+      /* Save the end of this list.  Further ophans of this type will
+	 follow the one we've just added.  */
+      place->section = &snew->next;
+
+      /* The following is non-cosmetic.  We try to put the output
+	 statements in some sort of reasonable order here, because
+	 they determine the final load addresses of the orphan
+	 sections.  In addition, placing output statements in the
+	 wrong order may require extra segments.  For instance,
+	 given a typical situation of all read-only sections placed
+	 in one segment and following that a segment containing all
+	 the read-write sections, we wouldn't want to place an orphan
+	 read/write section before or amongst the read-only ones.  */
+      if (add.head != NULL)
+	{
+	  if (place->stmt == NULL)
+	    {
+	      /* Put the new statement list right at the head.  */
+	      *add.tail = place->os->header.next;
+	      place->os->header.next = add.head;
+	    }
+	  else
+	    {
+	      /* Put it after the last orphan statement we added.  */
+	      *add.tail = *place->stmt;
+	      *place->stmt = add.head;
+	    }
+
+	  /* Fix the global list pointer if we happened to tack our
+	     new list at the tail.  */
+	  if (*old->tail == add.head)
+	    old->tail = add.tail;
+
+	  /* Save the end of this list.  */
+	  place->stmt = add.tail;
+	}
+    }
+
+  return true;
+}
+EOF
+fi
+
+if test x"$LDEMUL_FINISH" != xgld"$EMULATION_NAME"_finish; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static void
+gld${EMULATION_NAME}_finish ()
+{
+  if (bfd_elf${ELFSIZE}_discard_info (output_bfd, &link_info))
+    {
+      lang_reset_memory_regions ();
+
+      /* Resize the sections.  */
+      lang_size_sections (stat_ptr->head, abs_output_section,
+			  &stat_ptr->head, 0, (bfd_vma) 0, NULL);
+
+      /* Redo special stuff.  */
+      ldemul_after_allocation ();
+
+      /* Do the assignments again.  */
+      lang_do_assignments (stat_ptr->head, abs_output_section,
+			   (fill_type *) 0, (bfd_vma) 0);
+    }
+}
+EOF
+fi
+
+if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static char *
+gld${EMULATION_NAME}_get_script (isfile)
+     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"
+
+cat >>e${EMULATION_NAME}.c <<EOF
+{
+  *isfile = 0;
+
+  if (link_info.relocateable == true && config.build_constructors == true)
+    return
+EOF
+sed $sc ldscripts/${EMULATION_NAME}.xu                     >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.relocateable == true) 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_SHLIB_SCRIPT" ; then
+if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
+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) 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.
+
+cat >>e${EMULATION_NAME}.c <<EOF
+{
+  *isfile = 1;
+
+  if (link_info.relocateable == true && config.build_constructors == true)
+    return "ldscripts/${EMULATION_NAME}.xu";
+  else if (link_info.relocateable == true)
+    return "ldscripts/${EMULATION_NAME}.xr";
+  else if (!config.text_read_only)
+    return "ldscripts/${EMULATION_NAME}.xbn";
+  else if (!config.magic_demand_paged)
+    return "ldscripts/${EMULATION_NAME}.xn";
+  else if (link_info.shared)
+    return "ldscripts/${EMULATION_NAME}.xs";
+  else
+    return "ldscripts/${EMULATION_NAME}.x";
+}
+
+EOF
+fi
+fi
+
+if test -n "$PARSE_AND_LIST_ARGS_CASES" -o x"$GENERATE_SHLIB_SCRIPT" = xyes; then
+
+if test x"$LDEMUL_PARSE_ARGS" != xgld"$EMULATION_NAME"_parse_args; then
+
+if test -n "$PARSE_AND_LIST_PROLOGUE" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ $PARSE_AND_LIST_PROLOGUE
+EOF
+fi
+
+cat >>e${EMULATION_NAME}.c <<EOF
+
+#include "getopt.h"
+
+#define OPTION_IGNORE                   (300)
+#define OPTION_FLAVOR                   (OPTION_IGNORE + 1)
+
+#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)
+
+static struct option longopts[] =
+{
+  {"flavor", required_argument, NULL, OPTION_FLAVOR},
+EOF
+
+if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
+cat >>e${EMULATION_NAME}.c <<EOF
+  /* getopt allows abbreviations, so we do this to stop it from
+     treating -d/-e as abbreviations for these options. */
+  {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
+  {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
+  {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
+  {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
+  {"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR},
+  {"Bgroup", no_argument, NULL, OPTION_GROUP},
+  {"Bgroup", no_argument, NULL, OPTION_GROUP},
+EOF
+fi
+
+if test -n "$PARSE_AND_LIST_LONGOPTS" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ $PARSE_AND_LIST_LONGOPTS
+EOF
+fi
+
+cat >>e${EMULATION_NAME}.c <<EOF
+  {NULL, no_argument, NULL, 0}
+};
+
+
+static int gld${EMULATION_NAME}_parse_args PARAMS ((int, char **));
+
+static int
+gld${EMULATION_NAME}_parse_args (argc, argv)
+     int argc;
+     char ** argv;
+{
+  int longind;
+  int optc;
+  static int prevoptind = -1;
+  int prevopterr = opterr;
+  int wanterror;
+
+  if (prevoptind != optind)
+    opterr = 0;
+
+  wanterror = opterr;
+  prevoptind = optind;
+
+  optc = getopt_long_only (argc, argv,
+			   "-${PARSE_AND_LIST_SHORTOPTS}z:", longopts,
+			   &longind);
+  opterr = prevopterr;
+
+  switch (optc)
+    {
+    default:
+      if (wanterror)
+	xexit (1);
+      optind = prevoptind;
+      return 0;
+
+    case OPTION_FLAVOR:
+      ldfile_add_flavor (optarg);
+      break;
+EOF
+
+if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
+cat >>e${EMULATION_NAME}.c <<EOF
+    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.no_undefined = true;
+      break;
+
+    case 'z':
+      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, "origin") == 0)
+	{
+	  link_info.flags |= (bfd_vma) DF_ORIGIN;
+	  link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN;
+	}
+      else if (strcmp (optarg, "defs") == 0)
+	link_info.no_undefined = true;
+      else if (strcmp (optarg, "muldefs") == 0)
+	link_info.allow_multiple_definition = true;
+      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;
+      /* What about the other Solaris -z options? FIXME.  */
+      break;
+EOF
+fi
+
+if test -n "$PARSE_AND_LIST_ARGS_CASES" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ $PARSE_AND_LIST_ARGS_CASES
+EOF
+fi
+
+cat >>e${EMULATION_NAME}.c <<EOF
+    }
+
+  return 1;
+}
+
+EOF
+fi
+
+if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static void gld${EMULATION_NAME}_list_options PARAMS ((FILE * file));
+
+static void
+gld${EMULATION_NAME}_list_options (file)
+     FILE * file;
+{
+EOF
+
+if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
+cat >>e${EMULATION_NAME}.c <<EOF
+  fprintf (file, _("  -Bgroup\t\tSelects group name lookup rules for DSO\n"));
+  fprintf (file, _("  --disable-new-dtags\tDisable new dynamic tags\n"));
+  fprintf (file, _("  --enable-new-dtags\tEnable new dynamic tags\n"));
+  fprintf (file, _("  --eh-frame-hdr\tCreate .eh_frame_hdr section\n"));
+  fprintf (file, _("  -z combreloc\t\tMerge dynamic relocs into one section and sort\n"));
+  fprintf (file, _("  -z defs\t\tDisallows undefined symbols\n"));
+  fprintf (file, _("  -z initfirst\t\tMark DSO to be initialized first at runtime\n"));
+  fprintf (file, _("  -z interpose\t\tMark object to interpose all DSOs but executable\n"));
+  fprintf (file, _("  -z loadfltr\t\tMark object requiring immediate process\n"));
+  fprintf (file, _("  -z muldefs\t\tAllow multiple definitions\n"));
+  fprintf (file, _("  -z nocombreloc\tDon't merge dynamic relocs into one section\n"));
+  fprintf (file, _("  -z nocopyreloc\tDon't create copy relocs\n"));
+  fprintf (file, _("  -z nodefaultlib\tMark object not to use default search paths\n"));
+  fprintf (file, _("  -z nodelete\t\tMark DSO non-deletable at runtime\n"));
+  fprintf (file, _("  -z nodlopen\t\tMark DSO not available to dlopen\n"));
+  fprintf (file, _("  -z nodump\t\tMark DSO not available to dldump\n"));
+  fprintf (file, _("  -z now\t\tMark object non-lazy runtime binding\n"));
+  fprintf (file, _("  -z origin\t\tMark object requiring immediate \$ORIGIN processing\n\t\t\t  at runtime\n"));
+  fprintf (file, _("  -z KEYWORD\t\tIgnored for Solaris compatibility\n"));
+EOF
+fi
+
+if test -n "$PARSE_AND_LIST_OPTIONS" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ $PARSE_AND_LIST_OPTIONS
+EOF
+fi
+
+cat >>e${EMULATION_NAME}.c <<EOF
+}
+EOF
+
+if test -n "$PARSE_AND_LIST_EPILOGUE" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ $PARSE_AND_LIST_EPILOGUE
+EOF
+fi
+fi
+else
+if test x"$LDEMUL_PARSE_ARGS" != xgld"$EMULATION_NAME"_parse_args; then
+cat >>e${EMULATION_NAME}.c <<EOF
+#define gld${EMULATION_NAME}_parse_args   NULL
+EOF
+fi
+if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then
+cat >>e${EMULATION_NAME}.c <<EOF
+#define gld${EMULATION_NAME}_list_options NULL
+EOF
+fi
+fi
+
+cat >>e${EMULATION_NAME}.c <<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-after_allocation_default},
+  ${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-gld${EMULATION_NAME}_finish},
+  ${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-gld${EMULATION_NAME}_parse_args},
+  ${LDEMUL_UNRECOGNIZED_FILE-NULL},
+  ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options},
+  ${LDEMUL_RECOGNIZED_FILE-NULL},
+  ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
+  ${LDEMUL_NEW_VERS_PATTERN-NULL}
+};
+EOF
diff -ru --new-file a/ld/emultempl/morphos.em b/ld/emultempl/morphos.em
--- a/ld/emultempl/morphos.em	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/emultempl/morphos.em	2021-02-01 23:12:49.282838800 +0300
@@ -0,0 +1,1104 @@
+# 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
+cat >e${EMULATION_NAME}.c <<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 Free Software Foundation, Inc.
+   Written by Steve Chamberlain <sac@cygnus.com>
+   ELF support by Ian Lance Taylor <ian@cygnus.com>
+   MorphOS support by Emmanuel Lesueur <lesueur@club-internet.fr>
+
+This file is part of GLD, the Gnu Linker.
+
+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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define TARGET_IS_${EMULATION_NAME}
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libiberty.h"
+#include "safe-ctype.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"
+
+static void gld${EMULATION_NAME}_before_parse
+  PARAMS ((void));
+static void gld${EMULATION_NAME}_set_symbols
+  PARAMS ((void));
+static lang_output_section_statement_type *output_rel_find
+  PARAMS ((asection *));
+static asection *output_prev_sec_find
+  PARAMS ((lang_output_section_statement_type *));
+static boolean gld${EMULATION_NAME}_place_orphan
+  PARAMS ((lang_input_statement_type *, asection *));
+static void gld${EMULATION_NAME}_finish
+  PARAMS ((void));
+static char *gld${EMULATION_NAME}_get_script
+  PARAMS ((int *isfile));
+
+extern void ldfile_add_flavor (char*);
+static int morphos_resident;
+
+EOF
+
+# Import any needed special functions and/or overrides.
+#
+if test -n "$EXTRA_EM_FILE" ; then
+. ${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
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static void
+gld${EMULATION_NAME}_before_parse ()
+{
+  const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}");
+  if (arch)
+    {
+      ldfile_output_architecture = arch->arch;
+      ldfile_output_machine = arch->mach;
+      ldfile_output_machine_name = arch->printable_name;
+    }
+  else
+    ldfile_output_architecture = bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`;
+  config.dynamic_link = ${DYNAMIC_LINK-true};
+  config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`;
+  sort_flavors();
+}
+
+EOF
+fi
+
+if test x"$LDEMUL_SET_SYMBOLS" != xgld"$EMULATION_NAME"_set_symbols; then
+cat >>e${EMULATION_NAME}.c <<EOF
+static void
+gld${EMULATION_NAME}_set_symbols()
+{
+  if (link_info.strip == strip_all)
+    {
+      link_info.keep_hash = ((struct bfd_hash_table *)
+			     xmalloc (sizeof (struct bfd_hash_table)));
+
+      if (! bfd_hash_table_init (link_info.keep_hash, bfd_hash_newfunc))
+	einfo ("%P%F: bfd_hash_table_init failed: %E\n");
+
+      if (bfd_hash_lookup (link_info.keep_hash, "__amigappc__", true, true)
+	  == (struct bfd_hash_entry *) NULL)
+	einfo ("%P%F: bfd_hash_lookup for insertion failed: %E\n");
+
+      link_info.strip = strip_some;
+    }
+}
+EOF
+fi
+
+if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* This is called after all the input files have been opened.  */
+
+static void
+gld${EMULATION_NAME}_after_open ()
+{
+  struct bfd_link_needed_list *needed, *l;
+
+  /* We only need to worry about this when doing a final link.  */
+  if (link_info.relocateable || link_info.shared)
+    return;
+
+  /* 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 (output_bfd, &link_info);
+  for (l = needed; l != NULL; l = l->next)
+    {
+      struct bfd_link_needed_list *ll;
+      int force = 0;
+
+      /* If we've already seen this file, skip it.  */
+      for (ll = needed; ll != l; ll = ll->next)
+	if (strcmp (ll->name, l->name) == 0)
+	  break;
+      if (ll != l)
+	continue;
+
+#if 0
+      /* See if this file was included in the link explicitly.  */
+      global_needed = l;
+      global_found = false;
+      lang_for_each_input_file (gld${EMULATION_NAME}_check_needed);
+      if (global_found)
+	continue;
+
+      if (trace_file_tries)
+	info_msg (_("%s needed by %B\n"), l->name, l->by);
+
+      /* 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${host}" = "x${target}" ] ; then
+  case " ${EMULATION_LIBPATH} " in
+  *" ${EMULATION_NAME} "*)
+cat >>e${EMULATION_NAME}.c <<EOF
+	  const char *lib_path;
+	  struct bfd_link_needed_list *rp;
+	  int found;
+EOF
+  ;;
+  esac
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
+
+	  if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
+						  l->name, force))
+	    break;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+  case " ${EMULATION_LIBPATH} " in
+  *" ${EMULATION_NAME} "*)
+cat >>e${EMULATION_NAME}.c <<EOF
+	  if (gld${EMULATION_NAME}_search_needed (command_line.rpath,
+						  l->name, force))
+	    break;
+	  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, l->name,
+						      force))
+		break;
+	    }
+	  lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
+	  if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force))
+	    break;
+
+	  found = 0;
+	  rp = bfd_elf_get_runpath_list (output_bfd, &link_info);
+	  for (; !found && rp != NULL; rp = rp->next)
+	    {
+	      found = (rp->by == l->by
+		       && gld${EMULATION_NAME}_search_needed (rp->name,
+							      l->name,
+							      force));
+	    }
+	  if (found)
+	    break;
+
+EOF
+  ;;
+  esac
+fi
+cat >>e${EMULATION_NAME}.c <<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);
+	      if (gld${EMULATION_NAME}_try_needed (filename, force))
+		break;
+	      free (filename);
+	    }
+	  if (search != NULL)
+	    break;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+  case " ${EMULATION_LIBPATH} " in
+  *" ${EMULATION_NAME} "*)
+    case ${target} in
+      *-*-linux-gnu*)
+	cat >>e${EMULATION_NAME}.c <<EOF
+	  if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force))
+	    break;
+EOF
+	# Linux
+        ;;
+    esac
+  ;;
+  esac
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
+	}
+#endif
+      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
+
+
+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 = ${ELF_INTERPRETER_NAME};
+      sinterp->_raw_size = strlen (sinterp->contents) + 1;
+    }
+
+"
+  else
+    ELF_INTERPRETER_SET_DEFAULT=
+  fi
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* 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 ()
+{
+  const char *rpath;
+  asection *sinterp;
+
+  /* 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);*/
+
+  /* Add the data->data relocation table... */
+  if (morphos_resident)
+    {
+      asection *sec = bfd_make_section(output_bfd, "ddrelocs");
+      struct bfd_link_hash_entry *sym;
+
+      if (sec)
+	{
+	  bfd_set_section_flags(output_bfd, sec, SEC_ALLOC | SEC_LOAD | SEC_READONLY | 
+				SEC_DATA | SEC_HAS_CONTENTS);
+	  sec->output_section = sec;
+	  sec->output_offset = 0;
+	  sym = bfd_link_hash_lookup(link_info.hash, "__datadata_relocs", true, false, false);
+	  if (sym)
+	    {
+	      sym->type = bfd_link_hash_defined;
+	      sym->u.def.value = 0;
+	      sym->u.def.section = sec;
+	    }
+	}
+    }
+
+  /* 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");*/
+  if (! (bfd_elf${ELFSIZE}_size_dynamic_sections
+         (output_bfd, command_line.soname, rpath,
+	  command_line.filter_shlib,
+	  (const char * const *) command_line.auxiliary_filters,
+	  &link_info, &sinterp, lang_elf_version_info)))
+    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->_raw_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;
+	boolean ret;
+
+	if (is->just_syms_flag)
+	  continue;
+
+	s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning");
+	if (s == NULL)
+	  continue;
+
+	sz = bfd_section_size (is->the_bfd, s);
+	msg = 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 copying the
+	   warning into the output file.  */
+	s->_raw_size = 0;
+      }
+  }
+}
+
+EOF
+fi
+
+
+if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* A variant of lang_output_section_find.  Used by place_orphan.  */
+
+static lang_output_section_statement_type *
+output_rel_find (sec)
+     asection *sec;
+{
+  lang_statement_union_type *u;
+  lang_output_section_statement_type *lookup;
+  lang_output_section_statement_type *last = 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 (u = lang_output_section_statement.head; u; u = lookup->next)
+    {
+      lookup = &u->output_section_statement;
+      if (strncmp (".rel", lookup->name, 4) == 0)
+	{
+	  /* Don't place after .rel.plt as doing so results in wrong
+	     dynamic tags.  Also, place allocated reloc sections before
+	     non-allocated.  */
+	  int lookrela = lookup->name[4] == 'a';
+
+	  if (strcmp (".plt", lookup->name + 4 + lookrela) == 0
+	      || (lookup->bfd_section != NULL
+		  && (lookup->bfd_section->flags & SEC_ALLOC) == 0))
+	    break;
+	  last = lookup;
+	  if (rela == lookrela)
+	    last_rel = lookup;
+	  if (lookup->bfd_section != NULL
+	      && (lookup->bfd_section->flags & SEC_ALLOC) != 0)
+	    last_rel_alloc = lookup;
+	}
+    }
+
+  if (last_rel_alloc)
+    return last_rel_alloc;
+
+  if (last_rel)
+    return last_rel;
+
+  return last;
+}
+
+/* Find the last output section before given output statement.
+   Used by place_orphan.  */
+
+static asection *
+output_prev_sec_find (os)
+     lang_output_section_statement_type *os;
+{
+  asection *s = (asection *) NULL;
+  lang_statement_union_type *u;
+  lang_output_section_statement_type *lookup;
+
+  for (u = lang_output_section_statement.head;
+       u != (lang_statement_union_type *) NULL;
+       u = lookup->next)
+    {
+      lookup = &u->output_section_statement;
+      if (lookup == os)
+	return s;
+
+      if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
+	s = lookup->bfd_section;
+    }
+
+  return NULL;
+}
+
+/* Place an orphan section.  We use this to put random SHF_ALLOC
+   sections in the right segment.  */
+
+struct orphan_save {
+  lang_output_section_statement_type *os;
+  asection **section;
+  lang_statement_union_type **stmt;
+};
+
+static boolean
+gld${EMULATION_NAME}_place_orphan (file, s)
+     lang_input_statement_type *file;
+     asection *s;
+{
+  static struct orphan_save hold_text;
+  static struct orphan_save hold_rodata;
+  static struct orphan_save hold_data;
+  static struct orphan_save hold_bss;
+  static struct orphan_save hold_rel;
+  static struct orphan_save hold_interp;
+  static struct orphan_save hold_sdata;
+  static int count = 1;
+  struct orphan_save *place;
+  lang_statement_list_type *old;
+  lang_statement_list_type add;
+  etree_type *address;
+  const char *secname;
+  const char *ps = NULL;
+  lang_output_section_statement_type *os;
+  int isdyn = 0;
+
+  secname = bfd_get_section_name (s->owner, s);
+  if (! link_info.relocateable
+      && link_info.combreloc
+      && (s->flags & SEC_ALLOC)
+      && strncmp (secname, ".rel", 4) == 0)
+    {
+      if (secname[4] == 'a')
+	secname = ".rela.dyn";
+      else
+	secname = ".rel.dyn";
+      isdyn = 1;
+    }
+
+  if (isdyn || (!config.unique_orphan_sections && !unique_section_p (secname)))
+    {
+      /* Look through the script to see where to place this section.  */
+      os = lang_output_section_find (secname);
+
+      if (os != NULL
+	  && (os->bfd_section == NULL
+	      || ((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, if any, has compatible flags.  */
+	  lang_add_section (&os->children, s, os, file);
+	  return true;
+	}
+    }
+
+  if (hold_text.os == NULL)
+    hold_text.os = lang_output_section_find (".text");
+
+  /* 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.shared
+      && ! link_info.relocateable
+      && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
+      && hold_text.os != NULL)
+    {
+      lang_add_section (&hold_text.os->children, s, hold_text.os, file);
+      return true;
+    }
+
+  /* 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.  */
+#define HAVE_SECTION(hold, name) \
+(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
+
+  if ((s->flags & SEC_EXCLUDE) != 0 && !link_info.relocateable)
+    {
+      if (s->output_section == NULL)
+	s->output_section = bfd_abs_section_ptr;
+      return true;
+    }
+
+  place = NULL;
+  if ((s->flags & SEC_ALLOC) == 0)
+    ;
+  else if ((s->flags & SEC_LOAD) != 0
+	   && strncmp (secname, ".note", 5) == 0
+	   && HAVE_SECTION (hold_interp, ".interp"))
+    place = &hold_interp;
+  else if ((s->flags & SEC_HAS_CONTENTS) == 0
+	   && HAVE_SECTION (hold_bss, ".bss"))
+    place = &hold_bss;
+  else if ((s->flags & SEC_SMALL_DATA) != 0
+	   && HAVE_SECTION (hold_sdata, ".sdata"))
+    place = &hold_sdata;
+  else if ((s->flags & SEC_READONLY) == 0
+	   && HAVE_SECTION (hold_data, ".data"))
+    place = &hold_data;
+  else if (strncmp (secname, ".rel", 4) == 0
+	   && (s->flags & SEC_LOAD) != 0
+	   && (hold_rel.os != NULL
+	       || (hold_rel.os = output_rel_find (s)) != NULL))
+    place = &hold_rel;
+  else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
+	   && HAVE_SECTION (hold_rodata, ".rodata"))
+    place = &hold_rodata;
+  else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
+	   && hold_text.os != NULL)
+    place = &hold_text;
+
+#undef HAVE_SECTION
+
+  /* Choose a unique name for the section.  This will be needed if the
+     same section name appears in the input file with different
+     loadable or allocatable characteristics.  */
+  if (bfd_get_section_by_name (output_bfd, secname) != NULL)
+    {
+      secname = bfd_get_unique_section_name (output_bfd, secname, &count);
+      if (secname == NULL)
+	einfo ("%F%P: place_orphan failed: %E\n");
+    }
+
+  /* Start building a list of statements for this section.
+     First save the current statement pointer.  */
+  old = stat_ptr;
+
+  /* If we have found an appropriate place for the output section
+     statements for this orphan, add them to our own private list,
+     inserting them later into the global statement list.  */
+  if (place != NULL)
+    {
+      stat_ptr = &add;
+      lang_list_init (stat_ptr);
+    }
+
+  if (config.build_constructors)
+    {
+      /* If the name of the section is representable in C, then create
+	 symbols to mark the start and the end of the section.  */
+      for (ps = secname; *ps != '\0'; ps++)
+	if (! ISALNUM (*ps) && *ps != '_')
+	  break;
+      if (*ps == '\0')
+	{
+	  char *symname;
+	  etree_type *e_align;
+
+	  symname = (char *) xmalloc (ps - secname + sizeof "__start_");
+	  sprintf (symname, "__start_%s", secname);
+	  e_align = exp_unop (ALIGN_K,
+			      exp_intop ((bfd_vma) 1 << s->alignment_power));
+	  lang_add_assignment (exp_assop ('=', symname, e_align));
+	}
+    }
+
+  if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
+    address = exp_intop ((bfd_vma) 0);
+  else
+    address = NULL;
+
+  os = lang_enter_output_section_statement (secname, address, 0,
+					    (bfd_vma) 0,
+					    (etree_type *) NULL,
+					    (etree_type *) NULL,
+					    (etree_type *) NULL);
+
+  lang_add_section (&os->children, s, os, file);
+
+  lang_leave_output_section_statement
+    ((bfd_vma) 0, "*default*",
+     (struct lang_output_section_phdr_list *) NULL, NULL);
+
+  if (config.build_constructors && *ps == '\0')
+    {
+      char *symname;
+
+      /* lang_leave_ouput_section_statement resets stat_ptr.  Put
+	 stat_ptr back where we want it.  */
+      if (place != NULL)
+	stat_ptr = &add;
+
+      symname = (char *) xmalloc (ps - secname + sizeof "__stop_");
+      sprintf (symname, "__stop_%s", secname);
+      lang_add_assignment (exp_assop ('=', symname,
+				      exp_nameop (NAME, ".")));
+    }
+
+  /* Restore the global list pointer.  */
+  stat_ptr = old;
+
+  if (place != NULL && os->bfd_section != NULL)
+    {
+      asection *snew, **pps;
+
+      snew = os->bfd_section;
+
+      /* Shuffle the bfd section list to make the output file look
+	 neater.  This is really only cosmetic.  */
+      if (place->section == NULL)
+	{
+	  asection *bfd_section = place->os->bfd_section;
+
+	  /* If the output statement hasn't been used to place
+	     any input sections (and thus doesn't have an output
+	     bfd_section), look for the closest prior output statement
+	     having an output section.  */
+	  if (bfd_section == NULL)
+	    bfd_section = output_prev_sec_find (place->os);
+
+	  if (bfd_section != NULL && bfd_section != snew)
+	    place->section = &bfd_section->next;
+	}
+
+      if (place->section != NULL)
+	{
+	  /* Unlink the section.  */
+	  for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
+	    ;
+	  bfd_section_list_remove (output_bfd, pps);
+
+	  /* Now tack it on to the "place->os" section list.  */
+	  bfd_section_list_insert (output_bfd, place->section, snew);
+	}
+
+      /* Save the end of this list.  Further ophans of this type will
+	 follow the one we've just added.  */
+      place->section = &snew->next;
+
+      /* The following is non-cosmetic.  We try to put the output
+	 statements in some sort of reasonable order here, because
+	 they determine the final load addresses of the orphan
+	 sections.  In addition, placing output statements in the
+	 wrong order may require extra segments.  For instance,
+	 given a typical situation of all read-only sections placed
+	 in one segment and following that a segment containing all
+	 the read-write sections, we wouldn't want to place an orphan
+	 read/write section before or amongst the read-only ones.  */
+      if (add.head != NULL)
+	{
+	  if (place->stmt == NULL)
+	    {
+	      /* Put the new statement list right at the head.  */
+	      *add.tail = place->os->header.next;
+	      place->os->header.next = add.head;
+	    }
+	  else
+	    {
+	      /* Put it after the last orphan statement we added.  */
+	      *add.tail = *place->stmt;
+	      *place->stmt = add.head;
+	    }
+
+	  /* Fix the global list pointer if we happened to tack our
+	     new list at the tail.  */
+	  if (*old->tail == add.head)
+	    old->tail = add.tail;
+
+	  /* Save the end of this list.  */
+	  place->stmt = add.tail;
+	}
+    }
+
+  return true;
+}
+EOF
+fi
+
+if test x"$LDEMUL_FINISH" != xgld"$EMULATION_NAME"_finish; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static void
+gld${EMULATION_NAME}_finish ()
+{
+  if (bfd_elf${ELFSIZE}_discard_info (output_bfd, &link_info))
+    {
+      lang_reset_memory_regions ();
+
+      /* Resize the sections.  */
+      lang_size_sections (stat_ptr->head, abs_output_section,
+			  &stat_ptr->head, 0, (bfd_vma) 0, NULL);
+
+      /* Redo special stuff.  */
+      ldemul_after_allocation ();
+
+      /* Do the assignments again.  */
+      lang_do_assignments (stat_ptr->head, abs_output_section,
+			   (fill_type *) 0, (bfd_vma) 0);
+    }
+}
+EOF
+fi
+
+if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static char *
+gld${EMULATION_NAME}_get_script (isfile)
+     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"
+
+cat >>e${EMULATION_NAME}.c <<EOF
+{
+  *isfile = 0;
+
+  if (link_info.relocateable == true && config.build_constructors == true)
+    return
+EOF
+sed $sc ldscripts/${EMULATION_NAME}.xu                     >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.relocateable == true) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xr                     >> e${EMULATION_NAME}.c
+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.
+
+cat >>e${EMULATION_NAME}.c <<EOF
+{
+  *isfile = 1;
+
+  if (link_info.relocateable == true && config.build_constructors == true)
+    return "ldscripts/${EMULATION_NAME}.xu";
+  else if (link_info.relocateable == true)
+    return "ldscripts/${EMULATION_NAME}.xr";
+  else
+    return "ldscripts/${EMULATION_NAME}.x";
+}
+
+EOF
+fi
+fi
+
+if test -n "$PARSE_AND_LIST_ARGS_CASES" -o x"$GENERATE_SHLIB_SCRIPT" = xyes; then
+
+if test x"$LDEMUL_PARSE_ARGS" != xgld"$EMULATION_NAME"_parse_args; then
+
+if test -n "$PARSE_AND_LIST_PROLOGUE" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ $PARSE_AND_LIST_PROLOGUE
+EOF
+fi
+
+cat >>e${EMULATION_NAME}.c <<EOF
+
+#include "getopt.h"
+
+#define OPTION_IGNORE (300)
+#define OPTION_MORPHOS_DATADATA_RELOC  (OPTION_IGNORE + 1)
+#define OPTION_MORPHOS_BASEREL32       (OPTION_IGNORE + 2)
+#define OPTION_FLAVOR                  (OPTION_IGNORE + 3)
+
+#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)
+
+static struct option longopts[] =
+{
+  {"datadata-reloc", no_argument, NULL, OPTION_MORPHOS_DATADATA_RELOC},
+  /*    '\0', NULL, "Relocate for resident program", ONE_DASH },*/
+  {"flavor", required_argument, NULL, OPTION_FLAVOR},
+  /*'\0', NULL, "Select a library flavor", ONE_DASH },*/
+  /*{"baserel32", no_argument, NULL, OPTION_MORPHOS_BASEREL32},*/
+  /*    '\0', NULL, "Build a large-data base relative executable", ONE_DASH },*/
+EOF
+
+if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
+cat >>e${EMULATION_NAME}.c <<EOF
+  /* getopt allows abbreviations, so we do this to stop it from
+     treating -d/-e as abbreviations for these options. */
+  {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
+  {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
+  {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
+  {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
+  {"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR},
+  {"Bgroup", no_argument, NULL, OPTION_GROUP},
+  {"Bgroup", no_argument, NULL, OPTION_GROUP},
+EOF
+fi
+
+if test -n "$PARSE_AND_LIST_LONGOPTS" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ $PARSE_AND_LIST_LONGOPTS
+EOF
+fi
+
+cat >>e${EMULATION_NAME}.c <<EOF
+  {NULL, no_argument, NULL, 0}
+};
+
+
+static int gld${EMULATION_NAME}_parse_args PARAMS ((int, char **));
+
+static int
+gld${EMULATION_NAME}_parse_args (argc, argv)
+     int argc;
+     char ** argv;
+{
+  int longind;
+  int optc;
+  static int prevoptind = -1;
+  int prevopterr = opterr;
+  int wanterror;
+
+  if (prevoptind != optind)
+    opterr = 0;
+
+  wanterror = opterr;
+  prevoptind = optind;
+
+  optc = getopt_long_only (argc, argv,
+			   "-${PARSE_AND_LIST_SHORTOPTS}z:", longopts,
+			   &longind);
+  opterr = prevopterr;
+
+  switch (optc)
+    {
+    default:
+      if (wanterror)
+	xexit (1);
+      optind = prevoptind;
+      return 0;
+
+    case OPTION_MORPHOS_DATADATA_RELOC:
+      morphos_resident=1; /* Write out datadata_reloc array */
+      break;
+
+     /*case OPTION_MORPHOS_BASEREL32:
+      morphos_baserel32=1;
+      break;*/
+
+    case OPTION_FLAVOR:
+      ldfile_add_flavor (optarg);
+      break;
+EOF
+
+if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
+cat >>e${EMULATION_NAME}.c <<EOF
+    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.no_undefined = true;
+      break;
+
+    case 'z':
+      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, "origin") == 0)
+	{
+	  link_info.flags |= (bfd_vma) DF_ORIGIN;
+	  link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN;
+	}
+      else if (strcmp (optarg, "defs") == 0)
+	link_info.no_undefined = true;
+      else if (strcmp (optarg, "muldefs") == 0)
+	link_info.allow_multiple_definition = true;
+      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;
+      /* What about the other Solaris -z options? FIXME.  */
+      break;
+EOF
+fi
+
+if test -n "$PARSE_AND_LIST_ARGS_CASES" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ $PARSE_AND_LIST_ARGS_CASES
+EOF
+fi
+
+cat >>e${EMULATION_NAME}.c <<EOF
+    }
+
+  return 1;
+}
+
+EOF
+fi
+
+if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static void gld${EMULATION_NAME}_list_options PARAMS ((FILE * file));
+
+static void
+gld${EMULATION_NAME}_list_options (file)
+     FILE * file;
+{
+EOF
+
+if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
+cat >>e${EMULATION_NAME}.c <<EOF
+  fprintf (file, _("  -Bgroup\t\tSelects group name lookup rules for DSO\n"));
+  fprintf (file, _("  --disable-new-dtags\tDisable new dynamic tags\n"));
+  fprintf (file, _("  --enable-new-dtags\tEnable new dynamic tags\n"));
+  fprintf (file, _("  --eh-frame-hdr\tCreate .eh_frame_hdr section\n"));
+  fprintf (file, _("  -z combreloc\t\tMerge dynamic relocs into one section and sort\n"));
+  fprintf (file, _("  -z defs\t\tDisallows undefined symbols\n"));
+  fprintf (file, _("  -z initfirst\t\tMark DSO to be initialized first at runtime\n"));
+  fprintf (file, _("  -z interpose\t\tMark object to interpose all DSOs but executable\n"));
+  fprintf (file, _("  -z loadfltr\t\tMark object requiring immediate process\n"));
+  fprintf (file, _("  -z muldefs\t\tAllow multiple definitions\n"));
+  fprintf (file, _("  -z nocombreloc\tDon't merge dynamic relocs into one section\n"));
+  fprintf (file, _("  -z nocopyreloc\tDon't create copy relocs\n"));
+  fprintf (file, _("  -z nodefaultlib\tMark object not to use default search paths\n"));
+  fprintf (file, _("  -z nodelete\t\tMark DSO non-deletable at runtime\n"));
+  fprintf (file, _("  -z nodlopen\t\tMark DSO not available to dlopen\n"));
+  fprintf (file, _("  -z nodump\t\tMark DSO not available to dldump\n"));
+  fprintf (file, _("  -z now\t\tMark object non-lazy runtime binding\n"));
+  fprintf (file, _("  -z origin\t\tMark object requiring immediate \$ORIGIN processing\n\t\t\t  at runtime\n"));
+  fprintf (file, _("  -z KEYWORD\t\tIgnored for Solaris compatibility\n"));
+EOF
+fi
+
+if test -n "$PARSE_AND_LIST_OPTIONS" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ $PARSE_AND_LIST_OPTIONS
+EOF
+fi
+
+cat >>e${EMULATION_NAME}.c <<EOF
+}
+EOF
+
+if test -n "$PARSE_AND_LIST_EPILOGUE" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ $PARSE_AND_LIST_EPILOGUE
+EOF
+fi
+fi
+else
+if test x"$LDEMUL_PARSE_ARGS" != xgld"$EMULATION_NAME"_parse_args; then
+cat >>e${EMULATION_NAME}.c <<EOF
+#define gld${EMULATION_NAME}_parse_args   NULL
+EOF
+fi
+if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then
+cat >>e${EMULATION_NAME}.c <<EOF
+#define gld${EMULATION_NAME}_list_options NULL
+EOF
+fi
+fi
+
+cat >>e${EMULATION_NAME}.c <<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-after_allocation_default},
+  ${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-gld${EMULATION_NAME}_finish},
+  ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
+  ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-NULL},
+  ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
+  ${LDEMUL_SET_SYMBOLS-gld${EMULATION_NAME}_set_symbols},
+  ${LDEMUL_PARSE_ARGS-gld${EMULATION_NAME}_parse_args},
+  ${LDEMUL_UNRECOGNIZED_FILE-NULL},
+  ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options},
+  ${LDEMUL_RECOGNIZED_FILE-NULL},
+  ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
+  ${LDEMUL_NEW_VERS_PATTERN-NULL}
+};
+EOF
diff -ru --new-file a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em
--- a/ld/emultempl/ppc32elf.em	2013-11-04 19:33:39.000000000 +0400
+++ b/ld/emultempl/ppc32elf.em	2022-02-17 14:02:30.750937600 +0300
@@ -29,6 +29,9 @@
 #include "elf32-ppc.h"
 #include "ldlex.h"
 
+extern int ppc_elf_amigaos_select_plt_layout (bfd *, struct bfd_link_info *,
+    enum ppc_elf_plt_type, int);
+
 #define is_ppc_elf(bfd) \
   (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
    && elf_object_id (bfd) == PPC32_ELF_DATA)
@@ -59,8 +62,13 @@
 
       if (emit_stub_syms < 0)
 	emit_stub_syms = link_info.emitrelocations || link_info.shared;
+#ifdef TARGET_IS_amigaos
+      new_plt = ppc_elf_amigaos_select_plt_layout (link_info.output_bfd, &link_info,
+					   plt_style, emit_stub_syms);
+#else
       new_plt = ppc_elf_select_plt_layout (link_info.output_bfd, &link_info,
 					   plt_style, emit_stub_syms);
+#endif
       if (new_plt < 0)
 	einfo ("%X%P: select_plt_layout problem %E\n");
 
@@ -187,6 +195,9 @@
 #define OPTION_STUBSYMS			(OPTION_OLD_GOT + 1)
 #define OPTION_NO_STUBSYMS		(OPTION_STUBSYMS + 1)
 '
+#
+# CHECK: There was more here about use-dynld option.
+#
 
 PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}'
   { "emit-stub-syms", no_argument, NULL, OPTION_STUBSYMS },
diff -ru --new-file a/ld/ldctor.c b/ld/ldctor.c
--- a/ld/ldctor.c	2013-11-04 19:33:39.000000000 +0400
+++ b/ld/ldctor.c	2022-02-17 14:07:09.287287900 +0300
@@ -259,8 +259,12 @@
       /* If the symbol is defined, we may have been invoked from
 	 collect, and the sets may already have been built, so we do
 	 not do anything.  */
-      if (p->h->type == bfd_link_hash_defined
-	  || p->h->type == bfd_link_hash_defweak)
+      /* dgv -- libnix v1.1 uses absolute sets that are also explicitly
+	 defined in the library so that the sets need to be build even
+	 if the symbol is defined */
+      if ((bfd_get_flavour (link_info.output_bfd) != bfd_target_amiga_flavour) &&
+	  (p->h->type == bfd_link_hash_defined
+	  || p->h->type == bfd_link_hash_defweak))
 	continue;
 
       /* For each set we build:
@@ -356,15 +360,21 @@
 
 	      if (e->name != NULL)
 		minfo ("%T\n", e->name);
-	      else
+	      else if (e->section->owner)
 		minfo ("%G\n", e->section->owner, e->section, e->value);
+	      else
+		minfo ("%s\n", "** ABS **");
 	    }
 
 	  /* Need SEC_KEEP for --gc-sections.  */
 	  if (! bfd_is_abs_section (e->section))
 	    e->section->flags |= SEC_KEEP;
 
-	  if (link_info.relocatable)
+	  /* dgv -- on the amiga, we want the constructors to be relocateable
+	     objects. However, this should be arranged somewhere else (FIXME) */
+	  if (link_info.relocatable ||
+	      (bfd_get_flavour (link_info.output_bfd) == bfd_target_amiga_flavour &&
+	       e->section != bfd_abs_section_ptr))
 	    lang_add_reloc (p->reloc, howto, e->section, e->name,
 			    exp_intop (e->value));
 	  else
diff -ru --new-file a/ld/ldfile.c b/ld/ldfile.c
--- a/ld/ldfile.c	2013-11-04 19:33:39.000000000 +0400
+++ b/ld/ldfile.c	2022-02-17 14:10:00.694936300 +0300
@@ -66,6 +66,40 @@
 static search_arch_type *search_arch_head;
 static search_arch_type **search_arch_tail_ptr = &search_arch_head;
 
+/* Flavour support.  */
+
+static int flavors_cmp PARAMS ((const void *f1, const void *f2));
+
+static int n_flavors, flavors_len;
+static char **flavors;
+
+static int
+flavors_cmp (f1, f2)
+     const void *f1, *f2;
+{
+  return strcmp (*(char **)f1, *(char **)f2);
+}
+
+void
+ldfile_sort_flavors ()
+{
+  if (n_flavors > 1)
+    qsort ((void *) flavors, n_flavors, sizeof (char **), flavors_cmp);
+}
+
+void
+ldfile_add_flavor (name)
+     const char *name;
+{
+  n_flavors++;
+  if (flavors)
+    flavors = (char **) xrealloc ((PTR)flavors, n_flavors * sizeof (char *));
+  else
+    flavors = (char **) xmalloc (sizeof (char *));
+  flavors [n_flavors-1] = (char *) name;
+  flavors_len += strlen (name);
+}
+
 /* Test whether a pathname, after canonicalization, is the same or a
    sub-directory of the sysroot directory.  */
 
@@ -335,6 +369,7 @@
 			 const char *lib,
 			 const char *suffix)
 {
+  char *flavor_dir = (char *) alloca (flavors_len + n_flavors + 1);
   search_dirs_type *search;
 
   /* If this is not an archive, try to open it in the current
@@ -362,18 +397,31 @@
   for (search = search_head; search != NULL; search = search->next)
     {
       char *string;
-
+      int i, count;
+	  
       if (entry->flags.dynamic && ! link_info.relocatable)
 	{
 	  if (ldemul_open_dynamic_archive (arch, search, entry))
 	    return TRUE;
 	}
 
+  /* This is intentionally indented so strange to aid merging */
+  for (count=n_flavors; count>=0; count--)
+    {
+      *flavor_dir = '\0';
+      for (i=0; i<count; i++)
+	{
+	  strcat (flavor_dir, flavors[i]);
+	  strcat (flavor_dir, slash);
+	}
+
       if (entry->flags.maybe_archive)
-	string = concat (search->name, slash, lib, entry->filename,
+	string = concat (search->name, slash, flavor_dir, lib, entry->filename,
 			 arch, suffix, (const char *) NULL);
+      else if (entry->filename[0] == '/' || entry->filename[0] == '.')
+	string = concat(entry->filename, NULL);
       else
-	string = concat (search->name, slash, entry->filename,
+	string = concat (search->name, slash, flavor_dir, entry->filename,
 			 (const char *) 0);
 
       if (ldfile_try_open_bfd (string, entry))
@@ -385,6 +433,7 @@
       free (string);
     }
 
+	}
   return FALSE;
 }
 
diff -ru --new-file a/ld/ldfile.h b/ld/ldfile.h
--- a/ld/ldfile.h	2013-11-04 19:33:39.000000000 +0400
+++ b/ld/ldfile.h	2022-02-17 14:10:29.319543100 +0300
@@ -58,5 +58,9 @@
 extern bfd_boolean ldfile_open_file_search
   (const char *arch, struct lang_input_statement_struct *,
    const char *lib, const char *suffix);
+extern void ldfile_sort_flavors
+  PARAMS ((void));
+extern void ldfile_add_flavor
+  PARAMS ((const char *));
 
 #endif
diff -ru --new-file a/ld/ldlang.c b/ld/ldlang.c
--- a/ld/ldlang.c	2013-11-04 19:33:39.000000000 +0400
+++ b/ld/ldlang.c	2022-02-17 14:11:06.737219000 +0300
@@ -3392,6 +3392,13 @@
 void
 ldlang_add_undef (const char *const name, bfd_boolean cmdline)
 {
+#if 1
+  /* This is a quick ugly hak of getting around the problem
+   * with -use-dynld being passed to the linker
+   */
+  if (strcmp(name, "se-dynld") == 0)
+    return;
+#endif
   ldlang_undef_chain_list_type *new_undef;
 
   undef_from_cmdline = undef_from_cmdline || cmdline;
diff -ru --new-file a/ld/ldlang.h b/ld/ldlang.h
--- a/ld/ldlang.h	2013-11-04 19:33:39.000000000 +0400
+++ b/ld/ldlang.h	2022-02-17 14:11:29.223306100 +0300
@@ -305,6 +305,8 @@
   const char *target;
 
   struct lang_input_statement_flags flags;
+  /* Added for AMIGA support of section attributes */
+  int amiga_attribute;
 } lang_input_statement_type;
 
 typedef struct
diff -ru --new-file a/ld/ldlex.c b/ld/ldlex.c
--- a/ld/ldlex.c	2013-11-18 12:49:29.000000000 +0400
+++ b/ld/ldlex.c	2022-02-17 17:58:45.618153300 +0300
@@ -8,7 +8,7 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_SUBMINOR_VERSION 39
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -54,7 +54,6 @@
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
 
 /* Limits of integral types. */
 #ifndef INT8_MIN
@@ -84,6 +83,7 @@
 #ifndef UINT32_MAX
 #define UINT32_MAX             (4294967295U)
 #endif
+#endif /* ! C99 */
 
 #endif /* ! FLEXINT_H */
 
@@ -141,7 +141,15 @@
 
 /* Size of default input buffer. */
 #ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
 #define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
 #endif
 
 /* The state buf must be large enough to hold one state per character in the main buffer.
@@ -166,7 +174,8 @@
 #define EOB_ACT_END_OF_FILE 1
 #define EOB_ACT_LAST_MATCH 2
 
-    #define YY_LESS_LINENO(n)
+#define YY_LESS_LINENO(n)
+#define YY_LINENO_REWIND_TO(ptr)
     
 /* Return all but the first "n" matched characters back to the input stream. */
 #define yyless(n) \
@@ -1828,7 +1837,12 @@
 
 /* Amount of stuff to slurp up with each read. */
 #ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
 #define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
 #endif
 
 /* Copy whatever the last rule matched to the standard output. */
@@ -1836,7 +1850,7 @@
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
 #endif
 
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
@@ -1847,7 +1861,7 @@
 	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
 		{ \
 		int c = '*'; \
-		yy_size_t n; \
+		size_t n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -1928,27 +1942,6 @@
 	register yy_state_type yy_current_state;
 	register char *yy_cp, *yy_bp;
 	register int yy_act;
-    
-#line 119 "ldlex.l"
-
-
-  if (parser_input != input_selected)
-    {
-      /* The first token of the input determines the initial parser state.  */
-      input_type t = parser_input;
-      parser_input = input_selected;
-      switch (t)
-	{
-	case input_script: return INPUT_SCRIPT; break;
-	case input_mri_script: return INPUT_MRI_SCRIPT; break;
-	case input_version_script: return INPUT_VERSION_SCRIPT; break;
-	case input_dynamic_list: return INPUT_DYNAMIC_LIST; break;
-	case input_defsym: return INPUT_DEFSYM; break;
-	default: abort ();
-	}
-    }
-
-#line 1952 "ldlex.c"
 
 	if ( !(yy_init) )
 		{
@@ -1975,6 +1968,28 @@
 
 		yy_load_buffer_state( );
 		}
+	{
+#line 121 "ldlex.l"
+
+
+  if (parser_input != input_selected)
+    {
+      /* The first token of the input determines the initial parser state.  */
+      input_type t = parser_input;
+      parser_input = input_selected;
+      switch (t)
+	{
+	case input_script: return INPUT_SCRIPT; break;
+	case input_mri_script: return INPUT_MRI_SCRIPT; break;
+	case input_version_script: return INPUT_VERSION_SCRIPT; break;
+	case input_dynamic_list: return INPUT_DYNAMIC_LIST; break;
+	case input_defsym: return INPUT_DEFSYM; break;
+	default: abort ();
+	}
+    }
+
+#line 1967 "/home/sba/amiga/adtools/branches/binutils/2.23.2/ld/ldlex.c"
+
 
 	while ( 1 )		/* loops until end-of-file is reached */
 		{
@@ -1992,7 +2007,7 @@
 yy_match:
 		do
 			{
-			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
 			if ( yy_accept[yy_current_state] )
 				{
 				(yy_last_accepting_state) = yy_current_state;
@@ -3274,6 +3289,7 @@
 			"fatal flex scanner internal error--no action found" );
 	} /* end of action switch */
 		} /* end of scanning one token */
+	} /* end of user's declarations */
 } /* end of yylex */
 
 /* yy_get_next_buffer - try to read in a new buffer
@@ -3336,7 +3352,7 @@
 			{ /* Not enough room in the buffer - grow it. */
 
 			/* just a shorter name for the current buffer */
-			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
 
 			int yy_c_buf_p_offset =
 				(int) ((yy_c_buf_p) - b->yy_ch_buf);
@@ -3656,10 +3672,6 @@
 	yyfree((void *) b  );
 }
 
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-    
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
  * such as during a yyrestart() or at EOF.
@@ -3864,8 +3876,8 @@
 
 /** Setup the input buffer state to scan the given bytes. The next call to yylex() will
  * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
  * 
  * @return the newly allocated buffer state object.
  */
diff -ru --new-file a/ld/ldmain.c b/ld/ldmain.c
--- a/ld/ldmain.c	2013-11-08 14:13:48.000000000 +0400
+++ b/ld/ldmain.c	2022-02-17 14:24:21.816139100 +0300
@@ -409,13 +409,19 @@
     }
 
   lang_process ();
-
+  /* Print error messages for any missing symbols, for any warning
+     symbols, and possibly multiple definitions.  */
+#ifdef __amigaos4__
+  /* Make all files executable, even relocatable files */
+    link_info.output_bfd->flags |= EXEC_P;
+#else
   /* Print error messages for any missing symbols, for any warning
      symbols, and possibly multiple definitions.  */
   if (link_info.relocatable)
     link_info.output_bfd->flags &= ~EXEC_P;
   else
     link_info.output_bfd->flags |= EXEC_P;
+#endif
 
   ldwrite ();
 
diff -ru --new-file a/ld/Makefile.am b/ld/Makefile.am
--- a/ld/Makefile.am	2013-11-26 15:37:33.000000000 +0400
+++ b/ld/Makefile.am	2022-02-17 13:53:40.841355800 +0300
@@ -149,6 +149,10 @@
 	eaix5rs6.c \
 	eaixppc.c \
 	eaixrs6.c \
+	eamiga.c \
+	eamiga_bss.c \
+	eamigaos.c \
+	eamithlon.c \
 	ealpha.c \
 	ealphavms.c \
 	earcelf.c \
@@ -334,6 +338,8 @@
 	em68kpsos.c \
 	em88kbcs.c \
 	emcorepe.c \
+	emorphos.c \
+	emorphos_baserel.c \
 	emn10200.c \
 	emn10300.c \
 	emsp430x110.c \
@@ -402,6 +408,8 @@
 	eor32elf.c \
 	epc532macha.c \
 	epdp11.c \
+	eppcamiga.c \
+	eppcamiga_bss.c \
 	epjelf.c \
 	epjlelf.c \
 	eppclynx.c \
@@ -688,6 +696,20 @@
 
 @TDIRS@
 
+eamiga.c: $(srcdir)/emulparams/amiga.sh\
+   $(srcdir)/emultempl/amiga.em $(srcdir)/scripttempl/amiga.sc ${GEN_DEPENDS} 
+	${GENSCRIPTS} amiga "$(tdir_amiga)"
+eamiga_bss.c: $(srcdir)/emulparams/amiga_bss.sh\
+   $(srcdir)/emultempl/amiga.em $(srcdir)/scripttempl/amiga_bss.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} amiga_bss "$(tdir_amiga_bss)"
+eamigaos.c: $(srcdir)/emulparams/amigaos.sh \
+  $(srcdir)/emulparams/amigaos.sh $(srcdir)/emultempl/amigaos.em \
+  ldemul-list.h \
+  $(ELF_DEPS) $(srcdir)/scripttempl/amigaos.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} amigaos "$(tdir_amigaos)"
+eamithlon.c: $(srcdir)/emulparams/amithlon.sh \
+  $(srcdir)/emultempl/amithlon.em $(srcdir)/scripttempl/amithlon.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} amithlon "$(tdir_amithlon)"
 eaix5ppc.c: $(srcdir)/emulparams/aix5ppc.sh \
   $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} aix5ppc "$(tdir_aixppc)"
@@ -1505,6 +1527,12 @@
 emcorepe.c: $(srcdir)/emulparams/mcorepe.sh \
   $(srcdir)/emultempl/pe.em $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} mcorepe "$(tdir_mcorepe)"
+emorphos.c: $(srcdir)/emulparams/morphos.sh \
+  $(srcdir)/emultempl/morphos.em $(srcdir)/scripttempl/morphos.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} morphos "$(tdir_morphos)"
+emorphos_baserel.c: $(srcdir)/emulparams/morphos_baserel.sh \
+  $(srcdir)/emultempl/morphos.em $(srcdir)/scripttempl/morphos_baserel.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} morphos_baserel "$(tdir_morphos)"
 emn10200.c: $(srcdir)/emulparams/mn10200.sh \
   $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} mn10200 "$(tdir_mn10200)"
@@ -1815,6 +1843,16 @@
 epjlelf.c: $(srcdir)/emulparams/pjlelf.sh $(srcdir)/emulparams/pjelf.sh \
   $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} pjlelf "$(tdir_pjlelf)"
+eppcamiga.c: $(srcdir)/emulparams/ppcamiga.sh \
+  $(srcdir)/emulparams/ppcamiga.sh $(srcdir)/emultempl/ppcamiga.em \
+  ldemul-list.h \
+  $(ELF_DEPS) $(srcdir)/scripttempl/ppcamiga.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} ppcamiga "$(tdir_ppcamiga)"
+eppcamiga_bss.c: $(srcdir)/emulparams/ppcamiga_bss.sh \
+  $(srcdir)/emulparams/ppcamiga_bss.sh $(srcdir)/emultempl/ppcamiga_bss.em \
+  ldemul-list.h \
+  $(ELF_DEPS) $(srcdir)/scripttempl/ppcamiga_bss.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} ppcamiga_bss "$(tdir_ppcamiga_bss)"
 eppclynx.c: $(srcdir)/emulparams/ppclynx.sh \
   $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} ppclynx "$(tdir_ppclynx)"
diff -ru --new-file a/ld/Makefile.in b/ld/Makefile.in
--- a/ld/Makefile.in	2013-11-26 15:37:33.000000000 +0400
+++ b/ld/Makefile.in	2022-02-17 13:56:55.271774600 +0300
@@ -457,6 +457,10 @@
 	eaix5rs6.c \
 	eaixppc.c \
 	eaixrs6.c \
+	eamiga.c \
+	eamiga_bss.c \
+	eamigaos.c \
+	eamithlon.c \
 	ealpha.c \
 	ealphavms.c \
 	earcelf.c \
@@ -642,6 +646,8 @@
 	em68kpsos.c \
 	em88kbcs.c \
 	emcorepe.c \
+	emorphos.c \
+	emorphos_baserel.c \
 	emn10200.c \
 	emn10300.c \
 	emsp430x110.c \
@@ -710,6 +716,8 @@
 	eor32elf.c \
 	epc532macha.c \
 	epdp11.c \
+	eppcamiga.c \
+	eppcamiga_bss.c \
 	epjelf.c \
 	epjlelf.c \
 	eppclynx.c \
@@ -1095,6 +1103,10 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eaixrs6.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ealpha.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ealphavms.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eamiga.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eamiga_bss.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eamigaos.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eamithlon.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earcelf.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earm_epoc_pe.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earm_wince_pe.Po@am__quote@
@@ -1338,6 +1350,8 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emmo.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emn10200.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emn10300.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emorphos.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emorphos_baserel.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430X.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x110.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1101.Po@am__quote@
@@ -1406,6 +1420,8 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epdp11.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epjelf.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epjlelf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppcamiga.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppcamiga_bss.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppclynx.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppcmacos.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppcnw.Po@am__quote@
@@ -2172,6 +2188,20 @@
 
 @TDIRS@
 
+eamiga.c: $(srcdir)/emulparams/amiga.sh\
+   $(srcdir)/emultempl/amiga.em $(srcdir)/scripttempl/amiga.sc ${GEN_DEPENDS} 
+	${GENSCRIPTS} amiga "$(tdir_amiga)"
+eamiga_bss.c: $(srcdir)/emulparams/amiga_bss.sh\
+   $(srcdir)/emultempl/amiga.em $(srcdir)/scripttempl/amiga_bss.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} amiga_bss "$(tdir_amiga_bss)"
+eamigaos.c: $(srcdir)/emulparams/amigaos.sh \
+  $(srcdir)/emulparams/amigaos.sh $(srcdir)/emultempl/amigaos.em \
+  ldemul-list.h \
+  $(ELF_DEPS) $(srcdir)/scripttempl/amigaos.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} amigaos "$(tdir_amigaos)"
+eamithlon.c: $(srcdir)/emulparams/amithlon.sh \
+  $(srcdir)/emultempl/amithlon.em $(srcdir)/scripttempl/amithlon.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} amithlon "$(tdir_amithlon)"
 eaix5ppc.c: $(srcdir)/emulparams/aix5ppc.sh \
   $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} aix5ppc "$(tdir_aixppc)"
@@ -2989,6 +3019,12 @@
 emcorepe.c: $(srcdir)/emulparams/mcorepe.sh \
   $(srcdir)/emultempl/pe.em $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} mcorepe "$(tdir_mcorepe)"
+emorphos.c: $(srcdir)/emulparams/morphos.sh \
+  $(srcdir)/emultempl/morphos.em $(srcdir)/scripttempl/morphos.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} morphos "$(tdir_morphos)"
+emorphos_baserel.c: $(srcdir)/emulparams/morphos_baserel.sh \
+  $(srcdir)/emultempl/morphos.em $(srcdir)/scripttempl/morphos_baserel.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} morphos_baserel "$(tdir_morphos)"
 emn10200.c: $(srcdir)/emulparams/mn10200.sh \
   $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} mn10200 "$(tdir_mn10200)"
@@ -3299,6 +3335,16 @@
 epjlelf.c: $(srcdir)/emulparams/pjlelf.sh $(srcdir)/emulparams/pjelf.sh \
   $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} pjlelf "$(tdir_pjlelf)"
+eppcamiga.c: $(srcdir)/emulparams/ppcamiga.sh \
+  $(srcdir)/emulparams/ppcamiga.sh $(srcdir)/emultempl/ppcamiga.em \
+  ldemul-list.h \
+  $(ELF_DEPS) $(srcdir)/scripttempl/ppcamiga.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} ppcamiga "$(tdir_ppcamiga)"
+eppcamiga_bss.c: $(srcdir)/emulparams/ppcamiga_bss.sh \
+  $(srcdir)/emulparams/ppcamiga_bss.sh $(srcdir)/emultempl/ppcamiga_bss.em \
+  ldemul-list.h \
+  $(ELF_DEPS) $(srcdir)/scripttempl/ppcamiga_bss.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} ppcamiga_bss "$(tdir_ppcamiga_bss)"
 eppclynx.c: $(srcdir)/emulparams/ppclynx.sh \
   $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} ppclynx "$(tdir_ppclynx)"
diff -ru --new-file a/ld/scripttempl/amiga.sc b/ld/scripttempl/amiga.sc
--- a/ld/scripttempl/amiga.sc	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/scripttempl/amiga.sc	2021-02-01 23:12:49.302892200 +0300
@@ -0,0 +1,49 @@
+cat <<EOF
+OUTPUT_FORMAT("${OUTPUT_FORMAT}")
+OUTPUT_ARCH(${ARCH})
+
+${RELOCATING+${LIB_SEARCH_DIRS}}
+${STACKZERO+${RELOCATING+${STACKZERO}}}
+${SHLIB_PATH+${RELOCATING+${SHLIB_PATH}}}
+
+SECTIONS
+{
+  ${RELOCATING+PROVIDE(___machtype = 0x0);}
+  ${RELOCATING+. = ${TEXT_START_ADDR};}
+  .text :
+  {
+    ${RELOCATING+__stext = .;}
+    *(.text)
+    ${RELOCATING+___datadata_relocs = .;}
+    ${RELOCATING+__etext = .;}
+    ${PAD_TEXT+${RELOCATING+. = ${DATA_ALIGNMENT};}}
+  }
+  ${RELOCATING+___text_size = SIZEOF(.text);}
+  ${RELOCATING+. = ${DATA_ALIGNMENT};}
+  .data :
+  {
+    ${RELOCATING+__sdata = .;}
+    ${CONSTRUCTING+CONSTRUCTORS}
+    *(.data)
+    ${RELOCATING+___a4_init = 0x7ffe;}
+    ${RELOCATING+__edata = .;}
+  }
+  ${RELOCATING+___data_size = SIZEOF(.data);}
+  .bss :
+  {
+    ${RELOCATING+__bss_start = .;}
+    *(.bss)
+    *(COMMON)
+    ${RELOCATING+__end = .;}
+  }
+  ${RELOCATING+___bss_size = SIZEOF(.bss);}
+  .data_chip :
+  {
+    *(.data_chip)
+  }
+  .bss_chip :
+  {
+    *(.bss_chip)
+  }
+}
+EOF
diff -ru --new-file a/ld/scripttempl/amiga_bss.sc b/ld/scripttempl/amiga_bss.sc
--- a/ld/scripttempl/amiga_bss.sc	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/scripttempl/amiga_bss.sc	2021-02-01 23:12:49.303897300 +0300
@@ -0,0 +1,41 @@
+cat <<EOF
+OUTPUT_FORMAT("${OUTPUT_FORMAT}")
+OUTPUT_ARCH(${ARCH})
+
+${RELOCATING+${LIB_SEARCH_DIRS}}
+${STACKZERO+${RELOCATING+${STACKZERO}}}
+${SHLIB_PATH+${RELOCATING+${SHLIB_PATH}}}
+
+SECTIONS
+{
+  ${RELOCATING+PROVIDE(___machtype = 0x0);}
+  ${RELOCATING+. = ${TEXT_START_ADDR};}
+  .text :
+  {
+    ${RELOCATING+__stext = .;}
+    *(.text)
+    ${RELOCATING+___datadata_relocs = .;}
+    ${RELOCATING+__etext = .;}
+    ${PAD_TEXT+${RELOCATING+. = ${DATA_ALIGNMENT};}}
+  }
+  ${RELOCATING+___text_size = SIZEOF(.text);}
+  ${RELOCATING+. = ${DATA_ALIGNMENT};}
+  .data :
+  {
+    ${RELOCATING+__sdata = .;}
+    ${CONSTRUCTING+CONSTRUCTORS}
+    *(.data)
+    ${RELOCATING+___a4_init = 0x7ffe;}
+    ${RELOCATING+__edata = .;}
+  }
+  .bss :
+  {
+    ${RELOCATING+__bss_start = .;}
+    *(.bss)
+    *(COMMON)
+    ${RELOCATING+__end = .;}
+  }
+  ${RELOCATING+___data_size = SIZEOF(.data) + SIZEOF(.bss);}
+  ${RELOCATING+___bss_size = 0x0;}
+}
+EOF
diff -ru --new-file a/ld/scripttempl/amigaos.sc b/ld/scripttempl/amigaos.sc
--- a/ld/scripttempl/amigaos.sc	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/scripttempl/amigaos.sc	2022-02-17 18:58:37.288223500 +0300
@@ -0,0 +1,501 @@
+#
+# Unusual variables checked by this code:
+#	NOP - four byte opcode for no-op (defaults to 0)
+#	NO_SMALL_DATA - no .sbss/.sbss2/.sdata/.sdata2 sections if not
+#		empty.
+#	SMALL_DATA_CTOR - .ctors contains small data.
+#	SMALL_DATA_DTOR - .dtors contains small data.
+#	DATA_ADDR - if end-of-text-plus-one-page isn't right for data start
+#	INITIAL_READONLY_SECTIONS - at start of text segment
+#	OTHER_READONLY_SECTIONS - other than .text .init .rodata ...
+#		(e.g., .PARISC.milli)
+#	OTHER_TEXT_SECTIONS - these get put in .text when relocating
+#	OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ...
+#		(e.g., .PARISC.global)
+#	OTHER_RELRO_SECTIONS - other than .data.rel.ro ...
+#		(e.g. PPC32 .fixup, .got[12])
+#	OTHER_BSS_SECTIONS - other than .bss .sbss ...
+#	ATTRS_SECTIONS - at the end
+#	OTHER_SECTIONS - at the end
+#	EXECUTABLE_SYMBOLS - symbols that must be defined for an
+#		executable (e.g., _DYNAMIC_LINK)
+#       TEXT_START_ADDR - the first byte of the text segment, after any
+#               headers.
+#       TEXT_BASE_ADDRESS - the first byte of the text segment.
+#	TEXT_START_SYMBOLS - symbols that appear at the start of the
+#		.text section.
+#	DATA_START_SYMBOLS - symbols that appear at the start of the
+#		.data section.
+#	DATA_END_SYMBOLS - symbols that appear at the end of the
+#		writeable data sections.
+#	OTHER_GOT_SYMBOLS - symbols defined just before .got.
+#	OTHER_GOT_SECTIONS - sections just after .got.
+#	OTHER_SDATA_SECTIONS - sections just after .sdata.
+#	OTHER_BSS_SYMBOLS - symbols that appear at the start of the
+#		.bss section besides __bss_start.
+#	DATA_PLT - .plt should be in data segment, not text segment.
+#	PLT_BEFORE_GOT - .plt just before .got when .plt is in data segement.
+#	BSS_PLT - .plt should be in bss segment
+#	TEXT_DYNAMIC - .dynamic in text segment, not data segment.
+#	EMBEDDED - whether this is for an embedded system.
+#	SHLIB_TEXT_START_ADDR - if set, add to SIZEOF_HEADERS to set
+#		start address of shared library.
+#	INPUT_FILES - INPUT command of files to always include
+#	WRITABLE_RODATA - if set, the .rodata section should be writable
+#	INIT_START, INIT_END -  statements just before and just after
+# 	combination of .init sections.
+#	FINI_START, FINI_END - statements just before and just after
+# 	combination of .fini sections.
+#	STACK_ADDR - start of a .stack section.
+#	OTHER_SYMBOLS - symbols to place right at the end of the script.
+#	ETEXT_NAME - name of a symbol for the end of the text section,
+#		normally etext.
+#	SEPARATE_GOTPLT - if set, .got.plt should be separate output section,
+#		so that .got can be in the RELRO area.  It should be set to
+#		the number of bytes in the beginning of .got.plt which can be
+#		in the RELRO area as well.
+#	USER_LABEL_PREFIX - prefix to add to user-visible symbols.
+#
+# When adding sections, do note that the names of some sections are used
+# when specifying the start address of the next.
+#
+
+#  Many sections come in three flavours.  There is the 'real' section,
+#  like ".data".  Then there are the per-procedure or per-variable
+#  sections, generated by -ffunction-sections and -fdata-sections in GCC,
+#  and useful for --gc-sections, which for a variable "foo" might be
+#  ".data.foo".  Then there are the linkonce sections, for which the linker
+#  eliminates duplicates, which are named like ".gnu.linkonce.d.foo".
+#  The exact correspondences are:
+#
+#  Section	Linkonce section
+#  .text	.gnu.linkonce.t.foo
+#  .rodata	.gnu.linkonce.r.foo
+#  .data	.gnu.linkonce.d.foo
+#  .bss		.gnu.linkonce.b.foo
+#  .sdata	.gnu.linkonce.s.foo
+#  .sbss	.gnu.linkonce.sb.foo
+#  .sdata2	.gnu.linkonce.s2.foo
+#  .sbss2	.gnu.linkonce.sb2.foo
+#  .debug_info	.gnu.linkonce.wi.foo
+#  .tdata	.gnu.linkonce.td.foo
+#  .tbss	.gnu.linkonce.tb.foo
+#  .lrodata	.gnu.linkonce.lr.foo
+#  .ldata	.gnu.linkonce.l.foo
+#  .lbss	.gnu.linkonce.lb.foo
+#
+#  Each of these can also have corresponding .rel.* and .rela.* sections.
+
+test -z "$ENTRY" && ENTRY=_start
+test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT}
+test -z "${LITTLE_OUTPUT_FORMAT}" && LITTLE_OUTPUT_FORMAT=${OUTPUT_FORMAT}
+if [ -z "$MACHINE" ]; then OUTPUT_ARCH=${ARCH}; else OUTPUT_ARCH=${ARCH}:${MACHINE}; fi
+test -z "${ELFSIZE}" && ELFSIZE=32
+test -z "${ALIGNMENT}" && ALIGNMENT="${ELFSIZE} / 8"
+test "$LD_FLAG" = "N" && DATA_ADDR=.
+test -z "${ETEXT_NAME}" && ETEXT_NAME=etext
+test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE=""
+test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE=""
+test -n "$RELRO_NOW" && unset SEPARATE_GOTPLT
+test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }"
+DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE})"
+#DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
+DATA_SEGMENT_RELRO_END=""
+DATA_SEGMENT_END=""
+if test -n "${COMMONPAGESIZE}"; then
+  DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})"
+  DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);"
+  DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT-0}, .);"
+fi
+if test -z "${INITIAL_READONLY_SECTIONS}${CREATE_SHLIB}"; then
+  INITIAL_READONLY_SECTIONS=".interp       ${RELOCATING-0} : { *(.interp) }"
+fi
+if test -z "$PLT"; then
+  PLT=".plt          ${RELOCATING-0} : { *(.plt) }"
+fi
+test -n "${DATA_PLT-${BSS_PLT-text}}" && TEXT_PLT=yes
+if test -z "$GOT"; then
+  if test -z "$SEPARATE_GOTPLT"; then
+    GOT=".got          ${RELOCATING-0} : { *(.got.plt) *(.got) }"
+  else
+    GOT=".got          ${RELOCATING-0} : { *(.got) }"
+    GOTPLT=".got.plt      ${RELOCATING-0} : { *(.got.plt) }"
+  fi
+fi
+DYNAMIC=".dynamic      ${RELOCATING-0} : { *(.dynamic) }"
+RODATA=".rodata       ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
+DATARELRO=".data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }"
+DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) }"
+if test -z "${NO_SMALL_DATA}"; then
+  SBSS=".sbss         ${RELOCATING-0} :
+  {
+    ${RELOCATING+${SBSS_START_SYMBOLS}}
+    ${CREATE_SHLIB+*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)}
+    *(.dynsbss)
+    *(.sbss${RELOCATING+ .sbss.* .gnu.linkonce.sb.*})
+    *(.scommon)
+    ${RELOCATING+${SBSS_END_SYMBOLS}}
+  }"
+  SBSS2=".sbss2        ${RELOCATING-0} : { *(.sbss2${RELOCATING+ .sbss2.* .gnu.linkonce.sb2.*}) }"
+  SDATA="/* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata        ${RELOCATING-0} : 
+  {
+    ${RELOCATING+${SDATA_START_SYMBOLS}}
+    ${CREATE_SHLIB+*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)}
+    *(.sdata${RELOCATING+ .sdata.* .gnu.linkonce.s.*})
+  }"
+  SDATA2=".sdata2       ${RELOCATING-0} :
+  {
+    ${RELOCATING+${SDATA2_START_SYMBOLS}}
+    *(.sdata2${RELOCATING+ .sdata2.* .gnu.linkonce.s2.*})
+  }"
+  REL_SDATA=".rel.sdata    ${RELOCATING-0} : { *(.rel.sdata${RELOCATING+ .rel.sdata.* .rel.gnu.linkonce.s.*}) }
+  .rela.sdata   ${RELOCATING-0} : { *(.rela.sdata${RELOCATING+ .rela.sdata.* .rela.gnu.linkonce.s.*}) }"
+  REL_SBSS=".rel.sbss     ${RELOCATING-0} : { *(.rel.sbss${RELOCATING+ .rel.sbss.* .rel.gnu.linkonce.sb.*}) }
+  .rela.sbss    ${RELOCATING-0} : { *(.rela.sbss${RELOCATING+ .rela.sbss.* .rela.gnu.linkonce.sb.*}) }"
+  REL_SDATA2=".rel.sdata2   ${RELOCATING-0} : { *(.rel.sdata2${RELOCATING+ .rel.sdata2.* .rel.gnu.linkonce.s2.*}) }
+  .rela.sdata2  ${RELOCATING-0} : { *(.rela.sdata2${RELOCATING+ .rela.sdata2.* .rela.gnu.linkonce.s2.*}) }"
+  REL_SBSS2=".rel.sbss2    ${RELOCATING-0} : { *(.rel.sbss2${RELOCATING+ .rel.sbss2.* .rel.gnu.linkonce.sb2.*}) }
+  .rela.sbss2   ${RELOCATING-0} : { *(.rela.sbss2${RELOCATING+ .rela.sbss2.* .rela.gnu.linkonce.sb2.*}) }"
+else
+  NO_SMALL_DATA=" "
+fi
+if test -z "${DATA_GOT}"; then
+  if test -n "${NO_SMALL_DATA}"; then
+    DATA_GOT=" "
+  fi
+fi
+if test -z "${SDATA_GOT}"; then
+  if test -z "${NO_SMALL_DATA}"; then
+    SDATA_GOT=" "
+  fi
+fi
+test -n "$SEPARATE_GOTPLT" && SEPARATE_GOTPLT=" "
+test "${LARGE_SECTIONS}" = "yes" && REL_LARGE="
+  .rel.ldata    ${RELOCATING-0} : { *(.rel.ldata${RELOCATING+ .rel.ldata.* .rel.gnu.linkonce.l.*}) }
+  .rela.ldata   ${RELOCATING-0} : { *(.rela.ldata${RELOCATING+ .rela.ldata.* .rela.gnu.linkonce.l.*}) }
+  .rel.lbss     ${RELOCATING-0} : { *(.rel.lbss${RELOCATING+ .rel.lbss.* .rel.gnu.linkonce.lb.*}) }
+  .rela.lbss    ${RELOCATING-0} : { *(.rela.lbss${RELOCATING+ .rela.lbss.* .rela.gnu.linkonce.lb.*}) }
+  .rel.lrodata  ${RELOCATING-0} : { *(.rel.lrodata${RELOCATING+ .rel.lrodata.* .rel.gnu.linkonce.lr.*}) }
+  .rela.lrodata ${RELOCATING-0} : { *(.rela.lrodata${RELOCATING+ .rela.lrodata.* .rela.gnu.linkonce.lr.*}) }"
+test "${LARGE_SECTIONS}" = "yes" && OTHER_BSS_SECTIONS="
+  ${OTHER_BSS_SECTIONS}
+  .lbss ${RELOCATING-0} :
+  {
+    *(.dynlbss)
+    *(.lbss${RELOCATING+ .lbss.* .gnu.linkonce.lb.*})
+    *(LARGE_COMMON)
+  }"
+test "${LARGE_SECTIONS}" = "yes" && LARGE_SECTIONS="
+  .lrodata ${RELOCATING-0} ${RELOCATING+ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))} :
+  {
+    *(.lrodata${RELOCATING+ .lrodata.* .gnu.linkonce.lr.*})
+  }
+  .ldata ${RELOCATING-0} ${RELOCATING+ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))} :
+  {
+    *(.ldata${RELOCATING+ .ldata.* .gnu.linkonce.l.*})
+    ${RELOCATING+. = ALIGN(. != 0 ? ${ALIGNMENT} : 1);}
+  }"
+CTOR=".ctors        ${CONSTRUCTING-0} :
+  {
+    ${CONSTRUCTING+${CTOR_START}}
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*crtbegin?.o(.ctors))
+
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o $OTHER_EXCLUDE_FILES) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+    ${CONSTRUCTING+${CTOR_END}}
+  }"
+DTOR=".dtors        ${CONSTRUCTING-0} :
+  {
+    ${CONSTRUCTING+${DTOR_START}}
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*crtbegin?.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o $OTHER_EXCLUDE_FILES) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+    ${CONSTRUCTING+${DTOR_END}}
+  }"
+STACK="  .stack        ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} :
+  {
+    ${RELOCATING+_stack = .;}
+    *(.stack)
+  }"
+
+# if this is for an embedded system, don't add SIZEOF_HEADERS.
+if [ -z "$EMBEDDED" ]; then
+   test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR} + SIZEOF_HEADERS"
+else
+   test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR}"
+fi
+
+cat <<EOF
+OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}",
+	      "${LITTLE_OUTPUT_FORMAT}")
+OUTPUT_ARCH(${OUTPUT_ARCH})
+ENTRY(${ENTRY})
+
+${RELOCATING+${LIB_SEARCH_DIRS}}
+${RELOCATING+${EXECUTABLE_SYMBOLS}}
+${RELOCATING+${INPUT_FILES}}
+${RELOCATING- /* For some reason, the Solaris linker makes bad executables
+  if gld -r is used and the intermediate file has sections starting
+  at non-zero addresses.  Could be a Solaris ld bug, could be a GNU ld
+  bug.  But for now assigning the zero vmas works.  */}
+
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+PROVIDE (__executable_start = ${TEXT_START_ADDR}); . = ${TEXT_BASE_ADDRESS};}}}
+  ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}}
+  ${CREATE_PIE+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}}
+  ${INITIAL_READONLY_SECTIONS}
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+
+  ${TEXT_DYNAMIC+${DYNAMIC}}
+  .hash         ${RELOCATING-0} : { *(.hash) }
+  .gnu.hash     ${RELOCATING-0} : { *(.gnu.hash) }
+  .dynsym       ${RELOCATING-0} : { *(.dynsym) }
+  .dynstr       ${RELOCATING-0} : { *(.dynstr) }
+  .gnu.version  ${RELOCATING-0} : { *(.gnu.version) }
+  .gnu.version_d ${RELOCATING-0}: { *(.gnu.version_d) }
+  .gnu.version_r ${RELOCATING-0}: { *(.gnu.version_r) }
+EOF
+
+if [ "x$COMBRELOC" = x ]; then
+  COMBRELOCCAT=cat
+else
+  COMBRELOCCAT="cat > $COMBRELOC"
+fi
+eval $COMBRELOCCAT <<EOF
+  .rel.init     ${RELOCATING-0} : { *(.rel.init) }
+  .rela.init    ${RELOCATING-0} : { *(.rela.init) }
+  .rel.text     ${RELOCATING-0} : { *(.rel.text${RELOCATING+ .rel.text.* .rel.gnu.linkonce.t.*}) }
+  .rela.text    ${RELOCATING-0} : { *(.rela.text${RELOCATING+ .rela.text.* .rela.gnu.linkonce.t.*}) }
+  .rel.fini     ${RELOCATING-0} : { *(.rel.fini) }
+  .rela.fini    ${RELOCATING-0} : { *(.rela.fini) }
+  .rel.rodata   ${RELOCATING-0} : { *(.rel.rodata${RELOCATING+ .rel.rodata.* .rel.gnu.linkonce.r.*}) }
+  .rela.rodata  ${RELOCATING-0} : { *(.rela.rodata${RELOCATING+ .rela.rodata.* .rela.gnu.linkonce.r.*}) }
+  ${OTHER_READONLY_RELOC_SECTIONS}
+  .rel.data.rel.ro ${RELOCATING-0} : { *(.rel.data.rel.ro${RELOCATING+* .rel.gnu.linkonce.d.rel.ro.*}) }
+  .rela.data.rel.ro ${RELOCATING-0} : { *(.rela.data.rel.ro${RELOCATING+* .rela.gnu.linkonce.d.rel.ro.*}) }
+  .rel.data     ${RELOCATING-0} : { *(.rel.data${RELOCATING+ .rel.data.* .rel.gnu.linkonce.d.*}) }
+  .rela.data    ${RELOCATING-0} : { *(.rela.data${RELOCATING+ .rela.data.* .rela.gnu.linkonce.d.*}) }
+  .rel.tdata	${RELOCATING-0} : { *(.rel.tdata${RELOCATING+ .rel.tdata.* .rel.gnu.linkonce.td.*}) }
+  .rela.tdata	${RELOCATING-0} : { *(.rela.tdata${RELOCATING+ .rela.tdata.* .rela.gnu.linkonce.td.*}) }
+  .rel.tbss	${RELOCATING-0} : { *(.rel.tbss${RELOCATING+ .rel.tbss.* .rel.gnu.linkonce.tb.*}) }
+  .rela.tbss	${RELOCATING-0} : { *(.rela.tbss${RELOCATING+ .rela.tbss.* .rela.gnu.linkonce.tb.*}) }
+  .rel.ctors    ${RELOCATING-0} : { *(.rel.ctors) }
+  .rela.ctors   ${RELOCATING-0} : { *(.rela.ctors) }
+  .rel.dtors    ${RELOCATING-0} : { *(.rel.dtors) }
+  .rela.dtors   ${RELOCATING-0} : { *(.rela.dtors) }
+  .rel.got      ${RELOCATING-0} : { *(.rel.got) }
+  .rela.got     ${RELOCATING-0} : { *(.rela.got) }
+  ${OTHER_GOT_RELOC_SECTIONS}
+  ${REL_SDATA}
+  ${REL_SBSS}
+  ${REL_SDATA2}
+  ${REL_SBSS2}
+  .rel.bss      ${RELOCATING-0} : { *(.rel.bss${RELOCATING+ .rel.bss.* .rel.gnu.linkonce.b.*}) }
+  .rela.bss     ${RELOCATING-0} : { *(.rela.bss${RELOCATING+ .rela.bss.* .rela.gnu.linkonce.b.*}) }
+  ${REL_LARGE}
+EOF
+
+if [ -n "$COMBRELOC" ]; then
+cat <<EOF
+  .rel.dyn      ${RELOCATING-0} :
+    {
+EOF
+sed -e '/^[ 	]*[{}][ 	]*$/d;/:[ 	]*$/d;/\.rela\./d;s/^.*: { *\(.*\)}$/      \1/' $COMBRELOC
+cat <<EOF
+    }
+  .rela.dyn     ${RELOCATING-0} :
+    {
+EOF
+sed -e '/^[ 	]*[{}][ 	]*$/d;/:[ 	]*$/d;/\.rel\./d;s/^.*: { *\(.*\)}/      \1/' $COMBRELOC
+cat <<EOF
+    }
+EOF
+fi
+
+cat <<EOF
+  .rel.plt      ${RELOCATING-0} : { *(.rel.plt) }
+  .rela.plt     ${RELOCATING-0} : { *(.rela.plt) }
+  ${OTHER_PLT_RELOC_SECTIONS}
+
+
+  .init         ${RELOCATING-0} : 
+  { 
+    ${RELOCATING+${INIT_START}}
+    KEEP (*(.init))
+    ${RELOCATING+${INIT_END}}
+  } =${NOP-0}
+
+  ${TINY_READONLY_SECTION}
+  .text         ${RELOCATING-0} :
+  {
+    ${RELOCATING+${TEXT_START_SYMBOLS}}
+    *(.text .stub${RELOCATING+ .text.* .gnu.linkonce.t.*})
+	KEEP (*(.text.*personality*))
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    ${RELOCATING+${OTHER_TEXT_SECTIONS}}
+  } =${NOP-0}
+  . = ALIGN(4096);
+  ${TEXT_PLT+${PLT}}
+  . = ALIGN(4096);
+  .fini         ${RELOCATING-0} :
+  {
+    ${RELOCATING+${FINI_START}}
+    KEEP (*(.fini))
+    ${RELOCATING+${FINI_END}}
+  } =${NOP-0}
+  ${RELOCATING+PROVIDE (__${ETEXT_NAME} = .);}
+  ${RELOCATING+PROVIDE (_${ETEXT_NAME} = .);}
+  ${RELOCATING+PROVIDE (${ETEXT_NAME} = .);}
+  ${WRITABLE_RODATA-${RODATA}}
+  .rodata1      ${RELOCATING-0} : { *(.rodata1) }
+  ${CREATE_SHLIB-${SDATA2}}
+  ${CREATE_SHLIB-${SBSS2}}
+  ${OTHER_READONLY_SECTIONS}
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  .eh_frame     ${RELOCATING-0} : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+  .gcc_except_table ${RELOCATING-0} : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+. = ${DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}}
+  ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}
+  ${CREATE_PIE+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}
+
+  /* Exception handling  */
+  .eh_frame     ${RELOCATING-0} : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+  .gcc_except_table ${RELOCATING-0} : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+
+  /* Thread Local Storage sections  */
+  .tdata	${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) }
+  .tbss		${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} }
+
+  .preinit_array   ${RELOCATING-0} :
+  {
+    ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__preinit_array_start = .);}}
+    KEEP (*(.preinit_array))
+    ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__preinit_array_end = .);}}
+  }
+  .init_array   ${RELOCATING-0} :
+  {
+     ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__init_array_start = .);}}
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+     ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__init_array_end = .);}}
+  }
+  .fini_array   ${RELOCATING-0} :
+  {
+    ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_start = .);}}
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_end = .);}}
+  }
+  ${SMALL_DATA_CTOR-${RELOCATING+${CTOR}}}
+  ${SMALL_DATA_DTOR-${RELOCATING+${DTOR}}}
+  .jcr          ${RELOCATING-0} : { KEEP (*(.jcr)) }
+
+  ${RELOCATING+${DATARELRO}}
+  ${OTHER_RELRO_SECTIONS}
+  ${TEXT_DYNAMIC-${DYNAMIC}}
+  ${DATA_GOT+${RELRO_NOW+${GOT}}}
+  ${DATA_GOT+${RELRO_NOW+${GOTPLT}}}
+  ${DATA_GOT+${RELRO_NOW-${SEPARATE_GOTPLT+${GOT}}}}
+  ${RELOCATING+${DATA_SEGMENT_RELRO_END}}
+  ${DATA_GOT+${RELRO_NOW-${SEPARATE_GOTPLT-${GOT}}}}
+  ${DATA_GOT+${RELRO_NOW-${GOTPLT}}}
+
+  ${DATA_PLT+${PLT_BEFORE_GOT-${PLT}}}
+
+  .data         ${RELOCATING-0} :
+  {
+    ${RELOCATING+${DATA_START_SYMBOLS}}
+    *(.data${RELOCATING+ .data.* .gnu.linkonce.d.*})
+    ${RELOCATING+KEEP (*(.gnu.linkonce.d.*personality*))}
+    ${CONSTRUCTING+SORT(CONSTRUCTORS)}
+  }
+  .data1        ${RELOCATING-0} : { *(.data1) }
+  ${WRITABLE_RODATA+${RODATA}}
+  ${OTHER_READWRITE_SECTIONS}
+  ${SMALL_DATA_CTOR+${RELOCATING+${CTOR}}}
+  ${SMALL_DATA_DTOR+${RELOCATING+${DTOR}}}
+  ${DATA_PLT+${PLT_BEFORE_GOT+${PLT}}}
+  ${SDATA_GOT+${RELOCATING+${OTHER_GOT_SYMBOLS}}}
+  ${SDATA_GOT+${GOT}}
+  ${SDATA_GOT+${OTHER_GOT_SECTIONS}}
+  ${SDATA}
+  ${OTHER_SDATA_SECTIONS}
+  ${RELOCATING+${DATA_END_SYMBOLS-${USER_LABEL_PREFIX}_edata = .; PROVIDE (${USER_LABEL_PREFIX}edata = .);}}
+  ${RELOCATING+__bss_start = .;}
+  ${RELOCATING+${OTHER_BSS_SYMBOLS}}
+  ${SBSS}
+  ${BSS_PLT+${PLT}}
+  .bss          ${RELOCATING-0} :
+  {
+   *(.dynbss)
+   *(.bss${RELOCATING+ .bss.* .gnu.linkonce.b.*})
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   ${RELOCATING+. = ALIGN(. != 0 ? ${ALIGNMENT} : 1);}
+  }
+  ${OTHER_BSS_SECTIONS}
+  ${RELOCATING+${OTHER_BSS_END_SYMBOLS}}
+  ${RELOCATING+. = ALIGN(${ALIGNMENT});}
+  ${LARGE_SECTIONS}
+  ${RELOCATING+. = ALIGN(${ALIGNMENT});}
+  ${RELOCATING+${OTHER_END_SYMBOLS}}
+  ${RELOCATING+${END_SYMBOLS-${USER_LABEL_PREFIX}_end = .; PROVIDE (${USER_LABEL_PREFIX}end = .);}}
+  ${RELOCATING+${DATA_SEGMENT_END}}
+
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+
+  .comment       0 : { *(.comment) }
+
+EOF
+
+. $srcdir/scripttempl/DWARF.sc
+
+cat <<EOF
+  ${TINY_DATA_SECTION}
+  ${TINY_BSS_SECTION}
+
+  ${STACK_ADDR+${STACK}}
+  ${ATTRS_SECTIONS}
+  ${OTHER_SECTIONS}
+  ${RELOCATING+${OTHER_SYMBOLS}}
+  ${RELOCATING+${DISCARDED}}
+}
+EOF
diff -ru --new-file a/ld/scripttempl/amithlon.sc b/ld/scripttempl/amithlon.sc
--- a/ld/scripttempl/amithlon.sc	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/scripttempl/amithlon.sc	2021-02-01 23:12:49.305904900 +0300
@@ -0,0 +1,412 @@
+#
+# Unusual variables checked by this code:
+#	NOP - four byte opcode for no-op (defaults to 0)
+#	NO_SMALL_DATA - no .sbss/.sbss2/.sdata/.sdata2 sections if not
+#		empty.
+#	DATA_ADDR - if end-of-text-plus-one-page isn't right for data start
+#	INITIAL_READONLY_SECTIONS - at start of text segment
+#	OTHER_READONLY_SECTIONS - other than .text .init .rodata ...
+#		(e.g., .PARISC.milli)
+#	OTHER_TEXT_SECTIONS - these get put in .text when relocating
+#	OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ...
+#		(e.g., .PARISC.global)
+#	OTHER_BSS_SECTIONS - other than .bss .sbss ...
+#	OTHER_SECTIONS - at the end
+#	EXECUTABLE_SYMBOLS - symbols that must be defined for an
+#		executable (e.g., _DYNAMIC_LINK)
+#	TEXT_START_SYMBOLS - symbols that appear at the start of the
+#		.text section.
+#	DATA_START_SYMBOLS - symbols that appear at the start of the
+#		.data section.
+#	OTHER_GOT_SYMBOLS - symbols defined just before .got.
+#	OTHER_GOT_SECTIONS - sections just after .got.
+#	OTHER_SDATA_SECTIONS - sections just after .sdata.
+#	OTHER_BSS_SYMBOLS - symbols that appear at the start of the
+#		.bss section besides __bss_start.
+#	DATA_PLT - .plt should be in data segment, not text segment.
+#	BSS_PLT - .plt should be in bss segment
+#	TEXT_DYNAMIC - .dynamic in text segment, not data segment.
+#	EMBEDDED - whether this is for an embedded system.
+#	SHLIB_TEXT_START_ADDR - if set, add to SIZEOF_HEADERS to set
+#		start address of shared library.
+#	INPUT_FILES - INPUT command of files to always include
+#	WRITABLE_RODATA - if set, the .rodata section should be writable
+#	INIT_START, INIT_END -  statements just before and just after
+# 	combination of .init sections.
+#	FINI_START, FINI_END - statements just before and just after
+# 	combination of .fini sections.
+#	STACK_ADDR - start of a .stack section.
+#	OTHER_END_SYMBOLS - symbols to place right at the end of the script.
+#
+# When adding sections, do note that the names of some sections are used
+# when specifying the start address of the next.
+#
+
+#  Many sections come in three flavours.  There is the 'real' section,
+#  like ".data".  Then there are the per-procedure or per-variable
+#  sections, generated by -ffunction-sections and -fdata-sections in GCC,
+#  and useful for --gc-sections, which for a variable "foo" might be
+#  ".data.foo".  Then there are the linkonce sections, for which the linker
+#  eliminates duplicates, which are named like ".gnu.linkonce.d.foo".
+#  The exact correspondences are:
+#
+#  Section	Linkonce section
+#  .text	.gnu.linkonce.t.foo
+#  .rodata	.gnu.linkonce.r.foo
+#  .data	.gnu.linkonce.d.foo
+#  .bss		.gnu.linkonce.b.foo
+#  .sdata	.gnu.linkonce.s.foo
+#  .sbss	.gnu.linkonce.sb.foo
+#  .sdata2	.gnu.linkonce.s2.foo
+#  .sbss2	.gnu.linkonce.sb2.foo
+#  .debug_info	.gnu.linkonce.wi.foo
+#  .tdata	.gnu.linkonce.td.foo
+#  .tbss	.gnu.linkonce.tb.foo
+#
+#  Each of these can also have corresponding .rel.* and .rela.* sections.
+
+test -z "$ENTRY" && ENTRY=_start
+test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT}
+test -z "${LITTLE_OUTPUT_FORMAT}" && LITTLE_OUTPUT_FORMAT=${OUTPUT_FORMAT}
+if [ -z "$MACHINE" ]; then OUTPUT_ARCH=${ARCH}; else OUTPUT_ARCH=${ARCH}:${MACHINE}; fi
+test -z "${ELFSIZE}" && ELFSIZE=32
+test -z "${ALIGNMENT}" && ALIGNMENT="${ELFSIZE} / 8"
+test "$LD_FLAG" = "N" && DATA_ADDR=.
+test -n "$CREATE_SHLIB" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE=""
+test -z "$CREATE_SHLIB" && test -n "$DATA_ADDR" && COMMONPAGESIZE=""
+#DATA_SEGMENT_ALIGN="ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))"
+DATA_SEGMENT_ALIGN="ALIGN(${MAXPAGESIZE}) + ${MAXPAGESIZE}"
+DATA_SEGMENT_END=""
+if test -n "${COMMONPAGESIZE}"; then
+  DATA_SEGMENT_ALIGN="DATA_SEGMENT_ALIGN(${MAXPAGESIZE}, ${COMMONPAGESIZE})"
+  DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);"
+fi
+INTERP=".interp       ${RELOCATING-0} : { *(.interp) }"
+PLT=".plt          ${RELOCATING-0} : { *(.plt) }"
+DYNAMIC=".dynamic      ${RELOCATING-0} : { *(.dynamic) }"
+RODATA=".rodata       ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
+if test -z "${NO_SMALL_DATA}"; then
+  SBSS=".sbss         ${RELOCATING-0} :
+  {
+    ${RELOCATING+PROVIDE (__sbss_start = .);}
+    ${RELOCATING+PROVIDE (___sbss_start = .);}
+    *(.dynsbss)
+    *(.sbss${RELOCATING+ .sbss.* .gnu.linkonce.sb.*})
+    *(.scommon)
+    ${RELOCATING+PROVIDE (__sbss_end = .);}
+    ${RELOCATING+PROVIDE (___sbss_end = .);}
+  }"
+  SBSS2=".sbss2        ${RELOCATING-0} : { *(.sbss2${RELOCATING+ .sbss2.* .gnu.linkonce.sb2.*}) }"
+  SDATA="/* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata        ${RELOCATING-0} :
+  {
+    ${RELOCATING+${SDATA_START_SYMBOLS}}
+    *(.sdata${RELOCATING+ .sdata.* .gnu.linkonce.s.*})
+  }"
+  SDATA2=".sdata2       ${RELOCATING-0} : { *(.sdata2${RELOCATING+ .sdata2.* .gnu.linkonce.s2.*}) }"
+  REL_SDATA=".rel.sdata    ${RELOCATING-0} : { *(.rel.sdata${RELOCATING+ .rel.sdata.* .rel.gnu.linkonce.s.*}) }
+  .rela.sdata   ${RELOCATING-0} : { *(.rela.sdata${RELOCATING+ .rela.sdata.* .rela.gnu.linkonce.s.*}) }"
+  REL_SBSS=".rel.sbss     ${RELOCATING-0} : { *(.rel.sbss${RELOCATING+ .rel.sbss.* .rel.gnu.linkonce.sb.*}) }
+  .rela.sbss    ${RELOCATING-0} : { *(.rela.sbss${RELOCATING+ .rela.sbss.* .rela.gnu.linkonce.sb.*}) }"
+  REL_SDATA2=".rel.sdata2   ${RELOCATING-0} : { *(.rel.sdata2${RELOCATING+ .rel.sdata2.* .rel.gnu.linkonce.s2.*}) }
+  .rela.sdata2  ${RELOCATING-0} : { *(.rela.sdata2${RELOCATING+ .rela.sdata2.* .rela.gnu.linkonce.s2.*}) }"
+  REL_SBSS2=".rel.sbss2    ${RELOCATING-0} : { *(.rel.sbss2${RELOCATING+ .rel.sbss2.* .rel.gnu.linkonce.sb2.*}) }
+  .rela.sbss2   ${RELOCATING-0} : { *(.rela.sbss2${RELOCATING+ .rela.sbss2.* .rela.gnu.linkonce.sb2.*}) }"
+fi
+CTOR=".ctors        ${CONSTRUCTING-0} :
+  {
+    ${CONSTRUCTING+${CTOR_START}}
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+
+    KEEP (*crtbegin.o(.ctors))
+
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+
+    KEEP (*(EXCLUDE_FILE (*crtend.o $OTHER_EXCLUDE_FILES) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+    ${CONSTRUCTING+${CTOR_END}}
+  }"
+DTOR=".dtors        ${CONSTRUCTING-0} :
+  {
+    ${CONSTRUCTING+${DTOR_START}}
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o $OTHER_EXCLUDE_FILES) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+    ${CONSTRUCTING+${DTOR_END}}
+  }"
+STACK="  .stack        ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} :
+  {
+    ${RELOCATING+_stack = .;}
+    *(.stack)
+  }"
+
+# if this is for an embedded system, don't add SIZEOF_HEADERS.
+if [ -z "$EMBEDDED" ]; then
+   test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR} + SIZEOF_HEADERS"
+else
+   test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR}"
+fi
+
+cat <<EOF
+OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}",
+	      "${LITTLE_OUTPUT_FORMAT}")
+OUTPUT_ARCH(${OUTPUT_ARCH})
+ENTRY(${ENTRY})
+
+${RELOCATING+${LIB_SEARCH_DIRS}}
+${RELOCATING+/* Do we need any of these for elf?
+   __DYNAMIC = 0; ${STACKZERO+${STACKZERO}} ${SHLIB_PATH+${SHLIB_PATH}}  */}
+${RELOCATING+${EXECUTABLE_SYMBOLS}}
+${RELOCATING+${INPUT_FILES}}
+${RELOCATING- /* For some reason, the Solaris linker makes bad executables
+  if gld -r is used and the intermediate file has sections starting
+  at non-zero addresses.  Could be a Solaris ld bug, could be a GNU ld
+  bug.  But for now assigning the zero vmas works.  */}
+
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  ${CREATE_SHLIB-${RELOCATING+. = ${TEXT_BASE_ADDRESS};}}
+  ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}}
+  ${CREATE_SHLIB-${INTERP}}
+  ${INITIAL_READONLY_SECTIONS}
+  ${TEXT_DYNAMIC+${DYNAMIC}}
+  .hash         ${RELOCATING-0} : { *(.hash) }
+  .dynsym       ${RELOCATING-0} : { *(.dynsym) }
+  .dynstr       ${RELOCATING-0} : { *(.dynstr) }
+  .gnu.version  ${RELOCATING-0} : { *(.gnu.version) }
+  .gnu.version_d ${RELOCATING-0}: { *(.gnu.version_d) }
+  .gnu.version_r ${RELOCATING-0}: { *(.gnu.version_r) }
+
+EOF
+if [ "x$COMBRELOC" = x ]; then
+  COMBRELOCCAT=cat
+else
+  COMBRELOCCAT="cat > $COMBRELOC"
+fi
+eval $COMBRELOCCAT <<EOF
+  .rel.init     ${RELOCATING-0} : { *(.rel.init) }
+  .rela.init    ${RELOCATING-0} : { *(.rela.init) }
+  .rel.text     ${RELOCATING-0} : { *(.rel.text${RELOCATING+ .rel.text.* .rel.gnu.linkonce.t.*}) }
+  .rela.text    ${RELOCATING-0} : { *(.rela.text${RELOCATING+ .rela.text.* .rela.gnu.linkonce.t.*}) }
+  .rel.fini     ${RELOCATING-0} : { *(.rel.fini) }
+  .rela.fini    ${RELOCATING-0} : { *(.rela.fini) }
+  .rel.rodata   ${RELOCATING-0} : { *(.rel.rodata${RELOCATING+ .rel.rodata.* .rel.gnu.linkonce.r.*}) }
+  .rela.rodata  ${RELOCATING-0} : { *(.rela.rodata${RELOCATING+ .rela.rodata.* .rela.gnu.linkonce.r.*}) }
+  ${OTHER_READONLY_RELOC_SECTIONS}
+  .rel.data     ${RELOCATING-0} : { *(.rel.data${RELOCATING+ .rel.data.* .rel.gnu.linkonce.d.*}) }
+  .rela.data    ${RELOCATING-0} : { *(.rela.data${RELOCATING+ .rela.data.* .rela.gnu.linkonce.d.*}) }
+  .rel.tdata	${RELOCATING-0} : { *(.rel.tdata${RELOCATING+ .rel.tdata.* .rel.gnu.linkonce.td.*}) }
+  .rela.tdata	${RELOCATING-0} : { *(.rela.tdata${RELOCATING+ .rela.tdata.* .rela.gnu.linkonce.td.*}) }
+  .rel.tbss	${RELOCATING-0} : { *(.rel.tbss${RELOCATING+ .rel.tbss.* .rel.gnu.linkonce.tb.*}) }
+  .rela.tbss	${RELOCATING-0} : { *(.rela.tbss${RELOCATING+ .rela.tbss.* .rela.gnu.linkonce.tb.*}) }
+  .rel.ctors    ${RELOCATING-0} : { *(.rel.ctors) }
+  .rela.ctors   ${RELOCATING-0} : { *(.rela.ctors) }
+  .rel.dtors    ${RELOCATING-0} : { *(.rel.dtors) }
+  .rela.dtors   ${RELOCATING-0} : { *(.rela.dtors) }
+  .rel.got      ${RELOCATING-0} : { *(.rel.got) }
+  .rela.got     ${RELOCATING-0} : { *(.rela.got) }
+  ${OTHER_GOT_RELOC_SECTIONS}
+  ${REL_SDATA}
+  ${REL_SBSS}
+  ${REL_SDATA2}
+  ${REL_SBSS2}
+  .rel.bss      ${RELOCATING-0} : { *(.rel.bss${RELOCATING+ .rel.bss.* .rel.gnu.linkonce.b.*}) }
+  .rela.bss     ${RELOCATING-0} : { *(.rela.bss${RELOCATING+ .rela.bss.* .rela.gnu.linkonce.b.*}) }
+EOF
+if [ -n "$COMBRELOC" ]; then
+cat <<EOF
+  .rel.dyn      ${RELOCATING-0} :
+    {
+EOF
+sed -e '/^[ 	]*[{}][ 	]*$/d;/:[ 	]*$/d;/\.rela\./d;s/^.*: { *\(.*\)}$/      \1/' $COMBRELOC
+cat <<EOF
+    }
+  .rela.dyn     ${RELOCATING-0} :
+    {
+EOF
+sed -e '/^[ 	]*[{}][ 	]*$/d;/:[ 	]*$/d;/\.rel\./d;s/^.*: { *\(.*\)}/      \1/' $COMBRELOC
+cat <<EOF
+    }
+EOF
+fi
+cat <<EOF
+  .rel.plt      ${RELOCATING-0} : { *(.rel.plt) }
+  .rela.plt     ${RELOCATING-0} : { *(.rela.plt) }
+  ${OTHER_PLT_RELOC_SECTIONS}
+
+  /* Force a new section by skipping a page */
+  . = ALIGN(${MAXPAGESIZE}) + ${MAXPAGESIZE};
+
+  .init         ${RELOCATING-0} : 
+  { 
+    ${RELOCATING+${INIT_START}}
+    KEEP (*(.init))
+    ${RELOCATING+${INIT_END}}
+  } =${NOP-0}
+
+  ${DATA_PLT-${BSS_PLT-${PLT}}}
+  .text         ${RELOCATING-0} :
+  {
+    ${RELOCATING+${TEXT_START_SYMBOLS}}
+    *(.text .stub${RELOCATING+ .text.* .gnu.linkonce.t.*})
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    ${RELOCATING+${OTHER_TEXT_SECTIONS}}
+  } =${NOP-0}
+  .fini         ${RELOCATING-0} :
+  {
+    ${RELOCATING+${FINI_START}}
+    KEEP (*(.fini))
+    ${RELOCATING+${FINI_END}}
+  } =${NOP-0}
+  ${RELOCATING+PROVIDE (__etext = .);}
+  ${RELOCATING+PROVIDE (_etext = .);}
+  ${RELOCATING+PROVIDE (etext = .);}
+
+  /* Force a new section by skipping a page */
+  . = ALIGN(${MAXPAGESIZE}) + ${MAXPAGESIZE};
+
+  ${WRITABLE_RODATA-${RODATA}}
+  .rodata1      ${RELOCATING-0} : { *(.rodata1) }
+  ${CREATE_SHLIB-${SDATA2}}
+  ${CREATE_SHLIB-${SBSS2}}
+  ${OTHER_READONLY_SECTIONS}
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  ${CREATE_SHLIB-${RELOCATING+. = ${DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}
+  ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}
+
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  ${RELOCATING+. = ALIGN(${ALIGNMENT});}
+  ${RELOCATING+${CREATE_SHLIB-PROVIDE (__preinit_array_start = .);}}
+  .preinit_array   ${RELOCATING-0} : { *(.preinit_array) }
+  ${RELOCATING+${CREATE_SHLIB-PROVIDE (__preinit_array_end = .);}}
+
+  ${RELOCATING+${CREATE_SHLIB-PROVIDE (__init_array_start = .);}}
+  .init_array   ${RELOCATING-0} : { *(.init_array) }
+  ${RELOCATING+${CREATE_SHLIB-PROVIDE (__init_array_end = .);}}
+
+  ${RELOCATING+${CREATE_SHLIB-PROVIDE (__fini_array_start = .);}}
+  .fini_array   ${RELOCATING-0} : { *(.fini_array) }
+  ${RELOCATING+${CREATE_SHLIB-PROVIDE (__fini_array_end = .);}}
+
+  .data         ${RELOCATING-0} :
+  {
+    ${RELOCATING+${DATA_START_SYMBOLS}}
+    *(.data${RELOCATING+ .data.* .gnu.linkonce.d.*})
+    ${CONSTRUCTING+SORT(CONSTRUCTORS)}
+  }
+  .data1        ${RELOCATING-0} : { *(.data1) }
+  .tdata	${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) }
+  .tbss		${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} }
+  .eh_frame     ${RELOCATING-0} : { KEEP (*(.eh_frame)) }
+  .gcc_except_table ${RELOCATING-0} : { *(.gcc_except_table) }
+  ${WRITABLE_RODATA+${RODATA}}
+  ${OTHER_READWRITE_SECTIONS}
+  ${TEXT_DYNAMIC-${DYNAMIC}}
+  ${RELOCATING+${CTOR}}
+  ${RELOCATING+${DTOR}}
+  .jcr          ${RELOCATING-0} : { KEEP (*(.jcr)) }
+  ${DATA_PLT+${PLT}}
+  ${RELOCATING+${OTHER_GOT_SYMBOLS}}
+  .got          ${RELOCATING-0} : { *(.got.plt) *(.got) }
+  ${OTHER_GOT_SECTIONS}
+  ${CREATE_SHLIB+${SDATA2}}
+  ${CREATE_SHLIB+${SBSS2}}
+  ${SDATA}
+  ${OTHER_SDATA_SECTIONS}
+  ${RELOCATING+_edata = .;}
+  ${RELOCATING+PROVIDE (edata = .);}
+  ${RELOCATING+__bss_start = .;}
+  ${RELOCATING+${OTHER_BSS_SYMBOLS}}
+  ${SBSS}
+  ${BSS_PLT+${PLT}}
+  .bss          ${RELOCATING-0} :
+  {
+   *(.dynbss)
+   *(.bss${RELOCATING+ .bss.* .gnu.linkonce.b.*})
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   ${RELOCATING+. = ALIGN(${ALIGNMENT});}
+  }
+  ${OTHER_BSS_SECTIONS}
+  ${RELOCATING+. = ALIGN(${ALIGNMENT});}
+  ${RELOCATING+_end = .;}
+  ${RELOCATING+${OTHER_BSS_END_SYMBOLS}}
+  ${RELOCATING+PROVIDE (end = .);}
+  ${RELOCATING+${DATA_SEGMENT_END}}
+
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+
+  .comment       0 : { *(.comment) }
+
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+
+  ${STACK_ADDR+${STACK}}
+  ${OTHER_SECTIONS}
+  ${RELOCATING+${OTHER_END_SYMBOLS}}
+
+  /* Libnix sections */
+  .libnix___INIT_LIST__ ${RELOCATING-0} : { *(.libnix___INIT_LIST__) }
+  .libnix___EXIT_LIST__ ${RELOCATING-0} : { *(.libnix___EXIT_LIST__) }
+  .libnix___LIB_LIST__  ${RELOCATING-0} : { *(.libnix___LIB_LIST__)  }
+}
+EOF
diff -ru --new-file a/ld/scripttempl/DWARF.sc b/ld/scripttempl/DWARF.sc
--- a/ld/scripttempl/DWARF.sc	2013-11-04 19:33:39.000000000 +0400
+++ b/ld/scripttempl/DWARF.sc	2022-02-17 16:40:51.402208400 +0300
@@ -34,6 +34,4 @@
   .debug_pubtypes 0 : { *(.debug_pubtypes) }
   .debug_ranges   0 : { *(.debug_ranges) }
 
-  /* DWARF Extension.  */
-  .debug_macro    0 : { *(.debug_macro) }
 EOF
diff -ru --new-file a/ld/scripttempl/morphos.sc b/ld/scripttempl/morphos.sc
--- a/ld/scripttempl/morphos.sc	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/scripttempl/morphos.sc	2021-02-01 23:12:49.306903200 +0300
@@ -0,0 +1,232 @@
+#
+# Unusual variables checked by this code:
+#	NOP - two byte opcode for no-op (defaults to 0)
+#	DATA_ADDR - if end-of-text-plus-one-page isn't right for data start
+#	OTHER_READONLY_SECTIONS - other than .text .init .rodata ...
+#		(e.g., .PARISC.milli)
+#	OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ...
+#		(e.g., .PARISC.global)
+#	OTHER_SECTIONS - at the end
+#	EXECUTABLE_SYMBOLS - symbols that must be defined for an
+#		executable (e.g., _DYNAMIC_LINK)
+#	TEXT_START_SYMBOLS - symbols that appear at the start of the
+#		.text section.
+#	DATA_START_SYMBOLS - symbols that appear at the start of the
+#		.data section.
+#	OTHER_BSS_SYMBOLS - symbols that appear at the start of the
+#		.bss section besides __bss_start.
+#
+# When adding sections, do note that the names of some sections are used
+# when specifying the start address of the next.
+#
+test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT}
+test -z "${LITTLE_OUTPUT_FORMAT}" && LITTLE_OUTPUT_FORMAT=${OUTPUT_FORMAT}
+test "$LD_FLAG" = "N" && DATA_ADDR=.
+SBSS2=".sbss2 ${RELOCATING-0} : { *(.sbss2) }"
+SDATA2=".sdata2 ${RELOCATING-0} : { *(.sdata2) }"
+INTERP=".interp ${RELOCATING-0} : { *(.interp) }"
+PLT=".plt ${RELOCATING-0} : { *(.plt) }"
+cat <<EOF
+OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}",
+	      "${LITTLE_OUTPUT_FORMAT}")
+OUTPUT_ARCH(${ARCH})
+
+${RELOCATING+${LIB_SEARCH_DIRS}}
+${RELOCATING+/* Do we need any of these for elf?
+   __DYNAMIC = 0; ${STACKZERO+${STACKZERO}} ${SHLIB_PATH+${SHLIB_PATH}}  */}
+${RELOCATING+${EXECUTABLE_SYMBOLS}}
+${RELOCATING- /* For some reason, the Solaris linker makes bad executables
+  if gld -r is used and the intermediate file has sections starting
+  at non-zero addresses.  Could be a Solaris ld bug, could be a GNU ld
+  bug.  But for now assigning the zero vmas works.  */}
+
+${RELOCATING+PROVIDE (__stack = 0);}
+PROVIDE (__machtype = 0x1);
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  ${CREATE_SHLIB-${RELOCATING+. = ${TEXT_START_ADDR} + SIZEOF_HEADERS;}}
+  ${CREATE_SHLIB+${RELOCATING+. = SIZEOF_HEADERS;}}
+  ${CREATE_SHLIB-${INTERP}}
+  .hash		${RELOCATING-0} : { *(.hash)		}
+  .dynsym	${RELOCATING-0} : { *(.dynsym)		}
+  .dynstr	${RELOCATING-0} : { *(.dynstr)		}
+  .gnu.version ${RELOCATING-0} : { *(.gnu.version)      }
+  .gnu.version_d ${RELOCATING-0} : { *(.gnu.version_d)  }
+  .gnu.version_r ${RELOCATING-0} : { *(.gnu.version_r)  }
+  .rela.text   ${RELOCATING-0} :
+    { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+  .rela.data   ${RELOCATING-0} :
+    { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+  .rela.rodata ${RELOCATING-0} :
+    { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+  .rela.got	${RELOCATING-0} : { *(.rela.got)	}
+  .rela.got1	${RELOCATING-0} : { *(.rela.got1)	}
+  .rela.got2	${RELOCATING-0} : { *(.rela.got2)	}
+  .rela.ctors	${RELOCATING-0} : { *(.rela.ctors)	}
+  .rela.dtors	${RELOCATING-0} : { *(.rela.dtors)	}
+  .rela.init	${RELOCATING-0} : { *(.rela.init)	}
+  .rela.fini	${RELOCATING-0} : { *(.rela.fini)	}
+  .rela.bss	${RELOCATING-0} : { *(.rela.bss)	}
+  .rela.plt	${RELOCATING-0} : { *(.rela.plt)	}
+  .rela.sdata	${RELOCATING-0} : { *(.rela.sdata)	}
+  .rela.sbss	${RELOCATING-0} : { *(.rela.sbss)	}
+  .rela.sdata2	${RELOCATING-0} : { *(.rela.sdata2)	}
+  .rela.sbss2	${RELOCATING-0} : { *(.rela.sbss2)	}
+  .text    ${RELOCATING-0} :
+  {
+    PROVIDE (__text_start = .);
+    ${RELOCATING+${TEXT_START_SYMBOLS}}
+    *(.text)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+    PROVIDE (__text_end = .);
+  } =${NOP-0}
+  PROVIDE (__text_size = SIZEOF(.text));
+  .init		${RELOCATING-0} : { *(.init)		} =${NOP-0}
+  .fini		${RELOCATING-0} : { *(.fini)		} =${NOP-0}
+  .rodata	${RELOCATING-0} : { *(.rodata) *(.gnu.linkonce.r*) }
+  .rodata1	${RELOCATING-0} : { *(.rodata1) }
+  ${RELOCATING+_etext = .;}
+  ${RELOCATING+PROVIDE (etext = .);}
+  ${CREATE_SHLIB-${SDATA2}}
+  ${CREATE_SHLIB-${SBSS2}}
+  ${RELOCATING+${OTHER_READONLY_SECTIONS}}
+
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  It would
+     be more correct to do this:
+       ${RELOCATING+. = ${DATA_ADDR-ALIGN(${MAXPAGESIZE}) + (ALIGN(8) & (${MAXPAGESIZE} - 1))};}
+     The current expression does not correctly handle the case of a
+     text segment ending precisely at the end of a page; it causes the
+     data segment to skip a page.  The above expression does not have
+     this problem, but it will currently (2/95) cause BFD to allocate
+     a single segment, combining both text and data, for this case.
+     This will prevent the text segment from being shared among
+     multiple executions of the program; I think that is more
+     important than losing a page of the virtual address space (note
+     that no actual memory is lost; the page which is skipped can not
+     be referenced).  */
+  ${RELOCATING+. = ${DATA_ADDR- ALIGN(8) + ${MAXPAGESIZE}};}
+
+  .data  ${RELOCATING-0} :
+  {
+    PROVIDE (__data_start = .);
+    ${RELOCATING+${DATA_START_SYMBOLS}}
+    *(.data)
+    *(.gnu.linkonce.d*)
+    ${CONSTRUCTING+CONSTRUCTORS}
+    PROVIDE (__data_end = .);
+  }
+  PROVIDE (__data_size = SIZEOF(.data));
+  .data1 ${RELOCATING-0} : { *(.data1) }
+  ${RELOCATING+${OTHER_READWRITE_SECTIONS}}
+
+  .got1		${RELOCATING-0} : { *(.got1) }
+  .dynamic	${RELOCATING-0} : { *(.dynamic) }
+
+  /* Put .ctors and .dtors next to the .got2 section, so that the pointers
+     get relocated with -mrelocatable. Also put in the .fixup pointers.
+     The current compiler no longer needs this, but keep it around for 2.7.2  */
+
+		${RELOCATING+PROVIDE (_GOT2_START_ = .);}
+  .got2		${RELOCATING-0} :  { *(.got2) }
+
+		${RELOCATING+PROVIDE (__CTOR_LIST__ = .);}
+  .ctors	${RELOCATING-0} : { *(.ctors) }
+		${RELOCATING+PROVIDE (__CTOR_END__ = .);}
+
+		${RELOCATING+PROVIDE (__DTOR_LIST__ = .);}
+  .dtors	${RELOCATING-0} : { *(.dtors) }
+		${RELOCATING+PROVIDE (__DTOR_END__ = .);}
+
+		${RELOCATING+PROVIDE (_FIXUP_START_ = .);}
+  .fixup	${RELOCATING-0} : { *(.fixup) }
+		${RELOCATING+PROVIDE (_FIXUP_END_ = .);}
+		${RELOCATING+PROVIDE (_GOT2_END_ = .);}
+
+		${RELOCATING+PROVIDE (_GOT_START_ = .);}
+  .got		${RELOCATING-0} : { *(.got) }
+  .got.plt	${RELOCATING-0} : { *(.got.plt) }
+  ${CREATE_SHLIB+${SDATA2}}
+  ${CREATE_SHLIB+${SBSS2}}
+		${RELOCATING+PROVIDE (_GOT_END_ = .);}
+
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata	${RELOCATING-0} :
+  {
+    PROVIDE (__sdata_start = .);
+    *(.sdata)
+    PROVIDE (__r13_init = 0x8000);
+    PROVIDE (__sdata_end = .);
+  }
+  PROVIDE (__sdata_size = SIZEOF(.sdata));
+  ${RELOCATING+_edata  =  .;}
+  ${RELOCATING+PROVIDE (edata = .);}
+  .sbss    ${RELOCATING-0} :
+  {
+    PROVIDE (__sbss_start = .);
+    *(.sbss)
+    *(.scommon)
+    *(.dynsbss)
+    PROVIDE (__sbss_end = .);
+  }
+  PROVIDE (__sbss_size = SIZEOF(.sbss));
+  ${PLT}
+  .bss     ${RELOCATING-0} :
+  {
+    PROVIDE (__bss_start = .);
+    ${RELOCATING+${OTHER_BSS_SYMBOLS}}
+    ${RELOCATING+PROVIDE (__bss_start = .);}
+    *(.dynbss)
+    *(.bss)
+    *(COMMON)
+    PROVIDE (__bss_end = .);
+  }
+  PROVIDE (__bss_size = SIZEOF(.bss));
+  ${RELOCATING+_end = . ;}
+  ${RELOCATING+PROVIDE (end = .);}
+
+  /* These are needed for ELF backends which have not yet been
+     converted to the new style linker.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+
+  /* These must appear regardless of ${RELOCATING}.  */
+  ${OTHER_SECTIONS}
+}
+EOF
diff -ru --new-file a/ld/scripttempl/morphos_baserel.sc b/ld/scripttempl/morphos_baserel.sc
--- a/ld/scripttempl/morphos_baserel.sc	1970-01-01 03:00:00.000000000 +0300
+++ b/ld/scripttempl/morphos_baserel.sc	2021-02-01 23:12:49.307909500 +0300
@@ -0,0 +1,199 @@
+#
+# Unusual variables checked by this code:
+#	NOP - two byte opcode for no-op (defaults to 0)
+#	DATA_ADDR - if end-of-text-plus-one-page isn't right for data start
+#	OTHER_READONLY_SECTIONS - other than .text .init .rodata ...
+#		(e.g., .PARISC.milli)
+#	OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ...
+#		(e.g., .PARISC.global)
+#	OTHER_SECTIONS - at the end
+#	EXECUTABLE_SYMBOLS - symbols that must be defined for an
+#		executable (e.g., _DYNAMIC_LINK)
+#	TEXT_START_SYMBOLS - symbols that appear at the start of the
+#		.text section.
+#	DATA_START_SYMBOLS - symbols that appear at the start of the
+#		.data section.
+#	OTHER_BSS_SYMBOLS - symbols that appear at the start of the
+#		.bss section besides __bss_start.
+#
+# When adding sections, do note that the names of some sections are used
+# when specifying the start address of the next.
+#
+test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT}
+test -z "${LITTLE_OUTPUT_FORMAT}" && LITTLE_OUTPUT_FORMAT=${OUTPUT_FORMAT}
+test "$LD_FLAG" = "N" && DATA_ADDR=.
+SBSS2=".sbss2 ${RELOCATING-0} : { *(.sbss2) }"
+SDATA2=".sdata2 ${RELOCATING-0} : { *(.sdata2) }"
+INTERP=".interp ${RELOCATING-0} : { *(.interp) }"
+PLT=".plt ${RELOCATING-0} : { *(.plt) }"
+cat <<EOF
+OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}",
+	      "${LITTLE_OUTPUT_FORMAT}")
+OUTPUT_ARCH(${ARCH})
+
+${RELOCATING+${LIB_SEARCH_DIRS}}
+${RELOCATING+/* Do we need any of these for elf?
+   __DYNAMIC = 0; ${STACKZERO+${STACKZERO}} ${SHLIB_PATH+${SHLIB_PATH}}  */}
+${RELOCATING+${EXECUTABLE_SYMBOLS}}
+${RELOCATING- /* For some reason, the Solaris linker makes bad executables
+  if gld -r is used and the intermediate file has sections starting
+  at non-zero addresses.  Could be a Solaris ld bug, could be a GNU ld
+  bug.  But for now assigning the zero vmas works.  */}
+
+${RELOCATING+PROVIDE (__stack = 0);}
+PROVIDE (__machtype = 0x1);
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  ${CREATE_SHLIB-${RELOCATING+. = ${TEXT_START_ADDR} + SIZEOF_HEADERS;}}
+  ${CREATE_SHLIB+${RELOCATING+. = SIZEOF_HEADERS;}}
+  ${CREATE_SHLIB-${INTERP}}
+  .hash		${RELOCATING-0} : { *(.hash)		}
+  .dynsym	${RELOCATING-0} : { *(.dynsym)		}
+  .dynstr	${RELOCATING-0} : { *(.dynstr)		}
+  .gnu.version ${RELOCATING-0} : { *(.gnu.version)      }
+  .gnu.version_d ${RELOCATING-0} : { *(.gnu.version_d)  }
+  .gnu.version_r ${RELOCATING-0} : { *(.gnu.version_r)  }
+  .rela.text   ${RELOCATING-0} :
+    { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+  .rela.got	${RELOCATING-0} : { *(.rela.got)	}
+  .rela.got1	${RELOCATING-0} : { *(.rela.got1)	}
+  .rela.got2	${RELOCATING-0} : { *(.rela.got2)	}
+  .rela.ctors	${RELOCATING-0} : { *(.rela.ctors)	}
+  .rela.dtors	${RELOCATING-0} : { *(.rela.dtors)	}
+  .rela.init	${RELOCATING-0} : { *(.rela.init)	}
+  .rela.fini	${RELOCATING-0} : { *(.rela.fini)	}
+  .rela.plt	${RELOCATING-0} : { *(.rela.plt)	}
+  .rela.rodata  ${RELOCATING-0} :
+    { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+  .rela.sdata	${RELOCATING-0} :
+  {
+    *(.rela.data)
+    *(.rela.gnu.linkonce.d*)
+    *(.rela.sdata)
+  }
+  .rela.sbss	${RELOCATING-0} :
+  {
+    *(.rela.sbss)
+    *(.rela.bss)
+  }
+  .rela.sdata2	${RELOCATING-0} : { *(.rela.sdata2)	}
+  .rela.sbss2	${RELOCATING-0} : { *(.rela.sbss2)	}
+  .text    ${RELOCATING-0} :
+  {
+    PROVIDE (__text_start = .);
+    ${RELOCATING+${TEXT_START_SYMBOLS}}
+    *(.text)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+    PROVIDE (__text_end = .);
+  } =${NOP-0}
+  PROVIDE (__text_size = SIZEOF(.text));
+  .init		${RELOCATING-0} : { *(.init)		} =${NOP-0}
+  .fini		${RELOCATING-0} : { *(.fini)		} =${NOP-0}
+  ${RELOCATING+_etext = .;}
+  ${RELOCATING+PROVIDE (etext = .);}
+  ${CREATE_SHLIB-${SDATA2}}
+  ${CREATE_SHLIB-${SBSS2}}
+  ${RELOCATING+${OTHER_READONLY_SECTIONS}}
+
+  .got1		${RELOCATING-0} : { *(.got1) }
+  .dynamic	${RELOCATING-0} : { *(.dynamic) }
+
+  /* Put .ctors and .dtors next to the .got2 section, so that the pointers
+     get relocated with -mrelocatable. Also put in the .fixup pointers.
+     The current compiler no longer needs this, but keep it around for 2.7.2  */
+
+		${RELOCATING+PROVIDE (_GOT2_START_ = .);}
+  .got2		${RELOCATING-0} :  { *(.got2) }
+
+		${RELOCATING+PROVIDE (__CTOR_LIST__ = .);}
+  .ctors	${RELOCATING-0} : { *(.ctors) }
+		${RELOCATING+PROVIDE (__CTOR_END__ = .);}
+
+		${RELOCATING+PROVIDE (__DTOR_LIST__ = .);}
+  .dtors	${RELOCATING-0} : { *(.dtors) }
+		${RELOCATING+PROVIDE (__DTOR_END__ = .);}
+
+		${RELOCATING+PROVIDE (_FIXUP_START_ = .);}
+  .fixup	${RELOCATING-0} : { *(.fixup) }
+		${RELOCATING+PROVIDE (_FIXUP_END_ = .);}
+		${RELOCATING+PROVIDE (_GOT2_END_ = .);}
+
+		${RELOCATING+PROVIDE (_GOT_START_ = .);}
+  .got		${RELOCATING-0} : { *(.got) }
+  .got.plt	${RELOCATING-0} : { *(.got.plt) }
+  ${CREATE_SHLIB+${SDATA2}}
+  ${CREATE_SHLIB+${SBSS2}}
+		${RELOCATING+PROVIDE (_GOT_END_ = .);}
+  .rodata	${RELOCATING-0} : { *(.rodata) }
+ /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata	${RELOCATING-0} : 
+  { 
+    /*PROVIDE (__sdata_start = .);*/
+    __sdata_start = .;
+    *(.data)
+    *(.data1)
+    __small_start = .;	
+    *(.sdata) 
+    PROVIDE (__r13_init = /*__small_start*/ __sdata_start + 0x8000);
+    PROVIDE (__sdata_end = .);
+  }
+  PROVIDE (__sdata_size = SIZEOF(.sdata));
+  ${RELOCATING+_edata  =  .;}
+  ${RELOCATING+PROVIDE (edata = .);}
+  .sbss    ${RELOCATING-0} :
+  {
+    PROVIDE (__sbss_start = .);
+    *(.sbss)
+    *(.scommon)
+    *(.dynsbss)
+    *(.bss)
+    *(COMMON)
+    PROVIDE (__sbss_end = .);
+  }
+  PROVIDE (__sbss_size = SIZEOF(.sbss));
+
+  /* These are needed for ELF backends which have not yet been
+     converted to the new style linker.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+
+  /* These must appear regardless of ${RELOCATING}.  */
+  ${OTHER_SECTIONS}
+}
+EOF
diff -ru --new-file a/libiberty/config/mh-amigaos b/libiberty/config/mh-amigaos
--- a/libiberty/config/mh-amigaos	1970-01-01 03:00:00.000000000 +0300
+++ b/libiberty/config/mh-amigaos	2021-02-01 23:12:49.309912100 +0300
@@ -0,0 +1,12 @@
+# Host makefile fragment for Commodore Amiga running AmigaOS.
+
+# We don't actually use libmmalloc.a, since there is no sbrk(),
+# but this allows us to compile it (and then ignore it).
+MMALLOC=
+MMALLOC_DISABLE = -DNO_MMALLOC
+
+# There is no standard system compiler.  Assume using GNU C.
+#CC = gcc
+
+# Compile for automatic stack extension.
+#HDEFINES = -mstackextend
diff -ru --new-file a/libiberty/config/mh-morphos b/libiberty/config/mh-morphos
--- a/libiberty/config/mh-morphos	1970-01-01 03:00:00.000000000 +0300
+++ b/libiberty/config/mh-morphos	2021-02-01 23:12:49.311773200 +0300
@@ -0,0 +1,12 @@
+# Host makefile fragment for Commodore Amiga running AmigaOS.
+
+# We don't actually use libmmalloc.a, since there is no sbrk(),
+# but this allows us to compile it (and then ignore it).
+MMALLOC=
+MMALLOC_DISABLE = -DNO_MMALLOC
+
+# There is no standard system compiler.  Assume using GNU C.
+CC = gcc
+
+# Compile for automatic stack extension.
+HDEFINES =
diff -ru --new-file a/libiberty/lrealpath.c b/libiberty/lrealpath.c
--- a/libiberty/lrealpath.c	2013-11-04 19:33:40.000000000 +0400
+++ b/libiberty/lrealpath.c	2022-02-17 14:27:27.615504600 +0300
@@ -72,6 +72,12 @@
 # endif
 #endif
 
+/* OS4 does not have _PC_PATH_MAX so we use the
+   REALPATH_LIMIT method only */
+#if defined(__amigaos4__)
+#undef HAVE_REALPATH
+#endif
+
 char *
 lrealpath (const char *filename)
 {
diff -ru --new-file a/opcodes/m68k-dis.c b/opcodes/m68k-dis.c
--- a/opcodes/m68k-dis.c	2013-11-04 19:33:40.000000000 +0400
+++ b/opcodes/m68k-dis.c	2022-02-17 14:28:14.127212900 +0300
@@ -39,7 +39,7 @@
 static char *const reg_names[] =
 {
   "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
-  "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp",
+  "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp",
   "%ps", "%pc"
 };
 
