summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Young <chris@unsatisfactorysoftware.co.uk>2016-02-28 18:22:46 +0000
committerChris Young <chris@unsatisfactorysoftware.co.uk>2016-02-28 18:22:46 +0000
commit3dbd91ed0c3a25ea16c2f8d3c38dc5dca140226b (patch)
tree2ef03b96e81ce208fd56f1ea801b1d9863c2fd5b
parentc7999c6fe1025b1a7fdf7aa935acaa0639f20700 (diff)
parent49683e291055884ba0f6fc920be3ad21b21ff2ff (diff)
downloadtoolchains-3dbd91ed0c3a25ea16c2f8d3c38dc5dca140226b.tar.gz
toolchains-3dbd91ed0c3a25ea16c2f8d3c38dc5dca140226b.tar.bz2
Merge branch 'chris/gcc-530'
Update ppc-amigaos gcc to v5.3.0
-rw-r--r--ppc-amigaos/Makefile33
-rw-r--r--ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p26193
-rw-r--r--ppc-amigaos/recipes/patches/binutils/0002-Fixed-errors-occuring-with-more-recent-versions-of-t.p436
-rw-r--r--ppc-amigaos/recipes/patches/binutils/0003-Disabled-some-stuff-such-that-68k-vtarget-builds-aga.p110
-rw-r--r--ppc-amigaos/recipes/patches/binutils/0004-Print-symbol-name-when-an-unexpected-type-was-encoun.p31
-rw-r--r--ppc-amigaos/recipes/patches/binutils/0005-Bind-in-the-ld-unwind-options.p27
-rw-r--r--ppc-amigaos/recipes/patches/binutils/0006-Introduced-strip-unneeded-rel-relocs.p128
-rw-r--r--ppc-amigaos/recipes/patches/binutils/0007-Keep-symbols-for-stripped-sections.-This-is-importan.p42
-rw-r--r--ppc-amigaos/recipes/patches/binutils/missing-files.p13021
-rw-r--r--ppc-amigaos/recipes/patches/binutils/remove_unused.p406
-rw-r--r--ppc-amigaos/recipes/patches/gcc/0001-Changes-for-AmigaOS-version-of-gcc.p5166
-rw-r--r--ppc-amigaos/recipes/patches/gcc/0002-Added-new-function-attribute-lineartags-and-pragma-a.p376
-rw-r--r--ppc-amigaos/recipes/patches/gcc/0003-Disable-.machine-directive-generation.p49
-rw-r--r--ppc-amigaos/recipes/patches/gcc/0004-The-default-link-mode-is-static-for-AmigaOS.p51
-rw-r--r--ppc-amigaos/recipes/patches/gcc/0005-Disable-the-usage-of-dev-urandom-when-compiling-for-.p73
-rw-r--r--ppc-amigaos/recipes/patches/gcc/0006-Expand-arg-zero-on-AmigaOS-using-the-PROGDIR-assign.p41
-rw-r--r--ppc-amigaos/recipes/patches/gcc/gmp-configure.p11
17 files changed, 45760 insertions, 434 deletions
diff --git a/ppc-amigaos/Makefile b/ppc-amigaos/Makefile
index a53fe9c..51d0c87 100644
--- a/ppc-amigaos/Makefile
+++ b/ppc-amigaos/Makefile
@@ -1,21 +1,20 @@
-UPSTREAM_GCC_VERSION := 467
-UPSTREAM_GCC_TARBALL := gcc-$(UPSTREAM_GCC_VERSION)
-UPSTREAM_GCC_URI := http://svn.code.sf.net/p/adtools/code/branches/gcc/4.5.x@$(UPSTREAM_GCC_VERSION)
+UPSTREAM_GCC_VERSION := 5.3.0
+UPSTREAM_GCC_TARBALL := gcc-$(UPSTREAM_GCC_VERSION).tar.bz2
+UPSTREAM_GCC_URI := http://ftp.gnu.org/gnu/gcc/gcc-$(UPSTREAM_GCC_VERSION)/$(UPSTREAM_GCC_TARBALL)
-UPSTREAM_BINUTILS_VERSION := 467
-UPSTREAM_BINUTILS_TARBALL := binutils-$(UPSTREAM_BINUTILS_VERSION)
-UPSTREAM_BINUTILS_URI := http://svn.code.sf.net/p/adtools/code/trunk/binutils@$(UPSTREAM_BINUTILS_VERSION)
+UPSTREAM_BINUTILS_VERSION := 2.23.2
+UPSTREAM_BINUTILS_TARBALL := binutils-$(UPSTREAM_BINUTILS_VERSION).tar.bz2
+UPSTREAM_BINUTILS_URI := ftp://ftp.gnu.org/gnu/binutils/$(UPSTREAM_BINUTILS_TARBALL)
-UPSTREAM_GMP_VERSION := 4.3.2
+UPSTREAM_GMP_VERSION := 5.0.5
UPSTREAM_GMP_TARBALL := gmp-$(UPSTREAM_GMP_VERSION).tar.bz2
UPSTREAM_GMP_URI := http://ftp.gnu.org/gnu/gmp/$(UPSTREAM_GMP_TARBALL)
-# Would use 3.0.0, but that dislikes in-tree gmp sources
-UPSTREAM_MPFR_VERSION := 2.4.2
+UPSTREAM_MPFR_VERSION := 3.1.2
UPSTREAM_MPFR_TARBALL := mpfr-$(UPSTREAM_MPFR_VERSION).tar.bz2
UPSTREAM_MPFR_URI := http://www.mpfr.org/mpfr-$(UPSTREAM_MPFR_VERSION)/$(UPSTREAM_MPFR_TARBALL)
-UPSTREAM_MPC_VERSION := 0.8.2
+UPSTREAM_MPC_VERSION := 0.9
UPSTREAM_MPC_TARBALL := mpc-$(UPSTREAM_MPC_VERSION).tar.gz
UPSTREAM_MPC_URI := http://www.multiprecision.org/mpc/download/$(UPSTREAM_MPC_TARBALL)
@@ -118,7 +117,8 @@ $(BUILDSTEPS)/srcdir-step2.d: $(BUILDSTEPS)/srcdir-step1.d $(SOURCESDIR)/$(UPSTR
touch $@
$(BUILDSTEPS)/srcdir-step1.d: $(BUILDSTEPS)/$(UPSTREAM_GCC_TARBALL).d
- cp -r $(SOURCESDIR)/$(UPSTREAM_GCC_TARBALL) $(GCC_SRCDIR)
+ tar xjf $(SOURCESDIR)/$(UPSTREAM_GCC_TARBALL)
+ mv gcc-$(UPSTREAM_GCC_VERSION) $(GCC_SRCDIR)
touch $@
$(BUILDSTEPS)/$(UPSTREAM_GCC_TARBALL).d: $(BUILDSTEPS)/buildsteps.d $(SOURCESDIR)/$(UPSTREAM_GCC_TARBALL)
@@ -128,17 +128,16 @@ $(BUILDSTEPS)/$(UPSTREAM_GCC_TARBALL).d: $(BUILDSTEPS)/buildsteps.d $(SOURCESDIR
# Rules to build and install binutils
###
-# Ugh. Upstream binutils is not remotely 64-bit safe.
-# Build a 32bit binary until this gets fixed
$(BUILDSTEPS)/binutils.d: $(BUILDSTEPS)/binutils-srcdir.d
mkdir -p $(BUILDDIR)/binutils
- cd $(BUILDDIR)/binutils && CFLAGS="-m32" LDFLAGS="-m32" $(BINUTILS_SRCDIR)/configure --prefix=$(PREFIX) --target=$(TARGET_NAME) --disable-nls
+ cd $(BUILDDIR)/binutils && $(BINUTILS_SRCDIR)/configure --prefix=$(PREFIX) --target=$(TARGET_NAME) --disable-nls --enable-plugins
cd $(BUILDDIR)/binutils && make
cd $(BUILDDIR)/binutils && make install
touch $@
$(BUILDSTEPS)/binutils-srcdir.d: $(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL)
- cp -r $(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL) $(BINUTILS_SRCDIR)
+ tar xjf $(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL)
+ mv binutils-$(UPSTREAM_BINUTILS_VERSION) $(BINUTILS_SRCDIR)
for p in `ls $(RECIPES)/patches/binutils/*.p` ; do patch -d $(BINUTILS_SRCDIR) -p0 <$$p ; done
touch $@
@@ -147,7 +146,7 @@ $(BUILDSTEPS)/binutils-srcdir.d: $(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL)
###
$(SOURCESDIR)/$(UPSTREAM_GCC_TARBALL):
- svn co $(UPSTREAM_GCC_URI) $@
+ wget -q -O $@ $(UPSTREAM_GCC_URI)
$(SOURCESDIR)/$(UPSTREAM_GMP_TARBALL):
wget -q -O $@ $(UPSTREAM_GMP_URI)
@@ -159,7 +158,7 @@ $(SOURCESDIR)/$(UPSTREAM_MPC_TARBALL):
wget -q -O $@ $(UPSTREAM_MPC_URI)
$(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL):
- svn co $(UPSTREAM_BINUTILS_URI) $@
+ wget -q -O $@ $(UPSTREAM_BINUTILS_URI)
$(SOURCESDIR)/$(UPSTREAM_NDK_TARBALL):
wget -q -O $@ $(UPSTREAM_NDK_URI)
diff --git a/ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p b/ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p
new file mode 100644
index 0000000..ccc8a07
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p
@@ -0,0 +1,26193 @@
+From 1678a95339b8893195b307a953a0053ceeca0133 Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Sat, 14 Feb 2015 14:54:44 +0100
+Subject: [PATCH 1/7] Changes for various Amiga targets.
+
+---
+ bfd/ChangeLog-9697 | 64 +
+ bfd/ChangeLog-9899 | 5 +
+ bfd/Makefile.am | 18 +-
+ bfd/Makefile.in | 24 +-
+ bfd/amigaos.c | 3189 +++++++++
+ bfd/amigaoslink.c | 1032 +++
+ bfd/aout-amiga.c | 152 +
+ bfd/aoutx.h | 26 +-
+ bfd/bfd-in2.h | 12 +
+ bfd/bfd.c | 1 +
+ bfd/bfdio.c | 25 +
+ bfd/config.bfd | 28 +-
+ bfd/configure | 5 +
+ bfd/configure.host | 1 +
+ bfd/configure.in | 5 +
+ bfd/doc/Makefile.am | 15 +-
+ bfd/doc/Makefile.in | 15 +-
+ bfd/doc/bfd.texinfo | 9 +-
+ bfd/elf32-amiga.c | 3844 +++++++++++
+ bfd/{elf32-ppc.c => elf32-amigaos.c} | 341 +-
+ bfd/elf32-i386-amithlon.c | 198 +
+ bfd/elf32-i386.c | 17 +-
+ bfd/elf32-morphos.c | 7137 +++++++++++++++++++++
+ bfd/elf32-ppc.c | 4 +
+ bfd/hosts/amigaos.h | 5 +
+ bfd/hosts/morphos.h | 5 +
+ bfd/libamiga.h | 187 +
+ bfd/libbfd.h | 8 +
+ bfd/linker.c | 26 +-
+ bfd/reloc.c | 19 +
+ bfd/targets.c | 11 +
+ binutils/objcopy.c | 50 +-
+ binutils/readelf.c | 5 +
+ binutils/rename.c | 4 +-
+ config.sub | 11 +-
+ config/mh-amigaos | 13 +
+ config/mh-morphos | 13 +
+ configure | 6 +
+ configure.ac | 6 +
+ gas/ChangeLog-9697 | 12 +
+ gas/ChangeLog-9899 | 4 +
+ gas/Makefile.am | 5 +-
+ gas/Makefile.in | 20 +-
+ gas/as.c | 14 +
+ gas/config/m68k-parse.h | 3 +
+ gas/config/m68k-parse.y | 10 +-
+ gas/config/obj-amigahunk.c | 212 +
+ gas/config/obj-amigahunk.h | 54 +
+ gas/config/obj-elf.c | 4 +-
+ gas/config/tc-i386.h | 15 +-
+ gas/config/tc-m68k.c | 312 +-
+ gas/config/tc-m68k.h | 15 +
+ gas/config/tc-ppc.c | 36 +-
+ gas/config/tc-sh.c | 28 +-
+ gas/config/te-amiga.h | 24 +
+ gas/config/te-amigaos.h | 14 +
+ gas/config/{te-nbsd.h => te-amithlon.h} | 16 +-
+ gas/config/te-morphos.h | 14 +
+ gas/configure | 20 +
+ gas/configure.in | 18 +
+ gas/configure.tgt | 8 +-
+ gas/read.c | 21 +-
+ gas/read.h | 4 +
+ gas/write.c | 31 +-
+ gas/write.h | 4 +-
+ gprof/Makefile.am | 2 +-
+ gprof/Makefile.in | 2 +-
+ gprof/configure | 13 +
+ gprof/configure.in | 11 +
+ gprof/gconfig.in | 4 -
+ include/elf/amigaos.h | 27 +
+ include/elf/ppc.h | 12 +
+ include/libiberty.h | 2 +-
+ ld/ChangeLog-9197 | 15 +
+ ld/ChangeLog-9899 | 5 +
+ ld/Makefile.am | 38 +
+ ld/Makefile.in | 46 +
+ ld/configure.host | 4 +
+ ld/configure.tgt | 9 +
+ ld/emulparams/amiga.sh | 6 +
+ ld/emulparams/amiga_bss.sh | 6 +
+ ld/emulparams/amigaos.sh | 26 +
+ ld/emulparams/amithlon.sh | 11 +
+ ld/emulparams/morphos.sh | 6 +
+ ld/emulparams/morphos_baserel.sh | 6 +
+ ld/emulparams/ppcamiga.sh | 8 +
+ ld/emulparams/ppcamiga_bss.sh | 8 +
+ ld/emultempl/amiga.em | 288 +
+ ld/emultempl/{elf32.em => amigaos.em} | 0
+ ld/emultempl/amithlon.em | 1698 +++++
+ ld/emultempl/morphos.em | 1104 ++++
+ ld/emultempl/ppc32elf.em | 12 +
+ ld/ldctor.c | 18 +-
+ ld/ldfile.c | 54 +-
+ ld/ldfile.h | 5 +
+ ld/ldlang.c | 7 +
+ ld/ldlang.h | 2 +
+ ld/ldlex.c | 127 +-
+ ld/ldmain.c | 7 +
+ ld/scripttempl/amiga.sc | 49 +
+ ld/scripttempl/amiga_bss.sc | 41 +
+ ld/scripttempl/{elf64hppa.sc => amigaos.sc} | 132 +-
+ ld/scripttempl/{mep.sc => amithlon.sc} | 145 +-
+ ld/scripttempl/{elfi370.sc => morphos.sc} | 57 +-
+ ld/scripttempl/{elfi370.sc => morphos_baserel.sc} | 108 +-
+ libiberty/config/mh-amigaos | 12 +
+ libiberty/config/mh-morphos | 12 +
+ libiberty/lrealpath.c | 6 +
+ opcodes/m68k-dis.c | 2 +-
+ 109 files changed, 20966 insertions(+), 641 deletions(-)
+ create mode 100644 bfd/amigaos.c
+ create mode 100644 bfd/amigaoslink.c
+ create mode 100644 bfd/aout-amiga.c
+ create mode 100644 bfd/elf32-amiga.c
+ copy bfd/{elf32-ppc.c => elf32-amigaos.c} (97%)
+ create mode 100644 bfd/elf32-i386-amithlon.c
+ create mode 100644 bfd/elf32-morphos.c
+ create mode 100644 bfd/hosts/amigaos.h
+ create mode 100644 bfd/hosts/morphos.h
+ create mode 100644 bfd/libamiga.h
+ create mode 100644 config/mh-amigaos
+ create mode 100644 config/mh-morphos
+ create mode 100644 gas/config/obj-amigahunk.c
+ create mode 100644 gas/config/obj-amigahunk.h
+ create mode 100644 gas/config/te-amiga.h
+ create mode 100644 gas/config/te-amigaos.h
+ copy gas/config/{te-nbsd.h => te-amithlon.h} (65%)
+ create mode 100644 gas/config/te-morphos.h
+ create mode 100644 include/elf/amigaos.h
+ create mode 100644 ld/emulparams/amiga.sh
+ create mode 100644 ld/emulparams/amiga_bss.sh
+ create mode 100644 ld/emulparams/amigaos.sh
+ create mode 100644 ld/emulparams/amithlon.sh
+ create mode 100644 ld/emulparams/morphos.sh
+ create mode 100644 ld/emulparams/morphos_baserel.sh
+ create mode 100644 ld/emulparams/ppcamiga.sh
+ create mode 100644 ld/emulparams/ppcamiga_bss.sh
+ create mode 100644 ld/emultempl/amiga.em
+ copy ld/emultempl/{elf32.em => amigaos.em} (100%)
+ create mode 100644 ld/emultempl/amithlon.em
+ create mode 100644 ld/emultempl/morphos.em
+ create mode 100644 ld/scripttempl/amiga.sc
+ create mode 100644 ld/scripttempl/amiga_bss.sc
+ copy ld/scripttempl/{elf64hppa.sc => amigaos.sc} (88%)
+ copy ld/scripttempl/{mep.sc => amithlon.sc} (76%)
+ copy ld/scripttempl/{elfi370.sc => morphos.sc} (88%)
+ copy ld/scripttempl/{elfi370.sc => morphos_baserel.sc} (69%)
+ create mode 100644 libiberty/config/mh-amigaos
+ create mode 100644 libiberty/config/mh-morphos
+
+diff --git a/bfd/ChangeLog-9697 b/bfd/ChangeLog-9697
+index e9a5c1d60a313aaf09d1a8add619022cfdf575fa..1c2bb3f3c91d32e8b95f8b0cf16b98c58cde454b 100644
+--- bfd/ChangeLog-9697
++++ bfd/ChangeLog-9697
+@@ -46,12 +46,19 @@ Mon Dec 22 13:20:57 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ Mon Dec 22 13:04:33 1997 Joel Sherrill <joel@oarcorp.com>
+
+ * config.bfd (i[3456]86*-go32-rtems*): Fix to be the same as
+ i[3456]86-go32.
+
++Fri Dec 19 14:25:58 1997 Daniel Verite <daniel@brainstorm.fr>
++
++ * amigaos.c (amiga_bfd_copy_private_section_data): Add return
++ value.
++ * amigaoslink.c (amiga_final_link): Update linker_mark fields for
++ input sections involved in the output.
++
+ Thu Dec 18 16:01:25 1997 Doug Evans <devans@canuck.cygnus.com>
+
+ * configure: Regenerate to get @SHELL@ substituted.
+
+ Wed Dec 17 09:45:09 1997 Nick Clifton <nickc@cygnus.com>
+
+@@ -594,12 +601,22 @@ Tue Sep 23 19:03:13 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * elf.c (map_sections_to_segments): Even if we are not demand
+ paged, don't put a loadable section after a nonloadable section.
+ (assign_file_positions_for_segments): Increment the file offset
+ for a section with contents, even if it is not loadable.
+
++Tue Sep 23 09:46:10 1997 Fred Fish <fnf@ninemoons.com>
++
++ * amigaos.c (alloca): Only declare if not defined as macro.
++
++Mon Sep 22 10:15:30 1997 Fred Fish <fnf@ninemoons.com>
++
++ * amigaos.c (sysdep.h): Relocate include to provided needed
++ <sys/types.h> file.
++ * amigaoslink.c (sysdep.h): Ditto, and remove <sys/types.h>.
++
+ Sun Sep 21 11:03:24 1997 Nick Clifton <nickc@cygnus.com>
+
+ * elf32-v850.c (v850_elf_final_link_relocate): Add return code
+ indicating that __ctbp could not be found.
+
+ Thu Sep 18 15:04:57 1997 Nick Clifton <nickc@cygnus.com>
+@@ -764,12 +781,18 @@ Tue Aug 26 17:26:51 1997 Ian Lance Taylor <ian@cygnus.com>
+ * doc/Makefile.am (MKDOC): Use EXEEXT_FOR_BUILD, not EXEEXT.
+ * aclocal.m4: Rebuild.
+ * configure: Rebuild.
+ * Makefile.in: Rebuild.
+ * doc/Makefile.in: Rebuild.
+
++Mon Aug 25 16:32:00 1997 Steffen Opel <opel@rumms.uni-mannheim.de>
++
++ * Makefile.in (guide, install-guide, clean-guide, bfd.guide):
++ New targets for AmigaGuide documentation.
++ (install): Add install-info and install-guide.
++
+ Mon Aug 25 16:14:34 1997 Christopher Provenzano <proven@cygnus.com>
+
+ * configure: Rebuild with latest devo autoconf for NT support
+
+ Mon Aug 25 16:11:04 1997 Nick Clifton <nickc@cygnus.com>
+
+@@ -3764,12 +3787,18 @@ Fri Aug 30 11:49:19 1996 Ian Lance Taylor <ian@cygnus.com>
+ page before checking D_PAGED.
+
+ * ihex.c (ihex_scan): Removed unnecessary extbase variable.
+ (ihex_write_object_contents): Remove extbase; always use segbase
+ instead.
+
++Thu Aug 29 17:53:51 1996 Daniel Verite <daniel@brainstorm.eu.org>
++
++ * amigaos.c (amiga_get_section_contents): Handle sections that
++ are larger than their disksize.
++ (amiga_make_unique_section): Remove infinite loop.
++
+ Thu Aug 29 16:52:17 1996 Michael Meissner <meissner@tiktok.cygnus.com>
+
+ * configure.in (i[345]86-*-*): Recognize i686 for pentium pro.
+ * configure.host (i[345]86-*-*): Ditto.
+ * config.bfd (i[345]86-*-*): Ditto.
+ * configure: Regenerate.
+@@ -3989,12 +4018,19 @@ Mon Aug 5 13:42:41 1996 Ian Lance Taylor <ian@cygnus.com>
+ * elf.c (map_sections_to_segments): Rewrite tests for starting a
+ new segment to make them more comprehensible. If the relationship
+ between the LMA and the VMA changed, start a new segment. Don't
+ check dynsec when deciding whether to start a new segment for a
+ writeable section; -N will now handle this.
+
++Sun Aug 4 22:15:56 1996 Fred Fish <fnf@ninemoons.com>
++
++ * amigaoslink.c (sys/types.h): Include before genlink.h to get
++ definition for size_t which is used in genlink.h. This was not
++ getting defined during a cross compilation on alpha-dec-osf2.0 for
++ some reason.
++
+ Thu Aug 1 22:43:08 1996 Jeffrey A Law (law@cygnus.com)
+
+ * libhppa.h: Remove "esel" changes. Not the right approach.
+ * som.c: Corresponding changes.
+ (som_bfd_derive_misc_symbol_info): Use ST_DATA for symbols
+ which don't have a SOM symbol type associated with them.
+@@ -4085,12 +4121,17 @@ Mon Jul 22 15:30:30 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ Fri Jul 19 18:15:51 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * configure.in: Fix test for whether a compiler has a 64 bit
+ type. From Jim Wilson <wilson@cygnus.com>.
+
++Thu Jul 18 16:58:11 1996 Daniel Verite <daniel@brainstorm.eu.org>
++
++ * amigaoslink.c (aout_perform_reloc): Fix baserel 16 bits relocs.
++ (my_add_to): Fix sign bug in extraction of 16 bits values.
++
+ Thu Jul 18 15:39:10 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * configure.host (mips-sgi-irix6*): New host.
+
+ * configure.in: Set and substitute VERSION, BFD_HOST_64BIT_LONG
+ (replacing HOST_64BITLONG), BFD_HOST_64_BIT_DEFINED,
+@@ -4214,12 +4255,17 @@ Mon Jul 8 16:18:03 1996 Ian Lance Taylor <ian@cygnus.com>
+ (mips_relhi_addr, mips_relhi_addend): Remove.
+ (mips_relhi_reloc): Maintain a list of unmatched RELHI relocs.
+ (mips_rello_reloc): Process mips_relhi_list.
+ (mips_relocate_section): Permit an arbitrary number of REFHI or
+ RELHI relocs before the associated REFLO or RELLO reloc.
+
++Sun Jul 7 12:15:39 1996 Kamil Iskra <iskra@student.uci.agh.edu.pl>
++
++ * amigaos.c (amiga_write_symbols): Fix Daniel's workaround for
++ outputting long symbol names.
++
+ Fri Jul 5 19:27:49 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * aout-target.h (MY(callback)): Set reloc_count fields.
+
+ Thu Jul 4 12:00:37 1996 Ian Lance Taylor <ian@cygnus.com>
+
+@@ -4293,12 +4339,17 @@ Fri Jun 28 11:17:00 1996 Richard Henderson <rth@tamu.edu>
+ (elf64_alpha_link_hash_newfunc): Initialize flags field.
+ (elf64_alpha_check_relocs): Record types of LITUSE entries that
+ are found for LITERAL relocs.
+ (elf64_alpha_adjust_dynamic_symbol): If a symbol has its address
+ taken, we cannot generate a .plt entry for the symbol.
+
++Thu Jun 27 17:35:32 1996 Daniel Verite <daniel@brainstorm.eu.org>
++
++ * amigaos.c (amiga_write_object_contents): Don't output symbols
++ which are not attached to any section, such as indirect symbols.
++
+ Thu Jun 27 11:24:29 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * configure.in: Add AC_ISC_POSIX, and check for setitimer and
+ sysconf functions (for gprof).
+ * configure, config.in: Rebuild.
+
+@@ -4522,12 +4573,25 @@ Wed Jun 12 11:16:37 1996 Ian Lance Taylor <ian@cygnus.com>
+ Tue Jun 11 15:24:48 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * xcofflink.c (xcoff_build_ldsyms): Set XCOFF_DEF_REGULAR for a
+ common symbol defined by the linker. Don't export function code
+ even if export_defineds is set.
+
++Tue Jun 11 12:52:10 1996 Daniel Verite <daniel@brainstorm.eu.org>
++
++ * amigaoslink.c (mygeta4): Function removed.
++ (amiga_final_link): Search for ___a4_init symbol in the global hash
++ table and cache its value in the backend data.
++
++ * amigaos.c (write_longs): Return a boolean instead of the
++ number of longs written.
++ (write_section_contents): Split reloc hunks at 0xffff entries.
++ (amiga_write_symbols): Cut the names in hunk symbols at 124 characters
++ (workaround for an amigaos bug).
++ (amiga_handle_rest): Added a sanity check in reloc hunks parsing.
++
+ Mon Jun 10 11:57:27 1996 Jeffrey A Law (law@cygnus.com)
+
+ * coff-h8300.c (howto_table): Add new entries for R_BCC_INV
+ and R_JMP_DEL.
+ (rtype2howto): Handle R_BCC_INV and R_JMP_DEL.
+ (h8300_symbol_address_p): New function.
+diff --git a/bfd/ChangeLog-9899 b/bfd/ChangeLog-9899
+index 6d7f5cd616db22097b8238d8686f60484c9e6ee6..6e25901995a73646a13037d32c14563df20f74b3 100644
+--- bfd/ChangeLog-9899
++++ bfd/ChangeLog-9899
+@@ -5570,12 +5570,17 @@ Wed Jan 21 21:16:06 1998 Manfred Hollstein <manfred@s-direktnet.de>
+ (GET_SCNDHR_NLNNO): Likewise.
+
+ Mon Jan 19 12:49:52 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * cpu-sh.c (arch_info_struct): Correct next field of sh3e.
+
++Sun Jan 18 10:39:52 1998 Daniel Verite <daniel@brainstorm.fr>
++
++ * amigaos.c (CAN_WRITE_OUTSYM): New macro.
++ (amiga_write_object_contents): Use CAN_WRITE_OUTSYM
++
+ Wed Jan 14 17:23:27 1998 Nick Clifton <nickc@cygnus.com>
+
+ * elf32-m32r.c: Add macros to handle NOP insertion.
+
+ Wed Jan 14 16:15:22 1998 Richard Henderson <rth@cygnus.com>
+
+diff --git a/bfd/Makefile.am b/bfd/Makefile.am
+index 9ab2aa947a0a96ba5a469652c579a4d181793646..c224a3cecc392df96a6bc20c8dc73eb81c677269 100644
+--- bfd/Makefile.am
++++ bfd/Makefile.am
+@@ -232,13 +232,16 @@ ALL_MACHINES_CFILES = \
+ cpu-z80.c \
+ cpu-z8k.c
+
+ # 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 \
+ aout-sparcle.lo \
+ aout-tic30.lo \
+ aout0.lo \
+@@ -287,12 +290,13 @@ BFD32_BACKENDS = \
+ elf-strtab.lo \
+ elf-vxworks.lo \
+ elf.lo \
+ elf32-am33lin.lo \
+ elf32-arc.lo \
+ elf32-arm.lo \
++ elf32-amigaos.lo \
+ elf32-avr.lo \
+ elf32-bfin.lo \
+ elf32-cr16.lo \
+ elf32-cr16c.lo \
+ elf32-cris.lo \
+ elf32-crx.lo \
+@@ -320,12 +324,13 @@ BFD32_BACKENDS = \
+ elf32-m68k.lo \
+ elf32-m88k.lo \
+ elf32-mcore.lo \
+ elf32-mep.lo \
+ elf32-microblaze.lo \
+ elf32-mips.lo \
++ elf32-morphos.lo \
+ elf32-moxie.lo \
+ elf32-msp430.lo \
+ elf32-mt.lo \
+ elf32-openrisc.lo \
+ elf32-or32.lo \
+ elf32-pj.lo \
+@@ -420,13 +425,16 @@ BFD32_BACKENDS = \
+ xcofflink.lo \
+ xsym.lo \
+ xtensa-isa.lo \
+ 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 \
+ aout-sparcle.c \
+ aout-tic30.c \
+ aout0.c \
+@@ -475,12 +483,13 @@ BFD32_BACKENDS_CFILES = \
+ elf-strtab.c \
+ elf-vxworks.c \
+ elf.c \
+ elf32-am33lin.c \
+ elf32-arc.c \
+ elf32-arm.c \
++ elf32-amigaos.c \
+ elf32-avr.c \
+ elf32-bfin.c \
+ elf32-cr16.c \
+ elf32-cr16c.c \
+ elf32-cris.c \
+ elf32-crx.c \
+@@ -508,12 +517,13 @@ BFD32_BACKENDS_CFILES = \
+ elf32-m68k.c \
+ elf32-m88k.c \
+ elf32-mcore.c \
+ elf32-mep.c \
+ elf32-microblaze.c \
+ elf32-mips.c \
++ elf32-morphos.c \
+ elf32-moxie.c \
+ elf32-msp430.c \
+ elf32-mt.c \
+ elf32-openrisc.c \
+ elf32-or32.c \
+ elf32-pj.c \
+@@ -745,13 +755,13 @@ CFILES = $(SOURCE_CFILES) $(BUILD_CFILES)
+
+ ## This is a list of all .h files which are in the source tree.
+ SOURCE_HFILES = \
+ aout-target.h aoutf1.h aoutx.h coffcode.h coffswap.h ecoffswap.h \
+ elf-bfd.h elf-hppa.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 \
+ pef.h pef-traceback.h peicode.h som.h version.h \
+ vms.h xsym.h
+
+@@ -1013,12 +1023,6 @@ coff-tic4x.lo: coff-tic4x.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)
+
+-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 --git a/bfd/Makefile.in b/bfd/Makefile.in
+index 99902757111d8011447cde1dda030e5a9c817ff2..bcdf435a15eb144bca66d8bfe04122a45e647446 100644
+--- bfd/Makefile.in
++++ bfd/Makefile.in
+@@ -532,13 +532,16 @@ ALL_MACHINES_CFILES = \
+ cpu-z8k.c
+
+
+ # 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 \
+ aout-sparcle.lo \
+ aout-tic30.lo \
+ aout0.lo \
+@@ -587,12 +590,13 @@ BFD32_BACKENDS = \
+ elf-strtab.lo \
+ elf-vxworks.lo \
+ elf.lo \
+ elf32-am33lin.lo \
+ elf32-arc.lo \
+ elf32-arm.lo \
++ elf32-amigaos.lo \
+ elf32-avr.lo \
+ elf32-bfin.lo \
+ elf32-cr16.lo \
+ elf32-cr16c.lo \
+ elf32-cris.lo \
+ elf32-crx.lo \
+@@ -620,12 +624,13 @@ BFD32_BACKENDS = \
+ elf32-m68k.lo \
+ elf32-m88k.lo \
+ elf32-mcore.lo \
+ elf32-mep.lo \
+ elf32-microblaze.lo \
+ elf32-mips.lo \
++ elf32-morphos.lo \
+ elf32-moxie.lo \
+ elf32-msp430.lo \
+ elf32-mt.lo \
+ elf32-openrisc.lo \
+ elf32-or32.lo \
+ elf32-pj.lo \
+@@ -720,13 +725,16 @@ BFD32_BACKENDS = \
+ xcofflink.lo \
+ xsym.lo \
+ xtensa-isa.lo \
+ 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 \
+ aout-sparcle.c \
+ aout-tic30.c \
+ aout0.c \
+@@ -775,12 +783,13 @@ BFD32_BACKENDS_CFILES = \
+ elf-strtab.c \
+ elf-vxworks.c \
+ elf.c \
+ elf32-am33lin.c \
+ elf32-arc.c \
+ elf32-arm.c \
++ elf32-amigaos.c \
+ elf32-avr.c \
+ elf32-bfin.c \
+ elf32-cr16.c \
+ elf32-cr16c.c \
+ elf32-cris.c \
+ elf32-crx.c \
+@@ -808,12 +817,13 @@ BFD32_BACKENDS_CFILES = \
+ elf32-m68k.c \
+ elf32-m88k.c \
+ elf32-mcore.c \
+ elf32-mep.c \
+ elf32-microblaze.c \
+ elf32-mips.c \
++ elf32-morphos.c \
+ elf32-moxie.c \
+ elf32-msp430.c \
+ elf32-mt.c \
+ elf32-openrisc.c \
+ elf32-or32.c \
+ elf32-pj.c \
+@@ -1046,13 +1056,13 @@ BUILD_CFILES = \
+
+ CFILES = $(SOURCE_CFILES) $(BUILD_CFILES)
+ SOURCE_HFILES = \
+ aout-target.h aoutf1.h aoutx.h coffcode.h coffswap.h ecoffswap.h \
+ elf-bfd.h elf-hppa.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 \
+ pef.h pef-traceback.h peicode.h som.h version.h \
+ vms.h xsym.h
+
+@@ -1215,13 +1225,16 @@ mostlyclean-compile:
+
+ distclean-compile:
+ -rm -f *.tab.c
+
+ @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@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-sparcle.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-tic30.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout0.Plo@am__quote@
+@@ -1365,12 +1378,13 @@ distclean-compile:
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-m10300.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-nacl.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-strtab.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-vxworks.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf.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@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-bfin.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-cr16.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-cr16c.Plo@am__quote@
+@@ -1401,12 +1415,13 @@ distclean-compile:
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68k.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m88k.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mcore.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mep.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@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-openrisc.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-or32.Plo@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-pj.Plo@am__quote@
+@@ -2065,16 +2080,9 @@ coff-tic4x.lo: coff-tic4x.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)
+
+-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)
+-
+ # Tell versions [3.59,3.63) of GNU make to not export all variables.
+ # Otherwise a system limit (for SysV at least) may be exceeded.
+ .NOEXPORT:
+diff --git a/bfd/amigaos.c b/bfd/amigaos.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..9d715d64d458e6599c19ed65fbb61c253d2ab208
+--- /dev/null
++++ bfd/amigaos.c
+@@ -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 --git a/bfd/amigaoslink.c b/bfd/amigaoslink.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..9067a0a06b933c67bfd3542b299d1adb281182c3
+--- /dev/null
++++ bfd/amigaoslink.c
+@@ -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 --git a/bfd/aout-amiga.c b/bfd/aout-amiga.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..ced7584521b89943b1636d2b4c9b884242cd81c6
+--- /dev/null
++++ bfd/aout-amiga.c
+@@ -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 --git a/bfd/aoutx.h b/bfd/aoutx.h
+index 1e0ad38f95bcf990a9ffd4cfb89eae3f6496740c..2641f975fd575d0a651540dc886eeee68cf4b173 100644
+--- bfd/aoutx.h
++++ bfd/aoutx.h
+@@ -127,12 +127,16 @@ DESCRIPTION
+ #include "libaout.h"
+ #include "libbfd.h"
+ #include "aout/aout64.h"
+ #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
+
+ DESCRIPTION
+ The file @file{aoutx.h} provides for both the @emph{standard}
+@@ -1550,13 +1554,13 @@ translate_from_native_sym_flags (bfd *abfd, aout_symbol_type *cache_ptr)
+
+ return TRUE;
+ }
+
+ /* 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)
+ {
+ bfd_vma value = cache_ptr->value;
+ asection *sec;
+@@ -1946,16 +1950,32 @@ NAME (aout, swap_std_reloc_out) (bfd *abfd,
+ asection *output_section = sym->section->output_section;
+
+ PUT_WORD (abfd, g->address, natptr->r_address);
+
+ 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. */
+
+ /* If this relocation is relative to a symbol then set the
+ r_index to the symbols index, and the r_extern bit.
+
+@@ -2251,14 +2271,18 @@ NAME (aout, swap_std_reloc_in) (bfd *abfd,
+ else
+ cache_ptr->howto = NULL;
+
+ /* 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
+ to see the file even if it is bad. */
+ r_extern = 0;
+diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
+index e496083d6ebb0842cfe0a7777dc76cdbd18c7134..8a4d566298f86c56c4a2d21895a39e0d7c5002d7 100644
+--- bfd/bfd-in2.h
++++ bfd/bfd-in2.h
+@@ -3128,12 +3128,16 @@ instruction. */
+ BFD_RELOC_PPC_EMB_RELSEC16,
+ BFD_RELOC_PPC_EMB_RELST_LO,
+ BFD_RELOC_PPC_EMB_RELST_HI,
+ 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,
+ BFD_RELOC_PPC_VLE_LO16A,
+ BFD_RELOC_PPC_VLE_LO16D,
+ BFD_RELOC_PPC_VLE_HI16A,
+@@ -3213,12 +3217,18 @@ instruction. */
+ BFD_RELOC_PPC64_DTPREL16_LO_DS,
+ BFD_RELOC_PPC64_DTPREL16_HIGHER,
+ BFD_RELOC_PPC64_DTPREL16_HIGHERA,
+ BFD_RELOC_PPC64_DTPREL16_HIGHEST,
+ BFD_RELOC_PPC64_DTPREL16_HIGHESTA,
+
++/* 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,
+
+ /* The type of reloc used to build a constructor table - at the moment
+ probably a 32 bit wide absolute relocation, but the target can choose.
+ It generally does map to one of the other relocation types. */
+@@ -5904,12 +5914,13 @@ struct bfd
+ struct mach_o_data_struct *mach_o_data;
+ struct mach_o_fat_data_struct *mach_o_fat_data;
+ struct plugin_data_struct *plugin_data;
+ 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;
+
+ /* Used by the application to hold private data. */
+ void *usrdata;
+@@ -6215,12 +6226,13 @@ bfd_boolean generic_core_file_matches_executable_p
+ (bfd_assert (__FILE__,__LINE__), NULL))
+ #endif
+
+ enum bfd_flavour
+ {
+ bfd_target_unknown_flavour,
++ bfd_target_amiga_flavour,
+ bfd_target_aout_flavour,
+ bfd_target_coff_flavour,
+ bfd_target_ecoff_flavour,
+ bfd_target_xcoff_flavour,
+ bfd_target_elf_flavour,
+ bfd_target_ieee_flavour,
+diff --git a/bfd/bfd.c b/bfd/bfd.c
+index eed18960855bdc51be8b57ddba27975afb6b02ef..3487694a541417ec20453ca9116bbb86c383f979 100644
+--- bfd/bfd.c
++++ bfd/bfd.c
+@@ -261,12 +261,13 @@ CODE_FRAGMENT
+ . struct mach_o_data_struct *mach_o_data;
+ . struct mach_o_fat_data_struct *mach_o_fat_data;
+ . struct plugin_data_struct *plugin_data;
+ . 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;
+ .
+ . {* Used by the application to hold private data. *}
+ . void *usrdata;
+diff --git a/bfd/bfdio.c b/bfd/bfdio.c
+index be05581aeb4026addd3f4caf2b185ae73d893a24..a15208b16635c7174592b6ccf26685c4b1d05bc8 100644
+--- bfd/bfdio.c
++++ bfd/bfdio.c
+@@ -325,12 +325,37 @@ bfd_seek (bfd *abfd, file_ptr position, int direction)
+
+ if (abfd->iovec)
+ 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)
+ {
+ int hold_errno = errno;
+
+ /* Force redetermination of `where' field. */
+ bfd_tell (abfd);
+diff --git a/bfd/config.bfd b/bfd/config.bfd
+index 6025f2641b47915c79a7d643963e9d9080e0ed5c..fcbbce847bc65a44ee68deedd93b2943aac9f77f 100644
+--- bfd/config.bfd
++++ bfd/config.bfd
+@@ -78,15 +78,17 @@ c30*) targ_archs=bfd_tic30_arch ;;
+ c4x*) targ_archs=bfd_tic4x_arch ;;
+ c54x*) targ_archs=bfd_tic54x_arch ;;
+ cr16*) targ_archs=bfd_cr16_arch ;;
+ 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" ;;
+ m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;;
+ m68*) targ_archs=bfd_m68k_arch ;;
+ m88*) targ_archs=bfd_m88k_arch ;;
+@@ -719,12 +721,17 @@ case "${targ}" in
+ ;;
+ i[3-7]86-*-chaos)
+ 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
+ ;;
+ i860-stardent-sysv4* | i860-stardent-elf*)
+ targ_defvec=bfd_elf32_i860_little_vec
+ targ_selvecs="bfd_elf32_i860_vec bfd_elf32_i860_little_vec"
+@@ -800,12 +807,17 @@ case "${targ}" in
+ targ_selvecs="bfd_elf32_m68hc11_vec bfd_elf32_m68hc12_vec"
+ ;;
+
+ 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
+ ;;
+ m68*-*-aout*)
+ targ_defvec=aout0_big_vec
+@@ -871,13 +883,13 @@ case "${targ}" in
+ ;;
+ m68*-ericsson-*)
+ targ_defvec=sunos_big_vec
+ 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
+ ;;
+ m68*-*-psos*)
+ targ_defvec=bfd_elf32_m68k_vec
+ targ_selvecs=ieee_vec
+@@ -1164,12 +1176,24 @@ case "${targ}" in
+ *-*-aix4.[3456789]* | *-*-aix[56789]*)
+ want64=true;;
+ *)
+ 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
+ targ_selvecs=rs6000coff_vec
+ want64=true
+ ;;
+diff --git a/bfd/configure b/bfd/configure
+index e965796ef43d9346cd917bf20243707633fc632e..018a5913f1d96081342c66a64f0167b11cdb1add 100755
+--- bfd/configure
++++ bfd/configure
+@@ -15172,13 +15172,15 @@ do
+ case "$vec" in
+ # This list is alphabetized to make it easy to compare
+ # with the two vector lists in targets.c. For the same reason,
+ # 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" ;;
+ arm_epoc_pe_big_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;;
+ arm_epoc_pe_little_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;;
+ arm_epoc_pei_big_vec) tb="$tb epoc-pei-arm.lo peigen.lo cofflink.lo " ;;
+@@ -15195,12 +15197,13 @@ do
+ armpei_big_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
+ armpei_little_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
+ b_out_vec_big_host) tb="$tb bout.lo aout32.lo" ;;
+ 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" ;;
+ bfd_elf32_big_generic_vec) tb="$tb elf32-gen.lo elf32.lo $elf" ;;
+ bfd_elf32_bigarc_vec) tb="$tb elf32-arc.lo elf32.lo $elf" ;;
+ bfd_elf32_bigarm_vec) tb="$tb elf32-arm.lo elf32.lo elf-nacl.lo elf-vxworks.lo $elf" ;;
+@@ -15231,12 +15234,13 @@ do
+ bfd_elf32_i370_vec) tb="$tb elf32-i370.lo elf32.lo $elf" ;;
+ bfd_elf32_i386_sol2_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;;
+ bfd_elf32_i386_freebsd_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;;
+ 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" ;;
+ bfd_elf32_ia64_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf" ;;
+ bfd_elf32_ia64_hpux_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf";;
+ bfd_elf32_ip2k_vec) tb="$tb elf32-ip2k.lo elf32.lo $elf" ;;
+@@ -15267,12 +15271,13 @@ do
+ bfd_elf32_mcore_little_vec) tb="$tb elf32-mcore.lo elf32.lo $elf" ;;
+ bfd_elf32_mep_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;;
+ bfd_elf32_mep_little_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;;
+ 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_nbigmips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
+ bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
+ bfd_elf32_ntradbigmips_vec | bfd_elf32_ntradbigmips_freebsd_vec)
+ tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
+diff --git a/bfd/configure.host b/bfd/configure.host
+index 7c63de58397426d08501dd7a0fd527cb59a9809c..afa7c909a787d9121d01e4e99d8047cf7f11f0b7 100644
+--- bfd/configure.host
++++ bfd/configure.host
+@@ -53,12 +53,13 @@ mips64*-*-linux*) host64=true;;
+ mips64*-*-freebsd* | mips64*-*-kfreebsd*-gnu) host64=true;;
+ mips*-*-sysv4*) ;;
+ mips*-*-sysv*) HDEFINES="-G 4" ;;
+ 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
+ # default code page used by windres/windmc when not specified by a commandline
+ # option) to select the "WINDOWS-1252" name instead. See PR11280 for details.
+ *-*-solaris2.11) HDEFINES=-DCP_ACP=1 ;;
+diff --git a/bfd/configure.in b/bfd/configure.in
+index 4b4cb617ef74f5fb33e4de13856d685f5ffba025..5d882b3701b6e0d93f97be655123a2bb2728d63a 100644
+--- bfd/configure.in
++++ bfd/configure.in
+@@ -664,13 +664,15 @@ do
+ case "$vec" in
+ # This list is alphabetized to make it easy to compare
+ # with the two vector lists in targets.c. For the same reason,
+ # 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" ;;
+ arm_epoc_pe_big_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;;
+ arm_epoc_pe_little_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;;
+ arm_epoc_pei_big_vec) tb="$tb epoc-pei-arm.lo peigen.lo cofflink.lo " ;;
+@@ -687,12 +689,13 @@ do
+ armpei_big_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
+ armpei_little_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
+ b_out_vec_big_host) tb="$tb bout.lo aout32.lo" ;;
+ 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" ;;
+ bfd_elf32_big_generic_vec) tb="$tb elf32-gen.lo elf32.lo $elf" ;;
+ bfd_elf32_bigarc_vec) tb="$tb elf32-arc.lo elf32.lo $elf" ;;
+ bfd_elf32_bigarm_vec) tb="$tb elf32-arm.lo elf32.lo elf-nacl.lo elf-vxworks.lo $elf" ;;
+@@ -723,12 +726,13 @@ do
+ bfd_elf32_i370_vec) tb="$tb elf32-i370.lo elf32.lo $elf" ;;
+ bfd_elf32_i386_sol2_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;;
+ bfd_elf32_i386_freebsd_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;;
+ 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" ;;
+ bfd_elf32_ia64_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf" ;;
+ bfd_elf32_ia64_hpux_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf";;
+ bfd_elf32_ip2k_vec) tb="$tb elf32-ip2k.lo elf32.lo $elf" ;;
+@@ -759,12 +763,13 @@ do
+ bfd_elf32_mcore_little_vec) tb="$tb elf32-mcore.lo elf32.lo $elf" ;;
+ bfd_elf32_mep_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;;
+ bfd_elf32_mep_little_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;;
+ 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_nbigmips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
+ bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
+ bfd_elf32_ntradbigmips_vec | bfd_elf32_ntradbigmips_freebsd_vec)
+ tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
+diff --git a/bfd/doc/Makefile.am b/bfd/doc/Makefile.am
+index 7476ee5bab710b6b418072124b473cf0d340b247..1ddc9e3d2153b55f6f26645e5fc584074bb369fd 100644
+--- bfd/doc/Makefile.am
++++ bfd/doc/Makefile.am
+@@ -1,11 +1,11 @@
+ ## Process this file with automake to generate Makefile.in
+
+ 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 \
+ opncls.texi reloc.texi section.texi \
+ syms.texi targets.texi init.texi hash.texi linker.texi \
+ mmo.texi \
+@@ -26,12 +26,13 @@ IPROTOS = cache.ip libbfd.ip reloc.ip init.ip archures.ip coffcode.ip
+ SRCDOC = $(srcdir)/../aoutx.h $(srcdir)/../archive.c \
+ $(srcdir)/../archures.c $(srcdir)/../bfd.c \
+ $(srcdir)/../bfdio.c $(srcdir)/../bfdwin.c \
+ $(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 \
+ $(srcdir)/../hash.c $(srcdir)/../linker.c \
+ $(srcdir)/../mmo.c
+
+@@ -183,12 +184,24 @@ hash.texi: chew.c $(srcdir)/../hash.c $(srcdir)/doc.str
+
+ linker.texi: chew.c $(srcdir)/../linker.c $(srcdir)/doc.str
+ $(MAKE) $(MKDOC)
+ ./$(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 \
+ $(srcdir)/../libbfd.c \
+ $(srcdir)/../bfdio.c \
+ $(srcdir)/../bfdwin.c \
+diff --git a/bfd/doc/Makefile.in b/bfd/doc/Makefile.in
+index 7ba351d742bf53f9e5f51ad7ef74150295519f1a..67db3caf9886839b8d8f52a2a1878de878bb2f6a 100644
+--- bfd/doc/Makefile.in
++++ bfd/doc/Makefile.in
+@@ -268,13 +268,13 @@ target_vendor = @target_vendor@
+ tdefaults = @tdefaults@
+ top_build_prefix = @top_build_prefix@
+ top_builddir = @top_builddir@
+ 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 \
+ opncls.texi reloc.texi section.texi \
+ syms.texi targets.texi init.texi hash.texi linker.texi \
+ mmo.texi \
+@@ -295,12 +295,13 @@ IPROTOS = cache.ip libbfd.ip reloc.ip init.ip archures.ip coffcode.ip
+ SRCDOC = $(srcdir)/../aoutx.h $(srcdir)/../archive.c \
+ $(srcdir)/../archures.c $(srcdir)/../bfd.c \
+ $(srcdir)/../bfdio.c $(srcdir)/../bfdwin.c \
+ $(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 \
+ $(srcdir)/../hash.c $(srcdir)/../linker.c \
+ $(srcdir)/../mmo.c
+
+@@ -880,12 +881,24 @@ hash.texi: chew.c $(srcdir)/../hash.c $(srcdir)/doc.str
+
+ linker.texi: chew.c $(srcdir)/../linker.c $(srcdir)/doc.str
+ $(MAKE) $(MKDOC)
+ ./$(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 \
+ case $$file in \
+ *-in.h) cat $$file >> $@ ;; \
+ */header.sed) break ;; \
+diff --git a/bfd/doc/bfd.texinfo b/bfd/doc/bfd.texinfo
+index 45ffa73240ea22a74debe916fcd7e068a947a7dc..7b9774b71a3cb9b3c154c8c75a41de29a6813146 100644
+--- bfd/doc/bfd.texinfo
++++ bfd/doc/bfd.texinfo
+@@ -286,12 +286,13 @@ structures.
+ @chapter BFD back ends
+ @menu
+ * What to Put Where::
+ * aout :: a.out backends
+ * coff :: coff backends
+ * elf :: elf backends
++* amiga :: amigaos backend
+ * mmo :: mmo backend
+ @ignore
+ * oasys :: oasys backends
+ * ieee :: ieee backend
+ * srecord :: s-record backend
+ @end ignore
+@@ -303,18 +304,22 @@ All of BFD lives in one directory.
+ @node aout, coff, What to Put Where, BFD back ends
+ @include aoutx.texi
+
+ @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
+ @include fdl.texi
+
+ @node BFD Index, , GNU Free Documentation License, Top
+diff --git a/bfd/elf32-amiga.c b/bfd/elf32-amiga.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..cf6c6cb9efdd15c786932adedd2476ec3a4bc08d
+--- /dev/null
++++ bfd/elf32-amiga.c
+@@ -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 --git a/bfd/elf32-i386-amithlon.c b/bfd/elf32-i386-amithlon.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..4e029a5e90187a96013ed97e078fba920d95db28
+--- /dev/null
++++ bfd/elf32-i386-amithlon.c
+@@ -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 --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
+index 0a6b22ec19ec9daee29e49c64c5d3ba2299e99c1..46396c83d45bab97de1470ee44ffa21f9d03e4b4 100644
+--- bfd/elf32-i386.c
++++ bfd/elf32-i386.c
+@@ -29,12 +29,16 @@
+ #include "elf-vxworks.h"
+ #include "bfd_stdint.h"
+ #include "objalloc.h"
+ #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
+
+ #include "elf/i386.h"
+
+ static reloc_howto_type elf_howto_table[]=
+@@ -1779,13 +1783,13 @@ elf_i386_check_relocs (bfd *abfd,
+ 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
++ if (((ELF32_I386_RELOCATABLE_EXECUTABLES || info->shared)
+ && (sec->flags & SEC_ALLOC) != 0
+ && (r_type != R_386_PC32
+ || (h != NULL
+ && (! SYMBOLIC_BIND (info, h)
+ || h->root.type == bfd_link_hash_defweak
+ || !h->def_regular))))
+@@ -2410,13 +2414,13 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
+ /* 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 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
+ 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
+@@ -3592,13 +3596,13 @@ elf_i386_relocate_section (bfd *output_bfd,
+ case R_386_32:
+ case R_386_PC32:
+ if ((input_section->flags & SEC_ALLOC) == 0
+ || 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)
+ && (r_type != R_386_PC32
+ || !SYMBOL_CALLS_LOCAL (info, h)))
+ || (ELIMINATE_COPY_RELOCS
+@@ -3633,12 +3637,13 @@ elf_i386_relocate_section (bfd *output_bfd,
+ + input_section->output_offset);
+
+ if (skip)
+ 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)
+ || !h->def_regular))
+ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+ else
+@@ -4953,20 +4958,26 @@ elf_i386_add_symbol_hook (bfd * abfd,
+ #define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol
+ #define elf_backend_relocs_compatible _bfd_elf_relocs_compatible
+ #define elf_backend_check_relocs elf_i386_check_relocs
+ #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 \
+ ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
+ #define elf_backend_plt_sym_val elf_i386_plt_sym_val
+ #define elf_backend_hash_symbol elf_i386_hash_symbol
+diff --git a/bfd/elf32-morphos.c b/bfd/elf32-morphos.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..accc2d426bede6c9441313115fcd5ab5f99630f9
+--- /dev/null
++++ bfd/elf32-morphos.c
+@@ -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 --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
+index 6454a8350da35adf6ed1e2209d9e4774ab7c50e3..5c92c53da7b3dec8f85a0a0b930190635f89dcfb 100644
+--- bfd/elf32-ppc.c
++++ bfd/elf32-ppc.c
+@@ -4412,12 +4412,16 @@ ppc_elf_check_relocs (bfd *abfd,
+ p->count += 1;
+ if (!must_be_dyn_reloc (info, r_type))
+ p->pc_count += 1;
+ }
+
+ break;
++
++ default:
++ fprintf(stderr,"Switch case not handled!\n");
++ break;
+ }
+ }
+
+ return TRUE;
+ }
+
+diff --git a/bfd/hosts/amigaos.h b/bfd/hosts/amigaos.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..dc62d7f837f333ae8d2c5b47d01144cb0d3625f2
+--- /dev/null
++++ bfd/hosts/amigaos.h
+@@ -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 --git a/bfd/hosts/morphos.h b/bfd/hosts/morphos.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..d3c60ea9f5767ad0bfa22ba2c8c1e5ed9d94d481
+--- /dev/null
++++ bfd/hosts/morphos.h
+@@ -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 --git a/bfd/libamiga.h b/bfd/libamiga.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..351f0fa16a45680982f5b5807c8ba756defe1764
+--- /dev/null
++++ bfd/libamiga.h
+@@ -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 --git a/bfd/libbfd.h b/bfd/libbfd.h
+index 6c48d641f606b9ed6158b4567021769bacfbd54a..3cb9b36fe2379a5d7f118472e106c151d6153aea 100644
+--- bfd/libbfd.h
++++ bfd/libbfd.h
+@@ -1345,12 +1345,16 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
+ "BFD_RELOC_PPC_EMB_RELSEC16",
+ "BFD_RELOC_PPC_EMB_RELST_LO",
+ "BFD_RELOC_PPC_EMB_RELST_HI",
+ "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",
+ "BFD_RELOC_PPC_VLE_LO16A",
+ "BFD_RELOC_PPC_VLE_LO16D",
+ "BFD_RELOC_PPC_VLE_HI16A",
+@@ -1427,12 +1431,16 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
+ "BFD_RELOC_PPC64_DTPREL16_DS",
+ "BFD_RELOC_PPC64_DTPREL16_LO_DS",
+ "BFD_RELOC_PPC64_DTPREL16_HIGHER",
+ "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_I370_D12",
+ "BFD_RELOC_CTOR",
+ "BFD_RELOC_ARM_PCREL_BRANCH",
+ "BFD_RELOC_ARM_PCREL_BLX",
+ "BFD_RELOC_THUMB_PCREL_BLX",
+ "BFD_RELOC_ARM_PCREL_CALL",
+diff --git a/bfd/linker.c b/bfd/linker.c
+index d3ef9a43a5bca8096221870248daf58007c6ef78..4f0aa188f5017ea68023530f6ae9eaa6b98b5b11 100644
+--- bfd/linker.c
++++ bfd/linker.c
+@@ -430,13 +430,14 @@ static bfd_boolean generic_link_add_symbol_list
+ (bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
+ bfd_boolean);
+ static bfd_boolean generic_add_output_symbol
+ (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);
+
+ /* The link hash table structure is defined in bfdlink.h. It provides
+ a base hash table which the backend specific hash tables are built
+ upon. */
+@@ -1294,12 +1295,19 @@ generic_link_check_archive_element (bfd *abfd,
+ return FALSE;
+
+ size = bfd_asymbol_value (p);
+ 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;
+
+ if (p->section == bfd_com_section_ptr)
+ h->u.c.p->section = bfd_make_section_old_way (symbfd, "COMMON");
+@@ -1746,12 +1754,19 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
+ /* Select a default alignment based on the size. This may
+ be overridden by the caller. */
+ {
+ 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;
+ }
+
+ /* The section of a common symbol is only used if the common
+@@ -1799,12 +1814,19 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
+
+ h->u.c.size = value;
+
+ /* 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;
+
+ /* Some systems have special treatment for small commons,
+ hence we want to select the section used by the larger
+@@ -2709,13 +2731,13 @@ default_data_link_order (bfd *abfd,
+ free (fill);
+ return result;
+ }
+
+ /* 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,
+ struct bfd_link_order *link_order,
+ bfd_boolean generic_linker)
+ {
+diff --git a/bfd/reloc.c b/bfd/reloc.c
+index 47d052d1345847a7178f4c7ebe4f529396ae0a4f..6c3bb68f2da65b201b6288b8709fd60d9b0d5b2c 100644
+--- bfd/reloc.c
++++ bfd/reloc.c
+@@ -2803,12 +2803,20 @@ ENUMX
+ BFD_RELOC_PPC_EMB_RELST_HA
+ ENUMX
+ BFD_RELOC_PPC_EMB_BIT_FLD
+ 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
+ ENUMX
+ BFD_RELOC_PPC_VLE_REL24
+ ENUMX
+@@ -2973,12 +2981,23 @@ ENUMX
+ ENUMX
+ BFD_RELOC_PPC64_DTPREL16_HIGHESTA
+ ENUMDOC
+ 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
+
+ ENUM
+ BFD_RELOC_CTOR
+diff --git a/bfd/targets.c b/bfd/targets.c
+index fa206d24bef3a22255f6be42221647db3142eb06..9df24504bab564048f724fbbb641ca13c5805602 100644
+--- bfd/targets.c
++++ bfd/targets.c
+@@ -144,12 +144,13 @@ DESCRIPTION
+ the entry points which call them. Too bad we can't have one
+ macro to define them both!
+
+ .enum bfd_flavour
+ .{
+ . bfd_target_unknown_flavour,
++. bfd_target_amiga_flavour,
+ . bfd_target_aout_flavour,
+ . bfd_target_coff_flavour,
+ . bfd_target_ecoff_flavour,
+ . bfd_target_xcoff_flavour,
+ . bfd_target_elf_flavour,
+ . bfd_target_ieee_flavour,
+@@ -568,12 +569,14 @@ to find an alternative output format that is suitable.
+ /* All known xvecs (even those that don't compile on all systems).
+ Alphabetized for easy reference.
+ They are listed a second time below, since
+ 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;
+ extern const bfd_target aout_mips_big_vec;
+ extern const bfd_target aout_mips_little_vec;
+ extern const bfd_target apollocoff_vec;
+@@ -592,12 +595,13 @@ extern const bfd_target armpe_big_vec;
+ extern const bfd_target armpe_little_vec;
+ extern const bfd_target armpei_big_vec;
+ extern const bfd_target armpei_little_vec;
+ 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;
+ extern const bfd_target bfd_elf32_big_generic_vec;
+ extern const bfd_target bfd_elf32_bigarc_vec;
+ extern const bfd_target bfd_elf32_bigarm_vec;
+@@ -625,12 +629,13 @@ extern const bfd_target bfd_elf32_hppa_vec;
+ extern const bfd_target bfd_elf32_i370_vec;
+ extern const bfd_target bfd_elf32_i386_freebsd_vec;
+ extern const bfd_target bfd_elf32_i386_nacl_vec;
+ 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;
+ extern const bfd_target bfd_elf32_ia64_big_vec;
+ extern const bfd_target bfd_elf32_ia64_hpux_big_vec;
+ extern const bfd_target bfd_elf32_ip2k_vec;
+@@ -658,12 +663,13 @@ extern const bfd_target bfd_elf32_mcore_big_vec;
+ extern const bfd_target bfd_elf32_mcore_little_vec;
+ extern const bfd_target bfd_elf32_mep_vec;
+ extern const bfd_target bfd_elf32_mep_little_vec;
+ 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_nbigmips_vec;
+ extern const bfd_target bfd_elf32_nlittlemips_vec;
+ extern const bfd_target bfd_elf32_ntradbigmips_vec;
+ extern const bfd_target bfd_elf32_ntradlittlemips_vec;
+@@ -929,12 +935,14 @@ static const bfd_target * const _bfd_target_vector[] =
+ should have an entry here with #if 0 around it, to show that
+ it wasn't omitted by mistake. */
+ &a_out_adobe_vec,
+ #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. */
+ &aout_arm_big_vec,
+ &aout_arm_little_vec,
+ /* No one seems to use this. */
+@@ -961,12 +969,13 @@ static const bfd_target * const _bfd_target_vector[] =
+ &armpei_little_vec,
+ &b_out_vec_big_host,
+ &b_out_vec_little_host,
+ #ifdef BFD64
+ &bfd_pei_ia64_vec,
+ #endif
++ &bfd_elf32_amigaos_vec,
+ &bfd_elf32_avr_vec,
+ &bfd_elf32_bfin_vec,
+ &bfd_elf32_bfinfdpic_vec,
+
+ /* This, and other vectors, may not be used in any *.mt configuration.
+ But that does not mean they are unnecessary. If configured with
+@@ -998,12 +1007,13 @@ static const bfd_target * const _bfd_target_vector[] =
+ &bfd_elf32_i370_vec,
+ &bfd_elf32_i386_freebsd_vec,
+ &bfd_elf32_i386_nacl_vec,
+ &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,
+ #if 0
+ &bfd_elf32_ia64_big_vec,
+ #endif
+@@ -1032,12 +1042,13 @@ static const bfd_target * const _bfd_target_vector[] =
+ &bfd_elf32_mcore_big_vec,
+ &bfd_elf32_mcore_little_vec,
+ &bfd_elf32_mep_vec,
+ &bfd_elf32_microblaze_vec,
+ &bfd_elf32_mn10200_vec,
+ &bfd_elf32_mn10300_vec,
++ &bfd_elf32_morphos_vec,
+ &bfd_elf32_mt_vec,
+ &bfd_elf32_msp430_vec,
+ #ifdef BFD64
+ &bfd_elf32_nbigmips_vec,
+ &bfd_elf32_nlittlemips_vec,
+ &bfd_elf32_ntradbigmips_vec,
+diff --git a/binutils/objcopy.c b/binutils/objcopy.c
+index 020d54d6fbe27a5c90600e1d034a93e8fade0ff6..88bd071eefa8b5426eaadfd6431e9de5d4a4591b 100644
+--- binutils/objcopy.c
++++ binutils/objcopy.c
+@@ -1101,12 +1101,17 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
+ bfd_boolean undefined;
+ bfd_boolean rem_leading_char;
+ 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)
+ {
+ char *old_name, *new_name;
+
+ old_name = (char *) bfd_asymbol_name (sym);
+ new_name = (char *) lookup_sym_redefinition (old_name);
+@@ -1162,13 +1167,18 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
+ strcpy (ptr, name);
+ bfd_asymbol_name (sym) = n;
+ name = n;
+ }
+
+ 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
+ & BSF_KEEP) != 0))
+ {
+ keep = TRUE;
+@@ -1925,13 +1935,13 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
+
+ Note we iterate over the input sections examining their
+ relocations since the relocations for the output sections
+ 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);
+ osympp = (asymbol **) xmalloc ((symcount + 1) * sizeof (asymbol *));
+ symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount);
+ }
+@@ -2745,25 +2755,48 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
+ status = 1;
+ bfd_nonfatal_message (NULL, ibfd, isection,
+ _("relocation count is negative"));
+ 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. */
+ arelent **temp_relpp;
+ long temp_relcount = 0;
+ long i;
+
+ 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;
+ }
+
+ bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
+@@ -3155,13 +3188,17 @@ strip_main (int argc, char *argv[])
+
+ if (show_version)
+ print_version ("strip");
+
+ 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)
+ strip_symbols = STRIP_ALL;
+
+ if (output_target == NULL)
+@@ -3992,12 +4029,17 @@ copy_main (int argc, char *argv[])
+ if (show_version)
+ print_version ("objcopy");
+
+ 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"));
+
+ if (copy_width > interleave - copy_byte)
+ fatal (_("interleave width must be less than or equal to interleave - byte`"));
+
+diff --git a/binutils/readelf.c b/binutils/readelf.c
+index d9ec436af6fbea0bbc3dfa8e9cd40fcf9be140cf..f52d7168af3bc6559bd2483ff1fc126da385b38d 100644
+--- binutils/readelf.c
++++ binutils/readelf.c
+@@ -150,12 +150,13 @@
+ #include "elf/vax.h"
+ #include "elf/x86-64.h"
+ #include "elf/xc16x.h"
+ #include "elf/xgate.h"
+ #include "elf/xstormy16.h"
+ #include "elf/xtensa.h"
++#include "elf/amigaos.h"
+
+ #include "getopt.h"
+ #include "libiberty.h"
+ #include "safe-ctype.h"
+ #include "filenames.h"
+
+@@ -1520,12 +1521,13 @@ static const char *
+ get_ppc_dynamic_type (unsigned long type)
+ {
+ switch (type)
+ {
+ case DT_PPC_GOT: return "PPC_GOT";
+ case DT_PPC_TLSOPT: return "PPC_TLSOPT";
++ case DT_AMIGAOS_DYNVERSION: return "AMIGAOS_DYNVERSION";
+ default:
+ return NULL;
+ }
+ }
+
+ static const char *
+@@ -1789,12 +1791,15 @@ get_dynamic_type (unsigned long type)
+ && (type >= OLD_DT_LOOS) && (type <= OLD_DT_HIOS)))
+ {
+ const char * result;
+
+ 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;
+ case EM_IA_64:
+ result = get_ia64_dynamic_type (type);
+ break;
+diff --git a/binutils/rename.c b/binutils/rename.c
+index 5923a3f4ce2b2b5b0da96ff8225bf3c7750563bc..354b6fd1eab7f632995fed27698c76826ee8e753 100644
+--- binutils/rename.c
++++ binutils/rename.c
+@@ -27,13 +27,13 @@
+ #else /* ! HAVE_GOOD_UTIME_H */
+ #ifdef HAVE_UTIMES
+ #include <sys/time.h>
+ #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. */
+ #define COPY_BUF 8192
+
+ /* Copy file FROM to file TO, performing no translations.
+@@ -140,13 +140,13 @@ smart_rename (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNU
+ bfd_boolean exists;
+ struct stat s;
+ int ret = 0;
+
+ 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. */
+
+ if (exists)
+ remove (to);
+
+diff --git a/config.sub b/config.sub
+index 59bb593f109c8d795df4cbb96b015222eed91c07..88ccfd90050ad0d8d341c091b9920f62fc5996f8 100755
+--- config.sub
++++ config.sub
+@@ -353,13 +353,13 @@ case $basic_machine in
+ basic_machine=armel-unknown
+ ;;
+
+ # 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.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+@@ -482,17 +482,14 @@ case $basic_machine in
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ 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)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+@@ -1345,13 +1342,13 @@ case $os in
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* \
+ | -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* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+diff --git a/config/mh-amigaos b/config/mh-amigaos
+new file mode 100644
+index 0000000000000000000000000000000000000000..4889ea41c6889e2e15c06c8f355c30b5eb2aa5f4
+--- /dev/null
++++ config/mh-amigaos
+@@ -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 --git a/config/mh-morphos b/config/mh-morphos
+new file mode 100644
+index 0000000000000000000000000000000000000000..c00202aec0389eaa067ea48818a7d8fa4fd5fc6b
+--- /dev/null
++++ config/mh-morphos
+@@ -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 --git a/configure b/configure
+index 6079e6c07511e12bb51ae5197e7110d79c36b098..9667d72a79baf032fa22e054b88fb03e64673b63 100755
+--- configure
++++ configure
+@@ -3630,12 +3630,15 @@ case "${noconfigdirs}" in
+ esac
+
+ # Work in distributions that contain no compiler tools, like Autoconf.
+ 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"
+ ;;
+ *-cygwin*)
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if cat works as expected" >&5
+@@ -3674,12 +3677,15 @@ fi
+ hppa*-*)
+ host_makefile_frag="config/mh-pa"
+ ;;
+ *-*-darwin*)
+ host_makefile_frag="config/mh-darwin"
+ ;;
++ *-morphos*)
++ host_makefile_frag="config/mh-morphos"
++ ;;
+ powerpc-*-aix*)
+ host_makefile_frag="config/mh-ppc-aix"
+ ;;
+ rs6000-*-aix*)
+ host_makefile_frag="config/mh-ppc-aix"
+ ;;
+diff --git a/configure.ac b/configure.ac
+index 5efb4a32f114f23b90f838a5108f5016dc01bf43..fea7239acf315d982587796d8b93de4c894a14d8 100644
+--- configure.ac
++++ configure.ac
+@@ -1056,12 +1056,15 @@ case "${noconfigdirs}" in
+ esac
+
+ # Work in distributions that contain no compiler tools, like Autoconf.
+ 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"
+ ;;
+ *-cygwin*)
+ ACX_CHECK_CYGWIN_CAT_WORKS
+ host_makefile_frag="config/mh-cygwin"
+@@ -1081,12 +1084,15 @@ case "${host}" in
+ hppa*-*)
+ host_makefile_frag="config/mh-pa"
+ ;;
+ *-*-darwin*)
+ host_makefile_frag="config/mh-darwin"
+ ;;
++ *-morphos*)
++ host_makefile_frag="config/mh-morphos"
++ ;;
+ powerpc-*-aix*)
+ host_makefile_frag="config/mh-ppc-aix"
+ ;;
+ rs6000-*-aix*)
+ host_makefile_frag="config/mh-ppc-aix"
+ ;;
+diff --git a/gas/ChangeLog-9697 b/gas/ChangeLog-9697
+index f39e99554e87446d7eb8f0869701984c5df2137d..08dbfbc1d36608ec8e553593d445431cb1792cc5 100644
+--- gas/ChangeLog-9697
++++ gas/ChangeLog-9697
+@@ -874,12 +874,18 @@ Tue Aug 26 12:23:25 1997 Ian Lance Taylor <ian@cygnus.com>
+ Gabriel Paubert <paubert@iram.es>.
+
+ * config/tc-i386.c (md_assemble): In JumpByte case, when looking
+ for a WORD_PREFIX_OPCODE, change it to ADDR_PREFIX_OPCODE if this
+ is jcxz or a loop instruction.
+
++Mon Aug 25 16:32:00 1997 Steffen Opel <opel@rumms.uni-mannheim.de>
++
++ * Makefile.in (guide, install-guide, clean-guide): New targets
++ for AmigaGuide documentation.
++ (install): Add install-info and install-guide.
++
+ Mon Aug 25 16:04:14 1997 Nick Clifton <nickc@cygnus.com>
+
+ * config/tc-v850.c (pre_defined_registers): Add 'hp' as alias for
+ r2.
+ (md_begin): Set up machine architecture and type.
+
+@@ -3386,12 +3392,18 @@ Mon Nov 18 15:22:28 1996 Michael Meissner <meissner@tiktok.cygnus.com>
+ * config/tc-d10v.c (parallel_ok): Branch and link instructions
+ modify r13.
+ (write_2_short): Call parallel_ok to check whether two short
+ instructions the user requested execute in parallel, can be
+ executed that way.
+
++Sun Nov 17 21:09:55 1996 Kamil Iskra <iskra@student.uci.agh.edu.pl>
++
++ * config/tc-m68k.c (md_estimate_size_before_relax): Do not
++ output 'bsrl' instructions for external function calls when
++ compiling with '-m68020' or higher.
++
+ Thu Nov 14 11:17:49 1996 Martin M. Hunt <hunt@pizza.cygnus.com>
+
+ * config/tc-d10v.c (write_2_short): Fix bug that wouldn't
+ allow a branch and link in parallel with an exe instruction.
+
+ Fri Nov 8 13:55:03 1996 Martin M. Hunt <hunt@pizza.cygnus.com>
+diff --git a/gas/ChangeLog-9899 b/gas/ChangeLog-9899
+index ae38e5dd9223cf4e26355263197ea9f2cd0296c0..76861df24938b7ec7a3051da5cf20c44465b145e 100644
+--- gas/ChangeLog-9899
++++ gas/ChangeLog-9899
+@@ -3574,12 +3574,16 @@ Wed Jun 3 14:10:36 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ Wed Jun 3 09:16:00 1998 Catherine Moore <clm@cygnus.com>
+
+ * config/tc-v850.c (md_begin): Don't create special
+ sections by default.
+
++1998-06-02 David Zaroski <zaroski@firewall.ninemoons.com>
++
++ * config/tc-m68k.c: Add missing param to add_fix in "case '_'"
++
+ Tue Jun 2 14:52:56 1998 Jeffrey A Law (law@cygnus.com)
+
+ * config/tc-mips.c (macro): For div and udiv, close the
+ reorder block as soon as possible.
+
+ Tue Jun 2 15:36:13 1998 Ian Lance Taylor <ian@cygnus.com>
+diff --git a/gas/Makefile.am b/gas/Makefile.am
+index 256e2322fd80f84d8fa8fab735c85446dff4f506..851de3dc36be1138ad52026f7ace0ebd49da94b6 100644
+--- gas/Makefile.am
++++ gas/Makefile.am
+@@ -245,23 +245,25 @@ TARGET_CPU_HFILES = \
+ config/tc-z8k.h \
+ config/xtensa-relax.h
+
+ # OBJ files in config
+
+ OBJ_FORMAT_CFILES = \
++ config/obj-amigahunk.c \
+ config/obj-aout.c \
+ config/obj-coff.c \
+ config/obj-ecoff.c \
+ config/obj-elf.c \
+ config/obj-evax.c \
+ config/obj-fdpicelf.c \
+ config/obj-macho.c \
+ config/obj-multi.c \
+ config/obj-som.c
+
+ OBJ_FORMAT_HFILES = \
++ config/obj-amigahunk.h \
+ config/obj-aout.h \
+ config/obj-coff.h \
+ config/obj-ecoff.h \
+ config/obj-elf.h \
+ config/obj-evax.h \
+ config/obj-fdpicelf.h \
+@@ -271,12 +273,13 @@ OBJ_FORMAT_HFILES = \
+
+ # Emulation header files in config
+
+ 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 \
+ config/te-epoc-pe.h \
+ config/te-freebsd.h \
+ config/te-generic.h \
+@@ -342,13 +345,13 @@ EXTRA_SCRIPTS = .gdbinit
+
+ EXTRA_DIST = m68k-parse.c itbl-parse.c itbl-parse.h itbl-lex.c \
+ bfin-parse.c bfin-parse.h bfin-lex.c \
+ 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
+
+ # Now figure out from those variables how to compile and link.
+
+ BASEDIR = $(srcdir)/..
+diff --git a/gas/Makefile.in b/gas/Makefile.in
+index 94812d96db9cb13bdbdd0243a6b9a021e95e0a0b..c04f7d53feacb96ac3a82109375c3c94bcb15d56 100644
+--- gas/Makefile.in
++++ gas/Makefile.in
+@@ -513,23 +513,25 @@ TARGET_CPU_HFILES = \
+ config/tc-z8k.h \
+ config/xtensa-relax.h
+
+
+ # OBJ files in config
+ OBJ_FORMAT_CFILES = \
++ config/obj-amigahunk.c \
+ config/obj-aout.c \
+ config/obj-coff.c \
+ config/obj-ecoff.c \
+ config/obj-elf.c \
+ config/obj-evax.c \
+ config/obj-fdpicelf.c \
+ config/obj-macho.c \
+ config/obj-multi.c \
+ config/obj-som.c
+
+ OBJ_FORMAT_HFILES = \
++ config/obj-amigahunk.h \
+ config/obj-aout.h \
+ config/obj-coff.h \
+ config/obj-ecoff.h \
+ config/obj-elf.h \
+ config/obj-evax.h \
+ config/obj-fdpicelf.h \
+@@ -539,12 +541,13 @@ OBJ_FORMAT_HFILES = \
+
+
+ # Emulation header files in config
+ 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 \
+ config/te-epoc-pe.h \
+ config/te-freebsd.h \
+ config/te-generic.h \
+@@ -776,12 +779,13 @@ distclean-compile:
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/itbl-parse.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listing.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/literal.Po@am__quote@
+ @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@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-elf.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-evax.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-fdpicelf.Po@am__quote@
+@@ -1836,12 +1840,26 @@ xtensa-relax.obj: config/xtensa-relax.c
+ @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xtensa-relax.obj -MD -MP -MF $(DEPDIR)/xtensa-relax.Tpo -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`
+ @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xtensa-relax.Tpo $(DEPDIR)/xtensa-relax.Po
+ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/xtensa-relax.c' object='xtensa-relax.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 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
+ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/obj-aout.c' object='obj-aout.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-aout.o `test -f 'config/obj-aout.c' || echo '$(srcdir)/'`config/obj-aout.c
+@@ -2411,13 +2429,13 @@ uninstall-am:
+ tags tags-recursive uninstall uninstall-am
+
+ po/POTFILES.in: @MAINT@ Makefile
+ 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 \
+ true; \
+ else \
+ mkdir testsuite; \
+diff --git a/gas/as.c b/gas/as.c
+index fa4141f92bc887cfd403ec3eb93a7a20f26b642a..7b35f0e3f23662e09e8ce56c525239cf68b5dd3a 100644
+--- gas/as.c
++++ gas/as.c
+@@ -105,12 +105,17 @@ int keep_it = 0;
+ segT reg_section;
+ segT expr_section;
+ segT text_section;
+ 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;
+
+ static struct defsym_list *defsyms;
+
+ #ifdef HAVE_ITBL_CPU
+@@ -1046,22 +1051,31 @@ perform_an_assembly_pass (int argc, char ** argv)
+ #ifndef OBJ_MACH_O
+ /* Create the standard sections, and those the assembler uses
+ internally. */
+ 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);
+ bfd_set_section_flags (stdoutput, text_section,
+ applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC
+ | SEC_CODE | SEC_READONLY));
+ bfd_set_section_flags (stdoutput, data_section,
+ 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);
+ subseg_new (BFD_UND_SECTION_NAME, 0);
+ reg_section = subseg_new ("*GAS `reg' section*", 0);
+ expr_section = subseg_new ("*GAS `expr' section*", 0);
+diff --git a/gas/config/m68k-parse.h b/gas/config/m68k-parse.h
+index 4f91385f9222dc52c8cc9f490860729c2183e445..08e766c5523b90ac3cd2d685b239c0a7ed4d8230 100644
+--- gas/config/m68k-parse.h
++++ gas/config/m68k-parse.h
+@@ -293,12 +293,15 @@ struct m68k_exp
+ /* The type of pic relocation if any. */
+ enum pic_relocation pic_reloc;
+ #endif
+
+ /* The expression itself. */
+ expressionS exp;
++
++ /* base-relative? */
++ short baserel;
+ };
+
+ /* The operand modes. */
+
+ enum m68k_operand_type
+ {
+diff --git a/gas/config/m68k-parse.y b/gas/config/m68k-parse.y
+index 2c58266fb8e6bd8d57515fe5200daaf9a1e450a2..742cbf2eeaaa15766a4d44de76a9d58d56993367 100644
+--- gas/config/m68k-parse.y
++++ gas/config/m68k-parse.y
+@@ -972,31 +972,35 @@ yylex ()
+ else if (parens == 0
+ && (*s == ',' || *s == ']'))
+ break;
+ }
+
+ yylval.exp.size = SIZE_UNSPEC;
++ yylval.exp.baserel = 0;
+ if (s <= str + 2
+ || (s[-2] != '.' && s[-2] != ':'))
+ tail = 0;
+ else
+ {
+ 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:
+ break;
+ }
+ if (yylval.exp.size != SIZE_UNSPEC)
+diff --git a/gas/config/obj-amigahunk.c b/gas/config/obj-amigahunk.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..8755475ecfdfd5aafbf876ed1f87c9d343b560e9
+--- /dev/null
++++ gas/config/obj-amigahunk.c
+@@ -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 --git a/gas/config/obj-amigahunk.h b/gas/config/obj-amigahunk.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..0b7d80eeb291878dc871ce0591b2223bf6cb1de2
+--- /dev/null
++++ gas/config/obj-amigahunk.h
+@@ -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 --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
+index d7c766513ccc4111f51904a7e01904b7ebe96a03..bb8d9d1ebee6b76deee86848202fd06d5b1a4dfa 100644
+--- gas/config/obj-elf.c
++++ gas/config/obj-elf.c
+@@ -1390,13 +1390,13 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
+ if (bad)
+ return NULL;
+
+ 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
+ to the linker that a vtable slot was used. The syntax is
+ ".vtable_entry tablename, offset". */
+
+@@ -1423,13 +1423,13 @@ obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED)
+
+ offset = get_absolute_expression ();
+
+ 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);
+ }
+
+ void
+ elf_obj_read_begin_hook (void)
+ {
+ #ifdef NEED_ECOFF_DEBUG
+diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
+index de132d69d7ac3f854ea517a15267e8c75365714d..14b67f0506eacf6d3dbb11dbd08689fa69354678 100644
+--- gas/config/tc-i386.h
++++ gas/config/tc-i386.h
+@@ -24,13 +24,20 @@
+ #define TC_I386 1
+
+ #include "opcodes/i386-opc.h"
+
+ 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 ())
+ extern enum bfd_architecture i386_arch (void);
+ extern unsigned long i386_mach (void);
+
+@@ -64,12 +71,16 @@ extern unsigned long i386_mach (void);
+ #elif defined (TE_NACL)
+ #define ELF_TARGET_FORMAT "elf32-i386-nacl"
+ #define ELF_TARGET_FORMAT32 "elf32-x86-64-nacl"
+ #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"
+ #endif
+
+ #ifndef ELF_TARGET_FORMAT
+@@ -133,13 +144,13 @@ extern const char *i386_comment_chars;
+
+ #if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && !defined (LEX_AT)
+ #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) x86_cons (EXP, NBYTES)
+ #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 *);
+
+ #define TC_ADDRESS_BYTES x86_address_bytes
+ extern int x86_address_bytes (void);
+
+@@ -220,13 +231,13 @@ if (fragP->fr_type == rs_align_code) \
+ void i386_print_statistics (FILE *);
+ #define tc_print_statistics i386_print_statistics
+
+ 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
+ {
+ PROCESSOR_UNKNOWN,
+ PROCESSOR_I386,
+ PROCESSOR_I486,
+diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c
+index 21accf605b22ebc5af491e173faeef93888b6667..8b5f6c60f2141ee91d6e9d1d639815abdf4e5042 100644
+--- gas/config/tc-m68k.c
++++ gas/config/tc-m68k.c
+@@ -35,12 +35,22 @@
+ #endif
+
+ #ifdef M68KCOFF
+ #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
+
+ /* This string holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful. The macro
+@@ -81,12 +91,13 @@ const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
+ to denote pic relocations. */
+ int flag_want_pic;
+
+ 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;
+ #else
+ int flag_reg_prefix_optional;
+ #endif
+@@ -388,12 +399,13 @@ struct m68k_it
+ int pcrel_fix;
+ #ifdef OBJ_ELF
+ /* Whether this expression needs special pic relocation, and if
+ so, which. */
+ enum pic_relocation pic_reloc;
+ #endif
++ char baserel;
+ }
+ reloc[5]; /* Five is enough??? */
+ };
+
+ #define cpu_of_arch(x) ((x) & (m68000up | mcfisa_a | fido_a))
+ #define float_of_arch(x) ((x) & mfloat)
+@@ -438,26 +450,27 @@ insop (int w, const struct m68k_incant *opcode)
+ the_ins.numo++;
+ }
+
+ /* 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
+ : (width == 'b'
+ ? the_ins.numo * 2 + 1
+ : the_ins.numo * 2));
+ the_ins.reloc[the_ins.nrel].exp = exp->exp;
+ the_ins.reloc[the_ins.nrel].wid = width;
+ the_ins.reloc[the_ins.nrel].pcrel_fix = pc_fix;
+ #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
+ (that value is chosen in the frag_var call in md_assemble). TYPE
+ is the subtype of the frag to be generated; its primary type is
+ rs_machine_dependent.
+@@ -807,12 +820,24 @@ static void m68k_init_arch (void);
+
+ /* This relaxation is required for branches where there is no long
+ branch and we are in pcrel mode. We generate a bne/beq pair. */
+ #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
+
+ /* The fields are:
+ How far Forward this mode will reach:
+@@ -869,17 +894,27 @@ relax_typeS md_relax_table[] =
+ { 1, 1, 0, 0 },
+
+ { 1, 1, 0, 0 }, /* ABSTOPCREL doesn't come BYTE. */
+ { 32767, -32768, 2, TAB (ABSTOPCREL, LONG) },
+ { 0, 0, 4, 0 },
+ { 1, 1, 0, 0 },
+-
++
+ { 127, -128, 0, TAB (BRANCHBWPL, SHORT) },
+ { 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
+ the assembler can work on the output from the SUN C compiler, which
+ generates these. */
+
+@@ -1314,12 +1349,23 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("Cannot make %s relocation PC relative"),
+ bfd_get_reloc_code_name (code));
+ }
+ }
+ }
++ 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))
+ switch (F (fixp->fx_size, fixp->fx_pcrel))
+ {
+ #define MAP(SZ,PCREL,TYPE) case F(SZ,PCREL): code = (TYPE); break
+@@ -2510,13 +2556,24 @@ m68k_ip (char *instring)
+ tmpreg = 0x3c; /* 7.4 */
+ if (strchr ("bwl", s[1]))
+ nextword = get_num (&opP->disp, 90);
+ 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':
+ if (!isbyte (nextword))
+ opP->error = _("operand out of range");
+ addword (nextword);
+@@ -2679,26 +2736,26 @@ m68k_ip (char *instring)
+ relocation it cannot be relaxed. */
+ || opP->disp.pic_reloc != pic_none
+ #endif
+ )
+ {
+ addword (0x0170);
+- add_fix ('l', &opP->disp, 1, 2);
++ add_fix ('l', &opP->disp, 1, 2, opP->disp.baserel);
+ }
+ else
+ {
+ add_frag (adds (&opP->disp),
+ SEXT (offs (&opP->disp)),
+ TAB (PCREL1632, SZ_UNDEF));
+ break;
+ }
+ }
+ else
+ {
+ addword (0x0170);
+- add_fix ('l', &opP->disp, 0, 0);
++ add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel);
+ }
+ }
+ else
+ addword (0x0170);
+ addword (nextword >> 16);
+ }
+@@ -2710,16 +2767,16 @@ m68k_ip (char *instring)
+ tmpreg = 0x28 + opP->reg - ADDR; /* 5.areg */
+
+ if (isvar (&opP->disp))
+ {
+ 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);
+ break;
+
+ case POST:
+@@ -2823,15 +2880,15 @@ m68k_ip (char *instring)
+ if (isvar (&opP->disp))
+ {
+ /* Do a byte relocation. If it doesn't
+ 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)
+ {
+ if (siz1 != SIZE_UNSPEC)
+ as_warn (_("Forcing byte displacement"));
+ if (! issbyte (baseo))
+@@ -2956,23 +3013,23 @@ m68k_ip (char *instring)
+ }
+ addword (nextword);
+
+ 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);
+ if (siz1 != SIZE_UNSPEC)
+ 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)
+ addword (outro);
+
+ break;
+@@ -3006,27 +3063,36 @@ m68k_ip (char *instring)
+ SEXT (offs (&opP->disp)),
+ TAB (ABSTOPCREL, SZ_UNDEF));
+ break;
+ }
+ /* 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);
+ addword (nextword);
+ break;
+
+ case SIZE_BYTE:
+ as_bad (_("unsupported byte value; use a different suffix"));
+ /* Fall through. */
+
+ 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);
+ break;
+ }
+ break;
+@@ -3066,13 +3132,13 @@ m68k_ip (char *instring)
+ default:
+ tmpreg = 90;
+ break;
+ }
+ 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
+ certain types of overflow.
+ user beware! */
+ if (!isbyte (tmpreg))
+@@ -3133,22 +3199,22 @@ m68k_ip (char *instring)
+ case 'B':
+ tmpreg = get_num (&opP->disp, 90);
+
+ 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;
+ case 'g': /* Conditional branch */
+ have_disp = HAVE_LONG_CALL (current_architecture);
+ goto var_branch;
+@@ -3188,13 +3254,13 @@ m68k_ip (char *instring)
+ else /* jCC */
+ {
+ the_ins.opcode[0] ^= 0x0100;
+ 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;
+ }
+
+ /* Now we know it's going into the relaxer. Now figure
+@@ -3239,26 +3305,26 @@ m68k_ip (char *instring)
+ else
+ add_frag (adds (&opP->disp),
+ SEXT (offs (&opP->disp)),
+ 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;
+ case 'c': /* Var size Coprocesssor branches. */
+ 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);
+ }
+ else
+ add_frag (adds (&opP->disp),
+ SEXT (offs (&opP->disp)),
+@@ -3706,13 +3772,13 @@ m68k_ip (char *instring)
+ case 't':
+ tmpreg = get_num (&opP->disp, 20);
+ install_operand (s[1], tmpreg);
+ 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);
+ break;
+ case 'u':
+ install_operand (s[1], opP->reg - DATA0L);
+@@ -4055,12 +4121,18 @@ insert_reg (const char *regname, int regnum)
+ struct init_entry
+ {
+ const char *name;
+ int number;
+ };
+
++#if defined(TE_AMIGA)
++ #define FRAME ADDR5
++#else
++ #define FRAME ADDR6
++#endif
++
+ static const struct init_entry init_table[] =
+ {
+ { "d0", DATA0 },
+ { "d1", DATA1 },
+ { "d2", DATA2 },
+ { "d3", DATA3 },
+@@ -4072,13 +4144,13 @@ static const struct init_entry init_table[] =
+ { "a1", ADDR1 },
+ { "a2", ADDR2 },
+ { "a3", ADDR3 },
+ { "a4", ADDR4 },
+ { "a5", ADDR5 },
+ { "a6", ADDR6 },
+- { "fp", ADDR6 },
++ { "fp", FRAME },
+ { "a7", ADDR7 },
+ { "sp", ADDR7 },
+ { "ssp", ADDR7 },
+ { "fp0", FP0 },
+ { "fp1", FP1 },
+ { "fp2", FP2 },
+@@ -4443,13 +4515,14 @@ md_assemble (char *str)
+ ((toP - frag_now->fr_literal)
+ - the_ins.numo * 2 + the_ins.reloc[m].n),
+ n,
+ &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;
+ }
+ return;
+ }
+@@ -4505,13 +4578,14 @@ md_assemble (char *str)
+ ((toP - frag_now->fr_literal)
+ - the_ins.numo * 2 + the_ins.reloc[m].n),
+ wid,
+ &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,
+ (relax_substateT) (the_ins.fragb[n].fragty),
+ the_ins.fragb[n].fadd, the_ins.fragb[n].foff, to_beg_P);
+ }
+@@ -4542,13 +4616,14 @@ md_assemble (char *str)
+ ((the_ins.reloc[m].n + toP - frag_now->fr_literal)
+ - shorts_this_frag * 2),
+ wid,
+ &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;
+ }
+ }
+
+ /* Comparison function used by qsort to rank the opcode entries by name. */
+
+@@ -5058,29 +5133,29 @@ md_convert_frag_1 (fragS *fragP)
+ case TAB (BRANCHBWPL, BYTE):
+ know (issbyte (disp));
+ if (disp == 0)
+ 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):
+ case TAB (BRABSJUNC, SHORT):
+ case TAB (BRABSJCOND, SHORT):
+ case TAB (BRANCHBW, SHORT):
+ 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):
+ /* Here we are converting an unconditional branch into a pair of
+ conditional branches, in order to get the range. */
+ fragP->fr_opcode[0] = 0x66; /* bne */
+@@ -5096,32 +5171,36 @@ md_convert_frag_1 (fragS *fragP)
+ fragP->fr_fix += 2; /* Skip second branch opcode */
+ fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
+ fragP->fr_offset, 1, RELAX_RELOC_PC32);
+ 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)
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("Conversion of PC relative BSR to absolute JSR"));
+ 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 */
+ {
+ if (flag_keep_pcrel)
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("Conversion of PC relative branch to absolute jump"));
+ 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
+ {
+ /* This cannot happen, because jbsr and jbra are the only two
+ unconditional branches. */
+@@ -5142,31 +5221,31 @@ md_convert_frag_1 (fragS *fragP)
+ different frag, in which case referring to them is a no-no.
+ Only fr_opcode[0,1] are guaranteed to work. */
+ *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */
+ *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):
+ /* Only DBcc instructions can come here.
+ Change dbcc into dbcc/bral.
+ JF: these used to be fr_opcode[2-7], but that's wrong. */
+@@ -5180,13 +5259,13 @@ md_convert_frag_1 (fragS *fragP)
+ *buffer_address++ = 0x06;
+ *buffer_address++ = 0x60; /* Put in bral (0x60ff). */
+ *buffer_address++ = (char) 0xff;
+
+ 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):
+ /* Only DBcc instructions can come here.
+ Change dbcc into dbcc/jmp.
+ JF: these used to be fr_opcode[2-7], but that's wrong. */
+@@ -5200,61 +5279,61 @@ md_convert_frag_1 (fragS *fragP)
+ *buffer_address++ = 0x06;
+ *buffer_address++ = 0x4e; /* Put in jmp long (0x4ef9). */
+ *buffer_address++ = (char) 0xf9;
+
+ 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):
+ /* Already set to mode 7.3; this indicates: PC indirect with
+ suppressed index, 32-bit displacement. */
+ *buffer_address++ = 0x01;
+ *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;
+ case TAB (PCINDEX, BYTE):
+ 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):
+ gas_assert (fragP->fr_fix >= 2);
+ 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;
+ case TAB (PCINDEX, LONG):
+ gas_assert (fragP->fr_fix >= 2);
+ 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):
+ if (flag_keep_pcrel)
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("Conversion of PC relative displacement to absolute"));
+@@ -5262,15 +5341,87 @@ md_convert_frag_1 (fragS *fragP)
+ ABSTOPCREL is really trying to shorten an ABSOLUTE address anyway. */
+ if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
+ abort ();
+ 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)
+ {
+ fixP->fx_file = fragP->fr_file;
+ fixP->fx_line = fragP->fr_line;
+ }
+@@ -5300,13 +5451,13 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
+ {
+ if (S_GET_SEGMENT (fragP->fr_symbol) == segment
+ && relaxable_symbol (fragP->fr_symbol))
+ {
+ 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);
+ }
+ else
+ {
+@@ -5372,12 +5523,27 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
+ {
+ fragP->fr_subtype = TAB (ABSTOPCREL, LONG);
+ }
+ 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;
+ }
+
+ /* Now that SZ_UNDEF are taken care of, check others. */
+ switch (fragP->fr_subtype)
+@@ -5434,16 +5600,52 @@ md_ri_to_chars (char *the_bytes, struct reloc_info_generic *ri)
+ /* Now the fun stuff. */
+ the_bytes[4] = (ri->r_symbolnum >> 16) & 0x0ff;
+ the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff;
+ 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 */
+
+ #ifndef WORKING_DOT_WORD
+ int md_short_jump_size = 4;
+ int md_long_jump_size = 6;
+@@ -5472,13 +5674,13 @@ md_create_long_jump (char *ptr, addressT from_addr, addressT to_addr,
+ if (flag_keep_pcrel)
+ as_fatal (_("Tried to convert PC relative branch to absolute jump"));
+ offset = to_addr - S_GET_VALUE (to_symbol);
+ 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
+ {
+ offset = to_addr - (from_addr + 2);
+ md_number_to_chars (ptr, (valueT) 0x60ff, 2);
+ md_number_to_chars (ptr + 2, (valueT) offset, 4);
+@@ -7519,13 +7721,13 @@ m68k_set_extension (char const *name, int allow_m, int silent)
+ Invocation line includes a switch not recognized by the base assembler.
+ */
+
+ #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[] = {
+ #define OPTION_PIC (OPTION_MD_BASE)
+ {"pic", no_argument, NULL, OPTION_PIC},
+ #define OPTION_REGISTER_PREFIX_OPTIONAL (OPTION_MD_BASE + 1)
+@@ -7564,12 +7766,19 @@ md_parse_option (int c, char *arg)
+
+ case OPTION_PCREL: /* --pcrel means never turn PC-relative
+ branches into absolute jumps. */
+ 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;
+ break; /* -pic, Position Independent Code. */
+
+ case OPTION_REGISTER_PREFIX_OPTIONAL:
+@@ -7747,12 +7956,13 @@ md_show_usage (FILE *stream)
+ : m68k_extensions[i].alias < 0 ? " m68k" : "");
+
+ fprintf (stream, _("\
+ -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\
+ --bitwise-or do not treat `|' as a comment character\n\
+ --base-size-default-16 base reg without size is 16 bits\n\
+ --base-size-default-32 base reg without size is 32 bits (default)\n\
+@@ -7913,12 +8123,14 @@ md_pcrel_from (fixS *fixP)
+
+ /* Because fx_pcrel_adjust is a char, and may be unsigned, we explicitly
+ sign extend the value here. */
+ adjust = ((fixP->fx_pcrel_adjust & 0xff) ^ 0x80) - 0x80;
+ if (adjust == 64)
+ adjust = -1;
++ if (OBJ_AMIGAHUNK)
++ return -adjust;
+ return fixP->fx_where + fixP->fx_frag->fr_address - adjust;
+ }
+
+ #ifdef OBJ_ELF
+ void
+ m68k_elf_final_processing (void)
+diff --git a/gas/config/tc-m68k.h b/gas/config/tc-m68k.h
+index bcf4607ebebe16d575166d666a536fb1fbdfeaee..144b7c7d783bab80bd84fa0e57cfce9f349a528f 100644
+--- gas/config/tc-m68k.h
++++ gas/config/tc-m68k.h
+@@ -30,20 +30,27 @@ struct fix;
+ #ifdef TE_SUN3
+ #define TARGET_FORMAT "a.out-sunos-big"
+ #endif
+ #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
+ #ifndef TARGET_FORMAT
+ #define TARGET_FORMAT "a.out-zero-big"
+ #endif
+ #endif
+
++#ifdef OBJ_AMIGAHUNK
++#define TARGET_FORMAT "amiga"
++#endif
++
+ #ifdef OBJ_ELF
+ #define TARGET_FORMAT "elf32-m68k"
+ #endif
+
+ #ifdef TE_APOLLO
+ #define COFF_MAGIC APOLLOM68KMAGIC
+@@ -60,12 +67,17 @@ struct fix;
+
+ #ifndef COFF_MAGIC
+ #define COFF_MAGIC MC68MAGIC
+ #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;
+
+ #define LISTING_WORD_SIZE 2 /* A word is 2 bytes */
+ #define LISTING_LHS_WIDTH 2 /* One word on the first line */
+ #define LISTING_LHS_WIDTH_SECOND 2 /* One word on the second line */
+@@ -152,12 +164,15 @@ extern int m68k_parse_long_option (char *);
+
+ #define TARGET_ARCH bfd_arch_m68k
+
+ 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) \
+ do \
+ { \
+ if (aim == 0 && this_type->rlx_forward == 127) \
+diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
+index 208d76d847128c833f73713eff2b78deb610a764..11949323d80802138ec23fb8174727c0a7c4fd45 100644
+--- gas/config/tc-ppc.c
++++ gas/config/tc-ppc.c
+@@ -1421,22 +1421,28 @@ ppc_target_format (void)
+ # else
+ return (ppc_obj64 ? "aixcoff64-rs6000" : "aixcoff-rs6000");
+ # endif
+ #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)
+ return "elf32-powerpc-vxworks";
+ # else
+ return (target_big_endian
+ ? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc")
+ : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle"));
+ # endif
+ #endif
++#endif
+ }
+
+ /* Validate one entry in powerpc_opcodes[] or vle_opcodes[].
+ Return TRUE if there's a problem, otherwise FALSE. */
+
+ static bfd_boolean
+@@ -1872,12 +1878,24 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
+
+ #define MAP(str, reloc) { str, sizeof (str) - 1, 1, 1, reloc }
+ #define MAP32(str, reloc) { str, sizeof (str) - 1, 1, 0, reloc }
+ #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),
+ MAP ("brtaken", BFD_RELOC_PPC_B16_BRTAKEN),
+ MAP ("brntaken", BFD_RELOC_PPC_B16_BRNTAKEN),
+ MAP ("got", BFD_RELOC_16_GOTOFF),
+@@ -2098,13 +2116,13 @@ ppc_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long, 8=.llong */)
+ p = frag_more (nbytes);
+ memset (p, 0, nbytes);
+ offset = 0;
+ 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
+ emit_expr (&exp, (unsigned int) nbytes);
+ }
+ while (*input_line_pointer++ == ',');
+@@ -3307,25 +3325,25 @@ md_assemble (char *str)
+
+ fixP = fix_new_exp (frag_now,
+ f - frag_now->fr_literal + offset,
+ size,
+ &fixups[i].exp,
+ reloc_howto->pc_relative,
+- fixups[i].reloc);
++ fixups[i].reloc, 0);
+ }
+ else
+ {
+ const struct powerpc_operand *operand;
+
+ operand = &powerpc_operands[fixups[i].opindex];
+ fixP = fix_new_exp (frag_now,
+ f - frag_now->fr_literal,
+ 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;
+ }
+ }
+
+ /* Handle a macro. Gather all the operands, transform them as
+@@ -6650,12 +6668,16 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+ size = 2;
+ break;
+
+ case BFD_RELOC_8:
+ if (fixP->fx_pcrel)
+ {
++ case BFD_RELOC_PPC_MORPHOS_DREL:
++ case BFD_RELOC_PPC_MORPHOS_DREL_LO:
++ case BFD_RELOC_PPC_MORPHOS_DREL_HI:
++ case BFD_RELOC_PPC_MORPHOS_DREL_HA:
+ #ifdef OBJ_ELF
+ bad_pcrel:
+ #endif
+ if (fixP->fx_addsy)
+ {
+ char *sfile;
+@@ -6692,12 +6714,20 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+
+ case BFD_RELOC_VTABLE_ENTRY:
+ fixP->fx_done = 0;
+ 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:
+ if (fixP->fx_pcrel)
+ fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
+ case BFD_RELOC_LO16_PCREL:
+ size = 2;
+diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c
+index 4db1a0913602aaf18d1390cc315f6db0fbdef649..ba0ed8e89e44a9ab8411662047e6f85b4f28d5d9 100644
+--- gas/config/tc-sh.c
++++ gas/config/tc-sh.c
+@@ -800,13 +800,13 @@ sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
+ {
+ error:
+ as_bad (_("unsupported BFD relocation size %u"), size);
+ 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
+ suffixes such as @GOT, @GOTOFF and @PLT, that generate
+ machine-specific relocation types. So we must define it here. */
+ /* Clobbers input_line_pointer, checks end-of-line. */
+@@ -2239,24 +2239,24 @@ insert (char *where, int how, int pcrel, sh_operand_info *op)
+ {
+ fix_new_exp (frag_now,
+ where - frag_now->fr_literal,
+ 2,
+ &op->immediate,
+ pcrel,
+- how);
++ how, 0);
+ }
+
+ static void
+ insert4 (char * where, int how, int pcrel, sh_operand_info * op)
+ {
+ fix_new_exp (frag_now,
+ where - frag_now->fr_literal,
+ 4,
+ & op->immediate,
+ pcrel,
+- how);
++ how, 0);
+ }
+ static void
+ build_relax (sh_opcode_info *opcode, sh_operand_info *op)
+ {
+ int high_byte = target_big_endian ? 0 : 1;
+ char *p;
+@@ -2320,13 +2320,13 @@ insert_loop_bounds (char *output, sh_operand_info *operand)
+ #ifdef OBJ_COFF
+ SF_SET_LOCAL (end_sym);
+ #endif /* OBJ_COFF */
+ 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);
+ output[0] = 0x8e;
+ output[1] = 0x8e;
+ insert (output, BFD_RELOC_SH_LOOP_START, 1, operand);
+@@ -2974,13 +2974,13 @@ md_assemble (char *str)
+ if (sh_relax
+ && ! seg_info (now_seg)->tc_segment_info_data.in_code)
+ {
+ /* 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;
+ }
+
+ if (opcode->nibbles[0] == PPI)
+ {
+ size = assemble_ppi (op_end, opcode);
+@@ -3055,13 +3055,13 @@ sh_frob_label (symbolS *sym)
+ int offset;
+
+ offset = frag_now_fix ();
+ 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;
+ }
+ }
+
+ dwarf2_emit_label (sym);
+@@ -3074,13 +3074,13 @@ void
+ sh_flush_pending_output (void)
+ {
+ if (sh_relax
+ && 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;
+ }
+ }
+
+ symbolS *
+ md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+@@ -3115,13 +3115,13 @@ s_uses (int ignore ATTRIBUTE_UNUSED)
+ {
+ as_bad (_("bad .uses format"));
+ ignore_rest_of_line ();
+ 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 ();
+ }
+
+ enum options
+ {
+@@ -3514,13 +3514,13 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec,
+ /* Generate a BFD_RELOC_SH_COUNT fixup at the location of sym.
+ We have already adjusted the value of sym to include the
+ fragment address, so we undo that adjustment here. */
+ 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);
+ }
+ }
+
+ /* This function is called after the symbol table has been completed,
+ but before the relocs or section contents have been written out.
+ If we have seen any .uses pseudo-ops, they point to an instruction
+@@ -3555,21 +3555,21 @@ md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP)
+ switch (fragP->fr_subtype)
+ {
+ case C (COND_JUMP, COND8):
+ 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;
+
+ 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;
+
+ case C (UNCOND_JUMP, UNCOND32):
+ case C (UNCOND_JUMP, UNDEF_WORD_DISP):
+@@ -3620,19 +3620,19 @@ md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP)
+ its delay-slot insn already makes the branch reach. */
+
+ /* Build a relocation to six / four bytes farther on. */
+ 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)
+ {
+ buffer[highbyte] &= ~0x4; /* Removes delay slot from branch. */
+ fragP->fr_fix += 4;
+ }
+@@ -3798,13 +3798,13 @@ sh_handle_align (fragS *frag)
+ && (frag->fr_type == rs_align
+ || frag->fr_type == rs_align_code)
+ && frag->fr_address + frag->fr_fix > 0
+ && 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. */
+
+ static bfd_boolean
+ sh_local_pcrel (fixS *fix)
+diff --git a/gas/config/te-amiga.h b/gas/config/te-amiga.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..a7b93727031092cdeb4bf66e3813663d66d79c3b
+--- /dev/null
++++ gas/config/te-amiga.h
+@@ -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 --git a/gas/config/te-amigaos.h b/gas/config/te-amigaos.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..8bd15a3d19b3f383e6756d6e307bd10dc4dcfb6f
+--- /dev/null
++++ gas/config/te-amigaos.h
+@@ -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 --git a/gas/config/te-nbsd.h b/gas/config/te-amithlon.h
+similarity index 65%
+copy from gas/config/te-nbsd.h
+copy to gas/config/te-amithlon.h
+index ce291014824771b2081438766002c479eeb60d9b..2fbd88551330d46e5cd585d142d67e6b7efe1624 100644
+--- gas/config/te-nbsd.h
++++ gas/config/te-amithlon.h
+@@ -1,24 +1,26 @@
+-/* te-nbsd.h -- NetBSD target environment declarations.
+- Copyright 1987, 1990, 1991, 1992, 1994, 1998, 2000, 2005, 2007
+- Free Software Foundation, Inc.
++/* 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 3, or (at your option)
++ 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, 51 Franklin Street - Fifth Floor, Boston, MA
+- 02110-1301, USA. */
++ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
++ 02111-1307, USA. */
+
+-#define TE_NetBSD 1
++#define TE_Amithlon 1
++
++#define LOCAL_LABELS_DOLLAR 1
+ #define LOCAL_LABELS_FB 1
++
+ #include "obj-format.h"
+diff --git a/gas/config/te-morphos.h b/gas/config/te-morphos.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..43b0826fa79d9e9c97485cc6dd7d919771defbf9
+--- /dev/null
++++ gas/config/te-morphos.h
+@@ -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 --git a/gas/configure b/gas/configure
+index 2e674491f392b756186c52f7b0d28de8a20398c5..6eabef030df837c80ab009e12ad99a3086df5e43 100755
+--- gas/configure
++++ gas/configure
+@@ -12500,12 +12500,19 @@ _ACEOF
+
+ cat >>confdefs.h <<_ACEOF
+ #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
+
+ case ${reject_dev_configs}-${dev} in
+ yes-yes) # Oops.
+ as_fn_error "GAS does not support the ${generic_target} configuration." "$LINENO" 5
+ ;;
+@@ -12549,12 +12556,25 @@ _ACEOF
+
+ cat >>confdefs.h <<_ACEOF
+ #define TARGET_OS "${target_os}"
+ _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.
+ set dummy $ac_prog; ac_word=$2
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+ $as_echo_n "checking for $ac_word... " >&6; }
+diff --git a/gas/configure.in b/gas/configure.in
+index 14f6edfe5deb041e968454931c451e1da226e0d1..183d98e8a4ac56e2e8a7a87f7b824f302bbb04f4 100644
+--- gas/configure.in
++++ gas/configure.in
+@@ -598,12 +598,19 @@ if test `set . $emfiles ; shift ; echo $#` -gt 0 ; then
+ fi
+ AC_SUBST(extra_objects)
+ AC_DEFINE_UNQUOTED(EMULATIONS, $EMULATIONS, [Supported emulations.])
+ 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
+ yes-yes) # Oops.
+ AC_MSG_ERROR(GAS does not support the ${generic_target} configuration.)
+ ;;
+@@ -628,12 +635,23 @@ AC_SUBST(OPCODES_LIB)
+ AC_DEFINE_UNQUOTED(TARGET_ALIAS, "${target_alias}", [Target alias.])
+ AC_DEFINE_UNQUOTED(TARGET_CANONICAL, "${target}", [Canonical target.])
+ AC_DEFINE_UNQUOTED(TARGET_CPU, "${target_cpu}", [Target CPU.])
+ 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
+
+ ALL_LINGUAS="fr tr es rw id ru fi ja"
+ ZW_GNU_GETTEXT_SISTER_DIR
+ AM_PO_SUBDIRS
+diff --git a/gas/configure.tgt b/gas/configure.tgt
+index 9e44de000145c39abfd3ea325656a4d4bc066198..61f24acdb98484f43ac0c08d3cacfd38b1c1fb8b 100644
+--- gas/configure.tgt
++++ gas/configure.tgt
+@@ -40,13 +40,14 @@ case ${cpu} in
+ cr16*) cpu_type=cr16 endian=little ;;
+ crisv32) cpu_type=cris arch=crisv32 ;;
+ crx*) cpu_type=crx endian=little ;;
+ 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 ;;
+ lm32) cpu_type=lm32 ;;
+ m32c) cpu_type=m32c endian=little ;;
+ m32r) cpu_type=m32r endian=big ;;
+@@ -181,12 +182,13 @@ case ${generic_target} in
+ h8300-*-elf | h8300-*-rtems*) fmt=elf ;;
+
+ i370-*-elf* | i370-*-linux*) fmt=elf ;;
+
+ 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 ;;
+ i386-*-elf) fmt=elf ;;
+ i386-*-kaos*) fmt=elf ;;
+ i386-*-bsd*) fmt=aout em=386bsd ;;
+@@ -271,12 +273,14 @@ case ${generic_target} in
+ m32r-*-elf* | m32r-*-rtems*) fmt=elf ;;
+ m32r-*-linux*) fmt=elf em=linux;;
+
+ 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 ;;
+ m68k-*-rtems*) fmt=elf ;;
+ m68k-*-linux-*) fmt=elf em=linux ;;
+ m68k-*-uclinux*) fmt=elf em=uclinux ;;
+@@ -338,12 +342,14 @@ case ${generic_target} in
+
+ or32-*-rtems*) fmt=elf ;;
+ or32-*-elf) fmt=elf ;;
+
+ 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 ;;
+ ppc-*-aix[5-9].*) fmt=coff em=aix5 ;;
+ ppc-*-aix*) fmt=coff ;;
+ ppc-*-beos*) fmt=coff ;;
+diff --git a/gas/read.c b/gas/read.c
+index 21c42b27342fb8e2c687417bcdacc4c16e3905b7..9de62b9c512025212d52a19833ffe28004944dd1 100644
+--- gas/read.c
++++ gas/read.c
+@@ -43,12 +43,16 @@
+ #include "wchar.h"
+
+ #ifndef TC_START_LABEL
+ #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) \
+ do \
+ { \
+ if ((SIZE) >= 8) \
+@@ -314,12 +318,15 @@ static const pseudo_typeS potable[] = {
+ #endif
+ {"byte", cons, 1},
+ {"comm", s_comm, 0},
+ {"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},
+ #endif
+ {"dc.b", cons, 1},
+ {"dc.d", float_cons, 'd'},
+@@ -1895,12 +1902,22 @@ s_data (int ignore ATTRIBUTE_UNUSED)
+
+ subseg_set (section, (subsegT) temp);
+
+ 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
+ or CPU specific pseudo-ops. This function is also the default
+ definition for .file; the APPFILE argument is 1 for .appfile, 0 for
+ .file. */
+@@ -4526,13 +4543,13 @@ emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p)
+ {
+ memset (p, 0, nbytes);
+
+ /* 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;
+
+ switch (nbytes)
+ {
+@@ -4554,13 +4571,13 @@ emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p)
+ default:
+ as_bad (_("unsupported BFD relocation size %u"), nbytes);
+ r = BFD_RELOC_32;
+ break;
+ }
+ fix_new_exp (frag, p - frag->fr_literal, (int) nbytes, exp,
+- 0, r);
++ 0, r, 0);
+ }
+ #endif
+ }
+
+ #ifdef BITFIELD_CONS_EXPRESSIONS
+
+diff --git a/gas/read.h b/gas/read.h
+index 4e5d1bbd2dc7b0724a2fc047db01f97aec8a4bac..59e787e754a14e11195607d382f81992423584cb 100644
+--- gas/read.h
++++ gas/read.h
+@@ -130,12 +130,16 @@ extern void do_repeat (int,const char *,const char *);
+ extern void do_repeat_with_expander (int, const char *, const char *, const char *);
+ extern void end_repeat (int);
+ extern void do_parse_cons_expression (expressionS *, int);
+
+ 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);
+ extern void bss_alloc (symbolS *, addressT, int);
+ extern offsetT parse_align (int);
+ extern symbolS *s_comm_internal (int, symbolS *(*) (int, symbolS *, addressT));
+diff --git a/gas/write.c b/gas/write.c
+index 56ebb6c565bea35df43565b53206156270a41b66..8a9746c927a3e8b7007cdec9c7f16e47509b5f45 100644
+--- gas/write.c
++++ gas/write.c
+@@ -149,13 +149,14 @@ fix_new_internal (fragS *frag, /* Which frag? */
+ int size, /* 1, 2, or 4 usually. */
+ symbolS *add_symbol, /* X_add_symbol. */
+ symbolS *sub_symbol, /* X_op_symbol. */
+ 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;
+
+ n_fixups++;
+
+ fixP = (fixS *) obstack_alloc (&notes, sizeof (fixS));
+@@ -188,14 +189,17 @@ fix_new_internal (fragS *frag, /* Which frag? */
+ #ifdef USING_CGEN
+ fixP->fx_cgen.insn = NULL;
+ fixP->fx_cgen.opinfo = 0;
+ #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);
+
+ {
+
+ fixS **seg_fix_rootP = (frags_chained
+@@ -232,29 +236,31 @@ fixS *
+ fix_new (fragS *frag, /* Which frag? */
+ int where, /* Where in that frag? */
+ int size, /* 1, 2, or 4 usually. */
+ 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
+ for difference expressions. That is itself more than most object
+ file formats support anyhow. */
+
+ fixS *
+ fix_new_exp (fragS *frag, /* Which frag? */
+ int where, /* Where in that frag? */
+ 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;
+ offsetT off = 0;
+
+ switch (exp->X_op)
+@@ -274,13 +280,13 @@ fix_new_exp (fragS *frag, /* Which frag? */
+
+ exp->X_op = O_symbol;
+ exp->X_op_symbol = 0;
+ 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:
+ add = exp->X_add_symbol;
+ off = exp->X_add_number;
+ r_type = BFD_RELOC_RVA;
+@@ -304,24 +310,24 @@ fix_new_exp (fragS *frag, /* Which frag? */
+ default:
+ add = make_expr_symbol (exp);
+ break;
+ }
+
+ 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
+ as for fix_new, except that WHERE is implicitly 0. */
+
+ fixS *
+ fix_at_start (fragS *frag, int size, symbolS *add_symbol,
+ 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. */
+ int
+ generic_force_reloc (fixS *fix)
+ {
+@@ -892,12 +898,19 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED,
+ For each one, call md_apply_fix to put the fix into the frag data.
+
+ Result is a count of how many relocation structs will be needed to
+ handle the remaining fixS's that we couldn't completely handle here.
+ These 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 long
+ fixup_segment (fixS *fixP, segT this_segment)
+ {
+ long seg_reloc_count = 0;
+ valueT add_number;
+ fragS *fragP;
+@@ -1890,17 +1903,17 @@ write_object_file (void)
+ exp.X_add_symbol = lie->add;
+ exp.X_op_symbol = lie->sub;
+ exp.X_add_number = lie->addnum;
+ #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;
+ }
+ else
+ prevP = &(lie->next_broken_word);
+
+diff --git a/gas/write.h b/gas/write.h
+index 8303f1be98b6548e4e30a326f042f78e07aed7f5..5f3598655b2665fa86d7b5291643f563536e2f31 100644
+--- gas/write.h
++++ gas/write.h
+@@ -172,16 +172,16 @@ extern void write_object_file (void);
+ extern long relax_frag (segT, fragS *, long);
+ extern int relax_segment (struct frag *, segT, int);
+ extern void number_to_chars_littleendian (char *, valueT, int);
+ 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 --git a/gprof/Makefile.am b/gprof/Makefile.am
+index edd100ac924458a1e69da65cab55ddb6a3b61555..286d29546ecdfa6cfafbfc7f7fb83a0fdeadfb83 100644
+--- gprof/Makefile.am
++++ gprof/Makefile.am
+@@ -36,13 +36,13 @@ noinst_HEADERS = \
+ corefile.h gmon.h gmon_io.h gmon_out.h gprof.h hertz.h hist.h \
+ search_list.h source.h sym_ids.h symtab.h utils.h
+
+ 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.
+ CONFIG_STATUS_DEPENDENCIES = $(BFDDIR)/configure.in
+
+ # This empty rule is a hack against gmake patched by Apple.
+diff --git a/gprof/Makefile.in b/gprof/Makefile.in
+index a9d7073c799863dc3b39124f83dbcba73bf8bf85..4d487c22a56406d567643a6bd53310e501fa99aa 100644
+--- gprof/Makefile.in
++++ gprof/Makefile.in
+@@ -1013,13 +1013,13 @@ uninstall-man: uninstall-man1
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am uninstall-binPROGRAMS uninstall-dvi-am \
+ uninstall-html-am uninstall-info-am uninstall-man \
+ 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
+
+ .m.c:
+ awk -f $(srcdir)/gen-c-prog.awk > ./$*.c \
+diff --git a/gprof/configure b/gprof/configure
+index 6ffdbe30cef942eb7e28f26674b03c8ff5907711..665d5009457e7e17d7acc0c8bfb81301cd546b32 100755
+--- gprof/configure
++++ gprof/configure
+@@ -11850,12 +11850,25 @@ $as_echo "found xgettext program is not GNU xgettext; ignore it" >&6; }
+ fi
+
+ 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; }
+ # Check whether --enable-maintainer-mode was given.
+ if test "${enable_maintainer_mode+set}" = set; then :
+ enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+diff --git a/gprof/configure.in b/gprof/configure.in
+index 631e3e467314f3740c737f1534537c7532a00d08..7b4586b0aeee56169f321af15214054feec0c349 100644
+--- gprof/configure.in
++++ gprof/configure.in
+@@ -28,12 +28,23 @@ LT_INIT
+ AC_CHECK_FUNCS(setmode)
+
+ ALL_LINGUAS="fr tr sv es id da pt_BR de vi rw ga ms fi nl bg eo ja sr"
+ 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
+
+ AC_CHECK_HEADERS(sys/gmon_out.h)
+
+diff --git a/gprof/gconfig.in b/gprof/gconfig.in
+index 25679910ee73fb2ae8f1c3f7b1cb2951166da71f..4ad8775fd559a1c06b6f572b4af24ca46f7f7f3e 100644
+--- gprof/gconfig.in
++++ gprof/gconfig.in
+@@ -1,12 +1,8 @@
+ /* 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
+
+ /* Define to 1 if you have the <dlfcn.h> header file. */
+ #undef HAVE_DLFCN_H
+
+diff --git a/include/elf/amigaos.h b/include/elf/amigaos.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..2cbcd490a300f0248aecf2ca6d50865181a3c1f0
+--- /dev/null
++++ include/elf/amigaos.h
+@@ -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 --git a/include/elf/ppc.h b/include/elf/ppc.h
+index f80a1e8a3e9c5852902beaafbb6a2a9e36d815c3..9893a88d96a77d730d91ef2bfe89a18d75029dd1 100644
+--- include/elf/ppc.h
++++ include/elf/ppc.h
+@@ -128,12 +128,18 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type)
+ RELOC_NUMBER (R_PPC_EMB_RELST_LO, 112)
+ RELOC_NUMBER (R_PPC_EMB_RELST_HI, 113)
+ RELOC_NUMBER (R_PPC_EMB_RELST_HA, 114)
+ RELOC_NUMBER (R_PPC_EMB_BIT_FLD, 115)
+ RELOC_NUMBER (R_PPC_EMB_RELSDA, 116)
+
++/* 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)
+ RELOC_NUMBER (R_PPC_VLE_REL24, 218)
+ RELOC_NUMBER (R_PPC_VLE_LO16A, 219)
+ RELOC_NUMBER (R_PPC_VLE_LO16D, 220)
+diff --git a/include/libiberty.h b/include/libiberty.h
+index cacde800ea3dda438ea8292ab4b9354a63ad048b..595ecf48242a2067dd71c4dda07a57994bdb4981 100644
+--- include/libiberty.h
++++ include/libiberty.h
+@@ -103,13 +103,13 @@ extern int countargv (char**);
+ /* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is
+ undefined, we haven't run the autoconf check so provide the
+ declaration without arguments. If it is 0, we checked and failed
+ 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
+ either need to use the above prototype or have one from
+ autoconf which would result in HAVE_DECL_BASENAME being set. */
+ #define basename basename_cannot_be_used_without_a_prototype
+diff --git a/ld/ChangeLog-9197 b/ld/ChangeLog-9197
+index 9307f333e3b156758598c19ff0873c21fc1dad29..0f0e189765f0438cd3bbd7a04f36c8e006cef91c 100644
+--- ld/ChangeLog-9197
++++ ld/ChangeLog-9197
+@@ -144,12 +144,17 @@ Wed Oct 22 11:29:25 1997 Ian Lance Taylor <ian@cygnus.com>
+ Fri Oct 17 00:00:13 1997 Richard Henderson <rth@cygnus.com>
+
+ * ldlang.c (lang_register_vers_node): Only check globals<=>locals,
+ since we need to be able to export different versions of the same
+ symbol.
+
++Thu Oct 16 13:21:14 1997 Fred Fish <fnf@ninemoons.com>
++
++ * ldlang.c (new_afile): Only reference amiga_attribute when
++ the target is AmigaOS.
++
+ Wed Oct 15 14:52:36 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * scripttempl/pe.sc: Put .stab and .stabstr sections at end.
+
+ Wed Oct 8 12:37:05 1997 Richard Henderson <rth@cygnus.com>
+
+@@ -1280,12 +1285,18 @@ Mon Aug 5 16:26:14 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * ldgram.y (SIZEOF, ADDR): Do not specify type.
+
+ * ldcref.c (check_nocrossref): Skip symbols with no output
+ sections.
+
++Sun Aug 4 22:15:56 1996 Fred Fish <fnf@ninemoons.com>
++
++ * ldfile.c (ldfile_open_file_search): Use alloca to allocate
++ dynamically sized array, rather than using a GNU C extension that
++ is not portable.
++
+ Fri Aug 2 14:57:49 1996 Ian Lance Taylor <ian@cygnus.com>
+
+ * ldgram.y (LOADADDR): New terminal.
+ (exp): Handle LOADADDR.
+ * ldlex.l: Recognize LOADADDR.
+ * ldexp.c (exp_print_token): Add LOADADDR.
+@@ -1506,12 +1517,16 @@ Mon Jun 24 12:00:32 1996 Ian Lance Taylor <ian@cygnus.com>
+ at 0.
+
+ * configure.in: On alpha*-*-osf*, link against libbfd.a if not
+ using shared libraries.
+ * configure: Rebuild with autoconf 2.10.
+
++Sat Jun 22 21:41:37 1996 Daniel Verite <daniel@brainstorm.eu.org>
++
++ * ldfile.c, lexsup.c: Sort the flavors.
++
+ Fri Jun 21 17:40:56 1996 Joel Sherrill <joel@merlin.gcs.redstone.army.mil>
+
+ * configure.tgt: Add support for *-*-rtems* configurations.
+
+ Fri Jun 21 13:05:51 1996 Richard Henderson <rth@tamu.edu>
+
+diff --git a/ld/ChangeLog-9899 b/ld/ChangeLog-9899
+index 866e4a0cfbb8a086ae01716e4a806e3386914cab..de288123cb7b80422bfc2973640bbdd16c6af900 100644
+--- ld/ChangeLog-9899
++++ ld/ChangeLog-9899
+@@ -1881,12 +1881,17 @@ Wed Mar 18 09:42:24 1998 Nick Clifton <nickc@cygnus.com>
+ * configure.tgt (targ_extra_emuls): Add thumb-pe target.
+
+ Sun Mar 8 23:34:14 1998 Stan Cox <scox@equinox.cygnus.com>
+
+ * configure.tgt (sparclite*-*-elf): Added.
+
++Sun Mar 8 20:25:09 1998 Daniel Verite <daniel@brainstorm.fr>
++
++ * ldlang.c (new_afile): Remove obsolete references to
++ amiga_attribute.
++
+ Mon Mar 2 19:24:08 1998 Michael Meissner <meissner@cygnus.com>
+
+ * ldlang.c (lang_size_sections): If the default memory region is
+ *default*, see if there is a memory region that could be used.
+
+ Thu Feb 26 17:09:53 1998 Michael Meissner <meissner@cygnus.com>
+diff --git a/ld/Makefile.am b/ld/Makefile.am
+index e343ab06531054392ae09d67ecb2dc3022053c07..cbaa4c736f8e87f05a60d8580174e207069872fd 100644
+--- ld/Makefile.am
++++ ld/Makefile.am
+@@ -128,12 +128,16 @@ LIBIBERTY = ../libiberty/libiberty.a
+
+ ALL_EMULATION_SOURCES = \
+ eaix5ppc.c \
+ eaix5rs6.c \
+ eaixppc.c \
+ eaixrs6.c \
++ eamiga.c \
++ eamiga_bss.c \
++ eamigaos.c \
++ eamithlon.c \
+ ealpha.c \
+ ealphavms.c \
+ earcelf.c \
+ earm_epoc_pe.c \
+ earm_wince_pe.c \
+ earmaoutb.c \
+@@ -336,12 +340,14 @@ ALL_EMULATION_SOURCES = \
+ emipsbsd.c \
+ emipsidt.c \
+ emipsidtl.c \
+ emipslit.c \
+ emipslnews.c \
+ emipspe.c \
++ emorphos.c \
++ emorphos_baserel.c \
+ emn10200.c \
+ emn10300.c \
+ emsp430x110.c \
+ emsp430x1101.c \
+ emsp430x1111.c \
+ emsp430x112.c \
+@@ -403,12 +409,14 @@ ALL_EMULATION_SOURCES = \
+ enews.c \
+ ens32knbsd.c \
+ eor32.c \
+ eor32elf.c \
+ epc532macha.c \
+ epdp11.c \
++ eppcamiga.c \
++ eppcamiga_bss.c \
+ epjelf.c \
+ epjlelf.c \
+ eppclynx.c \
+ eppcmacos.c \
+ eppcnw.c \
+ eppcpe.c \
+@@ -661,12 +669,26 @@ GENSCRIPTS = LIB_PATH='${LIB_PATH}' $(SHELL) $(srcdir)/genscripts.sh "${srcdir}"
+ GEN_DEPENDS = $(srcdir)/genscripts.sh stringify.sed
+ ELF_DEPS = $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/elf-generic.em
+ ELF_GEN_DEPS = $(srcdir)/emultempl/generic.em $(srcdir)/emultempl/elf-generic.em $(srcdir)/emultempl/genelf.em
+
+ @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)"
+ eaix5rs6.c: $(srcdir)/emulparams/aix5rs6.sh \
+ $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} aix5rs6 "$(tdir_aixrs6)"
+@@ -1472,12 +1494,18 @@ emipslit.c: $(srcdir)/emulparams/mipslit.sh $(srcdir)/emultempl/generic.em \
+ emipslnews.c: $(srcdir)/emulparams/mipslnews.sh \
+ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/mips.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} mipslnews "$(tdir_mipslnews)"
+ emipspe.c: $(srcdir)/emulparams/mipspe.sh $(srcdir)/emultempl/pe.em \
+ $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} mipspe "$(tdir_mipspe)"
++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)"
+ emn10300.c: $(srcdir)/emulparams/mn10300.sh \
+ $(srcdir)/emulparams/mn10200.sh \
+ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+@@ -1756,12 +1784,22 @@ epdp11.c: $(srcdir)/emulparams/pdp11.sh \
+ epjelf.c: $(srcdir)/emulparams/pjelf.sh \
+ $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} pjelf "$(tdir_pjelf)"
+ 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)"
+ eppcmacos.c: $(srcdir)/emulparams/ppcmacos.sh \
+ $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} ppcmacos "$(tdir_ppcmacos)"
+diff --git a/ld/Makefile.in b/ld/Makefile.in
+index 7da93b46501b8f8aa076134b903e1cdf34025941..43947832717c60ff3a89a8fcea838f5151afd56e 100644
+--- ld/Makefile.in
++++ ld/Makefile.in
+@@ -435,12 +435,16 @@ BFDLIB = ../bfd/libbfd.la
+ LIBIBERTY = ../libiberty/libiberty.a
+ ALL_EMULATION_SOURCES = \
+ eaix5ppc.c \
+ eaix5rs6.c \
+ eaixppc.c \
+ eaixrs6.c \
++ eamiga.c \
++ eamiga_bss.c \
++ eamigaos.c \
++ eamithlon.c \
+ ealpha.c \
+ ealphavms.c \
+ earcelf.c \
+ earm_epoc_pe.c \
+ earm_wince_pe.c \
+ earmaoutb.c \
+@@ -643,12 +647,14 @@ ALL_EMULATION_SOURCES = \
+ emipsbsd.c \
+ emipsidt.c \
+ emipsidtl.c \
+ emipslit.c \
+ emipslnews.c \
+ emipspe.c \
++ emorphos.c \
++ emorphos_baserel.c \
+ emn10200.c \
+ emn10300.c \
+ emsp430x110.c \
+ emsp430x1101.c \
+ emsp430x1111.c \
+ emsp430x112.c \
+@@ -710,12 +716,14 @@ ALL_EMULATION_SOURCES = \
+ enews.c \
+ ens32knbsd.c \
+ eor32.c \
+ eor32elf.c \
+ epc532macha.c \
+ epdp11.c \
++ eppcamiga.c \
++ eppcamiga_bss.c \
+ epjelf.c \
+ epjlelf.c \
+ eppclynx.c \
+ eppcmacos.c \
+ eppcnw.c \
+ eppcpe.c \
+@@ -1063,12 +1071,16 @@ distclean-compile:
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eaix5ppc.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eaix5rs6.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eaixppc.Po@am__quote@
+ @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@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earmaoutb.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earmaoutl.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earmcoff.Po@am__quote@
+@@ -1299,12 +1311,14 @@ distclean-compile:
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emipslit.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emipslnews.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emipspe.Po@am__quote@
+ @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)/emsp430x110.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1101.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1111.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x112.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1121.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1122.Po@am__quote@
+@@ -1366,12 +1380,14 @@ distclean-compile:
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eor32.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eor32elf.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epc532macha.Po@am__quote@
+ @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@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppcpe.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eriscix.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/escore3_elf.Po@am__quote@
+@@ -2131,12 +2147,26 @@ ldemul-list.h: Makefile
+
+ stringify.sed: ${srcdir}/emultempl/$(STRINGIFY)
+ cp ${srcdir}/emultempl/$(STRINGIFY) stringify.sed
+
+ @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)"
+ eaix5rs6.c: $(srcdir)/emulparams/aix5rs6.sh \
+ $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} aix5rs6 "$(tdir_aixrs6)"
+@@ -2942,12 +2972,18 @@ emipslit.c: $(srcdir)/emulparams/mipslit.sh $(srcdir)/emultempl/generic.em \
+ emipslnews.c: $(srcdir)/emulparams/mipslnews.sh \
+ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/mips.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} mipslnews "$(tdir_mipslnews)"
+ emipspe.c: $(srcdir)/emulparams/mipspe.sh $(srcdir)/emultempl/pe.em \
+ $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} mipspe "$(tdir_mipspe)"
++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)"
+ emn10300.c: $(srcdir)/emulparams/mn10300.sh \
+ $(srcdir)/emulparams/mn10200.sh \
+ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+@@ -3226,12 +3262,22 @@ epdp11.c: $(srcdir)/emulparams/pdp11.sh \
+ epjelf.c: $(srcdir)/emulparams/pjelf.sh \
+ $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} pjelf "$(tdir_pjelf)"
+ 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)"
+ eppcmacos.c: $(srcdir)/emulparams/ppcmacos.sh \
+ $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} ppcmacos "$(tdir_ppcmacos)"
+diff --git a/ld/configure.host b/ld/configure.host
+index f47b961176fa37c2786aa9ff322b21b06081cdfd..c7e1e700c24e48e783d07023b678dbd59bee0b11 100644
+--- ld/configure.host
++++ ld/configure.host
+@@ -170,12 +170,16 @@ mips*-sgi-irix4* | mips*-sgi-irix5*)
+
+ mips*-sgi-irix6*)
+ HOSTING_CRT0='/usr/lib32/crt1.o `if [ -f ../gcc/crtbegin.o ]; then echo ../gcc/crtbegin.o ; else ${CC} -print-file-name=crtbegin.o; fi`'
+ 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
+ $HOSTING_LIBS
+ EOF`
+ ;;
+diff --git a/ld/configure.tgt b/ld/configure.tgt
+index 72bc5bca48d7c93f838de826a0685c13ef1db3c2..ddba96d6da87eb2f033eae77509639b6a630ec2a 100644
+--- ld/configure.tgt
++++ ld/configure.tgt
+@@ -298,12 +298,13 @@ x86_64-*-pe | x86_64-*-pep) targ_emul=i386pep ;
+ targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" ;;
+ x86_64-*-mingw*) targ_emul=i386pep ;
+ targ_extra_emuls=i386pe
+ 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 ;;
+ i[3-7]86-*-chaos) targ_emul=elf_i386_chaos
+ ;;
+ i[3-7]86-*-nacl*) targ_emul=elf_i386_nacl
+@@ -362,12 +363,13 @@ m68*-sun-sunos[34]*) targ_emul=sun3 ;;
+ m68*-wrs-vxworks*) targ_emul=sun3 ;;
+ m68*-ericsson-ose) targ_emul=sun3 ;;
+ m68*-apple-aux*) targ_emul=m68kaux ;;
+ 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 ;;
+ m68*-*-hpux*) targ_emul=hp3hpux ;;
+ m68k-*-linux*aout*) targ_emul=m68klinux
+ targ_extra_emuls=m68kelf
+@@ -488,12 +490,15 @@ or32-*-rtems*) targ_emul=or32elf
+ ;;
+ pdp11-*-*) targ_emul=pdp11
+ ;;
+ 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"
+ targ_extra_libpath=elf32ppc;
+ tdir_elf32ppcsim=`echo ${targ_alias} | sed -e 's/ppc/ppcsim/'` ;;
+ powerpc64-*-freebsd*)
+@@ -780,11 +785,15 @@ i[03-9x]86-*-cygwin*)
+ *-*-linux*)
+ ;;
+
+ *-*-netbsd*)
+ ;;
+
++powerpc-*-amigaos*)
++ NATIVE_LIB_DIRS='/gcc/local/lib /gcc/lib'
++ ;;
++
+ alpha*-*-*)
+ NATIVE_LIB_DIRS='/usr/local/lib /usr/ccs/lib /lib /usr/lib'
+ ;;
+
+ esac
+diff --git a/ld/emulparams/amiga.sh b/ld/emulparams/amiga.sh
+new file mode 100644
+index 0000000000000000000000000000000000000000..c2915d47d7964c6406eae9079ce90d695ecdbfda
+--- /dev/null
++++ ld/emulparams/amiga.sh
+@@ -0,0 +1,6 @@
++SCRIPT_NAME=amiga
++OUTPUT_FORMAT="amiga"
++TEXT_START_ADDR=0x0
++SEGMENT_SIZE=0x0
++TEMPLATE_NAME=amiga
++ARCH=m68k
+diff --git a/ld/emulparams/amiga_bss.sh b/ld/emulparams/amiga_bss.sh
+new file mode 100644
+index 0000000000000000000000000000000000000000..5405d737448875ea39e5d9c4edfd59ee32c8a7b4
+--- /dev/null
++++ ld/emulparams/amiga_bss.sh
+@@ -0,0 +1,6 @@
++SCRIPT_NAME=amiga_bss
++OUTPUT_FORMAT="amiga"
++TEXT_START_ADDR=0x0
++SEGMENT_SIZE=0x0
++TEMPLATE_NAME=amiga
++ARCH=m68k
+diff --git a/ld/emulparams/amigaos.sh b/ld/emulparams/amigaos.sh
+new file mode 100644
+index 0000000000000000000000000000000000000000..605b81e76bcbbd2322561d7d9502190dc7c00674
+--- /dev/null
++++ ld/emulparams/amigaos.sh
+@@ -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 --git a/ld/emulparams/amithlon.sh b/ld/emulparams/amithlon.sh
+new file mode 100644
+index 0000000000000000000000000000000000000000..14b1c776396e2424af51c9b409e2d05f2881a84d
+--- /dev/null
++++ ld/emulparams/amithlon.sh
+@@ -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 --git a/ld/emulparams/morphos.sh b/ld/emulparams/morphos.sh
+new file mode 100644
+index 0000000000000000000000000000000000000000..45908c662f9b6085877dd39621e813da45a9f5f7
+--- /dev/null
++++ ld/emulparams/morphos.sh
+@@ -0,0 +1,6 @@
++TEMPLATE_NAME=morphos
++SCRIPT_NAME=morphos
++OUTPUT_FORMAT="elf32-morphos"
++MAXPAGESIZE=0x40000
++ARCH=powerpc
++MACHINE=
+diff --git a/ld/emulparams/morphos_baserel.sh b/ld/emulparams/morphos_baserel.sh
+new file mode 100644
+index 0000000000000000000000000000000000000000..46c483484813395904772673d1ae1eed0bc9109f
+--- /dev/null
++++ ld/emulparams/morphos_baserel.sh
+@@ -0,0 +1,6 @@
++TEMPLATE_NAME=morphos
++SCRIPT_NAME=morphos_baserel
++OUTPUT_FORMAT="elf32-morphos"
++MAXPAGESIZE=0x40000
++ARCH=powerpc
++MACHINE=
+diff --git a/ld/emulparams/ppcamiga.sh b/ld/emulparams/ppcamiga.sh
+new file mode 100644
+index 0000000000000000000000000000000000000000..3f266cf5265f13748eeb78f67dd93227ade92de5
+--- /dev/null
++++ ld/emulparams/ppcamiga.sh
+@@ -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 --git a/ld/emulparams/ppcamiga_bss.sh b/ld/emulparams/ppcamiga_bss.sh
+new file mode 100644
+index 0000000000000000000000000000000000000000..8d1720fb17c876d55b75f0885eb9f6eb0c7e9f1e
+--- /dev/null
++++ ld/emulparams/ppcamiga_bss.sh
+@@ -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 --git a/ld/emultempl/amiga.em b/ld/emultempl/amiga.em
+new file mode 100644
+index 0000000000000000000000000000000000000000..c6abc5c644d3d93609d66972752e6cd3d474d70e
+--- /dev/null
++++ ld/emultempl/amiga.em
+@@ -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 --git a/ld/emultempl/elf32.em b/ld/emultempl/amigaos.em
+similarity index 100%
+copy from ld/emultempl/elf32.em
+copy to ld/emultempl/amigaos.em
+diff --git a/ld/emultempl/amithlon.em b/ld/emultempl/amithlon.em
+new file mode 100644
+index 0000000000000000000000000000000000000000..5e453a72f8c01e621d110d505b83d1abbcd19831
+--- /dev/null
++++ ld/emultempl/amithlon.em
+@@ -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 --git a/ld/emultempl/morphos.em b/ld/emultempl/morphos.em
+new file mode 100644
+index 0000000000000000000000000000000000000000..cd3b9a790fb286187d8fa3e11af9382f1603d16b
+--- /dev/null
++++ ld/emultempl/morphos.em
+@@ -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 --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em
+index 6843770ca9431d7a4b698bfda7060082b215c41f..801d1d6424bc1f61bb0e7171de9f9b5178bc8100 100644
+--- ld/emultempl/ppc32elf.em
++++ ld/emultempl/ppc32elf.em
+@@ -26,12 +26,15 @@
+ fragment <<EOF
+
+ #include "libbfd.h"
+ #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)
+
+ /* Whether to run tls optimization. */
+ static int notlsopt = 0;
+@@ -56,14 +59,19 @@ ppc_after_open (void)
+ lang_output_section_statement_type *os;
+ lang_output_section_statement_type *plt_os[2];
+ lang_output_section_statement_type *got_os[2];
+
+ 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");
+
+ num_got = 0;
+ num_plt = 0;
+ for (os = &lang_output_section_statement.head->output_section_statement;
+@@ -185,12 +193,16 @@ PARSE_AND_LIST_PROLOGUE=${PARSE_AND_LIST_PROLOGUE}'
+ #define OPTION_OLD_PLT (OPTION_NEW_PLT + 1)
+ #define OPTION_OLD_GOT (OPTION_OLD_PLT + 1)
+ #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 },
+ { "no-emit-stub-syms", no_argument, NULL, OPTION_NO_STUBSYMS },
+ { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT },
+ { "no-tls-get-addr-optimize", no_argument, NULL, OPTION_NO_TLS_GET_ADDR_OPT },
+ { "secure-plt", no_argument, NULL, OPTION_NEW_PLT },
+diff --git a/ld/ldctor.c b/ld/ldctor.c
+index b29c1e0cbb13463f58989042722775698365cf9a..18d5f9370c7a0e9b009c74fdff48a4c45659245f 100644
+--- ld/ldctor.c
++++ ld/ldctor.c
+@@ -256,14 +256,18 @@ ldctor_build_sets (void)
+ reloc_howto_type *howto;
+ int reloc_size, size;
+
+ /* 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:
+ set:
+ .long number_of_elements
+ .long element0
+@@ -353,21 +357,27 @@ ldctor_build_sets (void)
+ print_space ();
+ ++len;
+ }
+
+ 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
+ lang_add_data (size, exp_relop (e->section, e->value));
+ }
+
+diff --git a/ld/ldfile.c b/ld/ldfile.c
+index e9091e9fa9ab0cb1182a102de48096ac13215a39..034eb2a7e452623f8c2571f4d6186b981c10c11d 100644
+--- ld/ldfile.c
++++ ld/ldfile.c
+@@ -63,12 +63,46 @@ typedef struct search_arch
+ } search_arch_type;
+
+ static search_dirs_type **search_tail_ptr = &search_head;
+ 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. */
+
+ static bfd_boolean
+ is_sysrooted_pathname (const char *name)
+ {
+@@ -332,12 +366,13 @@ success:
+ bfd_boolean
+ ldfile_open_file_search (const char *arch,
+ lang_input_statement_type *entry,
+ 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
+ directory first. */
+ if (! entry->flags.maybe_archive)
+ {
+@@ -359,35 +394,50 @@ ldfile_open_file_search (const char *arch,
+ return FALSE;
+ }
+
+ 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))
+ {
+ entry->filename = string;
+ return TRUE;
+ }
+
+ free (string);
+ }
+
++ }
++
+ return FALSE;
+ }
+
+ /* Open the input file specified by ENTRY.
+ PR 4437: Do not stop on the first missing file, but
+ continue processing other input files in case there
+diff --git a/ld/ldfile.h b/ld/ldfile.h
+index 945609250afc6fede2985dbdd59bf035cb835843..530fb0f3b78f7ce54421b074bea4fcd5ae28022d 100644
+--- ld/ldfile.h
++++ ld/ldfile.h
+@@ -56,7 +56,12 @@ extern bfd_boolean ldfile_try_open_bfd
+ extern void ldfile_set_output_arch
+ (const char *, enum bfd_architecture);
+ 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 --git a/ld/ldlang.c b/ld/ldlang.c
+index 459f277a3ea5baa2f38e7b95db0ac9ef67d648b8..d199cda1fd9bd4d8bfa12fe72a44501861ffe1ff 100644
+--- ld/ldlang.c
++++ ld/ldlang.c
+@@ -3389,12 +3389,19 @@ typedef struct bfd_sym_chain ldlang_undef_chain_list_type;
+
+ #define ldlang_undef_chain_list_head entry_symbol.next
+
+ 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;
+ new_undef = (ldlang_undef_chain_list_type *) stat_alloc (sizeof (*new_undef));
+ new_undef->next = ldlang_undef_chain_list_head;
+ ldlang_undef_chain_list_head = new_undef;
+diff --git a/ld/ldlang.h b/ld/ldlang.h
+index d5ea8d20e34c9c4697d0aa14b4af09d2df8f0d20..f6f061dfe6e92cdb3a5097baf644773cc402ad3f 100644
+--- ld/ldlang.h
++++ ld/ldlang.h
+@@ -302,12 +302,14 @@ typedef struct lang_input_statement_struct
+ /* Point to the next file, but skips archive contents. */
+ union lang_statement_union *next_real_file;
+
+ 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
+ {
+ lang_statement_header_type header;
+ asection *section;
+diff --git a/ld/ldlex.c b/ld/ldlex.c
+index 50bb3b1e14133555e524ad059d7b578cfaac6b24..eb7e21a7741a0fc82b72f2c7e3d88d1888998db8 100644
+--- ld/ldlex.c
++++ ld/ldlex.c
+@@ -1,17 +1,17 @@
+
+-#line 3 "ldlex.c"
++#line 3 "/home/sba/amiga/adtools/branches/binutils/2.23.2/ld/ldlex.c"
+
+ #define YY_INT_ALIGNED short int
+
+ /* A lexical scanner generated by flex */
+
+ #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
+
+ /* First, we deal with platform-specific or compiler-specific issues. */
+
+@@ -50,13 +50,12 @@ typedef uint32_t flex_uint32_t;
+ typedef signed char flex_int8_t;
+ typedef short int flex_int16_t;
+ typedef int flex_int32_t;
+ 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
+ #define INT8_MIN (-128)
+ #endif
+ #ifndef INT16_MIN
+@@ -81,12 +80,14 @@ typedef unsigned int flex_uint32_t;
+ #define UINT16_MAX (65535U)
+ #endif
+ #ifndef UINT32_MAX
+ #define UINT32_MAX (4294967295U)
+ #endif
+
++#endif /* ! C99 */
++
+ #endif /* ! FLEXINT_H */
+
+ #ifdef __cplusplus
+
+ /* The "const" storage-class-modifier is valid. */
+ #define YY_USE_CONST
+@@ -137,33 +138,47 @@ typedef unsigned int flex_uint32_t;
+ #define YY_NEW_FILE yyrestart(yyin )
+
+ #define YY_END_OF_BUFFER_CHAR 0
+
+ /* 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.
+ */
+ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+ #ifndef YY_TYPEDEF_YY_BUFFER_STATE
+ #define YY_TYPEDEF_YY_BUFFER_STATE
+ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ #endif
+
+-extern int yyleng;
++#ifndef YY_TYPEDEF_YY_SIZE_T
++#define YY_TYPEDEF_YY_SIZE_T
++typedef size_t yy_size_t;
++#endif
++
++extern yy_size_t yyleng;
+
+ extern FILE *yyin, *yyout;
+
+ #define EOB_ACT_CONTINUE_SCAN 0
+ #define EOB_ACT_END_OF_FILE 1
+ #define EOB_ACT_LAST_MATCH 2
+
+ #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) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+@@ -175,17 +190,12 @@ extern FILE *yyin, *yyout;
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+ #define unput(c) yyunput( c, (yytext_ptr) )
+
+-#ifndef YY_TYPEDEF_YY_SIZE_T
+-#define YY_TYPEDEF_YY_SIZE_T
+-typedef size_t yy_size_t;
+-#endif
+-
+ #ifndef YY_STRUCT_YY_BUFFER_STATE
+ #define YY_STRUCT_YY_BUFFER_STATE
+ struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+@@ -197,13 +207,13 @@ struct yy_buffer_state
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+- int yy_n_chars;
++ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+@@ -267,14 +277,14 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+ * NULL or when we need an lvalue. For internal use only.
+ */
+ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+ /* yy_hold_char holds the character lost when yytext is formed. */
+ static char yy_hold_char;
+-static int yy_n_chars; /* number of characters read into yy_ch_buf */
+-int yyleng;
++static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
++yy_size_t yyleng;
+
+ /* Points to current character in buffer. */
+ static char *yy_c_buf_p = (char *) 0;
+ static int yy_init = 0; /* whether we need to initialize */
+ static int yy_start = 0; /* start state number */
+
+@@ -296,13 +306,13 @@ static void yy_load_buffer_state (void );
+ static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+ #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+ YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+ YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
+
+ void *yyalloc (yy_size_t );
+ void *yyrealloc (void *,yy_size_t );
+ void yyfree (void * );
+
+ #define yy_new_buffer yy_create_buffer
+@@ -1711,13 +1721,13 @@ int yywrap (void) { return 1; }
+
+
+
+
+
+
+-#line 1718 "ldlex.c"
++#line 1728 "/home/sba/amiga/adtools/branches/binutils/2.23.2/ld/ldlex.c"
+
+ #define INITIAL 0
+ #define SCRIPT 1
+ #define EXPRESSION 2
+ #define BOTH 3
+ #define DEFSYMEXP 4
+@@ -1758,13 +1768,13 @@ FILE *yyget_in (void );
+ void yyset_in (FILE * in_str );
+
+ FILE *yyget_out (void );
+
+ void yyset_out (FILE * out_str );
+
+-int yyget_leng (void );
++yy_size_t yyget_leng (void );
+
+ char *yyget_text (void );
+
+ int yyget_lineno (void );
+
+ void yyset_lineno (int line_number );
+@@ -1798,32 +1808,37 @@ static int input (void );
+ #endif
+
+ #endif
+
+ /* 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. */
+ #ifndef ECHO
+ /* 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,
+ * is returned in "result".
+ */
+ #ifndef YY_INPUT
+ #define YY_INPUT(buf,result,max_size) \
+ 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; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+@@ -1899,33 +1914,12 @@ extern int yylex (void);
+ YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+-#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 1925 "ldlex.c"
+-
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+ #ifdef YY_USER_INIT
+ YY_USER_INIT;
+@@ -1946,12 +1940,34 @@ YY_DECL
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ 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 */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+@@ -1962,13 +1978,13 @@ YY_DECL
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+ 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;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+@@ -3105,13 +3121,13 @@ lex_warn_invalid (" in expression", yytext);
+ YY_BREAK
+ case 195:
+ YY_RULE_SETUP
+ #line 468 "ldlex.l"
+ ECHO;
+ YY_BREAK
+-#line 3112 "ldlex.c"
++#line 3128 "/home/sba/amiga/adtools/branches/binutils/2.23.2/ld/ldlex.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+@@ -3234,12 +3250,13 @@ ECHO;
+
+ default:
+ YY_FATAL_ERROR(
+ "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
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+@@ -3289,27 +3306,27 @@ static int yy_get_next_buffer (void)
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+- int num_to_read =
++ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* 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);
+
+ if ( b->yy_is_our_buffer )
+ {
+- int new_size = b->yy_buf_size * 2;
++ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+@@ -3334,13 +3351,13 @@ static int yy_get_next_buffer (void)
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+- (yy_n_chars), (size_t) num_to_read );
++ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+@@ -3429,13 +3446,13 @@ static int yy_get_next_buffer (void)
+ if ( yy_current_state >= 1706 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 1705);
+
+- return yy_is_jam ? 0 : yy_current_state;
++ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+ #ifndef YY_NO_INPUT
+ #ifdef __cplusplus
+ static int yyinput (void)
+ #else
+@@ -3456,13 +3473,13 @@ static int yy_get_next_buffer (void)
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+- int offset = (yy_c_buf_p) - (yytext_ptr);
++ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+@@ -3616,16 +3633,12 @@ static void yy_load_buffer_state (void)
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ 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.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+@@ -3732,13 +3745,13 @@ void yypop_buffer_state (void)
+
+ /* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+ static void yyensure_buffer_stack (void)
+ {
+- int num_to_alloc;
++ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+@@ -3824,23 +3837,23 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+
+ return yy_scan_bytes(yystr,strlen(yystr) );
+ }
+
+ /** 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.
+ */
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+- int i;
++ yy_size_t i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+@@ -3916,13 +3929,13 @@ FILE *yyget_out (void)
+ return yyout;
+ }
+
+ /** Get the length of the current token.
+ *
+ */
+-int yyget_leng (void)
++yy_size_t yyget_leng (void)
+ {
+ return yyleng;
+ }
+
+ /** Get the current token.
+ *
+@@ -4064,13 +4077,13 @@ void yyfree (void * ptr )
+ {
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+ }
+
+ #define YYTABLES_NAME "yytables"
+
+-#line 468 "ldlex.l"
++#line 467 "ldlex.l"
+
+
+
+
+ /* Switch flex to reading script file NAME, open on FILE,
+ saving the current input info on the include stack. */
+diff --git a/ld/ldmain.c b/ld/ldmain.c
+index 73353309c3595a2e53e160cbf2bcfd215a92aab2..8b7513d8e83264c0cb236781cdb753181612fb14 100644
+--- ld/ldmain.c
++++ ld/ldmain.c
+@@ -408,16 +408,23 @@ main (int argc, char **argv)
+ }
+
+ 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 ();
+
+ if (config.map_file != NULL)
+ lang_map ();
+ if (command_line.cref)
+diff --git a/ld/scripttempl/amiga.sc b/ld/scripttempl/amiga.sc
+new file mode 100644
+index 0000000000000000000000000000000000000000..f5c9d694742ecabb3a2a9c6b85e8f2aaf23e78f1
+--- /dev/null
++++ ld/scripttempl/amiga.sc
+@@ -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 --git a/ld/scripttempl/amiga_bss.sc b/ld/scripttempl/amiga_bss.sc
+new file mode 100644
+index 0000000000000000000000000000000000000000..668ce7c0dee923dd0d4643a379bf24f4b352cef0
+--- /dev/null
++++ ld/scripttempl/amiga_bss.sc
+@@ -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 --git a/ld/scripttempl/elf64hppa.sc b/ld/scripttempl/amigaos.sc
+similarity index 88%
+copy from ld/scripttempl/elf64hppa.sc
+copy to ld/scripttempl/amigaos.sc
+index 18090e6b9b73969ba6c33ccb272d88fc125be19d..865c9ba63ca1746c6bc6b66153557a10da677e58 100644
+--- ld/scripttempl/elf64hppa.sc
++++ ld/scripttempl/amigaos.sc
+@@ -33,17 +33,14 @@
+ # 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
+-# NO_REL_RELOCS - Don't include .rel.* sections in script
+-# NO_RELA_RELOCS - Don't include .rela.* sections in script
+-# NON_ALLOC_DYN - Place dynamic sections after data segment.
+ # TEXT_DYNAMIC - .dynamic in text segment, not data segment.
+-# EMBEDDED - whether this is for an embedded system.
++# 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.
+@@ -98,13 +95,14 @@ 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}) + (. & (${MAXPAGESIZE} - 1))"
++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}, .);"
+@@ -123,14 +121,14 @@ if test -z "$GOT"; then
+ 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 .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }"
+-DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }"
++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)
+@@ -139,13 +137,13 @@ if test -z "${NO_SMALL_DATA}"; then
+ ${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} :
++ .sdata ${RELOCATING-0} :
+ {
+ ${RELOCATING+${SDATA_START_SYMBOLS}}
+ ${CREATE_SHLIB+*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)}
+ *(.sdata${RELOCATING+ .sdata.* .gnu.linkonce.s.*})
+ }"
+ SDATA2=".sdata2 ${RELOCATING-0} :
+@@ -197,27 +195,13 @@ test "${LARGE_SECTIONS}" = "yes" && LARGE_SECTIONS="
+ }
+ .ldata ${RELOCATING-0} ${RELOCATING+ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))} :
+ {
+ *(.ldata${RELOCATING+ .ldata.* .gnu.linkonce.l.*})
+ ${RELOCATING+. = ALIGN(. != 0 ? ${ALIGNMENT} : 1);}
+ }"
+-INIT_ARRAY=".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=".fini_array ${RELOCATING-0} :
+- {
+- ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_start = .);}}
+- KEEP (*(SORT(.fini_array.*)))
+- KEEP (*(.fini_array))
+- ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_end = .);}}
+- }"
+-CTOR=".ctors ${CONSTRUCTING-0} :
++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
+@@ -253,27 +237,24 @@ DTOR=".dtors ${CONSTRUCTING-0} :
+ STACK=" .stack ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} :
+ {
+ ${RELOCATING+_stack = .;}
+ *(.stack)
+ }"
+
+-TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${TEXT_START_ADDR})"
+-SHLIB_TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${SHLIB_TEXT_START_ADDR:-0})"
+-
+ # 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})
+-${RELOCATING+ENTRY(${ENTRY})}
++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
+@@ -281,33 +262,28 @@ ${RELOCATING- /* For some reason, the Solaris linker makes bad executables
+ 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} + SIZEOF_HEADERS;}}
+- ${CREATE_PIE+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR} + SIZEOF_HEADERS;}}
++ ${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) }
+-EOF
+-
+-test -n "${RELOCATING+0}" || unset NON_ALLOC_DYN
+-test -z "${NON_ALLOC_DYN}" || TEXT_DYNAMIC=
+-cat > ldscripts/dyntmp.$$ <<EOF
+ ${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
+
++EOF
+ if [ "x$COMBRELOC" = x ]; then
+- COMBRELOCCAT="cat >> ldscripts/dyntmp.$$"
++ COMBRELOCCAT=cat
+ else
+ COMBRELOCCAT="cat > $COMBRELOC"
+ fi
+ eval $COMBRELOCCAT <<EOF
+ .rel.init ${RELOCATING-0} : { *(.rel.init) }
+ .rela.init ${RELOCATING-0} : { *(.rela.init) }
+@@ -315,14 +291,14 @@ eval $COMBRELOCCAT <<EOF
+ .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.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*}) }
+- .rela.data.rel.ro ${RELOCATING-0} : { *(.rela.data.rel.ro${RELOCATING+ .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*}) }
++ .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.*}) }
+@@ -338,76 +314,53 @@ eval $COMBRELOCCAT <<EOF
+ ${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 >> ldscripts/dyntmp.$$ <<EOF
++cat <<EOF
+ .rel.dyn ${RELOCATING-0} :
+ {
+ EOF
+-sed -e '/^[ ]*[{}][ ]*$/d;/:[ ]*$/d;/\.rela\./d;s/^.*: { *\(.*\)}$/ \1/' $COMBRELOC >> ldscripts/dyntmp.$$
+-cat >> ldscripts/dyntmp.$$ <<EOF
+- }
+- .rel.ifunc.dyn ${RELOCATING-0} :
+- {
+- *(.rel.ifunc.*)
++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 >> ldscripts/dyntmp.$$
+-cat >> ldscripts/dyntmp.$$ <<EOF
+- }
+- .rela.ifunc.dyn ${RELOCATING-0} :
+- {
+- *(.rela.ifunc.*)
++sed -e '/^[ ]*[{}][ ]*$/d;/:[ ]*$/d;/\.rel\./d;s/^.*: { *\(.*\)}/ \1/' $COMBRELOC
++cat <<EOF
+ }
+ EOF
+ fi
+-
+-cat >> ldscripts/dyntmp.$$ <<EOF
++cat <<EOF
+ .rel.plt ${RELOCATING-0} : { *(.rel.plt) }
+ .rela.plt ${RELOCATING-0} : { *(.rela.plt) }
+ ${OTHER_PLT_RELOC_SECTIONS}
+-EOF
+
+-if test -z "${NON_ALLOC_DYN}"; then
+- if test -z "${NO_REL_RELOCS}${NO_RELA_RELOCS}"; then
+- cat ldscripts/dyntmp.$$
+- else
+- if test -z "${NO_REL_RELOCS}"; then
+- sed -e '/^[ ]*\.rela\.[^}]*$/,/}/d' -e '/^[ ]*\.rela\./d' ldscripts/dyntmp.$$
+- fi
+- if test -z "${NO_RELA_RELOCS}"; then
+- sed -e '/^[ ]*\.rel\.[^}]*$/,/}/d' -e '/^[ ]*\.rel\./d' ldscripts/dyntmp.$$
+- fi
+- fi
+- rm -f ldscripts/dyntmp.$$
+-fi
+-
+-cat <<EOF
+ .init ${RELOCATING-0} :
+ {
+ ${RELOCATING+${INIT_START}}
+ KEEP (*(.init))
+ ${RELOCATING+${INIT_END}}
+ } =${NOP-0}
+
+- ${TEXT_PLT+${PLT}}
+ ${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}
+@@ -432,21 +385,34 @@ cat <<EOF
+ /* 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 = .);}}
+ }
+- ${RELOCATING+${INIT_ARRAY}}
+- ${RELOCATING+${FINI_ARRAY}}
++ .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}
+@@ -461,12 +427,13 @@ cat <<EOF
+ ${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}}}
+@@ -499,29 +466,13 @@ cat <<EOF
+ ${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}}
+-EOF
+-
+-if test -n "${NON_ALLOC_DYN}"; then
+- if test -z "${NO_REL_RELOCS}${NO_RELA_RELOCS}"; then
+- cat ldscripts/dyntmp.$$
+- else
+- if test -z "${NO_REL_RELOCS}"; then
+- sed -e '/^[ ]*\.rela\.[^}]*$/,/}/d' -e '/^[ ]*\.rela\./d' ldscripts/dyntmp.$$
+- fi
+- if test -z "${NO_RELA_RELOCS}"; then
+- sed -e '/^[ ]*\.rel\.[^}]*$/,/}/d' -e '/^[ ]*\.rel\./d' ldscripts/dyntmp.$$
+- fi
+- fi
+- rm -f ldscripts/dyntmp.$$
+-fi
+
+-cat <<EOF
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+@@ -561,15 +512,12 @@ cat <<EOF
+ .debug_varnames 0 : { *(.debug_varnames) }
+
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+
+- /* DWARF Extension. */
+- .debug_macro 0 : { *(.debug_macro) }
+-
+ ${TINY_DATA_SECTION}
+ ${TINY_BSS_SECTION}
+
+ ${STACK_ADDR+${STACK}}
+ ${ATTRS_SECTIONS}
+ ${OTHER_SECTIONS}
+diff --git a/ld/scripttempl/mep.sc b/ld/scripttempl/amithlon.sc
+similarity index 76%
+copy from ld/scripttempl/mep.sc
+copy to ld/scripttempl/amithlon.sc
+index 3fc1352e19184c0319302e809cccf7cc861ec8d7..b8248cd4966e34e95c8b262e515ace1802c6db35 100644
+--- ld/scripttempl/mep.sc
++++ ld/scripttempl/amithlon.sc
+@@ -1,57 +1,45 @@
+ #
+ # 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 ...
+ # 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.
+ # 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.
++# 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.
+-# 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.
+ #
+ # 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,
+@@ -81,108 +69,85 @@ 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$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
+-DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
+-DATA_SEGMENT_RELRO_END=""
+-DATA_SEGMENT_RELRO_GOTPLT_END=""
++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="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})"
++ DATA_SEGMENT_ALIGN="DATA_SEGMENT_ALIGN(${MAXPAGESIZE}, ${COMMONPAGESIZE})"
+ DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);"
+- if test -n "${SEPARATE_GOTPLT}"; then
+- DATA_SEGMENT_RELRO_GOTPLT_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT}, .);"
+- else
+- DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (0, .);"
+- fi
+ fi
+ INTERP=".interp ${RELOCATING-0} : { *(.interp) }"
+ PLT=".plt ${RELOCATING-0} : { *(.plt) }"
+-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="${RELOCATING+${DATA_SEGMENT_RELRO_GOTPLT_END}}
+- .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) *(.data.rel.ro .data.rel.ro.*) }"
+-DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }"
+ if test -z "${NO_SMALL_DATA}"; then
+ SBSS=".sbss ${RELOCATING-0} :
+ {
+ ${RELOCATING+PROVIDE (__sbss_start = .);}
+ ${RELOCATING+PROVIDE (___sbss_start = .);}
+- ${CREATE_SHLIB+*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)}
+ *(.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} :
++ .sdata ${RELOCATING-0} :
+ {
+ ${RELOCATING+${SDATA_START_SYMBOLS}}
+- ${CREATE_SHLIB+*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)}
+ *(.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.*}) }"
+-else
+- NO_SMALL_DATA=" "
+ fi
+-test -n "$SEPARATE_GOTPLT" && SEPARATE_GOTPLT=" "
+-CTOR=".ctors ${CONSTRUCTING-0} :
++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
+ 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 (*(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 (*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}} :
+ {
+@@ -198,13 +163,13 @@ else
+ fi
+
+ cat <<EOF
+ OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}",
+ "${LITTLE_OUTPUT_FORMAT}")
+ OUTPUT_ARCH(${OUTPUT_ARCH})
+-${RELOCATING+ENTRY(${ENTRY})}
++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}}
+@@ -213,15 +178,14 @@ ${RELOCATING- /* For some reason, the Solaris linker makes bad executables
+ 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+. = ${TEXT_BASE_ADDRESS};}}
+ ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}}
+- ${CREATE_PIE+${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) }
+@@ -242,14 +206,12 @@ eval $COMBRELOCCAT <<EOF
+ .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.data.rel.ro.*}) }
+- .rela.data.rel.ro ${RELOCATING-0} : { *(.rela.data.rel.ro${RELOCATING+ .rela.data.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.*}) }
+@@ -285,12 +247,15 @@ 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}
+@@ -310,69 +275,68 @@ cat <<EOF
+ 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) }
+- .eh_frame ${RELOCATING-0} : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+- .gcc_except_table ${RELOCATING-0} : ONLY_IF_RO { KEEP (*(.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+. = ${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 { KEEP (*(.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} : { KEEP (*(.preinit_array)) }
+- .init_array ${RELOCATING-0} : { KEEP (*(.init_array)) }
+- .fini_array ${RELOCATING-0} : { KEEP (*(.fini_array)) }
+
+- ${SMALL_DATA_CTOR-${RELOCATING+${CTOR}}}
+- ${SMALL_DATA_DTOR-${RELOCATING+${DTOR}}}
+- .jcr ${RELOCATING-0} : { KEEP (*(.jcr)) }
++ /* 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+${DATARELRO}}
+- ${OTHER_RELRO_SECTIONS}
+- ${TEXT_DYNAMIC-${DYNAMIC}}
+- ${NO_SMALL_DATA+${RELRO_NOW+${GOT}}}
+- ${NO_SMALL_DATA+${RELRO_NOW-${SEPARATE_GOTPLT+${GOT}}}}
+- ${NO_SMALL_DATA+${RELRO_NOW-${SEPARATE_GOTPLT+${GOTPLT}}}}
+- ${RELOCATING+${DATA_SEGMENT_RELRO_END}}
+- ${NO_SMALL_DATA+${RELRO_NOW-${SEPARATE_GOTPLT-${GOT}}}}
++ ${RELOCATING+${CREATE_SHLIB-PROVIDE (__init_array_start = .);}}
++ .init_array ${RELOCATING-0} : { *(.init_array) }
++ ${RELOCATING+${CREATE_SHLIB-PROVIDE (__init_array_end = .);}}
+
+- ${DATA_PLT+${PLT_BEFORE_GOT-${PLT}}}
++ ${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}
+- ${SMALL_DATA_CTOR+${RELOCATING+${CTOR}}}
+- ${SMALL_DATA_DTOR+${RELOCATING+${DTOR}}}
+- ${DATA_PLT+${PLT_BEFORE_GOT+${PLT}}}
++ ${TEXT_DYNAMIC-${DYNAMIC}}
++ ${RELOCATING+${CTOR}}
++ ${RELOCATING+${DTOR}}
++ .jcr ${RELOCATING-0} : { KEEP (*(.jcr)) }
++ ${DATA_PLT+${PLT}}
+ ${RELOCATING+${OTHER_GOT_SYMBOLS}}
+- ${NO_SMALL_DATA-${GOT}}
++ .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}}
+@@ -433,19 +397,16 @@ cat <<EOF
+ /* 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) }
+
+- /* DWARF 3 */
+- .debug_pubtypes 0 : { *(.debug_pubtypes) }
+- .debug_ranges 0 : { *(.debug_ranges) }
+-
+- /* DWARF Extension. */
+- .debug_macro 0 : { *(.debug_macro) }
+-
+ ${STACK_ADDR+${STACK}}
+ ${OTHER_SECTIONS}
+ ${RELOCATING+${OTHER_END_SYMBOLS}}
+- ${RELOCATING+${DISCARDED}}
++
++ /* 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 --git a/libiberty/config/mh-amigaos b/libiberty/config/mh-amigaos
+new file mode 100644
+index 0000000000000000000000000000000000000000..495fa7e35897000efe600c9f1dd844b086731fcd
+--- /dev/null
++++ libiberty/config/mh-amigaos
+@@ -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 --git a/libiberty/config/mh-morphos b/libiberty/config/mh-morphos
+new file mode 100644
+index 0000000000000000000000000000000000000000..064647ab3397b088317905a47cce0171e25a4bae
+--- /dev/null
++++ libiberty/config/mh-morphos
+@@ -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 --git a/libiberty/lrealpath.c b/libiberty/lrealpath.c
+index b27c8de990e974c7294dfc4024ef44fbd3844a52..e94add4802d830aa3e04c9a784a8d081938ae0d5 100644
+--- libiberty/lrealpath.c
++++ libiberty/lrealpath.c
+@@ -69,12 +69,18 @@ extern char *canonicalize_file_name (const char *);
+ # if defined (_WIN32)
+ # define WIN32_LEAN_AND_MEAN
+ # include <windows.h> /* for GetFullPathName */
+ # 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)
+ {
+ /* Method 1: The system has a compile time upper bound on a filename
+ path. Use that and realpath() to canonicalize the name. This is
+ the most common case. Note that, if there isn't a compile time
+diff --git a/opcodes/m68k-dis.c b/opcodes/m68k-dis.c
+index bc2dd491592e56fb664cdf96fc32491c08e1e075..bc40541b7c5aecc30a7a74fd61f29225acd21fcd 100644
+--- opcodes/m68k-dis.c
++++ opcodes/m68k-dis.c
+@@ -36,13 +36,13 @@ const char * const fpcr_names[] =
+ "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr"
+ };
+
+ 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"
+ };
+
+ /* Name of register halves for MAC/EMAC.
+ Seperate from reg_names since 'spu', 'fpl' look weird. */
+ static char *const reg_half_names[] =
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/binutils/0002-Fixed-errors-occuring-with-more-recent-versions-of-t.p b/ppc-amigaos/recipes/patches/binutils/0002-Fixed-errors-occuring-with-more-recent-versions-of-t.p
new file mode 100644
index 0000000..eb82ebf
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/binutils/0002-Fixed-errors-occuring-with-more-recent-versions-of-t.p
@@ -0,0 +1,436 @@
+From e5811195ee1007420de6150b593fd6b3654c4921 Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Sat, 29 Nov 2014 11:32:22 +0100
+Subject: [PATCH 2/7] Fixed errors occuring with more recent versions of
+ texinfo.
+
+---
+ bfd/doc/bfd.texinfo | 4 ++--
+ binutils/doc/binutils.texi | 12 ++++++------
+ gas/doc/c-arc.texi | 4 ++--
+ gas/doc/c-arm.texi | 18 +++++++++---------
+ gas/doc/c-cr16.texi | 47 ++++++++++++++++++++++++++--------------------
+ gas/doc/c-mips.texi | 2 +-
+ gas/doc/c-score.texi | 8 ++++----
+ gas/doc/c-tic54x.texi | 10 +++++-----
+ ld/ld.texinfo | 4 ++--
+ 9 files changed, 58 insertions(+), 51 deletions(-)
+
+diff --git a/bfd/doc/bfd.texinfo b/bfd/doc/bfd.texinfo
+index 7b9774b71a3cb9b3c154c8c75a41de29a6813146..d3b14c56449321b5dfe33206b2c5cfcd87eb0b91 100644
+--- bfd/doc/bfd.texinfo
++++ bfd/doc/bfd.texinfo
+@@ -324,21 +324,21 @@ All of BFD lives in one directory.
+
+ @node BFD Index, , GNU Free Documentation License, Top
+ @unnumbered BFD Index
+ @printindex cp
+
+ @tex
+-% I think something like @colophon should be in texinfo. In the
++% I think something like @ colophon should be in texinfo. In the
+ % meantime:
+ \long\def\colophon{\hbox to0pt{}\vfill
+ \centerline{The body of this manual is set in}
+ \centerline{\fontname\tenrm,}
+ \centerline{with headings in {\bf\fontname\tenbf}}
+ \centerline{and examples in {\tt\fontname\tentt}.}
+ \centerline{{\it\fontname\tenit\/} and}
+ \centerline{{\sl\fontname\tensl\/}}
+ \centerline{are used for emphasis.}\vfill}
+ \page\colophon
+-% Blame: doc@cygnus.com, 28mar91.
++% Blame: doc at cygnus.com, 28mar91.
+ @end tex
+
+ @bye
+diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
+index 45174b739e568d8f7f01fc373035e010ffeced3d..ce7746c103d9f6a5770b43a850a2e26b68b4b58d 100644
+--- binutils/doc/binutils.texi
++++ binutils/doc/binutils.texi
+@@ -4410,45 +4410,45 @@ which fields in the ELF header should be updated.
+ The long and short forms of options, shown here as alternatives, are
+ equivalent. At least one of the @option{--output-mach},
+ @option{--output-type} and @option{--output-osabi} options must be given.
+
+ @table @env
+
+-@itemx --input-mach=@var{machine}
++@item --input-mach=@var{machine}
+ Set the matching input ELF machine type to @var{machine}. If
+ @option{--input-mach} isn't specified, it will match any ELF
+ machine types.
+
+ The supported ELF machine types are, @var{L1OM}, @var{K1OM} and
+ @var{x86-64}.
+
+-@itemx --output-mach=@var{machine}
++@item --output-mach=@var{machine}
+ Change the ELF machine type in the ELF header to @var{machine}. The
+ supported ELF machine types are the same as @option{--input-mach}.
+
+-@itemx --input-type=@var{type}
++@item --input-type=@var{type}
+ Set the matching input ELF file type to @var{type}. If
+ @option{--input-type} isn't specified, it will match any ELF file types.
+
+ The supported ELF file types are, @var{rel}, @var{exec} and @var{dyn}.
+
+-@itemx --output-type=@var{type}
++@item --output-type=@var{type}
+ Change the ELF file type in the ELF header to @var{type}. The
+ supported ELF types are the same as @option{--input-type}.
+
+-@itemx --input-osabi=@var{osabi}
++@item --input-osabi=@var{osabi}
+ Set the matching input ELF file OSABI to @var{osabi}. If
+ @option{--input-osabi} isn't specified, it will match any ELF OSABIs.
+
+ The supported ELF OSABIs are, @var{none}, @var{HPUX}, @var{NetBSD},
+ @var{GNU}, @var{Linux} (alias for @var{GNU}),
+ @var{Solaris}, @var{AIX}, @var{Irix},
+ @var{FreeBSD}, @var{TRU64}, @var{Modesto}, @var{OpenBSD}, @var{OpenVMS},
+ @var{NSK}, @var{AROS} and @var{FenixOS}.
+
+-@itemx --output-osabi=@var{osabi}
++@item --output-osabi=@var{osabi}
+ Change the ELF OSABI in the ELF header to @var{osabi}. The
+ supported ELF OSABI are the same as @option{--input-osabi}.
+
+ @item -v
+ @itemx --version
+ Display the version number of @command{elfedit}.
+diff --git a/gas/doc/c-arc.texi b/gas/doc/c-arc.texi
+index ea0fa4eb522c265700bdc3b6712894ec2ad61d7c..f27b3270abce6c40a7ff1b068313a14572c79b56 100644
+--- gas/doc/c-arc.texi
++++ gas/doc/c-arc.texi
+@@ -217,13 +217,13 @@ can shortcut the pipeline.
+ @item .extInstruction @var{name},@var{opcode},@var{subopcode},@var{suffixclass},@var{syntaxclass}
+ The ARCtangent A4 allows the user to specify extension instructions.
+ The extension instructions are not macros. The assembler creates
+ encodings for use of these instructions according to the specification
+ by the user. The parameters are:
+
+-@table @bullet
++@itemize @bullet
+ @item @var{name}
+ Name of the extension instruction
+
+ @item @var{opcode}
+ Opcode to be used. (Bits 27:31 in the encoding). Valid values
+ 0x10-0x1f or 0x03
+@@ -276,13 +276,13 @@ inst r1,r2
+ it really means that the first argument is an implied immediate (that
+ is, the result is discarded). This is the same as though the source
+ code were: inst 0,r1,r2. You use OP1_IMM_IMPLIED by bitwise ORing it
+ with SYNTAX_20P.
+
+ @end itemize
+-@end table
++@end itemize
+
+ For example, defining 64-bit multiplier with immediate operands:
+
+ @smallexample
+ .extInstruction mp64,0x14,0x0,SUFFIX_COND | SUFFIX_FLAG ,
+ SYNTAX_3OP|OP1_MUST_BE_IMM
+diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi
+index a46e08f4400ef64851828be4ab4df1046678699e..1944862d1caeb8f2aca57902f4ec1be55b68eb7e 100644
+--- gas/doc/c-arm.texi
++++ gas/doc/c-arm.texi
+@@ -387,13 +387,13 @@ features. The default is to warn.
+ Two slightly different syntaxes are support for ARM and THUMB
+ instructions. The default, @code{divided}, uses the old style where
+ ARM and THUMB instructions had their own, separate syntaxes. The new,
+ @code{unified} syntax, which can be selected via the @code{.syntax}
+ directive, and has the following main features:
+
+-@table @bullet
++@itemize @bullet
+ @item
+ Immediate operands do not require a @code{#} prefix.
+
+ @item
+ The @code{IT} instruction may appear, and if it does it is validated
+ against subsequent conditional affixes. In ARM mode it does not
+@@ -412,13 +412,13 @@ available. (Only a few such instructions can be written in the
+ @item
+ The @code{.N} and @code{.W} suffixes are recognized and honored.
+
+ @item
+ All instructions set the flags if and only if they have an @code{s}
+ affix.
+-@end table
++@end itemize
+
+ @node ARM-Chars
+ @subsection Special Characters
+
+ @cindex line comment character, ARM
+ @cindex ARM line comment character
+@@ -463,19 +463,12 @@ the @samp{@@} character as a "line comment" start,
+ so @samp{: @var{align}} is used instead. For example:
+
+ @smallexample
+ vld1.8 @{q0@}, [r0, :128]
+ @end smallexample
+
+-@node ARM Floating Point
+-@section Floating Point
+-
+-@cindex floating point, ARM (@sc{ieee})
+-@cindex ARM floating point (@sc{ieee})
+-The ARM family uses @sc{ieee} floating-point numbers.
+-
+ @node ARM-Relocations
+ @subsection ARM relocation generation
+
+ @cindex data relocations, ARM
+ @cindex ARM data relocations
+ Specific data relocations can be generated by putting the relocation name
+@@ -516,12 +509,19 @@ respectively. For example to load the 32-bit address of foo into r0:
+
+ @smallexample
+ MOVW r0, #:lower16:foo
+ MOVT r0, #:upper16:foo
+ @end smallexample
+
++@node ARM Floating Point
++@section Floating Point
++
++@cindex floating point, ARM (@sc{ieee})
++@cindex ARM floating point (@sc{ieee})
++The ARM family uses @sc{ieee} floating-point numbers.
++
+ @node ARM Directives
+ @section ARM Machine Directives
+
+ @cindex machine directives, ARM
+ @cindex ARM machine directives
+ @table @code
+diff --git a/gas/doc/c-cr16.texi b/gas/doc/c-cr16.texi
+index 19f859f71d8f8712e8250fda07ee5b148d2d13ac..592dc5a5459d0e48ba1ca2e2846dc5e380f18e63 100644
+--- gas/doc/c-cr16.texi
++++ gas/doc/c-cr16.texi
+@@ -41,32 +41,39 @@ Operand expression type qualifier is an optional field in the instruction operan
+ - @code{Specifies the CompactRISC Assembler generates a relocation entry for the operand, where pc has implied bit, the expression is adjusted accordingly. The linker uses the relocation entry to update the operand address at link time.}
+ @end table
+
+ CR16 target operand qualifiers and its size (in bits):
+
+ @table @samp
+-@item Immediate Operand
+-- s ---- 4 bits
+-@item
+-- m ---- 16 bits, for movb and movw instructions.
+-@item
+-- m ---- 20 bits, movd instructions.
+-@item
+-- l ---- 32 bits
+-
+-@item Absolute Operand
+-- s ---- Illegal specifier for this operand.
+-@item
+-- m ---- 20 bits, movd instructions.
+-
+-@item Displacement Operand
+-- s ---- 8 bits
+-@item
+-- m ---- 16 bits
+-@item
+-- l ---- 24 bits
++@item Immediate Operand: s
++4 bits.
++
++@item Immediate Operand: m
++16 bits, for movb and movw instructions.
++
++@item Immediate Operand: m
++20 bits, movd instructions.
++
++@item Immediate Operand: l
++32 bits
++
++@item Absolute Operand: s
++Illegal specifier for this operand.
++
++@item Absolute Operand: m
++20 bits, movd instructions.
++
++@item Displacement Operand: s
++8 bits
++
++@item Displacement Operand: m
++16 bits
++
++@item Displacement Operand: l
++24 bits
++
+ @end table
+
+ For example:
+ @example
+ 1 @code{movw $_myfun@@c,r1}
+
+diff --git a/gas/doc/c-mips.texi b/gas/doc/c-mips.texi
+index 9ed0420549220079a9c44d2eed0b9daca7805af5..6054ab90442b3de4622743ef73720b5c891334e4 100644
+--- gas/doc/c-mips.texi
++++ gas/doc/c-mips.texi
+@@ -231,13 +231,13 @@ option.
+ @itemx -no-m4650
+ Generate code for the MIPS @sc{r4650} chip. This tells the assembler to accept
+ the @samp{mad} and @samp{madu} instruction, and to not schedule @samp{nop}
+ instructions around accesses to the @samp{HI} and @samp{LO} registers.
+ @samp{-no-m4650} turns off this option.
+
+-@itemx -m3900
++@item -m3900
+ @itemx -no-m3900
+ @itemx -m4100
+ @itemx -no-m4100
+ For each option @samp{-m@var{nnnn}}, generate code for the MIPS
+ @sc{r@var{nnnn}} chip. This tells the assembler to accept instructions
+ specific to that chip, and to schedule for that chip's hazards.
+diff --git a/gas/doc/c-score.texi b/gas/doc/c-score.texi
+index 3af20a381dccc9738b4e6f5152a0f83edba9892e..40959f5b9cb2aef21b5e55289b6b9c981d57ce79 100644
+--- gas/doc/c-score.texi
++++ gas/doc/c-score.texi
+@@ -34,31 +34,31 @@ The following table lists all available SCORE options.
+ This option sets the largest size of an object that can be referenced
+ implicitly with the @code{gp} register. The default value is 8.
+
+ @item -EB
+ Assemble code for a big-endian cpu
+
+-@itemx -EL
++@item -EL
+ Assemble code for a little-endian cpu
+
+ @item -FIXDD
+ Assemble code for fix data dependency
+
+ @item -NWARN
+ Assemble code for no warning message for fix data dependency
+
+ @item -SCORE5
+ Assemble code for target is SCORE5
+
+-@itemx -SCORE5U
++@item -SCORE5U
+ Assemble code for target is SCORE5U
+
+-@itemx -SCORE7
++@item -SCORE7
+ Assemble code for target is SCORE7, this is default setting
+
+-@itemx -SCORE3
++@item -SCORE3
+ Assemble code for target is SCORE3
+
+ @item -march=score7
+ Assemble code for target is SCORE7, this is default setting
+
+ @item -march=score3
+diff --git a/gas/doc/c-tic54x.texi b/gas/doc/c-tic54x.texi
+index d61ec3af1a7de0b52e9a8230e65d8b55992c8540..2c3b0f2c111461debe9d4ea20d0219a04764c734 100644
+--- gas/doc/c-tic54x.texi
++++ gas/doc/c-tic54x.texi
+@@ -106,13 +106,13 @@ Expansion is recursive until a previously encountered symbol is seen, at
+ which point substitution stops.
+
+ In this example, x is replaced with SYM2; SYM2 is replaced with SYM1, and SYM1
+ is replaced with x. At this point, x has already been encountered
+ and the substitution stops.
+
+-@smallexample @code
++@smallexample
+ .asg "x",SYM1
+ .asg "SYM1",SYM2
+ .asg "SYM2",x
+ add x,a ; final code assembled is "add x, a"
+ @end smallexample
+
+@@ -123,20 +123,20 @@ directive is used to identify the subsym as a local macro variable
+ @pxref{TIC54X-Directives,,@code{.var}}.
+
+ Substitution may be forced in situations where replacement might be
+ ambiguous by placing colons on either side of the subsym. The following
+ code:
+
+-@smallexample @code
++@smallexample
+ .eval "10",x
+ LAB:X: add #x, a
+ @end smallexample
+
+ When assembled becomes:
+
+-@smallexample @code
++@smallexample
+ LAB10 add #10, a
+ @end smallexample
+
+ Smaller parts of the string assigned to a subsym may be accessed with
+ the following syntax:
+
+@@ -306,13 +306,13 @@ floating point.
+ @node TIC54X-Ext
+ @section Extended Addressing
+ The @code{LDX} pseudo-op is provided for loading the extended addressing bits
+ of a label or address. For example, if an address @code{_label} resides
+ in extended program memory, the value of @code{_label} may be loaded as
+ follows:
+-@smallexample @code
++@smallexample
+ ldx #_label,16,a ; loads extended bits of _label
+ or #_label,a ; loads lower 16 bits of _label
+ bacc a ; full address is in accumulator A
+ @end smallexample
+
+ @node TIC54X-Directives
+@@ -342,13 +342,13 @@ Align SPC to page boundary
+ @cindex @code{asg} directive, TIC54X
+ @item .asg @var{string}, @var{name}
+ Assign @var{name} the string @var{string}. String replacement is
+ performed on @var{string} before assignment.
+
+ @cindex @code{eval} directive, TIC54X
+-@itemx .eval @var{string}, @var{name}
++@item .eval @var{string}, @var{name}
+ Evaluate the contents of string @var{string} and assign the result as a
+ string to the subsym @var{name}. String replacement is performed on
+ @var{string} before assignment.
+
+ @cindex @code{bss} directive, TIC54X
+ @item .bss @var{symbol}, @var{size} [, [@var{blocking_flag}] [,@var{alignment_flag}]]
+diff --git a/ld/ld.texinfo b/ld/ld.texinfo
+index 71e909e4b61606d4ca8d1f855d9cd10a3ae1947b..81d538bad91eee08ae24dc88f589b6d07719fff0 100644
+--- ld/ld.texinfo
++++ ld/ld.texinfo
+@@ -7860,21 +7860,21 @@ If you have more than one @code{SECT} statement for the same
+ @node LD Index
+ @unnumbered LD Index
+
+ @printindex cp
+
+ @tex
+-% I think something like @colophon should be in texinfo. In the
++% I think something like @ colophon should be in texinfo. In the
+ % meantime:
+ \long\def\colophon{\hbox to0pt{}\vfill
+ \centerline{The body of this manual is set in}
+ \centerline{\fontname\tenrm,}
+ \centerline{with headings in {\bf\fontname\tenbf}}
+ \centerline{and examples in {\tt\fontname\tentt}.}
+ \centerline{{\it\fontname\tenit\/} and}
+ \centerline{{\sl\fontname\tensl\/}}
+ \centerline{are used for emphasis.}\vfill}
+ \page\colophon
+-% Blame: doc@cygnus.com, 28mar91.
++% Blame: doc @ cygnus.com, 28mar91.
+ @end tex
+
+ @bye
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/binutils/0003-Disabled-some-stuff-such-that-68k-vtarget-builds-aga.p b/ppc-amigaos/recipes/patches/binutils/0003-Disabled-some-stuff-such-that-68k-vtarget-builds-aga.p
new file mode 100644
index 0000000..f3b89fd
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/binutils/0003-Disabled-some-stuff-such-that-68k-vtarget-builds-aga.p
@@ -0,0 +1,110 @@
+From be1c62376ea16552979036768972be85ca66c9ed Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Tue, 17 Mar 2015 19:30:24 +0100
+Subject: [PATCH 3/7] Disabled some stuff such that 68k vtarget builds again.
+
+This doesn't imply that it is working.
+---
+ gas/config/tc-m68k.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c
+index 8b5f6c60f2141ee91d6e9d1d639815abdf4e5042..9070a862b9c1266e84a8cea8da697f333227fa98 100644
+--- gas/config/tc-m68k.c
++++ gas/config/tc-m68k.c
+@@ -5158,22 +5158,22 @@ md_convert_frag_1 (fragS *fragP)
+ case TAB (BRANCHBWPL, LONG):
+ /* Here we are converting an unconditional branch into a pair of
+ conditional branches, in order to get the range. */
+ fragP->fr_opcode[0] = 0x66; /* bne */
+ fragP->fr_opcode[1] = 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);
+ fixP->fx_file = fragP->fr_file;
+ fixP->fx_line = fragP->fr_line;
+ fragP->fr_fix += 4; /* Skip first offset */
+ buffer_address += 4;
+ *buffer_address++ = 0x67; /* beq */
+ *buffer_address++ = 0xff;
+ fragP->fr_fix += 2; /* Skip second branch opcode */
+ 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 (BRABSJUNC, LONG):
+ if (flag_small_code)
+ {
+ as_bad (_("Long branch in small code model, not supported."));
+@@ -5348,12 +5348,14 @@ md_convert_frag_1 (fragS *fragP)
+ fragP->fr_fix += 4;
+ break;
+ case TAB (ABSREL, BYTE):
+ as_bad (_("ABSREL_BYTE: how the ** does this look??"));
+ break;
+ case TAB (ABSREL, SHORT):
++ as_bad (_("ABSREL_SHORT: sorry, not supported. See" __FILE__));
++#if 0
+ 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;
+@@ -5362,20 +5364,23 @@ md_convert_frag_1 (fragS *fragP)
+ }
+ /* 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);
++#endif
+ 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):
++ as_bad (_("IMMREL_SHORT: sorry, not supported. See " __FILE__));
++#if 0
+ 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... */
+@@ -5415,12 +5420,13 @@ md_convert_frag_1 (fragS *fragP)
+ * 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;
++#endif
+ break;
+ }
+ if (fixP)
+ {
+ fixP->fx_file = fragP->fr_file;
+ fixP->fx_line = fragP->fr_line;
+@@ -8302,13 +8308,13 @@ m68k_elf_cons (int nbytes /* 4=.long */)
+
+ p = frag_more (nbytes);
+ offset = 0;
+ 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
+ emit_expr (&exp, (unsigned int) nbytes);
+ }
+ while (*input_line_pointer++ == ',');
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/binutils/0004-Print-symbol-name-when-an-unexpected-type-was-encoun.p b/ppc-amigaos/recipes/patches/binutils/0004-Print-symbol-name-when-an-unexpected-type-was-encoun.p
new file mode 100644
index 0000000..7c4f7a6
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/binutils/0004-Print-symbol-name-when-an-unexpected-type-was-encoun.p
@@ -0,0 +1,31 @@
+From 5e5e0a5505d8e5fc67697f3ab397fa5a39e085cc Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Sat, 12 Sep 2015 11:29:01 +0200
+Subject: [PATCH 4/7] Print symbol name when an unexpected type was
+ encountered.
+
+---
+ bfd/elflink.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/bfd/elflink.c b/bfd/elflink.c
+index bcd3add478ab13addffee21b54919afd5cdcd7d6..f10801b99e366ad956faf039401cfcbf0c42aaa1 100644
+--- bfd/elflink.c
++++ bfd/elflink.c
+@@ -8801,12 +8801,13 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
+
+ switch (h->root.type)
+ {
+ default:
+ case bfd_link_hash_new:
+ case bfd_link_hash_warning:
++ (*_bfd_error_handler)(_("Unexpected type (%d) of symbol %s"), h->root.type, h->root.root.string);
+ abort ();
+ return FALSE;
+
+ case bfd_link_hash_undefined:
+ case bfd_link_hash_undefweak:
+ input_sec = bfd_und_section_ptr;
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/binutils/0005-Bind-in-the-ld-unwind-options.p b/ppc-amigaos/recipes/patches/binutils/0005-Bind-in-the-ld-unwind-options.p
new file mode 100644
index 0000000..f82d880
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/binutils/0005-Bind-in-the-ld-unwind-options.p
@@ -0,0 +1,27 @@
+From ce074fe73deeb899bf1cd863092c174034f56e67 Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Thu, 22 Oct 2015 09:48:26 +0200
+Subject: [PATCH 5/7] Bind in the ld unwind options.
+
+---
+ ld/emulparams/amigaos.sh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/ld/emulparams/amigaos.sh b/ld/emulparams/amigaos.sh
+index 605b81e76bcbbd2322561d7d9502190dc7c00674..2661d4ddcd1c5ecab9adea84af7f7d0ba054aa95 100644
+--- ld/emulparams/amigaos.sh
++++ ld/emulparams/amigaos.sh
+@@ -1,7 +1,9 @@
+-#. ${srcdir}/emulparams/elf32ppccommon.sh
++. ${srcdir}/emulparams/elf32ppccommon.sh
++. ${srcdir}/emulparams/plt_unwind.sh
++
+ TEMPLATE_NAME=amigaos
+ SCRIPT_NAME=amigaos
+ OUTPUT_FORMAT="elf32-amigaos"
+ MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+ COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
+ ALIGNMENT=16
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/binutils/0006-Introduced-strip-unneeded-rel-relocs.p b/ppc-amigaos/recipes/patches/binutils/0006-Introduced-strip-unneeded-rel-relocs.p
new file mode 100644
index 0000000..db15c54
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/binutils/0006-Introduced-strip-unneeded-rel-relocs.p
@@ -0,0 +1,128 @@
+From 6b64c328f239a146c1ce5a85c27b0ff1636f3987 Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Tue, 1 Dec 2015 13:51:20 +0100
+Subject: [PATCH 6/7] Introduced strip-unneeded-rel-relocs.
+
+Normally, on AmigaOS we keep all relocs for executables as we don't have
+an isolated address space. However, not all relative relocs are necessary
+to be kept, for instance if they are refering to the same program section.
+With the newly introduced strip option --strip-unneeded-rel-relocs these
+can be removed now.
+---
+ binutils/objcopy.c | 30 +++++++++++++++++++++++-------
+ 1 file changed, 23 insertions(+), 7 deletions(-)
+
+diff --git a/binutils/objcopy.c b/binutils/objcopy.c
+index 88bd071eefa8b5426eaadfd6431e9de5d4a4591b..4beee77179b85479d5b43507d9eb2a6e0caf384e 100644
+--- binutils/objcopy.c
++++ binutils/objcopy.c
+@@ -101,12 +101,15 @@ enum strip_action
+ STRIP_ALL /* Strip all symbols. */
+ };
+
+ /* Which symbols to remove. */
+ static enum strip_action strip_symbols;
+
++/* Shall we strip unneeded relative relocs? */
++static int strip_unneeded_rel_relocs;
++
+ enum locals_action
+ {
+ LOCALS_UNDEF,
+ LOCALS_START_L, /* Discard locals starting with L. */
+ LOCALS_ALL /* Discard all locals. */
+ };
+@@ -315,13 +318,14 @@ enum command_line_switch
+ OPTION_IMAGE_BASE,
+ OPTION_SECTION_ALIGNMENT,
+ OPTION_STACK,
+ OPTION_INTERLEAVE_WIDTH,
+ OPTION_SUBSYSTEM,
+ OPTION_EXTRACT_DWO,
+- OPTION_STRIP_DWO
++ OPTION_STRIP_DWO,
++ OPTION_STRIP_UNNEEED_REL_RELOCS
+ };
+
+ /* Options to handle if running as "strip". */
+
+ static struct option strip_options[] =
+ {
+@@ -343,12 +347,13 @@ static struct option strip_options[] =
+ {"preserve-dates", no_argument, 0, 'p'},
+ {"remove-section", required_argument, 0, 'R'},
+ {"strip-all", no_argument, 0, 's'},
+ {"strip-debug", no_argument, 0, 'S'},
+ {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO},
+ {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
++ {"strip-unneeded-rel-relocs", no_argument, 0, OPTION_STRIP_UNNEEED_REL_RELOCS},
+ {"strip-symbol", required_argument, 0, 'N'},
+ {"target", required_argument, 0, 'F'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"wildcard", no_argument, 0, 'w'},
+ {0, no_argument, 0, 0}
+@@ -2771,30 +2776,38 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
+ 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",
++// printf("%ld: %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)
++ /* Don't keep the symbol, but keep the reloc unless it is a relative reloc that is
++ * requested by the user to be removed. For now, we also don't discard the reloc if
++ * its targeting a different section. This can happen for relocs in the .rodata
++ * segment that refering to the .text segment. AmigaOS will possibly split these
++ * up.
++ */
++ if (!strip_unneeded_rel_relocs || !relpp [i]->howto->pc_relative || sec->index != osection->index)
++ {
++ 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++;
++ temp_relpp [temp_relcount]->sym_ptr_ptr = sec->symbol_ptr_ptr;
++ temp_relcount++;
++ }
+ }
+ }
+ relcount = temp_relcount;
+ free (relpp);
+ relpp = temp_relpp;
+ }
+@@ -3124,12 +3137,15 @@ strip_main (int argc, char *argv[])
+ case OPTION_STRIP_DWO:
+ strip_symbols = STRIP_DWO;
+ break;
+ case OPTION_STRIP_UNNEEDED:
+ strip_symbols = STRIP_UNNEEDED;
+ break;
++ case OPTION_STRIP_UNNEEED_REL_RELOCS:
++ strip_unneeded_rel_relocs = 1;
++ break;
+ case 'K':
+ add_specific_symbol (optarg, keep_specific_htab);
+ break;
+ case 'N':
+ add_specific_symbol (optarg, strip_specific_htab);
+ break;
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/binutils/0007-Keep-symbols-for-stripped-sections.-This-is-importan.p b/ppc-amigaos/recipes/patches/binutils/0007-Keep-symbols-for-stripped-sections.-This-is-importan.p
new file mode 100644
index 0000000..7681051
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/binutils/0007-Keep-symbols-for-stripped-sections.-This-is-importan.p
@@ -0,0 +1,42 @@
+From 035f3afce47e01ee70c7972a71a9dccea2b61e6f Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Thu, 3 Dec 2015 23:48:21 +0100
+Subject: [PATCH 7/7] Keep symbols for stripped sections. This is important for
+ _SDA_BASE_,
+
+---
+ binutils/objcopy.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/binutils/objcopy.c b/binutils/objcopy.c
+index 4beee77179b85479d5b43507d9eb2a6e0caf384e..8750db51279ec56080aba114cd61780d061b168f 100644
+--- binutils/objcopy.c
++++ binutils/objcopy.c
+@@ -1239,13 +1239,23 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
+ if (!keep
+ && ((keep_file_symbols && (flags & BSF_FILE))
+ || is_specified_symbol (name, keep_specific_htab)))
+ keep = TRUE;
+
+ if (keep && is_strip_section (abfd, bfd_get_section (sym)))
+- keep = FALSE;
++ {
++ /* If the symbol refers to a stripped section, we still want to
++ * keep it, e.g., _SDA_BASE_ TODO: We should perhaps output a
++ * warning or add another option to trigger this behaviour.
++ * FIXME: The section to which symbol refers must be adjusted
++ * as well */
++ if (!is_specified_symbol (name, keep_specific_htab))
++ {
++ keep = FALSE;
++ }
++ }
+
+ if (keep)
+ {
+ if ((flags & BSF_GLOBAL) != 0
+ && (weaken || is_specified_symbol (name, weaken_specific_htab)))
+ {
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/binutils/missing-files.p b/ppc-amigaos/recipes/patches/binutils/missing-files.p
new file mode 100644
index 0000000..be93e0f
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/binutils/missing-files.p
@@ -0,0 +1,13021 @@
+--- /dev/null 2015-09-06 08:42:34.091999986 +0100
++++ bfd/elf32-amigaos.c 2016-01-03 01:46:50.503001072 +0000
+@@ -0,0 +1,9972 @@
++/* PowerPC-specific support for 32-bit ELF
++ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
++ 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
++ Free Software Foundation, Inc.
++ Written by Ian Lance Taylor, Cygnus Support.
++
++ This file is part of BFD, the Binary File Descriptor library.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the
++ Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
++ Boston, MA 02110-1301, USA. */
++
++
++/* This file is based on a preliminary PowerPC ELF ABI. The
++ information may not match the final PowerPC ELF ABI. It includes
++ suggestions from the in-progress Embedded PowerPC ABI, and that
++ information may also not match. */
++
++#include "sysdep.h"
++#include <stdarg.h>
++#include "bfd.h"
++#include "bfdlink.h"
++#include "libbfd.h"
++#include "elf-bfd.h"
++#include "elf/ppc.h"
++#include "elf/amigaos.h"
++#include "elf32-ppc.h"
++#include "elf-vxworks.h"
++#include "dwarf2.h"
++
++#undef DEBUG
++
++typedef enum split16_format_type
++{
++ split16a_type = 0,
++ split16d_type
++}
++split16_format_type;
++
++/* RELA relocations are used here. */
++#define USE_RELA
++#define USE_REL 0
++
++static bfd_reloc_status_type ppc_elf_addr16_ha_reloc
++ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
++static bfd_reloc_status_type ppc_elf_unhandled_reloc
++ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
++static void ppc_elf_vle_split16
++ (bfd *, bfd_byte *, bfd_vma, bfd_vma, split16_format_type);
++
++int ppc_elf_amigaos_select_plt_layout (bfd *, struct bfd_link_info *,
++ enum ppc_elf_plt_type, int);
++
++bfd_boolean ppc_elf_amigaos_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr);
++bfd_boolean ppc_elf_amigaos_modify_segment_map (bfd *abfd,
++ struct bfd_link_info *info ATTRIBUTE_UNUSED);
++asection *ppc_elf_amigaos_tls_setup (bfd *obfd, struct bfd_link_info *info,
++ int no_tls_get_addr_opt);
++bfd_boolean ppc_elf_amigaos_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
++ struct bfd_link_info *info);
++unsigned int _bfd_elf_amigaos_ppc_at_tls_transform (unsigned int insn, unsigned int reg);
++unsigned int _bfd_elf_amigaos_ppc_at_tprel_transform (unsigned int insn, unsigned int reg);
++
++/* Branch prediction bit for branch taken relocs. */
++#define BRANCH_PREDICT_BIT 0x200000
++/* Mask to set RA in memory instructions. */
++#define RA_REGISTER_MASK 0x001f0000
++/* Value to shift register by to insert RA. */
++#define RA_REGISTER_SHIFT 16
++
++/* The name of the dynamic interpreter. This is put in the .interp
++ section. */
++#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
++
++/* For old-style PLT. */
++/* The number of single-slot PLT entries (the rest use two slots). */
++#define PLT_NUM_SINGLE_ENTRIES 8192
++
++/* For new-style .glink and .plt. */
++#define GLINK_PLTRESOLVE 16*4
++#define GLINK_ENTRY_SIZE 4*4
++#define TLS_GET_ADDR_GLINK_SIZE 12*4
++
++/* VxWorks uses its own plt layout, filled in by the static linker. */
++
++/* The standard VxWorks PLT entry. */
++#define VXWORKS_PLT_ENTRY_SIZE 32
++static const bfd_vma ppc_elf_vxworks_plt_entry
++ [VXWORKS_PLT_ENTRY_SIZE / 4] =
++ {
++ 0x3d800000, /* lis r12,0 */
++ 0x818c0000, /* lwz r12,0(r12) */
++ 0x7d8903a6, /* mtctr r12 */
++ 0x4e800420, /* bctr */
++ 0x39600000, /* li r11,0 */
++ 0x48000000, /* b 14 <.PLT0resolve+0x4> */
++ 0x60000000, /* nop */
++ 0x60000000, /* nop */
++ };
++static const bfd_vma ppc_elf_vxworks_pic_plt_entry
++ [VXWORKS_PLT_ENTRY_SIZE / 4] =
++ {
++ 0x3d9e0000, /* addis r12,r30,0 */
++ 0x818c0000, /* lwz r12,0(r12) */
++ 0x7d8903a6, /* mtctr r12 */
++ 0x4e800420, /* bctr */
++ 0x39600000, /* li r11,0 */
++ 0x48000000, /* b 14 <.PLT0resolve+0x4> 14: R_PPC_REL24 .PLTresolve */
++ 0x60000000, /* nop */
++ 0x60000000, /* nop */
++ };
++
++/* The initial VxWorks PLT entry. */
++#define VXWORKS_PLT_INITIAL_ENTRY_SIZE 32
++static const bfd_vma ppc_elf_vxworks_plt0_entry
++ [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] =
++ {
++ 0x3d800000, /* lis r12,0 */
++ 0x398c0000, /* addi r12,r12,0 */
++ 0x800c0008, /* lwz r0,8(r12) */
++ 0x7c0903a6, /* mtctr r0 */
++ 0x818c0004, /* lwz r12,4(r12) */
++ 0x4e800420, /* bctr */
++ 0x60000000, /* nop */
++ 0x60000000, /* nop */
++ };
++static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
++ [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] =
++ {
++ 0x819e0008, /* lwz r12,8(r30) */
++ 0x7d8903a6, /* mtctr r12 */
++ 0x819e0004, /* lwz r12,4(r30) */
++ 0x4e800420, /* bctr */
++ 0x60000000, /* nop */
++ 0x60000000, /* nop */
++ 0x60000000, /* nop */
++ 0x60000000, /* nop */
++ };
++
++/* For executables, we have some additional relocations in
++ .rela.plt.unloaded, for the kernel loader. */
++
++/* The number of non-JMP_SLOT relocations per PLT0 slot. */
++#define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3
++/* The number of relocations in the PLTResolve slot. */
++#define VXWORKS_PLTRESOLVE_RELOCS 2
++/* The number of relocations in the PLTResolve slot when when creating
++ a shared library. */
++#define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0
++
++/* Some instructions. */
++#define ADDIS_11_11 0x3d6b0000
++#define ADDIS_11_30 0x3d7e0000
++#define ADDIS_12_12 0x3d8c0000
++#define ADDI_11_11 0x396b0000
++#define ADD_0_11_11 0x7c0b5a14
++#define ADD_3_12_2 0x7c6c1214
++#define ADD_11_0_11 0x7d605a14
++#define B 0x48000000
++#define BCL_20_31 0x429f0005
++#define BCTR 0x4e800420
++#define BEQLR 0x4d820020
++#define CMPWI_11_0 0x2c0b0000
++#define LIS_11 0x3d600000
++#define LIS_12 0x3d800000
++#define LWZU_0_12 0x840c0000
++#define LWZ_0_12 0x800c0000
++#define LWZ_11_3 0x81630000
++#define LWZ_11_11 0x816b0000
++#define LWZ_11_30 0x817e0000
++#define LWZ_12_3 0x81830000
++#define LWZ_12_12 0x818c0000
++#define MR_0_3 0x7c601b78
++#define MR_3_0 0x7c030378
++#define MFLR_0 0x7c0802a6
++#define MFLR_12 0x7d8802a6
++#define MTCTR_0 0x7c0903a6
++#define MTCTR_11 0x7d6903a6
++#define MTLR_0 0x7c0803a6
++#define NOP 0x60000000
++#define SUB_11_11_12 0x7d6c5850
++
++/* Offset of tp and dtp pointers from start of TLS block. */
++#define TP_OFFSET 0x7000
++#define DTP_OFFSET 0x8000
++
++/* The value of a defined global symbol. */
++#define SYM_VAL(SYM) \
++ ((SYM)->root.u.def.section->output_section->vma \
++ + (SYM)->root.u.def.section->output_offset \
++ + (SYM)->root.u.def.value)
++
++static reloc_howto_type *ppc_elf_howto_table[R_PPC_max];
++
++static reloc_howto_type ppc_elf_howto_raw[] = {
++ /* This reloc does nothing. */
++ HOWTO (R_PPC_NONE, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_NONE", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A standard 32 bit relocation. */
++ HOWTO (R_PPC_ADDR32, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_ADDR32", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* An absolute 26 bit branch; the lower two bits must be zero.
++ FIXME: we don't check that, we just clear them. */
++ HOWTO (R_PPC_ADDR24, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 26, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_ADDR24", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x3fffffc, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A standard 16 bit relocation. */
++ HOWTO (R_PPC_ADDR16, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_ADDR16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A 16 bit relocation without overflow. */
++ HOWTO (R_PPC_ADDR16_LO, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont,/* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_ADDR16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* The high order 16 bits of an address. */
++ HOWTO (R_PPC_ADDR16_HI, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_ADDR16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* The high order 16 bits of an address, plus 1 if the contents of
++ the low 16 bits, treated as a signed number, is negative. */
++ HOWTO (R_PPC_ADDR16_HA, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_addr16_ha_reloc, /* special_function */
++ "R_PPC_ADDR16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* An absolute 16 bit branch; the lower two bits must be zero.
++ FIXME: we don't check that, we just clear them. */
++ HOWTO (R_PPC_ADDR14, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_ADDR14", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xfffc, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* An absolute 16 bit branch, for which bit 10 should be set to
++ indicate that the branch is expected to be taken. The lower two
++ bits must be zero. */
++ HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_ADDR14_BRTAKEN",/* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xfffc, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* An absolute 16 bit branch, for which bit 10 should be set to
++ indicate that the branch is not expected to be taken. The lower
++ two bits must be zero. */
++ HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_ADDR14_BRNTAKEN",/* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xfffc, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A relative 26 bit branch; the lower two bits must be zero. */
++ HOWTO (R_PPC_REL24, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 26, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_REL24", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x3fffffc, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* A relative 16 bit branch; the lower two bits must be zero. */
++ HOWTO (R_PPC_REL14, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_REL14", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xfffc, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* A relative 16 bit branch. Bit 10 should be set to indicate that
++ the branch is expected to be taken. The lower two bits must be
++ zero. */
++ HOWTO (R_PPC_REL14_BRTAKEN, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_REL14_BRTAKEN", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xfffc, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* A relative 16 bit branch. Bit 10 should be set to indicate that
++ the branch is not expected to be taken. The lower two bits must
++ be zero. */
++ HOWTO (R_PPC_REL14_BRNTAKEN, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_REL14_BRNTAKEN",/* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xfffc, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* Like R_PPC_ADDR16, but referring to the GOT table entry for the
++ symbol. */
++ HOWTO (R_PPC_GOT16, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_GOT16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for
++ the symbol. */
++ HOWTO (R_PPC_GOT16_LO, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_GOT16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for
++ the symbol. */
++ HOWTO (R_PPC_GOT16_HI, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_GOT16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for
++ the symbol. */
++ HOWTO (R_PPC_GOT16_HA, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ ppc_elf_addr16_ha_reloc, /* special_function */
++ "R_PPC_GOT16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like R_PPC_REL24, but referring to the procedure linkage table
++ entry for the symbol. */
++ HOWTO (R_PPC_PLTREL24, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 26, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_PLTREL24", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x3fffffc, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* This is used only by the dynamic linker. The symbol should exist
++ both in the object being run and in some shared library. The
++ dynamic linker copies the data addressed by the symbol from the
++ shared library into the object, because the object being
++ run has to have the data at some particular address. */
++ HOWTO (R_PPC_COPY, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_COPY", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like R_PPC_ADDR32, but used when setting global offset table
++ entries. */
++ HOWTO (R_PPC_GLOB_DAT, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_GLOB_DAT", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Marks a procedure linkage table entry for a symbol. */
++ HOWTO (R_PPC_JMP_SLOT, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_JMP_SLOT", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Used only by the dynamic linker. When the object is run, this
++ longword is set to the load address of the object, plus the
++ addend. */
++ HOWTO (R_PPC_RELATIVE, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_RELATIVE", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like R_PPC_REL24, but uses the value of the symbol within the
++ object rather than the final value. Normally used for
++ _GLOBAL_OFFSET_TABLE_. */
++ HOWTO (R_PPC_LOCAL24PC, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 26, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_LOCAL24PC", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x3fffffc, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* Like R_PPC_ADDR32, but may be unaligned. */
++ HOWTO (R_PPC_UADDR32, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_UADDR32", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like R_PPC_ADDR16, but may be unaligned. */
++ HOWTO (R_PPC_UADDR16, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_UADDR16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* 32-bit PC relative */
++ HOWTO (R_PPC_REL32, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_REL32", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* 32-bit relocation to the symbol's procedure linkage table.
++ FIXME: not supported. */
++ HOWTO (R_PPC_PLT32, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_PLT32", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* 32-bit PC relative relocation to the symbol's procedure linkage table.
++ FIXME: not supported. */
++ HOWTO (R_PPC_PLTREL32, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_PLTREL32", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for
++ the symbol. */
++ HOWTO (R_PPC_PLT16_LO, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_PLT16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for
++ the symbol. */
++ HOWTO (R_PPC_PLT16_HI, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_PLT16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for
++ the symbol. */
++ HOWTO (R_PPC_PLT16_HA, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ ppc_elf_addr16_ha_reloc, /* special_function */
++ "R_PPC_PLT16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A sign-extended 16 bit value relative to _SDA_BASE_, for use with
++ small data items. */
++ HOWTO (R_PPC_SDAREL16, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_SDAREL16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* 16-bit section relative relocation. */
++ HOWTO (R_PPC_SECTOFF, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_SECTOFF", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* 16-bit lower half section relative relocation. */
++ HOWTO (R_PPC_SECTOFF_LO, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_SECTOFF_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* 16-bit upper half section relative relocation. */
++ HOWTO (R_PPC_SECTOFF_HI, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_SECTOFF_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* 16-bit upper half adjusted section relative relocation. */
++ HOWTO (R_PPC_SECTOFF_HA, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ ppc_elf_addr16_ha_reloc, /* special_function */
++ "R_PPC_SECTOFF_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Marker relocs for TLS. */
++ HOWTO (R_PPC_TLS,
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_TLS", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ HOWTO (R_PPC_TLSGD,
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_TLSGD", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ HOWTO (R_PPC_TLSLD,
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_TLSLD", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Computes the load module index of the load module that contains the
++ definition of its TLS sym. */
++ HOWTO (R_PPC_DTPMOD32,
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_DTPMOD32", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Computes a dtv-relative displacement, the difference between the value
++ of sym+add and the base address of the thread-local storage block that
++ contains the definition of sym, minus 0x8000. */
++ HOWTO (R_PPC_DTPREL32,
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_DTPREL32", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A 16 bit dtprel reloc. */
++ HOWTO (R_PPC_DTPREL16,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_DTPREL16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like DTPREL16, but no overflow. */
++ HOWTO (R_PPC_DTPREL16_LO,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_DTPREL16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like DTPREL16_LO, but next higher group of 16 bits. */
++ HOWTO (R_PPC_DTPREL16_HI,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_DTPREL16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like DTPREL16_HI, but adjust for low 16 bits. */
++ HOWTO (R_PPC_DTPREL16_HA,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_DTPREL16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Computes a tp-relative displacement, the difference between the value of
++ sym+add and the value of the thread pointer (r13). */
++ HOWTO (R_PPC_TPREL32,
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_TPREL32", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A 16 bit tprel reloc. */
++ HOWTO (R_PPC_TPREL16,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_TPREL16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like TPREL16, but no overflow. */
++ HOWTO (R_PPC_TPREL16_LO,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_TPREL16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like TPREL16_LO, but next higher group of 16 bits. */
++ HOWTO (R_PPC_TPREL16_HI,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_TPREL16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like TPREL16_HI, but adjust for low 16 bits. */
++ HOWTO (R_PPC_TPREL16_HA,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_TPREL16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Allocates two contiguous entries in the GOT to hold a tls_index structure,
++ with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset
++ to the first entry. */
++ HOWTO (R_PPC_GOT_TLSGD16,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TLSGD16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_TLSGD16, but no overflow. */
++ HOWTO (R_PPC_GOT_TLSGD16_LO,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TLSGD16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_TLSGD16_LO, but next higher group of 16 bits. */
++ HOWTO (R_PPC_GOT_TLSGD16_HI,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TLSGD16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_TLSGD16_HI, but adjust for low 16 bits. */
++ HOWTO (R_PPC_GOT_TLSGD16_HA,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TLSGD16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Allocates two contiguous entries in the GOT to hold a tls_index structure,
++ with values (sym+add)@dtpmod and zero, and computes the offset to the
++ first entry. */
++ HOWTO (R_PPC_GOT_TLSLD16,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TLSLD16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_TLSLD16, but no overflow. */
++ HOWTO (R_PPC_GOT_TLSLD16_LO,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TLSLD16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_TLSLD16_LO, but next higher group of 16 bits. */
++ HOWTO (R_PPC_GOT_TLSLD16_HI,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TLSLD16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_TLSLD16_HI, but adjust for low 16 bits. */
++ HOWTO (R_PPC_GOT_TLSLD16_HA,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TLSLD16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes
++ the offset to the entry. */
++ HOWTO (R_PPC_GOT_DTPREL16,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_DTPREL16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_DTPREL16, but no overflow. */
++ HOWTO (R_PPC_GOT_DTPREL16_LO,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_DTPREL16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_DTPREL16_LO, but next higher group of 16 bits. */
++ HOWTO (R_PPC_GOT_DTPREL16_HI,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_DTPREL16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_DTPREL16_HI, but adjust for low 16 bits. */
++ HOWTO (R_PPC_GOT_DTPREL16_HA,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_DTPREL16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the
++ offset to the entry. */
++ HOWTO (R_PPC_GOT_TPREL16,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TPREL16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_TPREL16, but no overflow. */
++ HOWTO (R_PPC_GOT_TPREL16_LO,
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TPREL16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_TPREL16_LO, but next higher group of 16 bits. */
++ HOWTO (R_PPC_GOT_TPREL16_HI,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TPREL16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Like GOT_TPREL16_HI, but adjust for low 16 bits. */
++ HOWTO (R_PPC_GOT_TPREL16_HA,
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_unhandled_reloc, /* special_function */
++ "R_PPC_GOT_TPREL16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* The remaining relocs are from the Embedded ELF ABI, and are not
++ in the SVR4 ELF ABI. */
++
++ /* 32 bit value resulting from the addend minus the symbol. */
++ HOWTO (R_PPC_EMB_NADDR32, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_EMB_NADDR32", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* 16 bit value resulting from the addend minus the symbol. */
++ HOWTO (R_PPC_EMB_NADDR16, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_EMB_NADDR16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* 16 bit value resulting from the addend minus the symbol. */
++ HOWTO (R_PPC_EMB_NADDR16_LO, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont,/* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_EMB_ADDR16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* The high order 16 bits of the addend minus the symbol. */
++ HOWTO (R_PPC_EMB_NADDR16_HI, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_EMB_NADDR16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* The high order 16 bits of the result of the addend minus the address,
++ plus 1 if the contents of the low 16 bits, treated as a signed number,
++ is negative. */
++ HOWTO (R_PPC_EMB_NADDR16_HA, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_addr16_ha_reloc, /* special_function */
++ "R_PPC_EMB_NADDR16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* 16 bit value resulting from allocating a 4 byte word to hold an
++ address in the .sdata section, and returning the offset from
++ _SDA_BASE_ for that relocation. */
++ HOWTO (R_PPC_EMB_SDAI16, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_EMB_SDAI16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* 16 bit value resulting from allocating a 4 byte word to hold an
++ address in the .sdata2 section, and returning the offset from
++ _SDA2_BASE_ for that relocation. */
++ HOWTO (R_PPC_EMB_SDA2I16, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_EMB_SDA2I16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with
++ small data items. */
++ HOWTO (R_PPC_EMB_SDA2REL, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_EMB_SDA2REL", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit
++ signed offset from the appropriate base, and filling in the register
++ field with the appropriate register (0, 2, or 13). */
++ HOWTO (R_PPC_EMB_SDA21, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_EMB_SDA21", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Relocation not handled: R_PPC_EMB_MRKREF */
++ /* Relocation not handled: R_PPC_EMB_RELSEC16 */
++ /* Relocation not handled: R_PPC_EMB_RELST_LO */
++ /* Relocation not handled: R_PPC_EMB_RELST_HI */
++ /* Relocation not handled: R_PPC_EMB_RELST_HA */
++ /* Relocation not handled: R_PPC_EMB_BIT_FLD */
++
++
++ /* A standard 32 bit base relative relocation. */
++ HOWTO (R_PPC_AMIGAOS_BREL, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_AMIGAOS_BREL", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A 16 bit base relative relocation without overflow. */
++ HOWTO (R_PPC_AMIGAOS_BREL_LO, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont,/* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_AMIGAOS_BREL_LO",/* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* The high order 16 bits of a base relative address. */
++ HOWTO (R_PPC_AMIGAOS_BREL_HI, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_AMIGAOS_BREL_HI",/* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* The high order 16 bits of a base relative address, plus 1 if the contents
++ of the low 16 bits, treated as a signed number, is negative. */
++ HOWTO (R_PPC_AMIGAOS_BREL_HA, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_addr16_ha_reloc, /* special_function */
++ "R_PPC_AMIGAOS_BREL_HA",/* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling
++ in the 16 bit signed offset from the appropriate base, and filling in the
++ register field with the appropriate register (0, 2, or 13). */
++ HOWTO (R_PPC_EMB_RELSDA, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_EMB_RELSDA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A relative 8 bit branch. */
++ HOWTO (R_PPC_VLE_REL8, /* type */
++ 1, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 8, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_REL8", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xff, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* A relative 15 bit branch. */
++ HOWTO (R_PPC_VLE_REL15, /* type */
++ 1, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 15, /* bitsize */
++ TRUE, /* pc_relative */
++ 1, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_REL15", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xfe, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* A relative 24 bit branch. */
++ HOWTO (R_PPC_VLE_REL24, /* type */
++ 1, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 24, /* bitsize */
++ TRUE, /* pc_relative */
++ 1, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_REL24", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1fffffe, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* The 16 LSBS in split16a format. */
++ HOWTO (R_PPC_VLE_LO16A, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_LO16A", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f007ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* The 16 LSBS in split16d format. */
++ HOWTO (R_PPC_VLE_LO16D, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_LO16D", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f07ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Bits 16-31 split16a format. */
++ HOWTO (R_PPC_VLE_HI16A, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_HI16A", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f007ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Bits 16-31 split16d format. */
++ HOWTO (R_PPC_VLE_HI16D, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_HI16D", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f07ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Bits 16-31 (High Adjusted) in split16a format. */
++ HOWTO (R_PPC_VLE_HA16A, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_HA16A", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f007ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Bits 16-31 (High Adjusted) in split16d format. */
++ HOWTO (R_PPC_VLE_HA16D, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_HA16D", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f07ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* This reloc does nothing. */
++ HOWTO (R_PPC_VLE_SDA21, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_SDA21", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* This reloc does nothing. */
++ HOWTO (R_PPC_VLE_SDA21_LO, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_SDA21_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* The 16 LSBS relative to _SDA_BASE_ in split16a format. */
++ HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_SDAREL_LO16A", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f007ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* The 16 LSBS relative to _SDA_BASE_ in split16d format. */
++ /* This reloc does nothing. */
++ HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_SDAREL_LO16D", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f07ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Bits 16-31 relative to _SDA_BASE_ in split16a format. */
++ HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_SDAREL_HI16A", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f007ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Bits 16-31 relative to _SDA_BASE_ in split16d format. */
++ HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_SDAREL_HI16D", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f07ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */
++ HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_SDAREL_HA16A", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f007ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */
++ HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_VLE_SDAREL_HA16D", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0x1f07ff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ HOWTO (R_PPC_IRELATIVE, /* type */
++ 0, /* rightshift */
++ 2, /* size (0 = byte, 1 = short, 2 = long) */
++ 32, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_IRELATIVE", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffffffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* A 16 bit relative relocation. */
++ HOWTO (R_PPC_REL16, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_bitfield, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_REL16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* A 16 bit relative relocation without overflow. */
++ HOWTO (R_PPC_REL16_LO, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont,/* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_REL16_LO", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* The high order 16 bits of a relative address. */
++ HOWTO (R_PPC_REL16_HI, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_REL16_HI", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* The high order 16 bits of a relative address, plus 1 if the contents of
++ the low 16 bits, treated as a signed number, is negative. */
++ HOWTO (R_PPC_REL16_HA, /* type */
++ 16, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ TRUE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ ppc_elf_addr16_ha_reloc, /* special_function */
++ "R_PPC_REL16_HA", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ TRUE), /* pcrel_offset */
++
++ /* GNU extension to record C++ vtable hierarchy. */
++ HOWTO (R_PPC_GNU_VTINHERIT, /* type */
++ 0, /* rightshift */
++ 0, /* size (0 = byte, 1 = short, 2 = long) */
++ 0, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ NULL, /* special_function */
++ "R_PPC_GNU_VTINHERIT", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* GNU extension to record C++ vtable member usage. */
++ HOWTO (R_PPC_GNU_VTENTRY, /* type */
++ 0, /* rightshift */
++ 0, /* size (0 = byte, 1 = short, 2 = long) */
++ 0, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ NULL, /* special_function */
++ "R_PPC_GNU_VTENTRY", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0, /* dst_mask */
++ FALSE), /* pcrel_offset */
++
++ /* Phony reloc to handle AIX style TOC entries. */
++ HOWTO (R_PPC_TOC16, /* type */
++ 0, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 16, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_signed, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_PPC_TOC16", /* name */
++ FALSE, /* partial_inplace */
++ 0, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++};
++
++/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */
++
++static void
++ppc_elf_howto_init (void)
++{
++ unsigned int i, type;
++
++ for (i = 0;
++ i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]);
++ i++)
++ {
++ type = ppc_elf_howto_raw[i].type;
++ if (type >= (sizeof (ppc_elf_howto_table)
++ / sizeof (ppc_elf_howto_table[0])))
++ abort ();
++ ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i];
++ }
++}
++
++static reloc_howto_type *
++ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
++ bfd_reloc_code_real_type code)
++{
++ enum elf_ppc_reloc_type r;
++
++ /* Initialize howto table if not already done. */
++ if (!ppc_elf_howto_table[R_PPC_ADDR32])
++ ppc_elf_howto_init ();
++
++ switch (code)
++ {
++ default:
++ return NULL;
++
++ case BFD_RELOC_NONE: r = R_PPC_NONE; break;
++ case BFD_RELOC_32: r = R_PPC_ADDR32; break;
++ case BFD_RELOC_PPC_BA26: r = R_PPC_ADDR24; break;
++ case BFD_RELOC_PPC64_ADDR16_DS:
++ case BFD_RELOC_16: r = R_PPC_ADDR16; break;
++ case BFD_RELOC_PPC64_ADDR16_LO_DS:
++ case BFD_RELOC_LO16: r = R_PPC_ADDR16_LO; break;
++ case BFD_RELOC_HI16: r = R_PPC_ADDR16_HI; break;
++ case BFD_RELOC_HI16_S: r = R_PPC_ADDR16_HA; break;
++ case BFD_RELOC_PPC_BA16: r = R_PPC_ADDR14; break;
++ case BFD_RELOC_PPC_BA16_BRTAKEN: r = R_PPC_ADDR14_BRTAKEN; break;
++ case BFD_RELOC_PPC_BA16_BRNTAKEN: r = R_PPC_ADDR14_BRNTAKEN; break;
++ case BFD_RELOC_PPC_B26: r = R_PPC_REL24; break;
++ case BFD_RELOC_PPC_B16: r = R_PPC_REL14; break;
++ case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC_REL14_BRTAKEN; break;
++ case BFD_RELOC_PPC_B16_BRNTAKEN: r = R_PPC_REL14_BRNTAKEN; break;
++ case BFD_RELOC_PPC64_GOT16_DS:
++ case BFD_RELOC_16_GOTOFF: r = R_PPC_GOT16; break;
++ case BFD_RELOC_PPC64_GOT16_LO_DS:
++ case BFD_RELOC_LO16_GOTOFF: r = R_PPC_GOT16_LO; break;
++ case BFD_RELOC_HI16_GOTOFF: r = R_PPC_GOT16_HI; break;
++ case BFD_RELOC_HI16_S_GOTOFF: r = R_PPC_GOT16_HA; break;
++ case BFD_RELOC_24_PLT_PCREL: r = R_PPC_PLTREL24; break;
++ case BFD_RELOC_PPC_COPY: r = R_PPC_COPY; break;
++ case BFD_RELOC_PPC_GLOB_DAT: r = R_PPC_GLOB_DAT; break;
++ case BFD_RELOC_PPC_LOCAL24PC: r = R_PPC_LOCAL24PC; break;
++ case BFD_RELOC_32_PCREL: r = R_PPC_REL32; break;
++ case BFD_RELOC_32_PLTOFF: r = R_PPC_PLT32; break;
++ case BFD_RELOC_32_PLT_PCREL: r = R_PPC_PLTREL32; break;
++ case BFD_RELOC_PPC64_PLT16_LO_DS:
++ case BFD_RELOC_LO16_PLTOFF: r = R_PPC_PLT16_LO; break;
++ case BFD_RELOC_HI16_PLTOFF: r = R_PPC_PLT16_HI; break;
++ case BFD_RELOC_HI16_S_PLTOFF: r = R_PPC_PLT16_HA; break;
++ case BFD_RELOC_GPREL16: r = R_PPC_SDAREL16; break;
++ case BFD_RELOC_PPC64_SECTOFF_DS:
++ case BFD_RELOC_16_BASEREL: r = R_PPC_SECTOFF; break;
++ case BFD_RELOC_PPC64_SECTOFF_LO_DS:
++ case BFD_RELOC_LO16_BASEREL: r = R_PPC_SECTOFF_LO; break;
++ case BFD_RELOC_HI16_BASEREL: r = R_PPC_SECTOFF_HI; break;
++ case BFD_RELOC_HI16_S_BASEREL: r = R_PPC_SECTOFF_HA; break;
++ case BFD_RELOC_CTOR: r = R_PPC_ADDR32; break;
++ case BFD_RELOC_PPC64_TOC16_DS:
++ case BFD_RELOC_PPC_TOC16: r = R_PPC_TOC16; break;
++ case BFD_RELOC_PPC_TLS: r = R_PPC_TLS; break;
++ case BFD_RELOC_PPC_TLSGD: r = R_PPC_TLSGD; break;
++ case BFD_RELOC_PPC_TLSLD: r = R_PPC_TLSLD; break;
++ case BFD_RELOC_PPC_DTPMOD: r = R_PPC_DTPMOD32; break;
++ case BFD_RELOC_PPC64_TPREL16_DS:
++ case BFD_RELOC_PPC_TPREL16: r = R_PPC_TPREL16; break;
++ case BFD_RELOC_PPC64_TPREL16_LO_DS:
++ case BFD_RELOC_PPC_TPREL16_LO: r = R_PPC_TPREL16_LO; break;
++ case BFD_RELOC_PPC_TPREL16_HI: r = R_PPC_TPREL16_HI; break;
++ case BFD_RELOC_PPC_TPREL16_HA: r = R_PPC_TPREL16_HA; break;
++ case BFD_RELOC_PPC_TPREL: r = R_PPC_TPREL32; break;
++ case BFD_RELOC_PPC64_DTPREL16_DS:
++ case BFD_RELOC_PPC_DTPREL16: r = R_PPC_DTPREL16; break;
++ case BFD_RELOC_PPC64_DTPREL16_LO_DS:
++ case BFD_RELOC_PPC_DTPREL16_LO: r = R_PPC_DTPREL16_LO; break;
++ case BFD_RELOC_PPC_DTPREL16_HI: r = R_PPC_DTPREL16_HI; break;
++ case BFD_RELOC_PPC_DTPREL16_HA: r = R_PPC_DTPREL16_HA; break;
++ case BFD_RELOC_PPC_DTPREL: r = R_PPC_DTPREL32; break;
++ case BFD_RELOC_PPC_GOT_TLSGD16: r = R_PPC_GOT_TLSGD16; break;
++ case BFD_RELOC_PPC_GOT_TLSGD16_LO: r = R_PPC_GOT_TLSGD16_LO; break;
++ case BFD_RELOC_PPC_GOT_TLSGD16_HI: r = R_PPC_GOT_TLSGD16_HI; break;
++ case BFD_RELOC_PPC_GOT_TLSGD16_HA: r = R_PPC_GOT_TLSGD16_HA; break;
++ case BFD_RELOC_PPC_GOT_TLSLD16: r = R_PPC_GOT_TLSLD16; break;
++ case BFD_RELOC_PPC_GOT_TLSLD16_LO: r = R_PPC_GOT_TLSLD16_LO; break;
++ case BFD_RELOC_PPC_GOT_TLSLD16_HI: r = R_PPC_GOT_TLSLD16_HI; break;
++ case BFD_RELOC_PPC_GOT_TLSLD16_HA: r = R_PPC_GOT_TLSLD16_HA; break;
++ case BFD_RELOC_PPC_GOT_TPREL16: r = R_PPC_GOT_TPREL16; break;
++ case BFD_RELOC_PPC_GOT_TPREL16_LO: r = R_PPC_GOT_TPREL16_LO; break;
++ case BFD_RELOC_PPC_GOT_TPREL16_HI: r = R_PPC_GOT_TPREL16_HI; break;
++ case BFD_RELOC_PPC_GOT_TPREL16_HA: r = R_PPC_GOT_TPREL16_HA; break;
++ case BFD_RELOC_PPC_GOT_DTPREL16: r = R_PPC_GOT_DTPREL16; break;
++ case BFD_RELOC_PPC_GOT_DTPREL16_LO: r = R_PPC_GOT_DTPREL16_LO; break;
++ case BFD_RELOC_PPC_GOT_DTPREL16_HI: r = R_PPC_GOT_DTPREL16_HI; break;
++ case BFD_RELOC_PPC_GOT_DTPREL16_HA: r = R_PPC_GOT_DTPREL16_HA; break;
++ case BFD_RELOC_PPC_EMB_NADDR32: r = R_PPC_EMB_NADDR32; break;
++ case BFD_RELOC_PPC_EMB_NADDR16: r = R_PPC_EMB_NADDR16; break;
++ case BFD_RELOC_PPC_EMB_NADDR16_LO: r = R_PPC_EMB_NADDR16_LO; break;
++ case BFD_RELOC_PPC_EMB_NADDR16_HI: r = R_PPC_EMB_NADDR16_HI; break;
++ case BFD_RELOC_PPC_EMB_NADDR16_HA: r = R_PPC_EMB_NADDR16_HA; break;
++ case BFD_RELOC_PPC_EMB_SDAI16: r = R_PPC_EMB_SDAI16; break;
++ case BFD_RELOC_PPC_EMB_SDA2I16: r = R_PPC_EMB_SDA2I16; break;
++ case BFD_RELOC_PPC_EMB_SDA2REL: r = R_PPC_EMB_SDA2REL; break;
++ case BFD_RELOC_PPC_EMB_SDA21: r = R_PPC_EMB_SDA21; break;
++ case BFD_RELOC_PPC_EMB_MRKREF: r = R_PPC_EMB_MRKREF; break;
++ case BFD_RELOC_PPC_EMB_RELSEC16: r = R_PPC_EMB_RELSEC16; break;
++ case BFD_RELOC_PPC_EMB_RELST_LO: r = R_PPC_EMB_RELST_LO; break;
++ case BFD_RELOC_PPC_EMB_RELST_HI: r = R_PPC_EMB_RELST_HI; break;
++ case BFD_RELOC_PPC_EMB_RELST_HA: r = R_PPC_EMB_RELST_HA; break;
++ case BFD_RELOC_PPC_EMB_BIT_FLD: r = R_PPC_EMB_BIT_FLD; break;
++ case BFD_RELOC_PPC_EMB_RELSDA: r = R_PPC_EMB_RELSDA; break;
++ case BFD_RELOC_PPC_VLE_REL8: r = R_PPC_VLE_REL8; break;
++ case BFD_RELOC_PPC_VLE_REL15: r = R_PPC_VLE_REL15; break;
++ case BFD_RELOC_PPC_VLE_REL24: r = R_PPC_VLE_REL24; break;
++ case BFD_RELOC_PPC_VLE_LO16A: r = R_PPC_VLE_LO16A; break;
++ case BFD_RELOC_PPC_VLE_LO16D: r = R_PPC_VLE_LO16D; break;
++ case BFD_RELOC_PPC_VLE_HI16A: r = R_PPC_VLE_HI16A; break;
++ case BFD_RELOC_PPC_VLE_HI16D: r = R_PPC_VLE_HI16D; break;
++ case BFD_RELOC_PPC_VLE_HA16A: r = R_PPC_VLE_HA16A; break;
++ case BFD_RELOC_PPC_VLE_HA16D: r = R_PPC_VLE_HA16D; break;
++ case BFD_RELOC_PPC_VLE_SDA21: r = R_PPC_VLE_SDA21; break;
++ case BFD_RELOC_PPC_VLE_SDA21_LO: r = R_PPC_VLE_SDA21_LO; break;
++ case BFD_RELOC_PPC_VLE_SDAREL_LO16A:
++ r = R_PPC_VLE_SDAREL_LO16A;
++ break;
++ case BFD_RELOC_PPC_VLE_SDAREL_LO16D:
++ r = R_PPC_VLE_SDAREL_LO16D;
++ break;
++ case BFD_RELOC_PPC_VLE_SDAREL_HI16A:
++ r = R_PPC_VLE_SDAREL_HI16A;
++ break;
++ case BFD_RELOC_PPC_VLE_SDAREL_HI16D:
++ r = R_PPC_VLE_SDAREL_HI16D;
++ break;
++ case BFD_RELOC_PPC_VLE_SDAREL_HA16A:
++ r = R_PPC_VLE_SDAREL_HA16A;
++ break;
++ case BFD_RELOC_PPC_VLE_SDAREL_HA16D:
++ r = R_PPC_VLE_SDAREL_HA16D;
++ break;
++ case BFD_RELOC_16_PCREL: r = R_PPC_REL16; break;
++ case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break;
++ case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break;
++ case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break;
++ case BFD_RELOC_PPC_AMIGAOS_BREL: r = R_PPC_AMIGAOS_BREL; break;
++ case BFD_RELOC_PPC_AMIGAOS_BREL_LO: r = R_PPC_AMIGAOS_BREL_LO; break;
++ case BFD_RELOC_PPC_AMIGAOS_BREL_HI: r = R_PPC_AMIGAOS_BREL_HI; break;
++ case BFD_RELOC_PPC_AMIGAOS_BREL_HA: r = R_PPC_AMIGAOS_BREL_HA; break;
++ case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break;
++ case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break;
++ }
++
++ return ppc_elf_howto_table[r];
++};
++
++static reloc_howto_type *
++ppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
++ const char *r_name)
++{
++ unsigned int i;
++
++ for (i = 0;
++ i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]);
++ i++)
++ if (ppc_elf_howto_raw[i].name != NULL
++ && strcasecmp (ppc_elf_howto_raw[i].name, r_name) == 0)
++ return &ppc_elf_howto_raw[i];
++
++ return NULL;
++}
++
++/* Set the howto pointer for a PowerPC ELF reloc. */
++
++static void
++ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
++ arelent *cache_ptr,
++ Elf_Internal_Rela *dst)
++{
++ /* Initialize howto table if not already done. */
++ if (!ppc_elf_howto_table[R_PPC_ADDR32])
++ ppc_elf_howto_init ();
++
++ BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max);
++ cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)];
++
++ /* Just because the above assert didn't trigger doesn't mean that
++ ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation. */
++ if (!cache_ptr->howto)
++ {
++ (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
++ abfd, ELF32_R_TYPE (dst->r_info));
++ bfd_set_error (bfd_error_bad_value);
++
++ cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
++ }
++}
++
++/* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs. */
++
++static bfd_reloc_status_type
++ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
++ arelent *reloc_entry,
++ asymbol *symbol,
++ void *data ATTRIBUTE_UNUSED,
++ asection *input_section,
++ bfd *output_bfd,
++ char **error_message ATTRIBUTE_UNUSED)
++{
++ bfd_vma relocation;
++
++ if (output_bfd != NULL)
++ {
++ reloc_entry->address += input_section->output_offset;
++ return bfd_reloc_ok;
++ }
++
++ if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
++ return bfd_reloc_outofrange;
++
++ if (bfd_is_com_section (symbol->section))
++ relocation = 0;
++ else
++ relocation = symbol->value;
++
++ relocation += symbol->section->output_section->vma;
++ relocation += symbol->section->output_offset;
++ relocation += reloc_entry->addend;
++ if (reloc_entry->howto->pc_relative)
++ relocation -= reloc_entry->address;
++
++ reloc_entry->addend += (relocation & 0x8000) << 1;
++
++ return bfd_reloc_continue;
++}
++
++static bfd_reloc_status_type
++ppc_elf_unhandled_reloc (bfd *abfd,
++ arelent *reloc_entry,
++ asymbol *symbol,
++ void *data,
++ asection *input_section,
++ bfd *output_bfd,
++ char **error_message)
++{
++ /* If this is a relocatable link (output_bfd test tells us), just
++ call the generic function. Any adjustment will be done at final
++ link time. */
++ if (output_bfd != NULL)
++ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
++ input_section, output_bfd, error_message);
++
++ if (error_message != NULL)
++ {
++ static char buf[60];
++ sprintf (buf, _("generic linker can't handle %s"),
++ reloc_entry->howto->name);
++ *error_message = buf;
++ }
++ return bfd_reloc_dangerous;
++}
++
++/* Sections created by the linker. */
++
++typedef struct elf_linker_section
++{
++ /* Pointer to the bfd section. */
++ asection *section;
++ /* Section name. */
++ const char *name;
++ /* Associated bss section name. */
++ const char *bss_name;
++ /* Associated symbol name. */
++ const char *sym_name;
++ /* Associated symbol. */
++ struct elf_link_hash_entry *sym;
++} elf_linker_section_t;
++
++/* Linked list of allocated pointer entries. This hangs off of the
++ symbol lists, and provides allows us to return different pointers,
++ based on different addend's. */
++
++typedef struct elf_linker_section_pointers
++{
++ /* next allocated pointer for this symbol */
++ struct elf_linker_section_pointers *next;
++ /* offset of pointer from beginning of section */
++ bfd_vma offset;
++ /* addend used */
++ bfd_vma addend;
++ /* which linker section this is */
++ elf_linker_section_t *lsect;
++} elf_linker_section_pointers_t;
++
++struct ppc_elf_obj_tdata
++{
++ struct elf_obj_tdata elf;
++
++ /* A mapping from local symbols to offsets into the various linker
++ sections added. This is index by the symbol index. */
++ elf_linker_section_pointers_t **linker_section_pointers;
++
++ /* Flags used to auto-detect plt type. */
++ unsigned int makes_plt_call : 1;
++ unsigned int has_rel16 : 1;
++};
++
++#define ppc_elf_tdata(bfd) \
++ ((struct ppc_elf_obj_tdata *) (bfd)->tdata.any)
++
++#define elf_local_ptr_offsets(bfd) \
++ (ppc_elf_tdata (bfd)->linker_section_pointers)
++
++#define is_ppc_elf(bfd) \
++ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
++ && elf_object_id (bfd) == PPC32_ELF_DATA)
++
++/* Override the generic function because we store some extras. */
++
++static bfd_boolean
++ppc_elf_mkobject (bfd *abfd)
++{
++ return bfd_elf_allocate_object (abfd, sizeof (struct ppc_elf_obj_tdata),
++ PPC32_ELF_DATA);
++}
++
++/* Fix bad default arch selected for a 32 bit input bfd when the
++ default is 64 bit. */
++
++static bfd_boolean
++ppc_elf_object_p (bfd *abfd)
++{
++ if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64)
++ {
++ Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
++
++ if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32)
++ {
++ /* Relies on arch after 64 bit default being 32 bit default. */
++ abfd->arch_info = abfd->arch_info->next;
++ BFD_ASSERT (abfd->arch_info->bits_per_word == 32);
++ }
++ }
++ return TRUE;
++}
++
++/* Function to set whether a module needs the -mrelocatable bit set. */
++
++static bfd_boolean
++ppc_elf_set_private_flags (bfd *abfd, flagword flags)
++{
++ BFD_ASSERT (!elf_flags_init (abfd)
++ || elf_elfheader (abfd)->e_flags == flags);
++
++ elf_elfheader (abfd)->e_flags = flags;
++ elf_flags_init (abfd) = TRUE;
++ return TRUE;
++}
++
++/* Support for core dump NOTE sections. */
++
++static bfd_boolean
++ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
++{
++ int offset;
++ unsigned int size;
++
++ switch (note->descsz)
++ {
++ default:
++ return FALSE;
++
++ case 268: /* Linux/PPC. */
++ /* pr_cursig */
++ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
++
++ /* pr_pid */
++ elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24);
++
++ /* pr_reg */
++ offset = 72;
++ size = 192;
++
++ break;
++ }
++
++ /* Make a ".reg/999" section. */
++ return _bfd_elfcore_make_pseudosection (abfd, ".reg",
++ size, note->descpos + offset);
++}
++
++static bfd_boolean
++ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
++{
++ switch (note->descsz)
++ {
++ default:
++ return FALSE;
++
++ case 128: /* Linux/PPC elf_prpsinfo. */
++ elf_tdata (abfd)->core_pid
++ = bfd_get_32 (abfd, note->descdata + 16);
++ elf_tdata (abfd)->core_program
++ = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16);
++ elf_tdata (abfd)->core_command
++ = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
++ }
++
++ /* Note that for some reason, a spurious space is tacked
++ onto the end of the args in some (at least one anyway)
++ implementations, so strip it off if it exists. */
++
++ {
++ char *command = elf_tdata (abfd)->core_command;
++ int n = strlen (command);
++
++ if (0 < n && command[n - 1] == ' ')
++ command[n - 1] = '\0';
++ }
++
++ return TRUE;
++}
++
++static char *
++ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...)
++{
++ switch (note_type)
++ {
++ default:
++ return NULL;
++
++ case NT_PRPSINFO:
++ {
++ char data[128];
++ va_list ap;
++
++ va_start (ap, note_type);
++ memset (data, 0, sizeof (data));
++ strncpy (data + 32, va_arg (ap, const char *), 16);
++ strncpy (data + 48, va_arg (ap, const char *), 80);
++ va_end (ap);
++ return elfcore_write_note (abfd, buf, bufsiz,
++ "CORE", note_type, data, sizeof (data));
++ }
++
++ case NT_PRSTATUS:
++ {
++ char data[268];
++ va_list ap;
++ long pid;
++ int cursig;
++ const void *greg;
++
++ va_start (ap, note_type);
++ memset (data, 0, 72);
++ pid = va_arg (ap, long);
++ bfd_put_32 (abfd, pid, data + 24);
++ cursig = va_arg (ap, int);
++ bfd_put_16 (abfd, cursig, data + 12);
++ greg = va_arg (ap, const void *);
++ memcpy (data + 72, greg, 192);
++ memset (data + 264, 0, 4);
++ va_end (ap);
++ return elfcore_write_note (abfd, buf, bufsiz,
++ "CORE", note_type, data, sizeof (data));
++ }
++ }
++}
++
++static flagword
++ppc_elf_lookup_section_flags (char *flag_name)
++{
++
++ if (!strcmp (flag_name, "SHF_PPC_VLE"))
++ return SHF_PPC_VLE;
++
++ return 0;
++}
++
++/* Add the VLE flag if required. */
++
++bfd_boolean
++ppc_elf_amigaos_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr)
++{
++ if (bfd_get_mach (abfd) == bfd_mach_ppc_vle
++ && (shdr->sh_flags & SHF_EXECINSTR) != 0)
++ shdr->sh_flags |= SHF_PPC_VLE;
++
++ return TRUE;
++}
++
++/* Return address for Ith PLT stub in section PLT, for relocation REL
++ or (bfd_vma) -1 if it should not be included. */
++
++static bfd_vma
++ppc_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED,
++ const asection *plt ATTRIBUTE_UNUSED,
++ const arelent *rel)
++{
++#ifdef DEBUG
++ fprintf (stderr, "ppc_elf_plt_sym_cal (0x%08x)\n", (unsigned int)rel->address);
++#endif
++ return rel->address;
++}
++
++/* Handle a PowerPC specific section when reading an object file. This
++ is called when bfd_section_from_shdr finds a section with an unknown
++ type. */
++
++static bfd_boolean
++ppc_elf_section_from_shdr (bfd *abfd,
++ Elf_Internal_Shdr *hdr,
++ const char *name,
++ int shindex)
++{
++ asection *newsect;
++ flagword flags;
++
++ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
++ return FALSE;
++
++ newsect = hdr->bfd_section;
++ flags = bfd_get_section_flags (abfd, newsect);
++ if (hdr->sh_flags & SHF_EXCLUDE)
++ flags |= SEC_EXCLUDE;
++
++ if (hdr->sh_type == SHT_ORDERED)
++ flags |= SEC_SORT_ENTRIES;
++
++ bfd_set_section_flags (abfd, newsect, flags);
++ return TRUE;
++}
++
++/* Set up any other section flags and such that may be necessary. */
++
++static bfd_boolean
++ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
++ Elf_Internal_Shdr *shdr,
++ asection *asect)
++{
++ if ((asect->flags & SEC_SORT_ENTRIES) != 0)
++ shdr->sh_type = SHT_ORDERED;
++
++ return TRUE;
++}
++
++/* If we have .sbss2 or .PPC.EMB.sbss0 output sections, we
++ need to bump up the number of section headers. */
++
++static int
++ppc_elf_additional_program_headers (bfd *abfd,
++ struct bfd_link_info *info ATTRIBUTE_UNUSED)
++{
++ asection *s;
++// int ret = 0;
++ int ret = 1;
++
++ s = bfd_get_section_by_name (abfd, ".sbss2");
++ if (s != NULL && (s->flags & SEC_ALLOC) != 0)
++ ++ret;
++
++ s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0");
++ if (s != NULL && (s->flags & SEC_ALLOC) != 0)
++ ++ret;
++
++ return ret;
++}
++
++/* Modify the segment map for VLE executables. */
++
++bfd_boolean
++ppc_elf_amigaos_modify_segment_map (bfd *abfd,
++ struct bfd_link_info *info ATTRIBUTE_UNUSED)
++{
++ struct elf_segment_map *m, *n;
++ bfd_size_type amt;
++ unsigned int j, k;
++ bfd_boolean sect0_vle, sectj_vle;
++
++ /* At this point in the link, output sections have already been sorted by
++ LMA and assigned to segments. All that is left to do is to ensure
++ there is no mixing of VLE & non-VLE sections in a text segment.
++ If we find that case, we split the segment.
++ We maintain the original output section order. */
++
++ for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
++ {
++ if (m->count == 0)
++ continue;
++
++ sect0_vle = (elf_section_flags (m->sections[0]) & SHF_PPC_VLE) != 0;
++ for (j = 1; j < m->count; ++j)
++ {
++ sectj_vle = (elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0;
++
++ if (sectj_vle != sect0_vle)
++ break;
++ }
++ if (j >= m->count)
++ continue;
++
++ /* sections 0..j-1 stay in this (current) segment,
++ the remainder are put in a new segment.
++ The scan resumes with the new segment. */
++
++ /* Fix the new segment. */
++ amt = sizeof (struct elf_segment_map);
++ amt += (m->count - j - 1) * sizeof (asection *);
++ n = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
++ if (n == NULL)
++ return FALSE;
++
++ n->p_type = PT_LOAD;
++ n->p_flags = PF_X | PF_R;
++ if (sectj_vle)
++ n->p_flags |= PF_PPC_VLE;
++ n->count = m->count - j;
++ for (k = 0; k < n->count; ++k)
++ {
++ n->sections[k] = m->sections[j+k];
++ m->sections[j+k] = NULL;
++ }
++ n->next = m->next;
++ m->next = n;
++
++ /* Fix the current segment */
++ m->count = j;
++ }
++
++ return TRUE;
++}
++
++/* Add extra PPC sections -- Note, for now, make .sbss2 and
++ .PPC.EMB.sbss0 a normal section, and not a bss section so
++ that the linker doesn't crater when trying to make more than
++ 2 sections. */
++
++static const struct bfd_elf_special_section ppc_elf_special_sections[] =
++{
++ { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR },
++ { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
++ { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC },
++ { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
++ { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC },
++ { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC },
++ { STRING_COMMA_LEN (".PPC.EMB.apuinfo"), 0, SHT_NOTE, 0 },
++ { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC },
++ { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC },
++ { NULL, 0, 0, 0, 0 }
++};
++
++/* This is what we want for new plt/got. */
++static struct bfd_elf_special_section ppc_alt_plt =
++ { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC };
++
++static const struct bfd_elf_special_section *
++ppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
++{
++ const struct bfd_elf_special_section *ssect;
++
++ /* See if this is one of the special sections. */
++ if (sec->name == NULL)
++ return NULL;
++
++ ssect = _bfd_elf_get_special_section (sec->name, ppc_elf_special_sections,
++ sec->use_rela_p);
++ if (ssect != NULL)
++ {
++ if (ssect == ppc_elf_special_sections && (sec->flags & SEC_LOAD) != 0)
++ ssect = &ppc_alt_plt;
++ return ssect;
++ }
++
++ return _bfd_elf_get_sec_type_attr (abfd, sec);
++}
++
++/* Very simple linked list structure for recording apuinfo values. */
++typedef struct apuinfo_list
++{
++ struct apuinfo_list *next;
++ unsigned long value;
++}
++apuinfo_list;
++
++static apuinfo_list *head;
++static bfd_boolean apuinfo_set;
++
++static void
++apuinfo_list_init (void)
++{
++ head = NULL;
++ apuinfo_set = FALSE;
++}
++
++static void
++apuinfo_list_add (unsigned long value)
++{
++ apuinfo_list *entry = head;
++
++ while (entry != NULL)
++ {
++ if (entry->value == value)
++ return;
++ entry = entry->next;
++ }
++
++ entry = bfd_malloc (sizeof (* entry));
++ if (entry == NULL)
++ return;
++
++ entry->value = value;
++ entry->next = head;
++ head = entry;
++}
++
++static unsigned
++apuinfo_list_length (void)
++{
++ apuinfo_list *entry;
++ unsigned long count;
++
++ for (entry = head, count = 0;
++ entry;
++ entry = entry->next)
++ ++ count;
++
++ return count;
++}
++
++static inline unsigned long
++apuinfo_list_element (unsigned long number)
++{
++ apuinfo_list * entry;
++
++ for (entry = head;
++ entry && number --;
++ entry = entry->next)
++ ;
++
++ return entry ? entry->value : 0;
++}
++
++static void
++apuinfo_list_finish (void)
++{
++ apuinfo_list *entry;
++
++ for (entry = head; entry;)
++ {
++ apuinfo_list *next = entry->next;
++ free (entry);
++ entry = next;
++ }
++
++ head = NULL;
++}
++
++#define APUINFO_SECTION_NAME ".PPC.EMB.apuinfo"
++#define APUINFO_LABEL "APUinfo"
++
++/* Scan the input BFDs and create a linked list of
++ the APUinfo values that will need to be emitted. */
++
++static void
++ppc_elf_amigaos_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
++{
++ bfd *ibfd;
++ asection *asec;
++ char *buffer = NULL;
++ bfd_size_type largest_input_size = 0;
++ unsigned i;
++ unsigned long length;
++ const char *error_message = NULL;
++
++ if (link_info == NULL)
++ return;
++
++ apuinfo_list_init ();
++
++ /* Read in the input sections contents. */
++ for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next)
++ {
++ unsigned long datum;
++
++ asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME);
++ if (asec == NULL)
++ continue;
++
++ error_message = _("corrupt %s section in %B");
++ length = asec->size;
++ if (length < 20)
++ goto fail;
++
++ apuinfo_set = TRUE;
++ if (largest_input_size < asec->size)
++ {
++ if (buffer)
++ free (buffer);
++ largest_input_size = asec->size;
++ buffer = bfd_malloc (largest_input_size);
++ if (!buffer)
++ return;
++ }
++
++ if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0
++ || (bfd_bread (buffer, length, ibfd) != length))
++ {
++ error_message = _("unable to read in %s section from %B");
++ goto fail;
++ }
++
++ /* Verify the contents of the header. Note - we have to
++ extract the values this way in order to allow for a
++ host whose endian-ness is different from the target. */
++ datum = bfd_get_32 (ibfd, buffer);
++ if (datum != sizeof APUINFO_LABEL)
++ goto fail;
++
++ datum = bfd_get_32 (ibfd, buffer + 8);
++ if (datum != 0x2)
++ goto fail;
++
++ if (strcmp (buffer + 12, APUINFO_LABEL) != 0)
++ goto fail;
++
++ /* Get the number of bytes used for apuinfo entries. */
++ datum = bfd_get_32 (ibfd, buffer + 4);
++ if (datum + 20 != length)
++ goto fail;
++
++ /* Scan the apuinfo section, building a list of apuinfo numbers. */
++ for (i = 0; i < datum; i += 4)
++ apuinfo_list_add (bfd_get_32 (ibfd, buffer + 20 + i));
++ }
++
++ error_message = NULL;
++
++ if (apuinfo_set)
++ {
++ /* Compute the size of the output section. */
++ unsigned num_entries = apuinfo_list_length ();
++
++ /* Set the output section size, if it exists. */
++ asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
++
++ if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4))
++ {
++ ibfd = abfd;
++ error_message = _("warning: unable to set size of %s section in %B");
++ }
++ }
++
++ fail:
++ if (buffer)
++ free (buffer);
++
++ if (error_message)
++ (*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME);
++}
++
++/* Prevent the output section from accumulating the input sections'
++ contents. We have already stored this in our linked list structure. */
++
++static bfd_boolean
++ppc_elf_amigaos_write_section (bfd *abfd ATTRIBUTE_UNUSED,
++ struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
++ asection *asec,
++ bfd_byte *contents ATTRIBUTE_UNUSED)
++{
++ return apuinfo_set && strcmp (asec->name, APUINFO_SECTION_NAME) == 0;
++}
++
++/* Finally we can generate the output section. */
++
++static void
++ppc_elf_amigaos_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
++{
++ bfd_byte *buffer;
++ asection *asec;
++ unsigned i;
++ unsigned num_entries;
++ bfd_size_type length;
++
++ asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
++ if (asec == NULL)
++ return;
++
++ if (!apuinfo_set)
++ return;
++
++ length = asec->size;
++ if (length < 20)
++ return;
++
++ buffer = bfd_malloc (length);
++ if (buffer == NULL)
++ {
++ (*_bfd_error_handler)
++ (_("failed to allocate space for new APUinfo section."));
++ return;
++ }
++
++ /* Create the apuinfo header. */
++ num_entries = apuinfo_list_length ();
++ bfd_put_32 (abfd, sizeof APUINFO_LABEL, buffer);
++ bfd_put_32 (abfd, num_entries * 4, buffer + 4);
++ bfd_put_32 (abfd, 0x2, buffer + 8);
++ strcpy ((char *) buffer + 12, APUINFO_LABEL);
++
++ length = 20;
++ for (i = 0; i < num_entries; i++)
++ {
++ bfd_put_32 (abfd, apuinfo_list_element (i), buffer + length);
++ length += 4;
++ }
++
++ if (length != asec->size)
++ (*_bfd_error_handler) (_("failed to compute new APUinfo section."));
++
++ if (! bfd_set_section_contents (abfd, asec, buffer, (file_ptr) 0, length))
++ (*_bfd_error_handler) (_("failed to install new APUinfo section."));
++
++ free (buffer);
++
++ apuinfo_list_finish ();
++}
++
++static bfd_boolean
++is_nonpic_glink_stub (bfd *abfd, asection *glink, bfd_vma off)
++{
++ bfd_byte buf[GLINK_ENTRY_SIZE];
++
++ if (!bfd_get_section_contents (abfd, glink, buf, off, GLINK_ENTRY_SIZE))
++ return FALSE;
++
++ return ((bfd_get_32 (abfd, buf + 0) & 0xffff0000) == LIS_11
++ && (bfd_get_32 (abfd, buf + 4) & 0xffff0000) == LWZ_11_11
++ && bfd_get_32 (abfd, buf + 8) == MTCTR_11
++ && bfd_get_32 (abfd, buf + 12) == BCTR);
++}
++
++static bfd_boolean
++section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr)
++{
++ bfd_vma vma = *(bfd_vma *) ptr;
++ return ((section->flags & SEC_ALLOC) != 0
++ && section->vma <= vma
++ && vma < section->vma + section->size);
++}
++
++static long
++ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
++ long dynsymcount, asymbol **dynsyms,
++ asymbol **ret)
++{
++ bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
++ asection *plt, *relplt, *dynamic, *glink;
++ bfd_vma glink_vma = 0;
++ bfd_vma resolv_vma = 0;
++ bfd_vma stub_vma;
++ asymbol *s;
++ arelent *p;
++ long count, i;
++ size_t size;
++ char *names;
++ bfd_byte buf[4];
++
++ *ret = NULL;
++
++ if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
++ return 0;
++
++ if (dynsymcount <= 0)
++ return 0;
++
++ relplt = bfd_get_section_by_name (abfd, ".rela.plt");
++ if (relplt == NULL)
++ return 0;
++
++ plt = bfd_get_section_by_name (abfd, ".plt");
++ if (plt == NULL)
++ return 0;
++
++ /* Call common code to handle old-style executable PLTs. */
++ if (elf_section_flags (plt) & SHF_EXECINSTR)
++ return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
++ dynsymcount, dynsyms, ret);
++
++ /* If this object was prelinked, the prelinker stored the address
++ of .glink at got[1]. If it wasn't prelinked, got[1] will be zero. */
++ dynamic = bfd_get_section_by_name (abfd, ".dynamic");
++ if (dynamic != NULL)
++ {
++ bfd_byte *dynbuf, *extdyn, *extdynend;
++ size_t extdynsize;
++ void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
++
++ if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf))
++ return -1;
++
++ extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
++ swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
++
++ extdyn = dynbuf;
++ extdynend = extdyn + dynamic->size;
++ for (; extdyn < extdynend; extdyn += extdynsize)
++ {
++ Elf_Internal_Dyn dyn;
++ (*swap_dyn_in) (abfd, extdyn, &dyn);
++
++ if (dyn.d_tag == DT_NULL)
++ break;
++
++ if (dyn.d_tag == DT_PPC_GOT)
++ {
++ unsigned int g_o_t = dyn.d_un.d_val;
++ asection *got = bfd_get_section_by_name (abfd, ".got");
++ if (got != NULL
++ && bfd_get_section_contents (abfd, got, buf,
++ g_o_t - got->vma + 4, 4))
++ glink_vma = bfd_get_32 (abfd, buf);
++ break;
++ }
++ }
++ free (dynbuf);
++ }
++
++ /* Otherwise we read the first plt entry. */
++ if (glink_vma == 0)
++ {
++ if (bfd_get_section_contents (abfd, plt, buf, 0, 4))
++ glink_vma = bfd_get_32 (abfd, buf);
++ }
++
++ if (glink_vma == 0)
++ return 0;
++
++ /* The .glink section usually does not survive the final
++ link; search for the section (usually .text) where the
++ glink stubs now reside. */
++ glink = bfd_sections_find_if (abfd, section_covers_vma, &glink_vma);
++ if (glink == NULL)
++ return 0;
++
++ /* Determine glink PLT resolver by reading the relative branch
++ from the first glink stub. */
++ if (bfd_get_section_contents (abfd, glink, buf,
++ glink_vma - glink->vma, 4))
++ {
++ unsigned int insn = bfd_get_32 (abfd, buf);
++
++ /* The first glink stub may either branch to the resolver ... */
++ insn ^= B;
++ if ((insn & ~0x3fffffc) == 0)
++ resolv_vma = glink_vma + (insn ^ 0x2000000) - 0x2000000;
++
++ /* ... or fall through a bunch of NOPs. */
++ else if ((insn ^ B ^ NOP) == 0)
++ for (i = 4;
++ bfd_get_section_contents (abfd, glink, buf,
++ glink_vma - glink->vma + i, 4);
++ i += 4)
++ if (bfd_get_32 (abfd, buf) != NOP)
++ {
++ resolv_vma = glink_vma + i;
++ break;
++ }
++ }
++
++ count = relplt->size / sizeof (Elf32_External_Rela);
++ stub_vma = glink_vma - (bfd_vma) count * 16;
++ /* If the stubs are those for -shared/-pie then we might have
++ multiple stubs for each plt entry. If that is the case then
++ there is no way to associate stubs with their plt entries short
++ of figuring out the GOT pointer value used in the stub. */
++ if (!is_nonpic_glink_stub (abfd, glink,
++ glink_vma - GLINK_ENTRY_SIZE - glink->vma))
++ return 0;
++
++ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
++ if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
++ return -1;
++
++ size = count * sizeof (asymbol);
++ p = relplt->relocation;
++ for (i = 0; i < count; i++, p++)
++ {
++ size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
++ if (p->addend != 0)
++ size += sizeof ("+0x") - 1 + 8;
++ }
++
++ size += sizeof (asymbol) + sizeof ("__glink");
++
++ if (resolv_vma)
++ size += sizeof (asymbol) + sizeof ("__glink_PLTresolve");
++
++ s = *ret = bfd_malloc (size);
++ if (s == NULL)
++ return -1;
++
++ names = (char *) (s + count + 1 + (resolv_vma != 0));
++ p = relplt->relocation;
++ for (i = 0; i < count; i++, p++)
++ {
++ size_t len;
++
++ *s = **p->sym_ptr_ptr;
++ /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since
++ we are defining a symbol, ensure one of them is set. */
++ if ((s->flags & BSF_LOCAL) == 0)
++ s->flags |= BSF_GLOBAL;
++ s->flags |= BSF_SYNTHETIC;
++ s->section = glink;
++ s->value = stub_vma - glink->vma;
++ s->name = names;
++ s->udata.p = NULL;
++ len = strlen ((*p->sym_ptr_ptr)->name);
++ memcpy (names, (*p->sym_ptr_ptr)->name, len);
++ names += len;
++ if (p->addend != 0)
++ {
++ memcpy (names, "+0x", sizeof ("+0x") - 1);
++ names += sizeof ("+0x") - 1;
++ bfd_sprintf_vma (abfd, names, p->addend);
++ names += strlen (names);
++ }
++ memcpy (names, "@plt", sizeof ("@plt"));
++ names += sizeof ("@plt");
++ ++s;
++ stub_vma += 16;
++ }
++
++ /* Add a symbol at the start of the glink branch table. */
++ memset (s, 0, sizeof *s);
++ s->the_bfd = abfd;
++ s->flags = BSF_GLOBAL | BSF_SYNTHETIC;
++ s->section = glink;
++ s->value = glink_vma - glink->vma;
++ s->name = names;
++ memcpy (names, "__glink", sizeof ("__glink"));
++ names += sizeof ("__glink");
++ s++;
++ count++;
++
++ if (resolv_vma)
++ {
++ /* Add a symbol for the glink PLT resolver. */
++ memset (s, 0, sizeof *s);
++ s->the_bfd = abfd;
++ s->flags = BSF_GLOBAL | BSF_SYNTHETIC;
++ s->section = glink;
++ s->value = resolv_vma - glink->vma;
++ s->name = names;
++ memcpy (names, "__glink_PLTresolve", sizeof ("__glink_PLTresolve"));
++ names += sizeof ("__glink_PLTresolve");
++ s++;
++ count++;
++ }
++
++ return count;
++}
++
++/* The following functions are specific to the ELF linker, while
++ functions above are used generally. They appear in this file more
++ or less in the order in which they are called. eg.
++ ppc_elf_check_relocs is called early in the link process,
++ ppc_elf_finish_dynamic_sections is one of the last functions
++ called. */
++
++/* Track PLT entries needed for a given symbol. We might need more
++ than one glink entry per symbol when generating a pic binary. */
++struct plt_entry
++{
++ struct plt_entry *next;
++
++ /* -fPIC uses multiple GOT sections, one per file, called ".got2".
++ This field stores the offset into .got2 used to initialise the
++ GOT pointer reg. It will always be at least 32768. (Current
++ gcc always uses an offset of 32768, but ld -r will pack .got2
++ sections together resulting in larger offsets). */
++ bfd_vma addend;
++
++ /* The .got2 section. */
++ asection *sec;
++
++ /* PLT refcount or offset. */
++ union
++ {
++ bfd_signed_vma refcount;
++ bfd_vma offset;
++ } plt;
++
++ /* .glink stub offset. */
++ bfd_vma glink_offset;
++};
++
++/* Of those relocs that might be copied as dynamic relocs, this function
++ selects those that must be copied when linking a shared library,
++ even when the symbol is local. */
++
++static int
++must_be_dyn_reloc (struct bfd_link_info *info,
++ enum elf_ppc_reloc_type r_type)
++{
++ switch (r_type)
++ {
++ default:
++ return 1;
++
++ case R_PPC_REL24:
++ case R_PPC_REL14:
++ case R_PPC_REL14_BRTAKEN:
++ case R_PPC_REL14_BRNTAKEN:
++ case R_PPC_REL32:
++ return 0;
++
++ case R_PPC_TPREL32:
++ case R_PPC_TPREL16:
++ case R_PPC_TPREL16_LO:
++ case R_PPC_TPREL16_HI:
++ case R_PPC_TPREL16_HA:
++ return !info->executable;
++ }
++}
++
++/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
++ copying dynamic variables from a shared lib into an app's dynbss
++ section, and instead use a dynamic relocation to point into the
++ shared lib. */
++#define ELIMINATE_COPY_RELOCS 1
++
++/* PPC ELF linker hash entry. */
++
++struct ppc_elf_link_hash_entry
++{
++ struct elf_link_hash_entry elf;
++
++ /* If this symbol is used in the linker created sections, the processor
++ specific backend uses this field to map the field into the offset
++ from the beginning of the section. */
++ elf_linker_section_pointers_t *linker_section_pointer;
++
++ /* Track dynamic relocs copied for this symbol. */
++ struct elf_dyn_relocs *dyn_relocs;
++
++ /* Contexts in which symbol is used in the GOT (or TOC).
++ TLS_GD .. TLS_TLS bits are or'd into the mask as the
++ corresponding relocs are encountered during check_relocs.
++ tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to
++ indicate the corresponding GOT entry type is not needed. */
++#define TLS_GD 1 /* GD reloc. */
++#define TLS_LD 2 /* LD reloc. */
++#define TLS_TPREL 4 /* TPREL reloc, => IE. */
++#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */
++#define TLS_TLS 16 /* Any TLS reloc. */
++#define TLS_TPRELGD 32 /* TPREL reloc resulting from GD->IE. */
++#define PLT_IFUNC 64 /* STT_GNU_IFUNC. */
++ char tls_mask;
++
++ /* Nonzero if we have seen a small data relocation referring to this
++ symbol. */
++ unsigned char has_sda_refs;
++};
++
++#define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent))
++
++/* PPC ELF linker hash table. */
++
++struct ppc_elf_link_hash_table
++{
++ struct elf_link_hash_table elf;
++
++ /* Short-cuts to get to dynamic linker sections. */
++ asection *got;
++ asection *relgot;
++ asection *glink;
++ asection *plt;
++ asection *relplt;
++ asection *iplt;
++ asection *reliplt;
++ asection *dynbss;
++ asection *relbss;
++ asection *dynsbss;
++ asection *relsbss;
++ elf_linker_section_t sdata[2];
++ asection *sbss;
++ asection *glink_eh_frame;
++
++ /* The (unloaded but important) .rela.plt.unloaded on VxWorks. */
++ asection *srelplt2;
++
++ /* The .got.plt section (VxWorks only)*/
++ asection *sgotplt;
++
++ /* Shortcut to __tls_get_addr. */
++ struct elf_link_hash_entry *tls_get_addr;
++
++ /* The bfd that forced an old-style PLT. */
++ bfd *old_bfd;
++
++ /* TLS local dynamic got entry handling. */
++ union {
++ bfd_signed_vma refcount;
++ bfd_vma offset;
++ } tlsld_got;
++
++ /* Offset of branch table to PltResolve function in glink. */
++ bfd_vma glink_pltresolve;
++
++ /* Size of reserved GOT entries. */
++ unsigned int got_header_size;
++ /* Non-zero if allocating the header left a gap. */
++ unsigned int got_gap;
++
++ /* The type of PLT we have chosen to use. */
++ enum ppc_elf_plt_type plt_type;
++
++ /* Set if we should emit symbols for stubs. */
++ unsigned int emit_stub_syms:1;
++
++ /* Set if __tls_get_addr optimization should not be done. */
++ unsigned int no_tls_get_addr_opt:1;
++
++ /* True if the target system is VxWorks. */
++ unsigned int is_vxworks:1;
++
++ /* The size of PLT entries. */
++ int plt_entry_size;
++ /* The distance between adjacent PLT slots. */
++ int plt_slot_size;
++ /* The size of the first PLT entry. */
++ int plt_initial_entry_size;
++
++ /* Small local sym cache. */
++ struct sym_cache sym_cache;
++};
++
++/* Rename some of the generic section flags to better document how they
++ are used for ppc32. The flags are only valid for ppc32 elf objects. */
++
++/* Nonzero if this section has TLS related relocations. */
++#define has_tls_reloc sec_flg0
++
++/* Nonzero if this section has a call to __tls_get_addr. */
++#define has_tls_get_addr_call sec_flg1
++
++/* Get the PPC ELF linker hash table from a link_info structure. */
++
++#define ppc_elf_hash_table(p) \
++ (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
++ == PPC32_ELF_DATA ? ((struct ppc_elf_link_hash_table *) ((p)->hash)) : NULL)
++
++/* Create an entry in a PPC ELF linker hash table. */
++
++static struct bfd_hash_entry *
++ppc_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
++ struct bfd_hash_table *table,
++ const char *string)
++{
++ /* Allocate the structure if it has not already been allocated by a
++ subclass. */
++ if (entry == NULL)
++ {
++ entry = bfd_hash_allocate (table,
++ sizeof (struct ppc_elf_link_hash_entry));
++ if (entry == NULL)
++ return entry;
++ }
++
++ /* Call the allocation method of the superclass. */
++ entry = _bfd_elf_link_hash_newfunc (entry, table, string);
++ if (entry != NULL)
++ {
++ ppc_elf_hash_entry (entry)->linker_section_pointer = NULL;
++ ppc_elf_hash_entry (entry)->dyn_relocs = NULL;
++ ppc_elf_hash_entry (entry)->tls_mask = 0;
++ ppc_elf_hash_entry (entry)->has_sda_refs = 0;
++ }
++
++ return entry;
++}
++
++/* Create a PPC ELF linker hash table. */
++
++static struct bfd_link_hash_table *
++ppc_elf_link_hash_table_create (bfd *abfd)
++{
++ struct ppc_elf_link_hash_table *ret;
++
++ ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
++ if (ret == NULL)
++ return NULL;
++
++ if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
++ ppc_elf_link_hash_newfunc,
++ sizeof (struct ppc_elf_link_hash_entry),
++ PPC32_ELF_DATA))
++ {
++ free (ret);
++ return NULL;
++ }
++
++ ret->elf.init_plt_refcount.refcount = 0;
++ ret->elf.init_plt_refcount.glist = NULL;
++ ret->elf.init_plt_offset.offset = 0;
++ ret->elf.init_plt_offset.glist = NULL;
++
++ ret->sdata[0].name = ".sdata";
++ ret->sdata[0].sym_name = "_SDA_BASE_";
++ ret->sdata[0].bss_name = ".sbss";
++
++ ret->sdata[1].name = ".sdata2";
++ ret->sdata[1].sym_name = "_SDA2_BASE_";
++ ret->sdata[1].bss_name = ".sbss2";
++
++ ret->plt_entry_size = 12;
++ ret->plt_slot_size = 8;
++ ret->plt_initial_entry_size = 72;
++
++ return &ret->elf.root;
++}
++
++/* Create .got and the related sections. */
++
++static bfd_boolean
++ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info)
++{
++ struct ppc_elf_link_hash_table *htab;
++ asection *s;
++ flagword flags;
++
++ if (!_bfd_elf_create_got_section (abfd, info))
++ return FALSE;
++
++ htab = ppc_elf_hash_table (info);
++ htab->got = s = bfd_get_linker_section (abfd, ".got");
++ if (s == NULL)
++ abort ();
++
++ if (htab->is_vxworks)
++ {
++ htab->sgotplt = bfd_get_linker_section (abfd, ".got.plt");
++ if (!htab->sgotplt)
++ abort ();
++ }
++ else
++ {
++ /* The powerpc .got has a blrl instruction in it. Mark it
++ executable. */
++ flags = (SEC_ALLOC | SEC_LOAD | /*SEC_CODE |*/ SEC_HAS_CONTENTS
++ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
++ if (!bfd_set_section_flags (abfd, s, flags))
++ return FALSE;
++ }
++
++ htab->relgot = bfd_get_linker_section (abfd, ".rela.got");
++ if (!htab->relgot)
++ abort ();
++
++ return TRUE;
++}
++
++static bfd_boolean
++ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
++{
++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
++ asection *s;
++ flagword flags;
++
++ flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY | SEC_HAS_CONTENTS
++ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
++ s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags);
++ htab->glink = s;
++ if (s == NULL
++ || !bfd_set_section_alignment (abfd, s, 4))
++ return FALSE;
++
++ if (!info->no_ld_generated_unwind_info)
++ {
++ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
++ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
++ s = bfd_make_section_anyway_with_flags (abfd, ".eh_frame", flags);
++ htab->glink_eh_frame = s;
++ if (s == NULL
++ || !bfd_set_section_alignment (abfd, s, 2))
++ return FALSE;
++ }
++
++ flags = SEC_ALLOC | SEC_LINKER_CREATED;
++ s = bfd_make_section_anyway_with_flags (abfd, ".iplt", flags);
++ htab->iplt = s;
++ if (s == NULL
++ || !bfd_set_section_alignment (abfd, s, 4))
++ return FALSE;
++
++ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
++ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
++ s = bfd_make_section_anyway_with_flags (abfd, ".rela.iplt", flags);
++ htab->reliplt = s;
++ if (s == NULL
++ || ! bfd_set_section_alignment (abfd, s, 2))
++ return FALSE;
++ return TRUE;
++}
++
++/* We have to create .dynsbss and .rela.sbss here so that they get mapped
++ to output sections (just like _bfd_elf_create_dynamic_sections has
++ to create .dynbss and .rela.bss). */
++
++static bfd_boolean
++ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
++{
++ struct ppc_elf_link_hash_table *htab;
++ asection *s;
++ flagword flags;
++
++ htab = ppc_elf_hash_table (info);
++
++ if (htab->got == NULL
++ && !ppc_elf_create_got (abfd, info))
++ return FALSE;
++
++ if (!_bfd_elf_create_dynamic_sections (abfd, info))
++ return FALSE;
++
++ if (htab->glink == NULL
++ && !ppc_elf_create_glink (abfd, info))
++ return FALSE;
++
++ htab->dynbss = bfd_get_linker_section (abfd, ".dynbss");
++ s = bfd_make_section_anyway_with_flags (abfd, ".dynsbss",
++ SEC_ALLOC | SEC_LINKER_CREATED);
++ htab->dynsbss = s;
++ if (s == NULL)
++ return FALSE;
++
++ if (! info->shared)
++ {
++ htab->relbss = bfd_get_linker_section (abfd, ".rela.bss");
++ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
++ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
++ s = bfd_make_section_anyway_with_flags (abfd, ".rela.sbss", flags);
++ htab->relsbss = s;
++ if (s == NULL
++ || ! bfd_set_section_alignment (abfd, s, 2))
++ return FALSE;
++ }
++
++ if (htab->is_vxworks
++ && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
++ return FALSE;
++
++ htab->relplt = bfd_get_linker_section (abfd, ".rela.plt");
++ htab->plt = s = bfd_get_linker_section (abfd, ".plt");
++ if (s == NULL)
++ abort ();
++
++ flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED | SEC_READONLY;
++ if (htab->plt_type == PLT_VXWORKS)
++ /* The VxWorks PLT is a loaded section with contents. */
++ flags |= SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY;
++ return bfd_set_section_flags (abfd, s, flags);
++}
++
++/* Copy the extra info we tack onto an elf_link_hash_entry. */
++
++static void
++ppc_elf_copy_indirect_symbol (struct bfd_link_info *info,
++ struct elf_link_hash_entry *dir,
++ struct elf_link_hash_entry *ind)
++{
++ struct ppc_elf_link_hash_entry *edir, *eind;
++
++ edir = (struct ppc_elf_link_hash_entry *) dir;
++ eind = (struct ppc_elf_link_hash_entry *) ind;
++
++ edir->tls_mask |= eind->tls_mask;
++ edir->has_sda_refs |= eind->has_sda_refs;
++
++ /* If called to transfer flags for a weakdef during processing
++ of elf_adjust_dynamic_symbol, don't copy non_got_ref.
++ We clear it ourselves for ELIMINATE_COPY_RELOCS. */
++ if (!(ELIMINATE_COPY_RELOCS
++ && eind->elf.root.type != bfd_link_hash_indirect
++ && edir->elf.dynamic_adjusted))
++ edir->elf.non_got_ref |= eind->elf.non_got_ref;
++
++ edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
++ edir->elf.ref_regular |= eind->elf.ref_regular;
++ edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
++ edir->elf.needs_plt |= eind->elf.needs_plt;
++ edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed;
++
++ if (eind->dyn_relocs != NULL)
++ {
++ if (edir->dyn_relocs != NULL)
++ {
++ struct elf_dyn_relocs **pp;
++ struct elf_dyn_relocs *p;
++
++ /* Add reloc counts against the indirect sym to the direct sym
++ list. Merge any entries against the same section. */
++ for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
++ {
++ struct elf_dyn_relocs *q;
++
++ for (q = edir->dyn_relocs; q != NULL; q = q->next)
++ if (q->sec == p->sec)
++ {
++ q->pc_count += p->pc_count;
++ q->count += p->count;
++ *pp = p->next;
++ break;
++ }
++ if (q == NULL)
++ pp = &p->next;
++ }
++ *pp = edir->dyn_relocs;
++ }
++
++ edir->dyn_relocs = eind->dyn_relocs;
++ eind->dyn_relocs = NULL;
++ }
++
++ /* If we were called to copy over info for a weak sym, that's all.
++ You might think dyn_relocs need not be copied over; After all,
++ both syms will be dynamic or both non-dynamic so we're just
++ moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
++ code in ppc_elf_adjust_dynamic_symbol needs to check for
++ dyn_relocs in read-only sections, and it does so on what is the
++ DIR sym here. */
++ if (eind->elf.root.type != bfd_link_hash_indirect)
++ return;
++
++ /* Copy over the GOT refcount entries that we may have already seen to
++ the symbol which just became indirect. */
++ edir->elf.got.refcount += eind->elf.got.refcount;
++ eind->elf.got.refcount = 0;
++
++ /* And plt entries. */
++ if (eind->elf.plt.plist != NULL)
++ {
++ if (edir->elf.plt.plist != NULL)
++ {
++ struct plt_entry **entp;
++ struct plt_entry *ent;
++
++ for (entp = &eind->elf.plt.plist; (ent = *entp) != NULL; )
++ {
++ struct plt_entry *dent;
++
++ for (dent = edir->elf.plt.plist; dent != NULL; dent = dent->next)
++ if (dent->sec == ent->sec && dent->addend == ent->addend)
++ {
++ dent->plt.refcount += ent->plt.refcount;
++ *entp = ent->next;
++ break;
++ }
++ if (dent == NULL)
++ entp = &ent->next;
++ }
++ *entp = edir->elf.plt.plist;
++ }
++
++ edir->elf.plt.plist = eind->elf.plt.plist;
++ eind->elf.plt.plist = NULL;
++ }
++
++ if (eind->elf.dynindx != -1)
++ {
++ if (edir->elf.dynindx != -1)
++ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
++ edir->elf.dynstr_index);
++ edir->elf.dynindx = eind->elf.dynindx;
++ edir->elf.dynstr_index = eind->elf.dynstr_index;
++ eind->elf.dynindx = -1;
++ eind->elf.dynstr_index = 0;
++ }
++}
++
++/* Hook called by the linker routine which adds symbols from an object
++ file. We use it to put .comm items in .sbss, and not .bss. */
++
++static bfd_boolean
++ppc_elf_add_symbol_hook (bfd *abfd,
++ struct bfd_link_info *info,
++ Elf_Internal_Sym *sym,
++ const char **namep ATTRIBUTE_UNUSED,
++ flagword *flagsp ATTRIBUTE_UNUSED,
++ asection **secp,
++ bfd_vma *valp)
++{
++ if (sym->st_shndx == SHN_COMMON
++ && !info->relocatable
++ && is_ppc_elf (info->output_bfd)
++ && sym->st_size <= elf_gp_size (abfd))
++ {
++ /* Common symbols less than or equal to -G nn bytes are automatically
++ put into .sbss. */
++ struct ppc_elf_link_hash_table *htab;
++
++ htab = ppc_elf_hash_table (info);
++ if (htab->sbss == NULL)
++ {
++ flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED;
++
++ if (!htab->elf.dynobj)
++ htab->elf.dynobj = abfd;
++
++ htab->sbss = bfd_make_section_anyway_with_flags (htab->elf.dynobj,
++ ".sbss",
++ flags);
++ if (htab->sbss == NULL)
++ return FALSE;
++ }
++
++ *secp = htab->sbss;
++ *valp = sym->st_size;
++ }
++
++ if ((abfd->flags & DYNAMIC) == 0
++ && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
++ || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
++ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
++
++ return TRUE;
++}
++
++static bfd_boolean
++create_sdata_sym (struct bfd_link_info *info, elf_linker_section_t *lsect)
++{
++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
++
++ lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name,
++ TRUE, FALSE, TRUE);
++ if (lsect->sym == NULL)
++ return FALSE;
++ if (lsect->sym->root.type == bfd_link_hash_new)
++ lsect->sym->non_elf = 0;
++ lsect->sym->ref_regular = 1;
++ _bfd_elf_link_hash_hide_symbol (info, lsect->sym, TRUE);
++ return TRUE;
++}
++
++/* Create a special linker section. */
++
++static bfd_boolean
++ppc_elf_create_linker_section (bfd *abfd,
++ struct bfd_link_info *info,
++ flagword flags,
++ elf_linker_section_t *lsect)
++{
++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
++ asection *s;
++
++ flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
++ | SEC_LINKER_CREATED);
++
++ /* Record the first bfd that needs the special sections. */
++ if (!htab->elf.dynobj)
++ htab->elf.dynobj = abfd;
++
++ s = bfd_make_section_anyway_with_flags (htab->elf.dynobj,
++ lsect->name,
++ flags);
++ if (s == NULL
++ || !bfd_set_section_alignment (htab->elf.dynobj, s, 2))
++ return FALSE;
++ lsect->section = s;
++
++ return create_sdata_sym (info, lsect);
++}
++
++/* Find a linker generated pointer with a given addend and type. */
++
++static elf_linker_section_pointers_t *
++elf_find_pointer_linker_section
++ (elf_linker_section_pointers_t *linker_pointers,
++ bfd_vma addend,
++ elf_linker_section_t *lsect)
++{
++ for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next)
++ if (lsect == linker_pointers->lsect && addend == linker_pointers->addend)
++ return linker_pointers;
++
++ return NULL;
++}
++
++/* Allocate a pointer to live in a linker created section. */
++
++static bfd_boolean
++elf_create_pointer_linker_section (bfd *abfd,
++ elf_linker_section_t *lsect,
++ struct elf_link_hash_entry *h,
++ const Elf_Internal_Rela *rel)
++{
++ elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL;
++ elf_linker_section_pointers_t *linker_section_ptr;
++ unsigned long r_symndx = ELF32_R_SYM (rel->r_info);
++ bfd_size_type amt;
++
++ BFD_ASSERT (lsect != NULL);
++
++ /* Is this a global symbol? */
++ if (h != NULL)
++ {
++ struct ppc_elf_link_hash_entry *eh;
++
++ /* Has this symbol already been allocated? If so, our work is done. */
++ eh = (struct ppc_elf_link_hash_entry *) h;
++ if (elf_find_pointer_linker_section (eh->linker_section_pointer,
++ rel->r_addend,
++ lsect))
++ return TRUE;
++
++ ptr_linker_section_ptr = &eh->linker_section_pointer;
++ }
++ else
++ {
++ BFD_ASSERT (is_ppc_elf (abfd));
++
++ /* Allocation of a pointer to a local symbol. */
++ elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd);
++
++ /* Allocate a table to hold the local symbols if first time. */
++ if (!ptr)
++ {
++ unsigned int num_symbols = elf_symtab_hdr (abfd).sh_info;
++
++ amt = num_symbols;
++ amt *= sizeof (elf_linker_section_pointers_t *);
++ ptr = bfd_zalloc (abfd, amt);
++
++ if (!ptr)
++ return FALSE;
++
++ elf_local_ptr_offsets (abfd) = ptr;
++ }
++
++ /* Has this symbol already been allocated? If so, our work is done. */
++ if (elf_find_pointer_linker_section (ptr[r_symndx],
++ rel->r_addend,
++ lsect))
++ return TRUE;
++
++ ptr_linker_section_ptr = &ptr[r_symndx];
++ }
++
++ /* Allocate space for a pointer in the linker section, and allocate
++ a new pointer record from internal memory. */
++ BFD_ASSERT (ptr_linker_section_ptr != NULL);
++ amt = sizeof (elf_linker_section_pointers_t);
++ linker_section_ptr = bfd_alloc (abfd, amt);
++
++ if (!linker_section_ptr)
++ return FALSE;
++
++ linker_section_ptr->next = *ptr_linker_section_ptr;
++ linker_section_ptr->addend = rel->r_addend;
++ linker_section_ptr->lsect = lsect;
++ *ptr_linker_section_ptr = linker_section_ptr;
++
++ linker_section_ptr->offset = lsect->section->size;
++ lsect->section->size += 4;
++
++#ifdef DEBUG
++ fprintf (stderr,
++ "Create pointer in linker section %s, offset = %ld, section size = %ld\n",
++ lsect->name, (long) linker_section_ptr->offset,
++ (long) lsect->section->size);
++#endif
++
++ return TRUE;
++}
++
++static struct plt_entry **
++update_local_sym_info (bfd *abfd,
++ Elf_Internal_Shdr *symtab_hdr,
++ unsigned long r_symndx,
++ int tls_type)
++{
++ bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd);
++ struct plt_entry **local_plt;
++ char *local_got_tls_masks;
++
++ if (local_got_refcounts == NULL)
++ {
++ bfd_size_type size = symtab_hdr->sh_info;
++
++ size *= (sizeof (*local_got_refcounts)
++ + sizeof (*local_plt)
++ + sizeof (*local_got_tls_masks));
++ local_got_refcounts = bfd_zalloc (abfd, size);
++ if (local_got_refcounts == NULL)
++ return NULL;
++ elf_local_got_refcounts (abfd) = local_got_refcounts;
++ }
++
++ local_plt = (struct plt_entry **) (local_got_refcounts + symtab_hdr->sh_info);
++ local_got_tls_masks = (char *) (local_plt + symtab_hdr->sh_info);
++ local_got_tls_masks[r_symndx] |= tls_type;
++ if (tls_type != PLT_IFUNC)
++ local_got_refcounts[r_symndx] += 1;
++ return local_plt + r_symndx;
++}
++
++static bfd_boolean
++update_plt_info (bfd *abfd, struct plt_entry **plist,
++ asection *sec, bfd_vma addend)
++{
++ struct plt_entry *ent;
++
++ if (addend < 32768)
++ sec = NULL;
++ for (ent = *plist; ent != NULL; ent = ent->next)
++ if (ent->sec == sec && ent->addend == addend)
++ break;
++ if (ent == NULL)
++ {
++ bfd_size_type amt = sizeof (*ent);
++ ent = bfd_alloc (abfd, amt);
++ if (ent == NULL)
++ return FALSE;
++ ent->next = *plist;
++ ent->sec = sec;
++ ent->addend = addend;
++ ent->plt.refcount = 0;
++ *plist = ent;
++ }
++ ent->plt.refcount += 1;
++ return TRUE;
++}
++
++static struct plt_entry *
++find_plt_ent (struct plt_entry **plist, asection *sec, bfd_vma addend)
++{
++ struct plt_entry *ent;
++
++ if (addend < 32768)
++ sec = NULL;
++ for (ent = *plist; ent != NULL; ent = ent->next)
++ if (ent->sec == sec && ent->addend == addend)
++ break;
++ return ent;
++}
++
++static bfd_boolean
++is_branch_reloc (enum elf_ppc_reloc_type r_type)
++{
++ return (r_type == R_PPC_PLTREL24
++ || r_type == R_PPC_LOCAL24PC
++ || r_type == R_PPC_REL24
++ || r_type == R_PPC_REL14
++ || r_type == R_PPC_REL14_BRTAKEN
++ || r_type == R_PPC_REL14_BRNTAKEN
++ || r_type == R_PPC_ADDR24
++ || r_type == R_PPC_ADDR14
++ || r_type == R_PPC_ADDR14_BRTAKEN
++ || r_type == R_PPC_ADDR14_BRNTAKEN);
++}
++
++static void
++bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
++{
++ (*_bfd_error_handler)
++ (_("%B: relocation %s cannot be used when making a shared object"),
++ abfd,
++ ppc_elf_howto_table[r_type]->name);
++ bfd_set_error (bfd_error_bad_value);
++}
++
++/* Look through the relocs for a section during the first phase, and
++ allocate space in the global offset table or procedure linkage
++ table. */
++
++static bfd_boolean
++ppc_elf_check_relocs (bfd *abfd,
++ struct bfd_link_info *info,
++ asection *sec,
++ const Elf_Internal_Rela *relocs)
++{
++ struct ppc_elf_link_hash_table *htab;
++ Elf_Internal_Shdr *symtab_hdr;
++ struct elf_link_hash_entry **sym_hashes;
++ const Elf_Internal_Rela *rel;
++ const Elf_Internal_Rela *rel_end;
++ asection *got2, *sreloc;
++ struct elf_link_hash_entry *tga;
++
++ if (info->relocatable)
++ return TRUE;
++
++ /* Don't do anything special with non-loaded, non-alloced sections.
++ In particular, any relocs in such sections should not affect GOT
++ and PLT reference counting (ie. we don't allow them to create GOT
++ or PLT entries), there's no possibility or desire to optimize TLS
++ relocs, and there's not much point in propagating relocs to shared
++ libs that the dynamic linker won't relocate. */
++ if ((sec->flags & SEC_ALLOC) == 0)
++ return TRUE;
++
++#ifdef DEBUG
++ _bfd_error_handler ("ppc_elf_check_relocs called for section %A in %B",
++ sec, abfd);
++#endif
++
++ BFD_ASSERT (is_ppc_elf (abfd));
++
++ /* Initialize howto table if not already done. */
++ if (!ppc_elf_howto_table[R_PPC_ADDR32])
++ ppc_elf_howto_init ();
++
++ htab = ppc_elf_hash_table (info);
++ if (htab->glink == NULL)
++ {
++ if (htab->elf.dynobj == NULL)
++ htab->elf.dynobj = abfd;
++ if (!ppc_elf_create_glink (htab->elf.dynobj, info))
++ return FALSE;
++ }
++ tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
++ FALSE, FALSE, TRUE);
++ symtab_hdr = &elf_symtab_hdr (abfd);
++ sym_hashes = elf_sym_hashes (abfd);
++ got2 = bfd_get_section_by_name (abfd, ".got2");
++ sreloc = NULL;
++
++ rel_end = relocs + sec->reloc_count;
++ for (rel = relocs; rel < rel_end; rel++)
++ {
++ unsigned long r_symndx;
++ enum elf_ppc_reloc_type r_type;
++ struct elf_link_hash_entry *h;
++ int tls_type;
++
++ r_symndx = ELF32_R_SYM (rel->r_info);
++ if (r_symndx < symtab_hdr->sh_info)
++ h = NULL;
++ else
++ {
++ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
++ while (h->root.type == bfd_link_hash_indirect
++ || h->root.type == bfd_link_hash_warning)
++ h = (struct elf_link_hash_entry *) h->root.u.i.link;
++ }
++
++ /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
++ This shows up in particular in an R_PPC_ADDR32 in the eabi
++ startup code. */
++ if (h != NULL
++ && htab->got == NULL
++ && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
++ {
++ if (htab->elf.dynobj == NULL)
++ htab->elf.dynobj = abfd;
++ if (!ppc_elf_create_got (htab->elf.dynobj, info))
++ return FALSE;
++ BFD_ASSERT (h == htab->elf.hgot);
++ }
++
++ tls_type = 0;
++ r_type = ELF32_R_TYPE (rel->r_info);
++ if (h == NULL && !htab->is_vxworks)
++ {
++ Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
++ abfd, r_symndx);
++ if (isym == NULL)
++ return FALSE;
++
++ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
++ && (!info->shared
++ || is_branch_reloc (r_type)))
++ {
++ struct plt_entry **ifunc;
++ bfd_vma addend;
++
++ ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
++ PLT_IFUNC);
++ if (ifunc == NULL)
++ return FALSE;
++
++ /* STT_GNU_IFUNC symbols must have a PLT entry;
++ In a non-pie executable even when there are
++ no plt calls. */
++ addend = 0;
++ if (r_type == R_PPC_PLTREL24)
++ {
++ ppc_elf_tdata (abfd)->makes_plt_call = 1;
++ if (info->shared)
++ addend = rel->r_addend;
++ }
++ if (!update_plt_info (abfd, ifunc, got2, addend))
++ return FALSE;
++ }
++ }
++
++ if (!htab->is_vxworks
++ && is_branch_reloc (r_type)
++ && h != NULL
++ && h == tga)
++ {
++ if (rel != relocs
++ && (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
++ || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
++ /* We have a new-style __tls_get_addr call with a marker
++ reloc. */
++ ;
++ else
++ /* Mark this section as having an old-style call. */
++ sec->has_tls_get_addr_call = 1;
++ }
++
++ switch (r_type)
++ {
++ case R_PPC_TLSGD:
++ case R_PPC_TLSLD:
++ /* These special tls relocs tie a call to __tls_get_addr with
++ its parameter symbol. */
++ break;
++
++ case R_PPC_GOT_TLSLD16:
++ case R_PPC_GOT_TLSLD16_LO:
++ case R_PPC_GOT_TLSLD16_HI:
++ case R_PPC_GOT_TLSLD16_HA:
++ tls_type = TLS_TLS | TLS_LD;
++ goto dogottls;
++
++ case R_PPC_GOT_TLSGD16:
++ case R_PPC_GOT_TLSGD16_LO:
++ case R_PPC_GOT_TLSGD16_HI:
++ case R_PPC_GOT_TLSGD16_HA:
++ tls_type = TLS_TLS | TLS_GD;
++ goto dogottls;
++
++ case R_PPC_GOT_TPREL16:
++ case R_PPC_GOT_TPREL16_LO:
++ case R_PPC_GOT_TPREL16_HI:
++ case R_PPC_GOT_TPREL16_HA:
++ if (!info->executable)
++ info->flags |= DF_STATIC_TLS;
++ tls_type = TLS_TLS | TLS_TPREL;
++ goto dogottls;
++
++ case R_PPC_GOT_DTPREL16:
++ case R_PPC_GOT_DTPREL16_LO:
++ case R_PPC_GOT_DTPREL16_HI:
++ case R_PPC_GOT_DTPREL16_HA:
++ tls_type = TLS_TLS | TLS_DTPREL;
++ dogottls:
++ sec->has_tls_reloc = 1;
++ /* Fall thru */
++
++ /* GOT16 relocations */
++ case R_PPC_GOT16:
++ case R_PPC_GOT16_LO:
++ case R_PPC_GOT16_HI:
++ case R_PPC_GOT16_HA:
++ /* This symbol requires a global offset table entry. */
++ if (htab->got == NULL)
++ {
++ if (htab->elf.dynobj == NULL)
++ htab->elf.dynobj = abfd;
++ if (!ppc_elf_create_got (htab->elf.dynobj, info))
++ return FALSE;
++ }
++ if (h != NULL)
++ {
++ h->got.refcount += 1;
++ ppc_elf_hash_entry (h)->tls_mask |= tls_type;
++ }
++ else
++ /* This is a global offset table entry for a local symbol. */
++ if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, tls_type))
++ return FALSE;
++
++ /* We may also need a plt entry if the symbol turns out to be
++ an ifunc. */
++ if (h != NULL && !info->shared)
++ {
++ if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
++ return FALSE;
++ }
++ break;
++
++ /* Indirect .sdata relocation. */
++ case R_PPC_EMB_SDAI16:
++ if (info->shared)
++ {
++ bad_shared_reloc (abfd, r_type);
++ return FALSE;
++ }
++ if (htab->sdata[0].section == NULL
++ && !ppc_elf_create_linker_section (abfd, info, 0,
++ &htab->sdata[0]))
++ return FALSE;
++ if (!elf_create_pointer_linker_section (abfd, &htab->sdata[0],
++ h, rel))
++ return FALSE;
++ if (h != NULL)
++ {
++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
++ h->non_got_ref = TRUE;
++ }
++ break;
++
++ /* Indirect .sdata2 relocation. */
++ case R_PPC_EMB_SDA2I16:
++ if (info->shared)
++ {
++ bad_shared_reloc (abfd, r_type);
++ return FALSE;
++ }
++ if (htab->sdata[1].section == NULL
++ && !ppc_elf_create_linker_section (abfd, info, SEC_READONLY,
++ &htab->sdata[1]))
++ return FALSE;
++ if (!elf_create_pointer_linker_section (abfd, &htab->sdata[1],
++ h, rel))
++ return FALSE;
++ if (h != NULL)
++ {
++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
++ h->non_got_ref = TRUE;
++ }
++ break;
++
++ case R_PPC_VLE_SDAREL_LO16A:
++ case R_PPC_VLE_SDAREL_LO16D:
++ case R_PPC_VLE_SDAREL_HI16A:
++ case R_PPC_VLE_SDAREL_HI16D:
++ case R_PPC_VLE_SDAREL_HA16A:
++ case R_PPC_VLE_SDAREL_HA16D:
++ case R_PPC_SDAREL16:
++ if (htab->sdata[0].sym == NULL
++ && !create_sdata_sym (info, &htab->sdata[0]))
++ return FALSE;
++
++ if (htab->sdata[1].sym == NULL
++ && !create_sdata_sym (info, &htab->sdata[1]))
++ return FALSE;
++
++ if (h != NULL)
++ {
++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
++ h->non_got_ref = TRUE;
++ }
++ break;
++
++ case R_PPC_VLE_REL8:
++ case R_PPC_VLE_REL15:
++ case R_PPC_VLE_REL24:
++ case R_PPC_VLE_LO16A:
++ case R_PPC_VLE_LO16D:
++ case R_PPC_VLE_HI16A:
++ case R_PPC_VLE_HI16D:
++ case R_PPC_VLE_HA16A:
++ case R_PPC_VLE_HA16D:
++ break;
++
++ case R_PPC_EMB_SDA2REL:
++ if (info->shared)
++ {
++ bad_shared_reloc (abfd, r_type);
++ return FALSE;
++ }
++ if (htab->sdata[1].sym == NULL
++ && !create_sdata_sym (info, &htab->sdata[1]))
++ return FALSE;
++ if (h != NULL)
++ {
++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
++ h->non_got_ref = TRUE;
++ }
++ break;
++
++ case R_PPC_VLE_SDA21_LO:
++ case R_PPC_VLE_SDA21:
++ case R_PPC_EMB_SDA21:
++ case R_PPC_EMB_RELSDA:
++ if (info->shared)
++ {
++ bad_shared_reloc (abfd, r_type);
++ return FALSE;
++ }
++ if (htab->sdata[0].sym == NULL
++ && !create_sdata_sym (info, &htab->sdata[0]))
++ return FALSE;
++ if (htab->sdata[1].sym == NULL
++ && !create_sdata_sym (info, &htab->sdata[1]))
++ return FALSE;
++ if (h != NULL)
++ {
++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
++ h->non_got_ref = TRUE;
++ }
++ break;
++
++ case R_PPC_EMB_NADDR32:
++ case R_PPC_EMB_NADDR16:
++ case R_PPC_EMB_NADDR16_LO:
++ case R_PPC_EMB_NADDR16_HI:
++ case R_PPC_EMB_NADDR16_HA:
++ if (info->shared)
++ {
++ bad_shared_reloc (abfd, r_type);
++ return FALSE;
++ }
++ if (h != NULL)
++ h->non_got_ref = TRUE;
++ break;
++
++ case R_PPC_PLTREL24:
++ if (h == NULL)
++ break;
++ /* Fall through */
++ case R_PPC_PLT32:
++ case R_PPC_PLTREL32:
++ case R_PPC_PLT16_LO:
++ case R_PPC_PLT16_HI:
++ case R_PPC_PLT16_HA:
++#ifdef DEBUG
++ fprintf (stderr, "Reloc requires a PLT entry\n");
++#endif
++ /* This symbol requires a procedure linkage table entry. We
++ actually build the entry in finish_dynamic_symbol,
++ because this might be a case of linking PIC code without
++ linking in any dynamic objects, in which case we don't
++ need to generate a procedure linkage table after all. */
++
++ if (h == NULL)
++ {
++ /* It does not make sense to have a procedure linkage
++ table entry for a local symbol. */
++ info->callbacks->einfo (_("%P: %H: %s reloc against local symbol\n"),
++ abfd, sec, rel->r_offset,
++ ppc_elf_howto_table[r_type]->name);
++ bfd_set_error (bfd_error_bad_value);
++ return FALSE;
++ }
++ else
++ {
++ bfd_vma addend = 0;
++
++ if (r_type == R_PPC_PLTREL24)
++ {
++ ppc_elf_tdata (abfd)->makes_plt_call = 1;
++ if (info->shared)
++ addend = rel->r_addend;
++ }
++ h->needs_plt = 1;
++ if (!update_plt_info (abfd, &h->plt.plist, got2, addend))
++ return FALSE;
++ }
++ break;
++
++ /* The following relocations don't need to propagate the
++ relocation if linking a shared object since they are
++ section relative. */
++ case R_PPC_SECTOFF:
++ case R_PPC_SECTOFF_LO:
++ case R_PPC_SECTOFF_HI:
++ case R_PPC_SECTOFF_HA:
++ case R_PPC_DTPREL16:
++ case R_PPC_DTPREL16_LO:
++ case R_PPC_DTPREL16_HI:
++ case R_PPC_DTPREL16_HA:
++ case R_PPC_TOC16:
++ break;
++
++ case R_PPC_REL16:
++ case R_PPC_REL16_LO:
++ case R_PPC_REL16_HI:
++ case R_PPC_REL16_HA:
++ ppc_elf_tdata (abfd)->has_rel16 = 1;
++ break;
++
++ /* These are just markers. */
++ case R_PPC_TLS:
++ case R_PPC_EMB_MRKREF:
++ case R_PPC_NONE:
++ case R_PPC_max:
++ case R_PPC_RELAX:
++ case R_PPC_RELAX_PLT:
++ case R_PPC_RELAX_PLTREL24:
++ break;
++
++ /* These should only appear in dynamic objects. */
++ case R_PPC_COPY:
++ case R_PPC_GLOB_DAT:
++ case R_PPC_JMP_SLOT:
++ case R_PPC_RELATIVE:
++ case R_PPC_IRELATIVE:
++ break;
++
++ /* These aren't handled yet. We'll report an error later. */
++ case R_PPC_ADDR30:
++ case R_PPC_EMB_RELSEC16:
++ case R_PPC_EMB_RELST_LO:
++ case R_PPC_EMB_RELST_HI:
++ case R_PPC_EMB_RELST_HA:
++ case R_PPC_EMB_BIT_FLD:
++ break;
++
++ /* These don't work with a GOT */
++ case R_PPC_AMIGAOS_BREL:
++ case R_PPC_AMIGAOS_BREL_HI:
++ case R_PPC_AMIGAOS_BREL_LO:
++ case R_PPC_AMIGAOS_BREL_HA:
++ break;
++
++ /* This refers only to functions defined in the shared library. */
++ case R_PPC_LOCAL24PC:
++ if (h != NULL && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
++ {
++ htab->plt_type = PLT_OLD;
++ htab->old_bfd = abfd;
++ }
++ break;
++
++ /* This relocation describes the C++ object vtable hierarchy.
++ Reconstruct it for later use during GC. */
++ case R_PPC_GNU_VTINHERIT:
++ if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
++ return FALSE;
++ break;
++
++ /* This relocation describes which C++ vtable entries are actually
++ used. Record for later use during GC. */
++ case R_PPC_GNU_VTENTRY:
++ BFD_ASSERT (h != NULL);
++ if (h != NULL
++ && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
++ return FALSE;
++ break;
++
++ /* We shouldn't really be seeing these. */
++ case R_PPC_TPREL32:
++ case R_PPC_TPREL16:
++ case R_PPC_TPREL16_LO:
++ case R_PPC_TPREL16_HI:
++ case R_PPC_TPREL16_HA:
++ if (!info->executable)
++ info->flags |= DF_STATIC_TLS;
++ goto dodyn;
++
++ /* Nor these. */
++ case R_PPC_DTPMOD32:
++ case R_PPC_DTPREL32:
++ goto dodyn;
++
++ case R_PPC_REL32:
++ if (h == NULL
++ && got2 != NULL
++ && (sec->flags & SEC_CODE) != 0
++ && info->shared
++ && htab->plt_type == PLT_UNSET)
++ {
++ /* Old -fPIC gcc code has .long LCTOC1-LCFx just before
++ the start of a function, which assembles to a REL32
++ reference to .got2. If we detect one of these, then
++ force the old PLT layout because the linker cannot
++ reliably deduce the GOT pointer value needed for
++ PLT call stubs. */
++ asection *s;
++ Elf_Internal_Sym *isym;
++
++ isym = bfd_sym_from_r_symndx (&htab->sym_cache,
++ abfd, r_symndx);
++ if (isym == NULL)
++ return FALSE;
++
++ s = bfd_section_from_elf_index (abfd, isym->st_shndx);
++ if (s == got2)
++ {
++ htab->plt_type = PLT_OLD;
++ htab->old_bfd = abfd;
++ }
++ }
++ if (h == NULL || h == htab->elf.hgot)
++ break;
++ /* fall through */
++
++ case R_PPC_ADDR32:
++ case R_PPC_ADDR16:
++ case R_PPC_ADDR16_LO:
++ case R_PPC_ADDR16_HI:
++ case R_PPC_ADDR16_HA:
++ case R_PPC_UADDR32:
++ case R_PPC_UADDR16:
++ if (h != NULL && !info->shared)
++ {
++ /* We may need a plt entry if the symbol turns out to be
++ a function defined in a dynamic object. */
++ if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
++ return FALSE;
++
++ /* We may need a copy reloc too. */
++ h->non_got_ref = 1;
++ h->pointer_equality_needed = 1;
++ }
++ goto dodyn;
++
++ case R_PPC_REL24:
++ case R_PPC_REL14:
++ case R_PPC_REL14_BRTAKEN:
++ case R_PPC_REL14_BRNTAKEN:
++ if (h == NULL)
++ break;
++ if (h == htab->elf.hgot)
++ {
++ if (htab->plt_type == PLT_UNSET)
++ {
++ htab->plt_type = PLT_OLD;
++ htab->old_bfd = abfd;
++ }
++ break;
++ }
++ /* fall through */
++
++ case R_PPC_ADDR24:
++ case R_PPC_ADDR14:
++ case R_PPC_ADDR14_BRTAKEN:
++ case R_PPC_ADDR14_BRNTAKEN:
++ if (h != NULL && !info->shared)
++ {
++ /* We may need a plt entry if the symbol turns out to be
++ a function defined in a dynamic object. */
++ h->needs_plt = 1;
++ if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
++ return FALSE;
++ break;
++ }
++
++ dodyn:
++ /* If we are creating a shared library, and this is a reloc
++ against a global symbol, or a non PC relative reloc
++ against a local symbol, then we need to copy the reloc
++ into the shared library. However, if we are linking with
++ -Bsymbolic, we do not need to copy a reloc against a
++ global symbol which is defined in an object we are
++ including in the link (i.e., DEF_REGULAR is set). At
++ this point we have not seen all the input files, so it is
++ possible that DEF_REGULAR is not set now but will be set
++ later (it is never cleared). In case of a weak definition,
++ DEF_REGULAR may be cleared later by a strong definition in
++ a shared library. We account for that possibility below by
++ storing information in the dyn_relocs field of the hash
++ table entry. A similar situation occurs when creating
++ shared libraries and symbol visibility changes render the
++ symbol local.
++
++ If on the other hand, we are creating an executable, we
++ may need to keep relocations for symbols satisfied by a
++ dynamic library if we manage to avoid copy relocs for the
++ symbol. */
++ if ((info->shared
++ && (must_be_dyn_reloc (info, r_type)
++ || (h != NULL
++ && (! info->symbolic
++ || h->root.type == bfd_link_hash_defweak
++ || !h->def_regular))))
++ || (ELIMINATE_COPY_RELOCS
++ && !info->shared
++ && h != NULL
++ && (h->root.type == bfd_link_hash_defweak
++ || !h->def_regular)))
++ {
++ struct elf_dyn_relocs *p;
++ struct elf_dyn_relocs **rel_head;
++
++#ifdef DEBUG
++ fprintf (stderr,
++ "ppc_elf_check_relocs needs to "
++ "create relocation for %s\n",
++ (h && h->root.root.string
++ ? h->root.root.string : "<unknown>"));
++#endif
++ if (sreloc == NULL)
++ {
++ if (htab->elf.dynobj == NULL)
++ htab->elf.dynobj = abfd;
++
++ sreloc = _bfd_elf_make_dynamic_reloc_section
++ (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE);
++
++ if (sreloc == NULL)
++ return FALSE;
++ }
++
++ /* If this is a global symbol, we count the number of
++ relocations we need for this symbol. */
++ if (h != NULL)
++ {
++ rel_head = &ppc_elf_hash_entry (h)->dyn_relocs;
++ }
++ else
++ {
++ /* Track dynamic relocs needed for local syms too.
++ We really need local syms available to do this
++ easily. Oh well. */
++ asection *s;
++ void *vpp;
++ Elf_Internal_Sym *isym;
++
++ isym = bfd_sym_from_r_symndx (&htab->sym_cache,
++ abfd, r_symndx);
++ if (isym == NULL)
++ return FALSE;
++
++ s = bfd_section_from_elf_index (abfd, isym->st_shndx);
++ if (s == NULL)
++ s = sec;
++
++ vpp = &elf_section_data (s)->local_dynrel;
++ rel_head = (struct elf_dyn_relocs **) vpp;
++ }
++
++ p = *rel_head;
++ if (p == NULL || p->sec != sec)
++ {
++ p = bfd_alloc (htab->elf.dynobj, sizeof *p);
++ if (p == NULL)
++ return FALSE;
++ p->next = *rel_head;
++ *rel_head = p;
++ p->sec = sec;
++ p->count = 0;
++ p->pc_count = 0;
++ }
++
++ p->count += 1;
++ if (!must_be_dyn_reloc (info, r_type))
++ p->pc_count += 1;
++ }
++
++ break;
++ }
++ }
++
++ return TRUE;
++}
++
++
++/* Merge object attributes from IBFD into OBFD. Raise an error if
++ there are conflicting attributes. */
++static bfd_boolean
++ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
++{
++ obj_attribute *in_attr, *in_attrs;
++ obj_attribute *out_attr, *out_attrs;
++
++ if (!elf_known_obj_attributes_proc (obfd)[0].i)
++ {
++ /* This is the first object. Copy the attributes. */
++ _bfd_elf_copy_obj_attributes (ibfd, obfd);
++
++ /* Use the Tag_null value to indicate the attributes have been
++ initialized. */
++ elf_known_obj_attributes_proc (obfd)[0].i = 1;
++
++ return TRUE;
++ }
++
++ in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
++ out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
++
++ /* Check for conflicting Tag_GNU_Power_ABI_FP attributes and merge
++ non-conflicting ones. */
++ in_attr = &in_attrs[Tag_GNU_Power_ABI_FP];
++ out_attr = &out_attrs[Tag_GNU_Power_ABI_FP];
++ if (in_attr->i != out_attr->i)
++ {
++ out_attr->type = 1;
++ if (out_attr->i == 0)
++ out_attr->i = in_attr->i;
++ else if (in_attr->i == 0)
++ ;
++ else if (out_attr->i == 1 && in_attr->i == 2)
++ _bfd_error_handler
++ (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
++ else if (out_attr->i == 1 && in_attr->i == 3)
++ _bfd_error_handler
++ (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
++ obfd, ibfd);
++ else if (out_attr->i == 3 && in_attr->i == 1)
++ _bfd_error_handler
++ (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
++ ibfd, obfd);
++ else if (out_attr->i == 3 && in_attr->i == 2)
++ _bfd_error_handler
++ (_("Warning: %B uses soft float, %B uses single-precision hard float"),
++ ibfd, obfd);
++ else if (out_attr->i == 2 && (in_attr->i == 1 || in_attr->i == 3))
++ _bfd_error_handler
++ (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
++ else if (in_attr->i > 3)
++ _bfd_error_handler
++ (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
++ in_attr->i);
++ else
++ _bfd_error_handler
++ (_("Warning: %B uses unknown floating point ABI %d"), obfd,
++ out_attr->i);
++ }
++
++ /* Check for conflicting Tag_GNU_Power_ABI_Vector attributes and
++ merge non-conflicting ones. */
++ in_attr = &in_attrs[Tag_GNU_Power_ABI_Vector];
++ out_attr = &out_attrs[Tag_GNU_Power_ABI_Vector];
++ if (in_attr->i != out_attr->i)
++ {
++ const char *in_abi = NULL, *out_abi = NULL;
++
++ switch (in_attr->i)
++ {
++ case 1: in_abi = "generic"; break;
++ case 2: in_abi = "AltiVec"; break;
++ case 3: in_abi = "SPE"; break;
++ }
++
++ switch (out_attr->i)
++ {
++ case 1: out_abi = "generic"; break;
++ case 2: out_abi = "AltiVec"; break;
++ case 3: out_abi = "SPE"; break;
++ }
++
++ out_attr->type = 1;
++ if (out_attr->i == 0)
++ out_attr->i = in_attr->i;
++ else if (in_attr->i == 0)
++ ;
++ /* For now, allow generic to transition to AltiVec or SPE
++ without a warning. If GCC marked files with their stack
++ alignment and used don't-care markings for files which are
++ not affected by the vector ABI, we could warn about this
++ case too. */
++ else if (out_attr->i == 1)
++ out_attr->i = in_attr->i;
++ else if (in_attr->i == 1)
++ ;
++ else if (in_abi == NULL)
++ _bfd_error_handler
++ (_("Warning: %B uses unknown vector ABI %d"), ibfd,
++ in_attr->i);
++ else if (out_abi == NULL)
++ _bfd_error_handler
++ (_("Warning: %B uses unknown vector ABI %d"), obfd,
++ in_attr->i);
++ else
++ _bfd_error_handler
++ (_("Warning: %B uses vector ABI \"%s\", %B uses \"%s\""),
++ ibfd, obfd, in_abi, out_abi);
++ }
++
++ /* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes
++ and merge non-conflicting ones. */
++ in_attr = &in_attrs[Tag_GNU_Power_ABI_Struct_Return];
++ out_attr = &out_attrs[Tag_GNU_Power_ABI_Struct_Return];
++ if (in_attr->i != out_attr->i)
++ {
++ out_attr->type = 1;
++ if (out_attr->i == 0)
++ out_attr->i = in_attr->i;
++ else if (in_attr->i == 0)
++ ;
++ else if (out_attr->i == 1 && in_attr->i == 2)
++ _bfd_error_handler
++ (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), obfd, ibfd);
++ else if (out_attr->i == 2 && in_attr->i == 1)
++ _bfd_error_handler
++ (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), ibfd, obfd);
++ else if (in_attr->i > 2)
++ _bfd_error_handler
++ (_("Warning: %B uses unknown small structure return convention %d"), ibfd,
++ in_attr->i);
++ else
++ _bfd_error_handler
++ (_("Warning: %B uses unknown small structure return convention %d"), obfd,
++ out_attr->i);
++ }
++
++ /* Merge Tag_compatibility attributes and any common GNU ones. */
++ _bfd_elf_merge_object_attributes (ibfd, obfd);
++
++ return TRUE;
++}
++
++/* Merge backend specific data from an object file to the output
++ object file when linking. */
++
++static bfd_boolean
++ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
++{
++ flagword old_flags;
++ flagword new_flags;
++ bfd_boolean error;
++
++ if (!is_ppc_elf (ibfd) || !is_ppc_elf (obfd))
++ return TRUE;
++
++ /* Check if we have the same endianness. */
++ if (! _bfd_generic_verify_endian_match (ibfd, obfd))
++ return FALSE;
++
++ if (!ppc_elf_merge_obj_attributes (ibfd, obfd))
++ return FALSE;
++
++ new_flags = elf_elfheader (ibfd)->e_flags;
++ old_flags = elf_elfheader (obfd)->e_flags;
++ if (!elf_flags_init (obfd))
++ {
++ /* First call, no flags set. */
++ elf_flags_init (obfd) = TRUE;
++ elf_elfheader (obfd)->e_flags = new_flags;
++ }
++
++ /* Compatible flags are ok. */
++ else if (new_flags == old_flags)
++ ;
++
++ /* Incompatible flags. */
++ else
++ {
++ /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib
++ to be linked with either. */
++ error = FALSE;
++ if ((new_flags & EF_PPC_RELOCATABLE) != 0
++ && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
++ {
++ error = TRUE;
++ (*_bfd_error_handler)
++ (_("%B: compiled with -mrelocatable and linked with "
++ "modules compiled normally"), ibfd);
++ }
++ else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0
++ && (old_flags & EF_PPC_RELOCATABLE) != 0)
++ {
++ error = TRUE;
++ (*_bfd_error_handler)
++ (_("%B: compiled normally and linked with "
++ "modules compiled with -mrelocatable"), ibfd);
++ }
++
++ /* The output is -mrelocatable-lib iff both the input files are. */
++ if (! (new_flags & EF_PPC_RELOCATABLE_LIB))
++ elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB;
++
++ /* The output is -mrelocatable iff it can't be -mrelocatable-lib,
++ but each input file is either -mrelocatable or -mrelocatable-lib. */
++ if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB)
++ && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))
++ && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)))
++ elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE;
++
++ /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if
++ any module uses it. */
++ elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB);
++
++ new_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB);
++ old_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB);
++
++ /* Warn about any other mismatches. */
++ if (new_flags != old_flags)
++ {
++ error = TRUE;
++ (*_bfd_error_handler)
++ (_("%B: uses different e_flags (0x%lx) fields "
++ "than previous modules (0x%lx)"),
++ ibfd, (long) new_flags, (long) old_flags);
++ }
++
++ if (error)
++ {
++ bfd_set_error (bfd_error_bad_value);
++ return FALSE;
++ }
++ }
++
++ return TRUE;
++}
++
++static void
++ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents,
++ bfd_vma offset, bfd_vma relocation,
++ split16_format_type split16_format)
++
++{
++ bfd_vma insn, top5, bottom11;
++
++ insn = bfd_get_32 (output_bfd, contents + offset);
++ top5 = relocation >> 11;
++ top5 = top5 << (split16_format == split16a_type ? 20 : 16);
++ bottom11 = relocation & 0x7ff;
++ insn |= top5;
++ insn |= bottom11;
++ bfd_put_32 (output_bfd, insn, contents + offset);
++}
++
++
++/* Choose which PLT scheme to use, and set .plt flags appropriately.
++ Returns -1 on error, 0 for old PLT, 1 for new PLT. */
++int
++ppc_elf_amigaos_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
++ struct bfd_link_info *info,
++ enum ppc_elf_plt_type plt_style,
++ int emit_stub_syms)
++{
++ struct ppc_elf_link_hash_table *htab;
++ flagword flags;
++
++ htab = ppc_elf_hash_table (info);
++
++ htab->emit_stub_syms = emit_stub_syms;
++
++ if (htab->plt_type == PLT_UNSET)
++ {
++ struct elf_link_hash_entry *h;
++
++ if (plt_style == PLT_OLD)
++ htab->plt_type = PLT_OLD;
++ else if (info->shared
++ && htab->elf.dynamic_sections_created
++ && (h = elf_link_hash_lookup (&htab->elf, "_mcount",
++ FALSE, FALSE, TRUE)) != NULL
++ && (h->type == STT_FUNC
++ || h->needs_plt)
++ && h->ref_regular
++ && !(SYMBOL_CALLS_LOCAL (info, h)
++ || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
++ && h->root.type == bfd_link_hash_undefweak)))
++ {
++ /* Profiling of shared libs (and pies) is not supported with
++ secure plt, because ppc32 does profiling before a
++ function prologue and a secure plt pic call stubs needs
++ r30 to be set up. */
++ htab->plt_type = PLT_OLD;
++ }
++ else
++ {
++ bfd *ibfd;
++ enum ppc_elf_plt_type plt_type = plt_style;
++
++ /* Look through the reloc flags left by ppc_elf_check_relocs.
++ Use the old style bss plt if a file makes plt calls
++ without using the new relocs, and if ld isn't given
++ --secure-plt and we never see REL16 relocs. */
++ if (plt_type == PLT_UNSET)
++ plt_type = PLT_OLD;
++ for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
++ if (is_ppc_elf (ibfd))
++ {
++ if (ppc_elf_tdata (ibfd)->has_rel16)
++ plt_type = PLT_NEW;
++ else if (ppc_elf_tdata (ibfd)->makes_plt_call)
++ {
++ plt_type = PLT_OLD;
++ htab->old_bfd = ibfd;
++ break;
++ }
++ }
++ htab->plt_type = plt_type;
++ }
++ }
++ if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW)
++ {
++ if (htab->old_bfd != NULL)
++ info->callbacks->einfo (_("%P: bss-plt forced due to %B\n"),
++ htab->old_bfd);
++ else
++ info->callbacks->einfo (_("%P: bss-plt forced by profiling\n"));
++ }
++
++ BFD_ASSERT (htab->plt_type != PLT_VXWORKS);
++
++ if (htab->plt_type == PLT_NEW)
++ {
++ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
++ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
++
++ /* The new PLT is a loaded section. */
++ if (htab->plt != NULL
++ && !bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags))
++ return -1;
++
++ /* The new GOT is not executable. */
++ if (htab->got != NULL
++ && !bfd_set_section_flags (htab->elf.dynobj, htab->got, flags))
++ return -1;
++ }
++ else
++ {
++ /* Stop an unused .glink section from affecting .text alignment. */
++ if (htab->glink != NULL
++ && !bfd_set_section_alignment (htab->elf.dynobj, htab->glink, 0))
++ return -1;
++ }
++ return htab->plt_type == PLT_NEW;
++}
++
++/* Return the section that should be marked against GC for a given
++ relocation. */
++
++static asection *
++ppc_elf_gc_mark_hook (asection *sec,
++ struct bfd_link_info *info,
++ Elf_Internal_Rela *rel,
++ struct elf_link_hash_entry *h,
++ Elf_Internal_Sym *sym)
++{
++ if (h != NULL)
++ switch (ELF32_R_TYPE (rel->r_info))
++ {
++ case R_PPC_GNU_VTINHERIT:
++ case R_PPC_GNU_VTENTRY:
++ return NULL;
++ }
++
++ return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
++}
++
++/* Update the got, plt and dynamic reloc reference counts for the
++ section being removed. */
++
++static bfd_boolean
++ppc_elf_gc_sweep_hook (bfd *abfd,
++ struct bfd_link_info *info,
++ asection *sec,
++ const Elf_Internal_Rela *relocs)
++{
++ struct ppc_elf_link_hash_table *htab;
++ Elf_Internal_Shdr *symtab_hdr;
++ struct elf_link_hash_entry **sym_hashes;
++ bfd_signed_vma *local_got_refcounts;
++ const Elf_Internal_Rela *rel, *relend;
++ asection *got2;
++
++ if (info->relocatable)
++ return TRUE;
++
++ if ((sec->flags & SEC_ALLOC) == 0)
++ return TRUE;
++
++ elf_section_data (sec)->local_dynrel = NULL;
++
++ htab = ppc_elf_hash_table (info);
++ symtab_hdr = &elf_symtab_hdr (abfd);
++ sym_hashes = elf_sym_hashes (abfd);
++ local_got_refcounts = elf_local_got_refcounts (abfd);
++ got2 = bfd_get_section_by_name (abfd, ".got2");
++
++ relend = relocs + sec->reloc_count;
++ for (rel = relocs; rel < relend; rel++)
++ {
++ unsigned long r_symndx;
++ enum elf_ppc_reloc_type r_type;
++ struct elf_link_hash_entry *h = NULL;
++
++ r_symndx = ELF32_R_SYM (rel->r_info);
++ if (r_symndx >= symtab_hdr->sh_info)
++ {
++ struct elf_dyn_relocs **pp, *p;
++ struct ppc_elf_link_hash_entry *eh;
++
++ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
++ while (h->root.type == bfd_link_hash_indirect
++ || h->root.type == bfd_link_hash_warning)
++ h = (struct elf_link_hash_entry *) h->root.u.i.link;
++ eh = (struct ppc_elf_link_hash_entry *) h;
++
++ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
++ if (p->sec == sec)
++ {
++ /* Everything must go for SEC. */
++ *pp = p->next;
++ break;
++ }
++ }
++
++ r_type = ELF32_R_TYPE (rel->r_info);
++ if (!htab->is_vxworks
++ && h == NULL
++ && local_got_refcounts != NULL
++ && (!info->shared
++ || is_branch_reloc (r_type)))
++ {
++ struct plt_entry **local_plt = (struct plt_entry **)
++ (local_got_refcounts + symtab_hdr->sh_info);
++ char *local_got_tls_masks = (char *)
++ (local_plt + symtab_hdr->sh_info);
++ if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
++ {
++ struct plt_entry **ifunc = local_plt + r_symndx;
++ bfd_vma addend = 0;
++ struct plt_entry *ent;
++
++ if (r_type == R_PPC_PLTREL24 && info->shared)
++ addend = rel->r_addend;
++ ent = find_plt_ent (ifunc, got2, addend);
++ if (ent->plt.refcount > 0)
++ ent->plt.refcount -= 1;
++ continue;
++ }
++ }
++
++ switch (r_type)
++ {
++ case R_PPC_GOT_TLSLD16:
++ case R_PPC_GOT_TLSLD16_LO:
++ case R_PPC_GOT_TLSLD16_HI:
++ case R_PPC_GOT_TLSLD16_HA:
++ case R_PPC_GOT_TLSGD16:
++ case R_PPC_GOT_TLSGD16_LO:
++ case R_PPC_GOT_TLSGD16_HI:
++ case R_PPC_GOT_TLSGD16_HA:
++ case R_PPC_GOT_TPREL16:
++ case R_PPC_GOT_TPREL16_LO:
++ case R_PPC_GOT_TPREL16_HI:
++ case R_PPC_GOT_TPREL16_HA:
++ case R_PPC_GOT_DTPREL16:
++ case R_PPC_GOT_DTPREL16_LO:
++ case R_PPC_GOT_DTPREL16_HI:
++ case R_PPC_GOT_DTPREL16_HA:
++ case R_PPC_GOT16:
++ case R_PPC_GOT16_LO:
++ case R_PPC_GOT16_HI:
++ case R_PPC_GOT16_HA:
++ if (h != NULL)
++ {
++ if (h->got.refcount > 0)
++ h->got.refcount--;
++ if (!info->shared)
++ {
++ struct plt_entry *ent;
++
++ ent = find_plt_ent (&h->plt.plist, NULL, 0);
++ if (ent != NULL && ent->plt.refcount > 0)
++ ent->plt.refcount -= 1;
++ }
++ }
++ else if (local_got_refcounts != NULL)
++ {
++ if (local_got_refcounts[r_symndx] > 0)
++ local_got_refcounts[r_symndx]--;
++ }
++ break;
++
++ case R_PPC_REL24:
++ case R_PPC_REL14:
++ case R_PPC_REL14_BRTAKEN:
++ case R_PPC_REL14_BRNTAKEN:
++ case R_PPC_REL32:
++ if (h == NULL || h == htab->elf.hgot)
++ break;
++ /* Fall thru */
++
++ case R_PPC_ADDR32:
++ case R_PPC_ADDR24:
++ case R_PPC_ADDR16:
++ case R_PPC_ADDR16_LO:
++ case R_PPC_ADDR16_HI:
++ case R_PPC_ADDR16_HA:
++ case R_PPC_ADDR14:
++ case R_PPC_ADDR14_BRTAKEN:
++ case R_PPC_ADDR14_BRNTAKEN:
++ case R_PPC_UADDR32:
++ case R_PPC_UADDR16:
++ if (info->shared)
++ break;
++
++ case R_PPC_PLT32:
++ case R_PPC_PLTREL24:
++ case R_PPC_PLTREL32:
++ case R_PPC_PLT16_LO:
++ case R_PPC_PLT16_HI:
++ case R_PPC_PLT16_HA:
++ if (h != NULL)
++ {
++ bfd_vma addend = 0;
++ struct plt_entry *ent;
++
++ if (r_type == R_PPC_PLTREL24 && info->shared)
++ addend = rel->r_addend;
++ ent = find_plt_ent (&h->plt.plist, got2, addend);
++ if (ent != NULL && ent->plt.refcount > 0)
++ ent->plt.refcount -= 1;
++ }
++ break;
++
++ default:
++ break;
++ }
++ }
++ return TRUE;
++}
++
++/* Set plt output section type, htab->tls_get_addr, and call the
++ generic ELF tls_setup function. */
++
++asection *
++ppc_elf_amigaos_tls_setup (bfd *obfd,
++ struct bfd_link_info *info,
++ int no_tls_get_addr_opt)
++{
++ struct ppc_elf_link_hash_table *htab;
++
++ htab = ppc_elf_hash_table (info);
++ htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
++ FALSE, FALSE, TRUE);
++ if (!no_tls_get_addr_opt)
++ {
++ struct elf_link_hash_entry *opt, *tga;
++ opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
++ FALSE, FALSE, TRUE);
++ if (opt != NULL
++ && (opt->root.type == bfd_link_hash_defined
++ || opt->root.type == bfd_link_hash_defweak))
++ {
++ /* If glibc supports an optimized __tls_get_addr call stub,
++ signalled by the presence of __tls_get_addr_opt, and we'll
++ be calling __tls_get_addr via a plt call stub, then
++ make __tls_get_addr point to __tls_get_addr_opt. */
++ tga = htab->tls_get_addr;
++ if (htab->elf.dynamic_sections_created
++ && tga != NULL
++ && (tga->type == STT_FUNC
++ || tga->needs_plt)
++ && !(SYMBOL_CALLS_LOCAL (info, tga)
++ || (ELF_ST_VISIBILITY (tga->other) != STV_DEFAULT
++ && tga->root.type == bfd_link_hash_undefweak)))
++ {
++ struct plt_entry *ent;
++ for (ent = tga->plt.plist; ent != NULL; ent = ent->next)
++ if (ent->plt.refcount > 0)
++ break;
++ if (ent != NULL)
++ {
++ tga->root.type = bfd_link_hash_indirect;
++ tga->root.u.i.link = &opt->root;
++ ppc_elf_copy_indirect_symbol (info, opt, tga);
++ if (opt->dynindx != -1)
++ {
++ /* Use __tls_get_addr_opt in dynamic relocations. */
++ opt->dynindx = -1;
++ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
++ opt->dynstr_index);
++ if (!bfd_elf_link_record_dynamic_symbol (info, opt))
++ return FALSE;
++ }
++ htab->tls_get_addr = opt;
++ }
++ }
++ }
++ else
++ no_tls_get_addr_opt = TRUE;
++ }
++ htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
++ if (htab->plt_type == PLT_NEW
++ && htab->plt != NULL
++ && htab->plt->output_section != NULL)
++ {
++ elf_section_type (htab->plt->output_section) = SHT_PROGBITS;
++ elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE;
++ }
++
++ return _bfd_elf_tls_setup (obfd, info);
++}
++
++/* Return TRUE iff REL is a branch reloc with a global symbol matching
++ HASH. */
++
++static bfd_boolean
++branch_reloc_hash_match (const bfd *ibfd,
++ const Elf_Internal_Rela *rel,
++ const struct elf_link_hash_entry *hash)
++{
++ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
++ enum elf_ppc_reloc_type r_type = ELF32_R_TYPE (rel->r_info);
++ unsigned int r_symndx = ELF32_R_SYM (rel->r_info);
++
++ if (r_symndx >= symtab_hdr->sh_info && is_branch_reloc (r_type))
++ {
++ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
++ struct elf_link_hash_entry *h;
++
++ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
++ while (h->root.type == bfd_link_hash_indirect
++ || h->root.type == bfd_link_hash_warning)
++ h = (struct elf_link_hash_entry *) h->root.u.i.link;
++ if (h == hash)
++ return TRUE;
++ }
++ return FALSE;
++}
++
++/* Run through all the TLS relocs looking for optimization
++ opportunities. */
++
++bfd_boolean
++ppc_elf_amigaos_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
++ struct bfd_link_info *info)
++{
++ bfd *ibfd;
++ asection *sec;
++ struct ppc_elf_link_hash_table *htab;
++ int pass;
++
++ if (info->relocatable || !info->executable)
++ return TRUE;
++
++ htab = ppc_elf_hash_table (info);
++ if (htab == NULL)
++ return FALSE;
++
++ /* Make two passes through the relocs. First time check that tls
++ relocs involved in setting up a tls_get_addr call are indeed
++ followed by such a call. If they are not, don't do any tls
++ optimization. On the second pass twiddle tls_mask flags to
++ notify relocate_section that optimization can be done, and
++ adjust got and plt refcounts. */
++ for (pass = 0; pass < 2; ++pass)
++ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
++ {
++ Elf_Internal_Sym *locsyms = NULL;
++ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
++ asection *got2 = bfd_get_section_by_name (ibfd, ".got2");
++
++ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
++ if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
++ {
++ Elf_Internal_Rela *relstart, *rel, *relend;
++ int expecting_tls_get_addr = 0;
++
++ /* Read the relocations. */
++ relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
++ info->keep_memory);
++ if (relstart == NULL)
++ return FALSE;
++
++ relend = relstart + sec->reloc_count;
++ for (rel = relstart; rel < relend; rel++)
++ {
++ enum elf_ppc_reloc_type r_type;
++ unsigned long r_symndx;
++ struct elf_link_hash_entry *h = NULL;
++ char *tls_mask;
++ char tls_set, tls_clear;
++ bfd_boolean is_local;
++ bfd_signed_vma *got_count;
++
++ r_symndx = ELF32_R_SYM (rel->r_info);
++ if (r_symndx >= symtab_hdr->sh_info)
++ {
++ struct elf_link_hash_entry **sym_hashes;
++
++ sym_hashes = elf_sym_hashes (ibfd);
++ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
++ while (h->root.type == bfd_link_hash_indirect
++ || h->root.type == bfd_link_hash_warning)
++ h = (struct elf_link_hash_entry *) h->root.u.i.link;
++ }
++
++ is_local = FALSE;
++ if (h == NULL
++ || !h->def_dynamic)
++ is_local = TRUE;
++
++ r_type = ELF32_R_TYPE (rel->r_info);
++ /* If this section has old-style __tls_get_addr calls
++ without marker relocs, then check that each
++ __tls_get_addr call reloc is preceded by a reloc
++ that conceivably belongs to the __tls_get_addr arg
++ setup insn. If we don't find matching arg setup
++ relocs, don't do any tls optimization. */
++ if (pass == 0
++ && sec->has_tls_get_addr_call
++ && h != NULL
++ && h == htab->tls_get_addr
++ && !expecting_tls_get_addr
++ && is_branch_reloc (r_type))
++ {
++ info->callbacks->minfo ("%H __tls_get_addr lost arg, "
++ "TLS optimization disabled\n",
++ ibfd, sec, rel->r_offset);
++ if (elf_section_data (sec)->relocs != relstart)
++ free (relstart);
++ return TRUE;
++ }
++
++ expecting_tls_get_addr = 0;
++ switch (r_type)
++ {
++ case R_PPC_GOT_TLSLD16:
++ case R_PPC_GOT_TLSLD16_LO:
++ expecting_tls_get_addr = 1;
++ /* Fall thru */
++
++ case R_PPC_GOT_TLSLD16_HI:
++ case R_PPC_GOT_TLSLD16_HA:
++ /* These relocs should never be against a symbol
++ defined in a shared lib. Leave them alone if
++ that turns out to be the case. */
++ if (!is_local)
++ continue;
++
++ /* LD -> LE */
++ tls_set = 0;
++ tls_clear = TLS_LD;
++ break;
++
++ case R_PPC_GOT_TLSGD16:
++ case R_PPC_GOT_TLSGD16_LO:
++ expecting_tls_get_addr = 1;
++ /* Fall thru */
++
++ case R_PPC_GOT_TLSGD16_HI:
++ case R_PPC_GOT_TLSGD16_HA:
++ if (is_local)
++ /* GD -> LE */
++ tls_set = 0;
++ else
++ /* GD -> IE */
++ tls_set = TLS_TLS | TLS_TPRELGD;
++ tls_clear = TLS_GD;
++ break;
++
++ case R_PPC_GOT_TPREL16:
++ case R_PPC_GOT_TPREL16_LO:
++ case R_PPC_GOT_TPREL16_HI:
++ case R_PPC_GOT_TPREL16_HA:
++ if (is_local)
++ {
++ /* IE -> LE */
++ tls_set = 0;
++ tls_clear = TLS_TPREL;
++ break;
++ }
++ else
++ continue;
++
++ case R_PPC_TLSGD:
++ case R_PPC_TLSLD:
++ expecting_tls_get_addr = 2;
++ tls_set = 0;
++ tls_clear = 0;
++ break;
++
++ default:
++ continue;
++ }
++
++ if (pass == 0)
++ {
++ if (!expecting_tls_get_addr
++ || (expecting_tls_get_addr == 1
++ && !sec->has_tls_get_addr_call))
++ continue;
++
++ if (rel + 1 < relend
++ && branch_reloc_hash_match (ibfd, rel + 1,
++ htab->tls_get_addr))
++ continue;
++
++ /* Uh oh, we didn't find the expected call. We
++ could just mark this symbol to exclude it
++ from tls optimization but it's safer to skip
++ the entire optimization. */
++ info->callbacks->minfo (_("%H arg lost __tls_get_addr, "
++ "TLS optimization disabled\n"),
++ ibfd, sec, rel->r_offset);
++ if (elf_section_data (sec)->relocs != relstart)
++ free (relstart);
++ return TRUE;
++ }
++
++ if (expecting_tls_get_addr)
++ {
++ struct plt_entry *ent;
++ bfd_vma addend = 0;
++
++ if (info->shared
++ && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
++ addend = rel[1].r_addend;
++ ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
++ got2, addend);
++ if (ent != NULL && ent->plt.refcount > 0)
++ ent->plt.refcount -= 1;
++
++ if (expecting_tls_get_addr == 2)
++ continue;
++ }
++
++ if (h != NULL)
++ {
++ tls_mask = &ppc_elf_hash_entry (h)->tls_mask;
++ got_count = &h->got.refcount;
++ }
++ else
++ {
++ bfd_signed_vma *lgot_refs;
++ struct plt_entry **local_plt;
++ char *lgot_masks;
++
++ if (locsyms == NULL)
++ {
++ locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
++ if (locsyms == NULL)
++ locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
++ symtab_hdr->sh_info,
++ 0, NULL, NULL, NULL);
++ if (locsyms == NULL)
++ {
++ if (elf_section_data (sec)->relocs != relstart)
++ free (relstart);
++ return FALSE;
++ }
++ }
++ lgot_refs = elf_local_got_refcounts (ibfd);
++ if (lgot_refs == NULL)
++ abort ();
++ local_plt = (struct plt_entry **)
++ (lgot_refs + symtab_hdr->sh_info);
++ lgot_masks = (char *) (local_plt + symtab_hdr->sh_info);
++ tls_mask = &lgot_masks[r_symndx];
++ got_count = &lgot_refs[r_symndx];
++ }
++
++ if (tls_set == 0)
++ {
++ /* We managed to get rid of a got entry. */
++ if (*got_count > 0)
++ *got_count -= 1;
++ }
++
++ *tls_mask |= tls_set;
++ *tls_mask &= ~tls_clear;
++ }
++
++ if (elf_section_data (sec)->relocs != relstart)
++ free (relstart);
++ }
++
++ if (locsyms != NULL
++ && (symtab_hdr->contents != (unsigned char *) locsyms))
++ {
++ if (!info->keep_memory)
++ free (locsyms);
++ else
++ symtab_hdr->contents = (unsigned char *) locsyms;
++ }
++ }
++ return TRUE;
++}
++
++/* Return true if we have dynamic relocs that apply to read-only sections. */
++
++static bfd_boolean
++readonly_dynrelocs (struct elf_link_hash_entry *h)
++{
++ struct elf_dyn_relocs *p;
++
++ for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
++ {
++ asection *s = p->sec->output_section;
++
++ if (s != NULL
++ && ((s->flags & (SEC_READONLY | SEC_ALLOC))
++ == (SEC_READONLY | SEC_ALLOC)))
++ return TRUE;
++ }
++ return FALSE;
++}
++
++/* Adjust a symbol defined by a dynamic object and referenced by a
++ regular object. The current definition is in some section of the
++ dynamic object, but we're not including those sections. We have to
++ change the definition to something the rest of the link can
++ understand. */
++
++static bfd_boolean
++ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
++ struct elf_link_hash_entry *h)
++{
++ struct ppc_elf_link_hash_table *htab;
++ asection *s;
++
++#ifdef DEBUG
++ fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n",
++ h->root.root.string);
++#endif
++
++ /* Make sure we know what is going on here. */
++ htab = ppc_elf_hash_table (info);
++ BFD_ASSERT (htab->elf.dynobj != NULL
++ && (h->needs_plt
++ || h->type == STT_GNU_IFUNC
++ || h->u.weakdef != NULL
++ || (h->def_dynamic
++ && h->ref_regular
++ && !h->def_regular)));
++
++ /* Deal with function syms. */
++ if (h->type == STT_FUNC
++ || h->type == STT_GNU_IFUNC
++ || h->needs_plt)
++ {
++ /* Clear procedure linkage table information for any symbol that
++ won't need a .plt entry. */
++ struct plt_entry *ent;
++ for (ent = h->plt.plist; ent != NULL; ent = ent->next)
++ if (ent->plt.refcount > 0)
++ break;
++ if (ent == NULL
++ || (h->type != STT_GNU_IFUNC
++ && (SYMBOL_CALLS_LOCAL (info, h)
++ || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
++ && h->root.type == bfd_link_hash_undefweak))))
++ {
++ /* A PLT entry is not required/allowed when:
++
++ 1. We are not using ld.so; because then the PLT entry
++ can't be set up, so we can't use one. In this case,
++ ppc_elf_adjust_dynamic_symbol won't even be called.
++
++ 2. GC has rendered the entry unused.
++
++ 3. We know for certain that a call to this symbol
++ will go to this object, or will remain undefined. */
++ h->plt.plist = NULL;
++ h->needs_plt = 0;
++ }
++ else
++ {
++ /* After adjust_dynamic_symbol, non_got_ref set in the
++ non-shared case means that we have allocated space in
++ .dynbss for the symbol and thus dyn_relocs for this
++ symbol should be discarded.
++ If we get here we know we are making a PLT entry for this
++ symbol, and in an executable we'd normally resolve
++ relocations against this symbol to the PLT entry. Allow
++ dynamic relocs if the reference is weak, and the dynamic
++ relocs will not cause text relocation. */
++ if (!h->ref_regular_nonweak
++ && h->non_got_ref
++ && h->type != STT_GNU_IFUNC
++ && !htab->is_vxworks
++ && !ppc_elf_hash_entry (h)->has_sda_refs
++ && !readonly_dynrelocs (h))
++ h->non_got_ref = 0;
++ }
++ return TRUE;
++ }
++ else
++ h->plt.plist = NULL;
++
++ /* If this is a weak symbol, and there is a real definition, the
++ processor independent code will have arranged for us to see the
++ real definition first, and we can just use the same value. */
++ if (h->u.weakdef != NULL)
++ {
++ BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
++ || h->u.weakdef->root.type == bfd_link_hash_defweak);
++ h->root.u.def.section = h->u.weakdef->root.u.def.section;
++ h->root.u.def.value = h->u.weakdef->root.u.def.value;
++ if (ELIMINATE_COPY_RELOCS)
++ h->non_got_ref = h->u.weakdef->non_got_ref;
++ return TRUE;
++ }
++
++ /* This is a reference to a symbol defined by a dynamic object which
++ is not a function. */
++
++ /* If we are creating a shared library, we must presume that the
++ only references to the symbol are via the global offset table.
++ For such cases we need not do anything here; the relocations will
++ be handled correctly by relocate_section. */
++ if (info->shared)
++ return TRUE;
++
++ /* If there are no references to this symbol that do not use the
++ GOT, we don't need to generate a copy reloc. */
++ if (!h->non_got_ref)
++ return TRUE;
++
++ /* If we didn't find any dynamic relocs in read-only sections, then
++ we'll be keeping the dynamic relocs and avoiding the copy reloc.
++ We can't do this if there are any small data relocations. This
++ doesn't work on VxWorks, where we can not have dynamic
++ relocations (other than copy and jump slot relocations) in an
++ executable. */
++ if (ELIMINATE_COPY_RELOCS
++ && !ppc_elf_hash_entry (h)->has_sda_refs
++ && !htab->is_vxworks
++ && !h->def_regular
++ && !readonly_dynrelocs (h))
++ {
++ h->non_got_ref = 0;
++ return TRUE;
++ }
++
++ /* We must allocate the symbol in our .dynbss section, which will
++ become part of the .bss section of the executable. There will be
++ an entry for this symbol in the .dynsym section. The dynamic
++ object will contain position independent code, so all references
++ from the dynamic object to this symbol will go through the global
++ offset table. The dynamic linker will use the .dynsym entry to
++ determine the address it must put in the global offset table, so
++ both the dynamic object and the regular object will refer to the
++ same memory location for the variable.
++
++ Of course, if the symbol is referenced using SDAREL relocs, we
++ must instead allocate it in .sbss. */
++
++ if (ppc_elf_hash_entry (h)->has_sda_refs)
++ s = htab->dynsbss;
++ else
++ s = htab->dynbss;
++ BFD_ASSERT (s != NULL);
++
++ /* We must generate a R_PPC_COPY reloc to tell the dynamic linker to
++ copy the initial value out of the dynamic object and into the
++ runtime process image. We need to remember the offset into the
++ .rela.bss section we are going to use. */
++ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
++ {
++ asection *srel;
++
++ if (ppc_elf_hash_entry (h)->has_sda_refs)
++ srel = htab->relsbss;
++ else
++ srel = htab->relbss;
++ BFD_ASSERT (srel != NULL);
++ srel->size += sizeof (Elf32_External_Rela);
++ h->needs_copy = 1;
++ }
++
++ return _bfd_elf_adjust_dynamic_copy (h, s);
++}
++
++/* Generate a symbol to mark plt call stubs. For non-PIC code the sym is
++ xxxxxxxx.plt_call32.<callee> where xxxxxxxx is a hex number, usually 0,
++ specifying the addend on the plt relocation. For -fpic code, the sym
++ is xxxxxxxx.plt_pic32.<callee>, and for -fPIC
++ xxxxxxxx.got2.plt_pic32.<callee>. */
++
++static bfd_boolean
++add_stub_sym (struct plt_entry *ent,
++ struct elf_link_hash_entry *h,
++ struct bfd_link_info *info)
++{
++ struct elf_link_hash_entry *sh;
++ size_t len1, len2, len3;
++ char *name;
++ const char *stub;
++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
++
++ if (info->shared)
++ stub = ".plt_pic32.";
++ else
++ stub = ".plt_call32.";
++
++ len1 = strlen (h->root.root.string);
++ len2 = strlen (stub);
++ len3 = 0;
++ if (ent->sec)
++ len3 = strlen (ent->sec->name);
++ name = bfd_malloc (len1 + len2 + len3 + 9);
++ if (name == NULL)
++ return FALSE;
++ sprintf (name, "%08x", (unsigned) ent->addend & 0xffffffff);
++ if (ent->sec)
++ memcpy (name + 8, ent->sec->name, len3);
++ memcpy (name + 8 + len3, stub, len2);
++ memcpy (name + 8 + len3 + len2, h->root.root.string, len1 + 1);
++ sh = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
++ if (sh == NULL)
++ return FALSE;
++ if (sh->root.type == bfd_link_hash_new)
++ {
++ sh->root.type = bfd_link_hash_defined;
++ sh->root.u.def.section = htab->glink;
++ sh->root.u.def.value = ent->glink_offset;
++ sh->ref_regular = 1;
++ sh->def_regular = 1;
++ sh->ref_regular_nonweak = 1;
++ sh->forced_local = 1;
++ sh->non_elf = 0;
++ }
++ return TRUE;
++}
++
++/* Allocate NEED contiguous space in .got, and return the offset.
++ Handles allocation of the got header when crossing 32k. */
++
++static bfd_vma
++allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need)
++{
++ bfd_vma where;
++ unsigned int max_before_header;
++
++ if (htab->plt_type == PLT_VXWORKS)
++ {
++ where = htab->got->size;
++ htab->got->size += need;
++ }
++ else
++ {
++ max_before_header = htab->plt_type == PLT_NEW ? 32768 : 32764;
++ if (need <= htab->got_gap)
++ {
++ where = max_before_header - htab->got_gap;
++ htab->got_gap -= need;
++ }
++ else
++ {
++ if (htab->got->size + need > max_before_header
++ && htab->got->size <= max_before_header)
++ {
++ htab->got_gap = max_before_header - htab->got->size;
++ htab->got->size = max_before_header + htab->got_header_size;
++ }
++ where = htab->got->size;
++ htab->got->size += need;
++ }
++ }
++ return where;
++}
++
++/* Allocate space in associated reloc sections for dynamic relocs. */
++
++static bfd_boolean
++allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
++{
++ struct bfd_link_info *info = inf;
++ struct ppc_elf_link_hash_entry *eh;
++ struct ppc_elf_link_hash_table *htab;
++ struct elf_dyn_relocs *p;
++
++ if (h->root.type == bfd_link_hash_indirect)
++ return TRUE;
++
++ htab = ppc_elf_hash_table (info);
++ if (htab->elf.dynamic_sections_created
++ || h->type == STT_GNU_IFUNC)
++ {
++ struct plt_entry *ent;
++ bfd_boolean doneone = FALSE;
++ bfd_vma plt_offset = 0, glink_offset = 0;
++ bfd_boolean dyn;
++
++ for (ent = h->plt.plist; ent != NULL; ent = ent->next)
++ if (ent->plt.refcount > 0)
++ {
++ /* Make sure this symbol is output as a dynamic symbol. */
++ if (h->dynindx == -1
++ && !h->forced_local
++ && !h->def_regular
++ && htab->elf.dynamic_sections_created)
++ {
++ if (! bfd_elf_link_record_dynamic_symbol (info, h))
++ return FALSE;
++ }
++
++ dyn = htab->elf.dynamic_sections_created;
++ if (info->shared
++ || h->type == STT_GNU_IFUNC
++ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
++ {
++ asection *s = htab->plt;
++ if (!dyn || h->dynindx == -1)
++ s = htab->iplt;
++
++ if (htab->plt_type == PLT_NEW || !dyn || h->dynindx == -1)
++ {
++ if (!doneone)
++ {
++ plt_offset = s->size;
++ s->size += 4;
++ }
++ ent->plt.offset = plt_offset;
++
++ s = htab->glink;
++ if (!doneone || info->shared)
++ {
++ glink_offset = s->size;
++ s->size += GLINK_ENTRY_SIZE;
++ if (h == htab->tls_get_addr
++ && !htab->no_tls_get_addr_opt)
++ s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
++ }
++ if (!doneone
++ && !info->shared
++ && h->def_dynamic
++ && !h->def_regular)
++ {
++ h->root.u.def.section = s;
++ h->root.u.def.value = glink_offset;
++ }
++ ent->glink_offset = glink_offset;
++
++ if (htab->emit_stub_syms
++ && !add_stub_sym (ent, h, info))
++ return FALSE;
++ }
++ else
++ {
++ if (!doneone)
++ {
++ /* If this is the first .plt entry, make room
++ for the special first entry. */
++ if (s->size == 0)
++ s->size += htab->plt_initial_entry_size;
++
++ /* The PowerPC PLT is actually composed of two
++ parts, the first part is 2 words (for a load
++ and a jump), and then there is a remaining
++ word available at the end. */
++ plt_offset = (htab->plt_initial_entry_size
++ + (htab->plt_slot_size
++ * ((s->size
++ - htab->plt_initial_entry_size)
++ / htab->plt_entry_size)));
++
++ /* If this symbol is not defined in a regular
++ file, and we are not generating a shared
++ library, then set the symbol to this location
++ in the .plt. This is to avoid text
++ relocations, and is required to make
++ function pointers compare as equal between
++ the normal executable and the shared library. */
++ if (! info->shared
++ && h->def_dynamic
++ && !h->def_regular)
++ {
++ h->root.u.def.section = s;
++ h->root.u.def.value = plt_offset;
++ }
++
++ /* Make room for this entry. */
++ s->size += htab->plt_entry_size;
++ /* After the 8192nd entry, room for two entries
++ is allocated. */
++ if (htab->plt_type == PLT_OLD
++ && (s->size - htab->plt_initial_entry_size)
++ / htab->plt_entry_size
++ > PLT_NUM_SINGLE_ENTRIES)
++ s->size += htab->plt_entry_size;
++ }
++ ent->plt.offset = plt_offset;
++ }
++
++ /* We also need to make an entry in the .rela.plt section. */
++ if (!doneone)
++ {
++ if (!htab->elf.dynamic_sections_created
++ || h->dynindx == -1)
++ htab->reliplt->size += sizeof (Elf32_External_Rela);
++ else
++ {
++ htab->relplt->size += sizeof (Elf32_External_Rela);
++
++ if (htab->plt_type == PLT_VXWORKS)
++ {
++ /* Allocate space for the unloaded relocations. */
++ if (!info->shared
++ && htab->elf.dynamic_sections_created)
++ {
++ if (ent->plt.offset
++ == (bfd_vma) htab->plt_initial_entry_size)
++ {
++ htab->srelplt2->size
++ += (sizeof (Elf32_External_Rela)
++ * VXWORKS_PLTRESOLVE_RELOCS);
++ }
++
++ htab->srelplt2->size
++ += (sizeof (Elf32_External_Rela)
++ * VXWORKS_PLT_NON_JMP_SLOT_RELOCS);
++ }
++
++ /* Every PLT entry has an associated GOT entry in
++ .got.plt. */
++ htab->sgotplt->size += 4;
++ }
++ }
++ doneone = TRUE;
++ }
++ }
++ else
++ ent->plt.offset = (bfd_vma) -1;
++ }
++ else
++ ent->plt.offset = (bfd_vma) -1;
++
++ if (!doneone)
++ {
++ h->plt.plist = NULL;
++ h->needs_plt = 0;
++ }
++ }
++ else
++ {
++ h->plt.plist = NULL;
++ h->needs_plt = 0;
++ }
++
++ eh = (struct ppc_elf_link_hash_entry *) h;
++ if (eh->elf.got.refcount > 0)
++ {
++ bfd_boolean dyn;
++ unsigned int need;
++
++ /* Make sure this symbol is output as a dynamic symbol. */
++ if (eh->elf.dynindx == -1
++ && !eh->elf.forced_local
++ && eh->elf.type != STT_GNU_IFUNC
++ && htab->elf.dynamic_sections_created)
++ {
++ if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf))
++ return FALSE;
++ }
++
++ need = 0;
++ if ((eh->tls_mask & TLS_TLS) != 0)
++ {
++ if ((eh->tls_mask & TLS_LD) != 0)
++ {
++ if (!eh->elf.def_dynamic)
++ /* We'll just use htab->tlsld_got.offset. This should
++ always be the case. It's a little odd if we have
++ a local dynamic reloc against a non-local symbol. */
++ htab->tlsld_got.refcount += 1;
++ else
++ need += 8;
++ }
++ if ((eh->tls_mask & TLS_GD) != 0)
++ need += 8;
++ if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
++ need += 4;
++ if ((eh->tls_mask & TLS_DTPREL) != 0)
++ need += 4;
++ }
++ else
++ need += 4;
++ if (need == 0)
++ eh->elf.got.offset = (bfd_vma) -1;
++ else
++ {
++ eh->elf.got.offset = allocate_got (htab, need);
++ dyn = htab->elf.dynamic_sections_created;
++ if ((info->shared
++ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
++ && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
++ || eh->elf.root.type != bfd_link_hash_undefweak))
++ {
++ asection *rsec = htab->relgot;
++ /* All the entries we allocated need relocs.
++ Except LD only needs one. */
++ if ((eh->tls_mask & TLS_LD) != 0
++ && eh->elf.def_dynamic)
++ need -= 4;
++ rsec->size += need * (sizeof (Elf32_External_Rela) / 4);
++ }
++ }
++ }
++ else
++ eh->elf.got.offset = (bfd_vma) -1;
++
++ if (eh->dyn_relocs == NULL
++ || !htab->elf.dynamic_sections_created)
++ return TRUE;
++
++ /* In the shared -Bsymbolic case, discard space allocated for
++ dynamic pc-relative relocs against symbols which turn out to be
++ defined in regular objects. For the normal shared case, discard
++ space for relocs that have become local due to symbol visibility
++ changes. */
++
++ if (info->shared)
++ {
++ /* Relocs that use pc_count are those that appear on a call insn,
++ or certain REL relocs (see must_be_dyn_reloc) that can be
++ generated via assembly. We want calls to protected symbols to
++ resolve directly to the function rather than going via the plt.
++ If people want function pointer comparisons to work as expected
++ then they should avoid writing weird assembly. */
++ if (SYMBOL_CALLS_LOCAL (info, h))
++ {
++ struct elf_dyn_relocs **pp;
++
++ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
++ {
++ p->count -= p->pc_count;
++ p->pc_count = 0;
++ if (p->count == 0)
++ *pp = p->next;
++ else
++ pp = &p->next;
++ }
++ }
++
++ if (htab->is_vxworks)
++ {
++ struct elf_dyn_relocs **pp;
++
++ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
++ {
++ if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
++ *pp = p->next;
++ else
++ pp = &p->next;
++ }
++ }
++
++ /* Discard relocs on undefined symbols that must be local. */
++ if (eh->dyn_relocs != NULL
++ && h->root.type == bfd_link_hash_undefined
++ && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
++ || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
++ eh->dyn_relocs = NULL;
++
++ /* Also discard relocs on undefined weak syms with non-default
++ visibility. */
++ if (eh->dyn_relocs != NULL
++ && h->root.type == bfd_link_hash_undefweak)
++ {
++ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
++ eh->dyn_relocs = NULL;
++
++ /* Make sure undefined weak symbols are output as a dynamic
++ symbol in PIEs. */
++ else if (h->dynindx == -1
++ && !h->forced_local
++ && !h->def_regular)
++ {
++ if (! bfd_elf_link_record_dynamic_symbol (info, h))
++ return FALSE;
++ }
++ }
++ }
++ else if (ELIMINATE_COPY_RELOCS)
++ {
++ /* For the non-shared case, discard space for relocs against
++ symbols which turn out to need copy relocs or are not
++ dynamic. */
++
++ if (!h->non_got_ref
++ && !h->def_regular)
++ {
++ /* Make sure this symbol is output as a dynamic symbol.
++ Undefined weak syms won't yet be marked as dynamic. */
++ if (h->dynindx == -1
++ && !h->forced_local)
++ {
++ if (! bfd_elf_link_record_dynamic_symbol (info, h))
++ return FALSE;
++ }
++
++ /* If that succeeded, we know we'll be keeping all the
++ relocs. */
++ if (h->dynindx != -1)
++ goto keep;
++ }
++
++ eh->dyn_relocs = NULL;
++
++ keep: ;
++ }
++
++ /* Finally, allocate space. */
++ for (p = eh->dyn_relocs; p != NULL; p = p->next)
++ {
++ asection *sreloc = elf_section_data (p->sec)->sreloc;
++ if (!htab->elf.dynamic_sections_created)
++ sreloc = htab->reliplt;
++ sreloc->size += p->count * sizeof (Elf32_External_Rela);
++ }
++
++ return TRUE;
++}
++
++/* Set DF_TEXTREL if we find any dynamic relocs that apply to
++ read-only sections. */
++
++static bfd_boolean
++maybe_set_textrel (struct elf_link_hash_entry *h, void *info)
++{
++ if (h->root.type == bfd_link_hash_indirect)
++ return TRUE;
++
++ if (readonly_dynrelocs (h))
++ {
++ ((struct bfd_link_info *) info)->flags |= DF_TEXTREL;
++
++ /* Not an error, just cut short the traversal. */
++ return FALSE;
++ }
++ return TRUE;
++}
++
++static const unsigned char glink_eh_frame_cie[] =
++{
++ 0, 0, 0, 16, /* length. */
++ 0, 0, 0, 0, /* id. */
++ 1, /* CIE version. */
++ 'z', 'R', 0, /* Augmentation string. */
++ 4, /* Code alignment. */
++ 0x7c, /* Data alignment. */
++ 65, /* RA reg. */
++ 1, /* Augmentation size. */
++ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */
++ DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */
++};
++
++/* Set the sizes of the dynamic sections. */
++
++static bfd_boolean
++ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
++ struct bfd_link_info *info)
++{
++ struct ppc_elf_link_hash_table *htab;
++ asection *s;
++ bfd_boolean relocs;
++ bfd *ibfd;
++
++#ifdef DEBUG
++ fprintf (stderr, "ppc_elf_size_dynamic_sections called\n");
++#endif
++
++ htab = ppc_elf_hash_table (info);
++ BFD_ASSERT (htab->elf.dynobj != NULL);
++
++#ifdef DEBUG
++ fprintf (stderr, "ppc_elf_size_dynamic_sections: dynamic_sections_created = %d\n", elf_hash_table (info)->dynamic_sections_created);
++#endif
++
++ if (elf_hash_table (info)->dynamic_sections_created)
++ {
++ /* Set the contents of the .interp section to the interpreter. */
++ if (info->executable)
++ {
++ s = bfd_get_linker_section (htab->elf.dynobj, ".interp");
++ BFD_ASSERT (s != NULL);
++ s->size = sizeof ELF_DYNAMIC_INTERPRETER;
++ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
++ }
++ }
++
++ if (htab->plt_type == PLT_OLD)
++ htab->got_header_size = 16;
++ else if (htab->plt_type == PLT_NEW)
++ htab->got_header_size = 12;
++
++ /* Set up .got offsets for local syms, and space for local dynamic
++ relocs. */
++ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
++ {
++ bfd_signed_vma *local_got;
++ bfd_signed_vma *end_local_got;
++ struct plt_entry **local_plt;
++ struct plt_entry **end_local_plt;
++ char *lgot_masks;
++ bfd_size_type locsymcount;
++ Elf_Internal_Shdr *symtab_hdr;
++
++#ifdef DEBUG
++ fprintf (stderr, "ppc_elf_size_dynamic_sections: is_ppc_elf() = %d (flavour = %d)\n", is_ppc_elf (ibfd), bfd_get_flavour (ibfd));
++#endif
++
++ if (!is_ppc_elf (ibfd))
++ continue;
++
++ for (s = ibfd->sections; s != NULL; s = s->next)
++ {
++ struct elf_dyn_relocs *p;
++
++ for (p = ((struct elf_dyn_relocs *)
++ elf_section_data (s)->local_dynrel);
++ p != NULL;
++ p = p->next)
++ {
++ if (!bfd_is_abs_section (p->sec)
++ && bfd_is_abs_section (p->sec->output_section))
++ {
++ /* Input section has been discarded, either because
++ it is a copy of a linkonce section or due to
++ linker script /DISCARD/, so we'll be discarding
++ the relocs too. */
++ }
++ else if (htab->is_vxworks
++ && strcmp (p->sec->output_section->name,
++ ".tls_vars") == 0)
++ {
++ /* Relocations in vxworks .tls_vars sections are
++ handled specially by the loader. */
++ }
++ else if (p->count != 0)
++ {
++ asection *sreloc = elf_section_data (p->sec)->sreloc;
++ if (!htab->elf.dynamic_sections_created)
++ sreloc = htab->reliplt;
++ sreloc->size += p->count * sizeof (Elf32_External_Rela);
++ if ((p->sec->output_section->flags
++ & (SEC_READONLY | SEC_ALLOC))
++ == (SEC_READONLY | SEC_ALLOC))
++ info->flags |= DF_TEXTREL;
++ }
++ }
++ }
++
++ local_got = elf_local_got_refcounts (ibfd);
++ if (!local_got)
++ continue;
++
++ symtab_hdr = &elf_symtab_hdr (ibfd);
++ locsymcount = symtab_hdr->sh_info;
++ end_local_got = local_got + locsymcount;
++ local_plt = (struct plt_entry **) end_local_got;
++ end_local_plt = local_plt + locsymcount;
++ lgot_masks = (char *) end_local_plt;
++
++ for (; local_got < end_local_got; ++local_got, ++lgot_masks)
++ if (*local_got > 0)
++ {
++ unsigned int need = 0;
++ if ((*lgot_masks & TLS_TLS) != 0)
++ {
++ if ((*lgot_masks & TLS_GD) != 0)
++ need += 8;
++ if ((*lgot_masks & TLS_LD) != 0)
++ htab->tlsld_got.refcount += 1;
++ if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0)
++ need += 4;
++ if ((*lgot_masks & TLS_DTPREL) != 0)
++ need += 4;
++ }
++ else
++ need += 4;
++ if (need == 0)
++ *local_got = (bfd_vma) -1;
++ else
++ {
++ *local_got = allocate_got (htab, need);
++ if (info->shared)
++ htab->relgot->size += (need
++ * (sizeof (Elf32_External_Rela) / 4));
++ }
++ }
++ else
++ *local_got = (bfd_vma) -1;
++
++ if (htab->is_vxworks)
++ continue;
++
++ /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */
++ for (; local_plt < end_local_plt; ++local_plt)
++ {
++ struct plt_entry *ent;
++ bfd_boolean doneone = FALSE;
++ bfd_vma plt_offset = 0, glink_offset = 0;
++
++ for (ent = *local_plt; ent != NULL; ent = ent->next)
++ if (ent->plt.refcount > 0)
++ {
++ s = htab->iplt;
++
++ if (!doneone)
++ {
++ plt_offset = s->size;
++ s->size += 4;
++ }
++ ent->plt.offset = plt_offset;
++
++ s = htab->glink;
++ if (!doneone || info->shared)
++ {
++ glink_offset = s->size;
++ s->size += GLINK_ENTRY_SIZE;
++ }
++ ent->glink_offset = glink_offset;
++
++ if (!doneone)
++ {
++ htab->reliplt->size += sizeof (Elf32_External_Rela);
++ doneone = TRUE;
++ }
++ }
++ else
++ ent->plt.offset = (bfd_vma) -1;
++ }
++ }
++
++ /* Allocate space for global sym dynamic relocs. */
++ elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
++
++ if (htab->tlsld_got.refcount > 0)
++ {
++ htab->tlsld_got.offset = allocate_got (htab, 8);
++ if (info->shared)
++ htab->relgot->size += sizeof (Elf32_External_Rela);
++ }
++ else
++ htab->tlsld_got.offset = (bfd_vma) -1;
++
++ if (htab->got != NULL && htab->plt_type != PLT_VXWORKS)
++ {
++ unsigned int g_o_t = 32768;
++
++ /* If we haven't allocated the header, do so now. When we get here,
++ for old plt/got the got size will be 0 to 32764 (not allocated),
++ or 32780 to 65536 (header allocated). For new plt/got, the
++ corresponding ranges are 0 to 32768 and 32780 to 65536. */
++ if (htab->got->size <= 32768)
++ {
++ g_o_t = htab->got->size;
++ if (htab->plt_type == PLT_OLD)
++ g_o_t += 4;
++ htab->got->size += htab->got_header_size;
++ }
++
++ htab->elf.hgot->root.u.def.value = g_o_t;
++ }
++ if (info->shared)
++ {
++ struct elf_link_hash_entry *sda = htab->sdata[0].sym;
++ if (sda != NULL
++ && !(sda->root.type == bfd_link_hash_defined
++ || sda->root.type == bfd_link_hash_defweak))
++ {
++ sda->root.type = bfd_link_hash_defined;
++ sda->root.u.def.section = htab->elf.hgot->root.u.def.section;
++ sda->root.u.def.value = htab->elf.hgot->root.u.def.value;
++ }
++ }
++
++ if (htab->glink != NULL
++ && htab->glink->size != 0
++ && htab->elf.dynamic_sections_created)
++ {
++ htab->glink_pltresolve = htab->glink->size;
++ /* Space for the branch table. */
++ htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
++ /* Pad out to align the start of PLTresolve. */
++ htab->glink->size += -htab->glink->size & 15;
++ htab->glink->size += GLINK_PLTRESOLVE;
++
++ if (htab->emit_stub_syms)
++ {
++ struct elf_link_hash_entry *sh;
++ sh = elf_link_hash_lookup (&htab->elf, "__glink",
++ TRUE, FALSE, FALSE);
++ if (sh == NULL)
++ return FALSE;
++ if (sh->root.type == bfd_link_hash_new)
++ {
++ sh->root.type = bfd_link_hash_defined;
++ sh->root.u.def.section = htab->glink;
++ sh->root.u.def.value = htab->glink_pltresolve;
++ sh->ref_regular = 1;
++ sh->def_regular = 1;
++ sh->ref_regular_nonweak = 1;
++ sh->forced_local = 1;
++ sh->non_elf = 0;
++ }
++ sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
++ TRUE, FALSE, FALSE);
++ if (sh == NULL)
++ return FALSE;
++ if (sh->root.type == bfd_link_hash_new)
++ {
++ sh->root.type = bfd_link_hash_defined;
++ sh->root.u.def.section = htab->glink;
++ sh->root.u.def.value = htab->glink->size - GLINK_PLTRESOLVE;
++ sh->ref_regular = 1;
++ sh->def_regular = 1;
++ sh->ref_regular_nonweak = 1;
++ sh->forced_local = 1;
++ sh->non_elf = 0;
++ }
++ }
++ }
++
++ if (htab->glink != NULL
++ && htab->glink->size != 0
++ && htab->glink_eh_frame != NULL
++ && !bfd_is_abs_section (htab->glink_eh_frame->output_section)
++ && _bfd_elf_eh_frame_present (info))
++ {
++ s = htab->glink_eh_frame;
++ s->size = sizeof (glink_eh_frame_cie) + 20;
++ if (info->shared)
++ {
++ s->size += 4;
++ if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256)
++ s->size += 4;
++ }
++ }
++
++ /* We've now determined the sizes of the various dynamic sections.
++ Allocate memory for them. */
++ relocs = FALSE;
++ for (s = htab->elf.dynobj->sections; s != NULL; s = s->next)
++ {
++ bfd_boolean strip_section = TRUE;
++
++ if ((s->flags & SEC_LINKER_CREATED) == 0)
++ continue;
++
++ if (s == htab->plt
++ || s == htab->got)
++ {
++ /* We'd like to strip these sections if they aren't needed, but if
++ we've exported dynamic symbols from them we must leave them.
++ It's too late to tell BFD to get rid of the symbols. */
++ if (htab->elf.hplt != NULL)
++ strip_section = FALSE;
++ /* Strip this section if we don't need it; see the
++ comment below. */
++ }
++ else if (s == htab->iplt
++ || s == htab->glink
++ || s == htab->glink_eh_frame
++ || s == htab->sgotplt
++ || s == htab->sbss
++ || s == htab->dynbss
++ || s == htab->dynsbss
++ || s == htab->sdata[0].section
++ || s == htab->sdata[1].section)
++ {
++ /* Strip these too. */
++ }
++ else if (CONST_STRNEQ (bfd_get_section_name (htab->elf.dynobj, s),
++ ".rela"))
++ {
++ if (s->size != 0)
++ {
++ /* Remember whether there are any relocation sections. */
++ relocs = TRUE;
++
++ /* We use the reloc_count field as a counter if we need
++ to copy relocs into the output file. */
++ s->reloc_count = 0;
++ }
++ }
++ else
++ {
++ /* It's not one of our sections, so don't allocate space. */
++ continue;
++ }
++
++ if (s->size == 0 && strip_section)
++ {
++ /* If we don't need this section, strip it from the
++ output file. This is mostly to handle .rela.bss and
++ .rela.plt. We must create both sections in
++ create_dynamic_sections, because they must be created
++ before the linker maps input sections to output
++ sections. The linker does that before
++ adjust_dynamic_symbol is called, and it is that
++ function which decides whether anything needs to go
++ into these sections. */
++ s->flags |= SEC_EXCLUDE;
++ continue;
++ }
++
++ if ((s->flags & SEC_HAS_CONTENTS) == 0)
++ continue;
++
++ /* Allocate memory for the section contents. */
++ s->contents = bfd_zalloc (htab->elf.dynobj, s->size);
++ if (s->contents == NULL)
++ return FALSE;
++ }
++
++ if (htab->elf.dynamic_sections_created)
++ {
++ /* Add some entries to the .dynamic section. We fill in the
++ values later, in ppc_elf_finish_dynamic_sections, but we
++ must add the entries now so that we get the correct size for
++ the .dynamic section. The DT_DEBUG entry is filled in by the
++ dynamic linker and used by the debugger. */
++#define add_dynamic_entry(TAG, VAL) \
++ _bfd_elf_add_dynamic_entry (info, TAG, VAL)
++
++ if (info->executable)
++ {
++ if (!add_dynamic_entry (DT_DEBUG, 0))
++ return FALSE;
++ }
++
++ if (htab->plt != NULL && htab->plt->size != 0)
++ {
++ if (!add_dynamic_entry (DT_PLTGOT, 0)
++ || !add_dynamic_entry (DT_PLTRELSZ, 0)
++ || !add_dynamic_entry (DT_PLTREL, DT_RELA)
++ || !add_dynamic_entry (DT_JMPREL, 0))
++ return FALSE;
++ }
++
++ if (htab->glink != NULL && htab->glink->size != 0)
++ {
++ if (!add_dynamic_entry (DT_PPC_GOT, 0))
++ return FALSE;
++ if (!htab->no_tls_get_addr_opt
++ && htab->tls_get_addr != NULL
++ && htab->tls_get_addr->plt.plist != NULL
++ && !add_dynamic_entry (DT_PPC_TLSOPT, 0))
++ return FALSE;
++ }
++
++ if (relocs)
++ {
++ if (!add_dynamic_entry (DT_RELA, 0)
++ || !add_dynamic_entry (DT_RELASZ, 0)
++ || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
++ return FALSE;
++ }
++
++ /* If any dynamic relocs apply to a read-only section, then we
++ need a DT_TEXTREL entry. */
++ if ((info->flags & DF_TEXTREL) == 0)
++ elf_link_hash_traverse (elf_hash_table (info), maybe_set_textrel,
++ info);
++
++ if ((info->flags & DF_TEXTREL) != 0)
++ {
++ if (!add_dynamic_entry (DT_TEXTREL, 0))
++ return FALSE;
++ }
++ if (htab->is_vxworks
++ && !elf_vxworks_add_dynamic_entries (output_bfd, info))
++ return FALSE;
++
++ /* Flag it as a version 2 dynamic binary */
++ if (!add_dynamic_entry(DT_AMIGAOS_DYNVERSION, 2))
++ return FALSE;
++ }
++#undef add_dynamic_entry
++
++ if (htab->glink_eh_frame != NULL
++ && htab->glink_eh_frame->contents != NULL)
++ {
++ unsigned char *p = htab->glink_eh_frame->contents;
++ bfd_vma val;
++
++ memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
++ /* CIE length (rewrite in case little-endian). */
++ bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p);
++ p += sizeof (glink_eh_frame_cie);
++ /* FDE length. */
++ val = htab->glink_eh_frame->size - 4 - sizeof (glink_eh_frame_cie);
++ bfd_put_32 (htab->elf.dynobj, val, p);
++ p += 4;
++ /* CIE pointer. */
++ val = p - htab->glink_eh_frame->contents;
++ bfd_put_32 (htab->elf.dynobj, val, p);
++ p += 4;
++ /* Offset to .glink. Set later. */
++ p += 4;
++ /* .glink size. */
++ bfd_put_32 (htab->elf.dynobj, htab->glink->size, p);
++ p += 4;
++ /* Augmentation. */
++ p += 1;
++
++ if (info->shared
++ && htab->elf.dynamic_sections_created)
++ {
++ bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2;
++ if (adv < 64)
++ *p++ = DW_CFA_advance_loc + adv;
++ else if (adv < 256)
++ {
++ *p++ = DW_CFA_advance_loc1;
++ *p++ = adv;
++ }
++ else if (adv < 65536)
++ {
++ *p++ = DW_CFA_advance_loc2;
++ bfd_put_16 (htab->elf.dynobj, adv, p);
++ p += 2;
++ }
++ else
++ {
++ *p++ = DW_CFA_advance_loc4;
++ bfd_put_32 (htab->elf.dynobj, adv, p);
++ p += 4;
++ }
++ *p++ = DW_CFA_register;
++ *p++ = 65;
++ p++;
++ *p++ = DW_CFA_advance_loc + 4;
++ *p++ = DW_CFA_restore_extended;
++ *p++ = 65;
++ }
++ BFD_ASSERT ((bfd_vma) ((p + 3 - htab->glink_eh_frame->contents) & -4)
++ == htab->glink_eh_frame->size);
++ }
++
++ return TRUE;
++}
++
++/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
++
++static bfd_boolean
++ppc_elf_hash_symbol (struct elf_link_hash_entry *h)
++{
++ if (h->plt.plist != NULL
++ && !h->def_regular
++ && (!h->pointer_equality_needed
++ || !h->ref_regular_nonweak))
++ return FALSE;
++
++ return _bfd_elf_hash_symbol (h);
++}
++
++#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
++
++/* Relaxation trampolines. r12 is available for clobbering (r11, is
++ used for some functions that are allowed to break the ABI). */
++static const int shared_stub_entry[] =
++ {
++ 0x7c0802a6, /* mflr 0 */
++ 0x429f0005, /* bcl 20, 31, .Lxxx */
++ 0x7d8802a6, /* mflr 12 */
++ 0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */
++ 0x398c0008, /* addi 12, 12, (xxx-.Lxxx)@l */
++ 0x7c0803a6, /* mtlr 0 */
++ 0x7d8903a6, /* mtctr 12 */
++ 0x4e800420, /* bctr */
++ };
++
++static const int stub_entry[] =
++ {
++ 0x3d800000, /* lis 12,xxx@ha */
++ 0x398c0000, /* addi 12,12,xxx@l */
++ 0x7d8903a6, /* mtctr 12 */
++ 0x4e800420, /* bctr */
++ };
++
++static bfd_boolean
++ppc_elf_relax_section (bfd *abfd,
++ asection *isec,
++ struct bfd_link_info *link_info,
++ bfd_boolean *again)
++{
++ struct one_fixup
++ {
++ struct one_fixup *next;
++ asection *tsec;
++ /* Final link, can use the symbol offset. For a
++ relocatable link we use the symbol's index. */
++ bfd_vma toff;
++ bfd_vma trampoff;
++ };
++
++ Elf_Internal_Shdr *symtab_hdr;
++ bfd_byte *contents = NULL;
++ Elf_Internal_Sym *isymbuf = NULL;
++ Elf_Internal_Rela *internal_relocs = NULL;
++ Elf_Internal_Rela *irel, *irelend;
++ struct one_fixup *fixups = NULL;
++ unsigned changes = 0;
++ struct ppc_elf_link_hash_table *htab;
++ bfd_size_type trampoff;
++ asection *got2;
++ bfd_boolean maybe_pasted;
++
++ *again = FALSE;
++
++ /* Nothing to do if there are no relocations, and no need to do
++ anything with non-alloc or non-code sections. */
++ if ((isec->flags & SEC_ALLOC) == 0
++ || (isec->flags & SEC_CODE) == 0
++ || (isec->flags & SEC_RELOC) == 0
++ || isec->reloc_count == 0)
++ return TRUE;
++
++ /* We cannot represent the required PIC relocs in the output, so don't
++ do anything. The linker doesn't support mixing -shared and -r
++ anyway. */
++ if (link_info->relocatable && link_info->shared)
++ return TRUE;
++
++ trampoff = (isec->size + 3) & (bfd_vma) -4;
++ maybe_pasted = (strcmp (isec->output_section->name, ".init") == 0
++ || strcmp (isec->output_section->name, ".fini") == 0);
++ /* Space for a branch around any trampolines. */
++ if (maybe_pasted)
++ trampoff += 4;
++
++ symtab_hdr = &elf_symtab_hdr (abfd);
++
++ /* Get a copy of the native relocations. */
++ internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL,
++ link_info->keep_memory);
++ if (internal_relocs == NULL)
++ goto error_return;
++
++ htab = ppc_elf_hash_table (link_info);
++ got2 = bfd_get_section_by_name (abfd, ".got2");
++
++ irelend = internal_relocs + isec->reloc_count;
++ for (irel = internal_relocs; irel < irelend; irel++)
++ {
++ unsigned long r_type = ELF32_R_TYPE (irel->r_info);
++ bfd_vma toff, roff;
++ asection *tsec;
++ struct one_fixup *f;
++ size_t insn_offset = 0;
++ bfd_vma max_branch_offset, val;
++ bfd_byte *hit_addr;
++ unsigned long t0;
++ struct elf_link_hash_entry *h;
++ struct plt_entry **plist;
++ unsigned char sym_type;
++
++ switch (r_type)
++ {
++ case R_PPC_REL24:
++ case R_PPC_LOCAL24PC:
++ case R_PPC_PLTREL24:
++ max_branch_offset = 1 << 25;
++ break;
++
++ case R_PPC_REL14:
++ case R_PPC_REL14_BRTAKEN:
++ case R_PPC_REL14_BRNTAKEN:
++ max_branch_offset = 1 << 15;
++ break;
++
++ default:
++ continue;
++ }
++
++ /* Get the value of the symbol referred to by the reloc. */
++ h = NULL;
++ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
++ {
++ /* A local symbol. */
++ Elf_Internal_Sym *isym;
++
++ /* Read this BFD's local symbols. */
++ if (isymbuf == NULL)
++ {
++ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
++ if (isymbuf == NULL)
++ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
++ symtab_hdr->sh_info, 0,
++ NULL, NULL, NULL);
++ if (isymbuf == 0)
++ goto error_return;
++ }
++ isym = isymbuf + ELF32_R_SYM (irel->r_info);
++ if (isym->st_shndx == SHN_UNDEF)
++ tsec = bfd_und_section_ptr;
++ else if (isym->st_shndx == SHN_ABS)
++ tsec = bfd_abs_section_ptr;
++ else if (isym->st_shndx == SHN_COMMON)
++ tsec = bfd_com_section_ptr;
++ else
++ tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
++
++ toff = isym->st_value;
++ sym_type = ELF_ST_TYPE (isym->st_info);
++ }
++ else
++ {
++ /* Global symbol handling. */
++ unsigned long indx;
++
++ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
++ h = elf_sym_hashes (abfd)[indx];
++
++ while (h->root.type == bfd_link_hash_indirect
++ || h->root.type == bfd_link_hash_warning)
++ h = (struct elf_link_hash_entry *) h->root.u.i.link;
++
++ if (h->root.type == bfd_link_hash_defined
++ || h->root.type == bfd_link_hash_defweak)
++ {
++ tsec = h->root.u.def.section;
++ toff = h->root.u.def.value;
++ }
++ else if (h->root.type == bfd_link_hash_undefined
++ || h->root.type == bfd_link_hash_undefweak)
++ {
++ tsec = bfd_und_section_ptr;
++ toff = link_info->relocatable ? indx : 0;
++ }
++ else
++ continue;
++
++ sym_type = h->type;
++ }
++
++ /* The condition here under which we call find_plt_ent must
++ match that in relocate_section. If we call find_plt_ent here
++ but not in relocate_section, or vice versa, then the branch
++ destination used here may be incorrect. */
++ plist = NULL;
++ if (h != NULL)
++ {
++ /* We know is_branch_reloc (r_type) is true. */
++ if (h->type == STT_GNU_IFUNC
++ || r_type == R_PPC_PLTREL24)
++ plist = &h->plt.plist;
++ }
++ else if (sym_type == STT_GNU_IFUNC
++ && elf_local_got_offsets (abfd) != NULL)
++ {
++ bfd_vma *local_got_offsets = elf_local_got_offsets (abfd);
++ struct plt_entry **local_plt = (struct plt_entry **)
++ (local_got_offsets + symtab_hdr->sh_info);
++ plist = local_plt + ELF32_R_SYM (irel->r_info);
++ }
++ if (plist != NULL)
++ {
++ bfd_vma addend = 0;
++ struct plt_entry *ent;
++
++ if (r_type == R_PPC_PLTREL24 && link_info->shared)
++ addend = irel->r_addend;
++ ent = find_plt_ent (plist, got2, addend);
++ if (ent != NULL)
++ {
++ if (htab->plt_type == PLT_NEW
++ || h == NULL
++ || !htab->elf.dynamic_sections_created
++ || h->dynindx == -1)
++ {
++ tsec = htab->glink;
++ toff = ent->glink_offset;
++ }
++ else
++ {
++ tsec = htab->plt;
++ toff = ent->plt.offset;
++ }
++ }
++ }
++
++ /* If the branch and target are in the same section, you have
++ no hope of adding stubs. We'll error out later should the
++ branch overflow. */
++ if (tsec == isec)
++ continue;
++
++ /* There probably isn't any reason to handle symbols in
++ SEC_MERGE sections; SEC_MERGE doesn't seem a likely
++ attribute for a code section, and we are only looking at
++ branches. However, implement it correctly here as a
++ reference for other target relax_section functions. */
++ if (0 && tsec->sec_info_type == SEC_INFO_TYPE_MERGE)
++ {
++ /* At this stage in linking, no SEC_MERGE symbol has been
++ adjusted, so all references to such symbols need to be
++ passed through _bfd_merged_section_offset. (Later, in
++ relocate_section, all SEC_MERGE symbols *except* for
++ section symbols have been adjusted.)
++
++ gas may reduce relocations against symbols in SEC_MERGE
++ sections to a relocation against the section symbol when
++ the original addend was zero. When the reloc is against
++ a section symbol we should include the addend in the
++ offset passed to _bfd_merged_section_offset, since the
++ location of interest is the original symbol. On the
++ other hand, an access to "sym+addend" where "sym" is not
++ a section symbol should not include the addend; Such an
++ access is presumed to be an offset from "sym"; The
++ location of interest is just "sym". */
++ if (sym_type == STT_SECTION)
++ toff += irel->r_addend;
++
++ toff = _bfd_merged_section_offset (abfd, &tsec,
++ elf_section_data (tsec)->sec_info,
++ toff);
++
++ if (sym_type != STT_SECTION)
++ toff += irel->r_addend;
++ }
++ /* PLTREL24 addends are special. */
++ else if (r_type != R_PPC_PLTREL24)
++ toff += irel->r_addend;
++
++ /* Attempted -shared link of non-pic code loses. */
++ if (tsec->output_section == NULL)
++ continue;
++
++ roff = irel->r_offset;
++
++ /* If the branch is in range, no need to do anything. */
++ if (tsec != bfd_und_section_ptr
++ && (!link_info->relocatable
++ /* A relocatable link may have sections moved during
++ final link, so do not presume they remain in range. */
++ || tsec->output_section == isec->output_section))
++ {
++ bfd_vma symaddr, reladdr;
++
++ symaddr = tsec->output_section->vma + tsec->output_offset + toff;
++ reladdr = isec->output_section->vma + isec->output_offset + roff;
++ if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset)
++ continue;
++ }
++
++ /* Look for an existing fixup to this address. */
++ for (f = fixups; f ; f = f->next)
++ if (f->tsec == tsec && f->toff == toff)
++ break;
++
++ if (f == NULL)
++ {
++ size_t size;
++ unsigned long stub_rtype;
++
++ val = trampoff - roff;
++ if (val >= max_branch_offset)
++ /* Oh dear, we can't reach a trampoline. Don't try to add
++ one. We'll report an error later. */
++ continue;
++
++ if (link_info->shared)
++ {
++ size = 4 * ARRAY_SIZE (shared_stub_entry);
++ insn_offset = 12;
++ }
++ else
++ {
++ size = 4 * ARRAY_SIZE (stub_entry);
++ insn_offset = 0;
++ }
++ stub_rtype = R_PPC_RELAX;
++ if (tsec == htab->plt
++ || tsec == htab->glink)
++ {
++ stub_rtype = R_PPC_RELAX_PLT;
++ if (r_type == R_PPC_PLTREL24)
++ stub_rtype = R_PPC_RELAX_PLTREL24;
++ }
++
++ /* Hijack the old relocation. Since we need two
++ relocations for this use a "composite" reloc. */
++ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
++ stub_rtype);
++ irel->r_offset = trampoff + insn_offset;
++ if (r_type == R_PPC_PLTREL24
++ && stub_rtype != R_PPC_RELAX_PLTREL24)
++ irel->r_addend = 0;
++
++ /* Record the fixup so we don't do it again this section. */
++ f = bfd_malloc (sizeof (*f));
++ f->next = fixups;
++ f->tsec = tsec;
++ f->toff = toff;
++ f->trampoff = trampoff;
++ fixups = f;
++
++ trampoff += size;
++ changes++;
++ }
++ else
++ {
++ val = f->trampoff - roff;
++ if (val >= max_branch_offset)
++ continue;
++
++ /* Nop out the reloc, since we're finalizing things here. */
++ irel->r_info = ELF32_R_INFO (0, R_PPC_NONE);
++ }
++
++ /* Get the section contents. */
++ if (contents == NULL)
++ {
++ /* Get cached copy if it exists. */
++ if (elf_section_data (isec)->this_hdr.contents != NULL)
++ contents = elf_section_data (isec)->this_hdr.contents;
++ else
++ {
++ /* Go get them off disk. */
++ if (!bfd_malloc_and_get_section (abfd, isec, &contents))
++ goto error_return;
++ }
++ }
++
++ /* Fix up the existing branch to hit the trampoline. */
++ hit_addr = contents + roff;
++ switch (r_type)
++ {
++ case R_PPC_REL24:
++ case R_PPC_LOCAL24PC:
++ case R_PPC_PLTREL24:
++ t0 = bfd_get_32 (abfd, hit_addr);
++ t0 &= ~0x3fffffc;
++ t0 |= val & 0x3fffffc;
++ bfd_put_32 (abfd, t0, hit_addr);
++ break;
++
++ case R_PPC_REL14:
++ case R_PPC_REL14_BRTAKEN:
++ case R_PPC_REL14_BRNTAKEN:
++ t0 = bfd_get_32 (abfd, hit_addr);
++ t0 &= ~0xfffc;
++ t0 |= val & 0xfffc;
++ bfd_put_32 (abfd, t0, hit_addr);
++ break;
++ }
++ }
++
++ /* Write out the trampolines. */
++ if (fixups != NULL)
++ {
++ const int *stub;
++ bfd_byte *dest;
++ int i, size;
++
++ do
++ {
++ struct one_fixup *f = fixups;
++ fixups = fixups->next;
++ free (f);
++ }
++ while (fixups);
++
++ contents = bfd_realloc_or_free (contents, trampoff);
++ if (contents == NULL)
++ goto error_return;
++
++ isec->size = (isec->size + 3) & (bfd_vma) -4;
++ dest = contents + isec->size;
++ /* Branch around the trampolines. */
++ if (maybe_pasted)
++ {
++ bfd_vma val = B + trampoff - isec->size;
++ bfd_put_32 (abfd, val, dest);
++ dest += 4;
++ }
++ isec->size = trampoff;
++
++ if (link_info->shared)
++ {
++ stub = shared_stub_entry;
++ size = ARRAY_SIZE (shared_stub_entry);
++ }
++ else
++ {
++ stub = stub_entry;
++ size = ARRAY_SIZE (stub_entry);
++ }
++
++ i = 0;
++ while (dest < contents + trampoff)
++ {
++ bfd_put_32 (abfd, stub[i], dest);
++ i++;
++ if (i == size)
++ i = 0;
++ dest += 4;
++ }
++ BFD_ASSERT (i == 0);
++ }
++
++ if (isymbuf != NULL
++ && symtab_hdr->contents != (unsigned char *) isymbuf)
++ {
++ if (! link_info->keep_memory)
++ free (isymbuf);
++ else
++ {
++ /* Cache the symbols for elf_link_input_bfd. */
++ symtab_hdr->contents = (unsigned char *) isymbuf;
++ }
++ }
++
++ if (contents != NULL
++ && elf_section_data (isec)->this_hdr.contents != contents)
++ {
++ if (!changes && !link_info->keep_memory)
++ free (contents);
++ else
++ {
++ /* Cache the section contents for elf_link_input_bfd. */
++ elf_section_data (isec)->this_hdr.contents = contents;
++ }
++ }
++
++ if (changes != 0)
++ {
++ /* Append sufficient NOP relocs so we can write out relocation
++ information for the trampolines. */
++ Elf_Internal_Shdr *rel_hdr;
++ Elf_Internal_Rela *new_relocs = bfd_malloc ((changes + isec->reloc_count)
++ * sizeof (*new_relocs));
++ unsigned ix;
++
++ if (!new_relocs)
++ goto error_return;
++ memcpy (new_relocs, internal_relocs,
++ isec->reloc_count * sizeof (*new_relocs));
++ for (ix = changes; ix--;)
++ {
++ irel = new_relocs + ix + isec->reloc_count;
++
++ irel->r_info = ELF32_R_INFO (0, R_PPC_NONE);
++ }
++ if (internal_relocs != elf_section_data (isec)->relocs)
++ free (internal_relocs);
++ elf_section_data (isec)->relocs = new_relocs;
++ isec->reloc_count += changes;
++ rel_hdr = _bfd_elf_single_rel_hdr (isec);
++ rel_hdr->sh_size += changes * rel_hdr->sh_entsize;
++ }
++ else if (elf_section_data (isec)->relocs != internal_relocs)
++ free (internal_relocs);
++
++ *again = changes != 0;
++ if (!*again && link_info->relocatable)
++ {
++ /* Convert the internal relax relocs to external form. */
++ for (irel = internal_relocs; irel < irelend; irel++)
++ if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX)
++ {
++ unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
++
++ /* Rewrite the reloc and convert one of the trailing nop
++ relocs to describe this relocation. */
++ BFD_ASSERT (ELF32_R_TYPE (irelend[-1].r_info) == R_PPC_NONE);
++ /* The relocs are at the bottom 2 bytes */
++ irel[0].r_offset += 2;
++ memmove (irel + 1, irel, (irelend - irel - 1) * sizeof (*irel));
++ irel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
++ irel[1].r_offset += 4;
++ irel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
++ irel++;
++ }
++ }
++
++ return TRUE;
++
++ error_return:
++ if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
++ free (isymbuf);
++ if (contents != NULL
++ && elf_section_data (isec)->this_hdr.contents != contents)
++ free (contents);
++ if (internal_relocs != NULL
++ && elf_section_data (isec)->relocs != internal_relocs)
++ free (internal_relocs);
++ return FALSE;
++}
++
++/* What to do when ld finds relocations against symbols defined in
++ discarded sections. */
++
++static unsigned int
++ppc_elf_action_discarded (asection *sec)
++{
++ if (strcmp (".fixup", sec->name) == 0)
++ return 0;
++
++ if (strcmp (".got2", sec->name) == 0)
++ return 0;
++
++ return _bfd_elf_default_action_discarded (sec);
++}
++
++/* Fill in the address for a pointer generated in a linker section. */
++
++static bfd_vma
++elf_finish_pointer_linker_section (bfd *input_bfd,
++ elf_linker_section_t *lsect,
++ struct elf_link_hash_entry *h,
++ bfd_vma relocation,
++ const Elf_Internal_Rela *rel)
++{
++ elf_linker_section_pointers_t *linker_section_ptr;
++
++ BFD_ASSERT (lsect != NULL);
++
++ if (h != NULL)
++ {
++ /* Handle global symbol. */
++ struct ppc_elf_link_hash_entry *eh;
++
++ eh = (struct ppc_elf_link_hash_entry *) h;
++ BFD_ASSERT (eh->elf.def_regular);
++ linker_section_ptr = eh->linker_section_pointer;
++ }
++ else
++ {
++ /* Handle local symbol. */
++ unsigned long r_symndx = ELF32_R_SYM (rel->r_info);
++
++ BFD_ASSERT (is_ppc_elf (input_bfd));
++ BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL);
++ linker_section_ptr = elf_local_ptr_offsets (input_bfd)[r_symndx];
++ }
++
++ linker_section_ptr = elf_find_pointer_linker_section (linker_section_ptr,
++ rel->r_addend,
++ lsect);
++ BFD_ASSERT (linker_section_ptr != NULL);
++
++ /* Offset will always be a multiple of four, so use the bottom bit
++ as a "written" flag. */
++ if ((linker_section_ptr->offset & 1) == 0)
++ {
++ bfd_put_32 (lsect->section->owner,
++ relocation + linker_section_ptr->addend,
++ lsect->section->contents + linker_section_ptr->offset);
++ linker_section_ptr->offset += 1;
++ }
++
++ relocation = (lsect->section->output_section->vma
++ + lsect->section->output_offset
++ + linker_section_ptr->offset - 1
++ - SYM_VAL (lsect->sym));
++
++#ifdef DEBUG
++ fprintf (stderr,
++ "Finish pointer in linker section %s, offset = %ld (0x%lx)\n",
++ lsect->name, (long) relocation, (long) relocation);
++#endif
++
++ return relocation;
++}
++
++#define PPC_LO(v) ((v) & 0xffff)
++#define PPC_HI(v) (((v) >> 16) & 0xffff)
++#define PPC_HA(v) PPC_HI ((v) + 0x8000)
++
++static void
++write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
++ struct bfd_link_info *info)
++{
++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
++ bfd *output_bfd = info->output_bfd;
++ bfd_vma plt;
++
++ plt = ((ent->plt.offset & ~1)
++ + plt_sec->output_section->vma
++ + plt_sec->output_offset);
++
++ if (info->shared)
++ {
++ bfd_vma got = 0;
++
++ if (ent->addend >= 32768)
++ got = (ent->addend
++ + ent->sec->output_section->vma
++ + ent->sec->output_offset);
++ else if (htab->elf.hgot != NULL)
++ got = SYM_VAL (htab->elf.hgot);
++
++ plt -= got;
++
++ if (plt + 0x8000 < 0x10000)
++ {
++ bfd_put_32 (output_bfd, LWZ_11_30 + PPC_LO (plt), p);
++ p += 4;
++ bfd_put_32 (output_bfd, MTCTR_11, p);
++ p += 4;
++ bfd_put_32 (output_bfd, BCTR, p);
++ p += 4;
++ bfd_put_32 (output_bfd, NOP, p);
++ p += 4;
++ }
++ else
++ {
++ bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (plt), p);
++ p += 4;
++ bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
++ p += 4;
++ bfd_put_32 (output_bfd, MTCTR_11, p);
++ p += 4;
++ bfd_put_32 (output_bfd, BCTR, p);
++ p += 4;
++ }
++ }
++ else
++ {
++ bfd_put_32 (output_bfd, LIS_11 + PPC_HA (plt), p);
++ p += 4;
++ bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
++ p += 4;
++ bfd_put_32 (output_bfd, MTCTR_11, p);
++ p += 4;
++ bfd_put_32 (output_bfd, BCTR, p);
++ p += 4;
++ }
++}
++
++/* Return true if symbol is defined statically. */
++
++static bfd_boolean
++is_static_defined (struct elf_link_hash_entry *h)
++{
++ return ((h->root.type == bfd_link_hash_defined
++ || h->root.type == bfd_link_hash_defweak)
++ && h->root.u.def.section != NULL
++ && h->root.u.def.section->output_section != NULL);
++}
++
++/* If INSN is an opcode that may be used with an @tls operand, return
++ the transformed insn for TLS optimisation, otherwise return 0. If
++ REG is non-zero only match an insn with RB or RA equal to REG. */
++
++unsigned int
++_bfd_elf_amigaos_ppc_at_tls_transform (unsigned int insn, unsigned int reg)
++{
++ unsigned int rtra;
++
++ if ((insn & (0x3f << 26)) != 31 << 26)
++ return 0;
++
++ if (reg == 0 || ((insn >> 11) & 0x1f) == reg)
++ rtra = insn & ((1 << 26) - (1 << 16));
++ else if (((insn >> 16) & 0x1f) == reg)
++ rtra = (insn & (0x1f << 21)) | ((insn & (0x1f << 11)) << 5);
++ else
++ return 0;
++
++ if ((insn & (0x3ff << 1)) == 266 << 1)
++ /* add -> addi. */
++ insn = 14 << 26;
++ else if ((insn & (0x1f << 1)) == 23 << 1
++ && ((insn & (0x1f << 6)) < 14 << 6
++ || ((insn & (0x1f << 6)) >= 16 << 6
++ && (insn & (0x1f << 6)) < 24 << 6)))
++ /* load and store indexed -> dform. */
++ insn = (32 | ((insn >> 6) & 0x1f)) << 26;
++ else if ((insn & (((0x1a << 5) | 0x1f) << 1)) == 21 << 1)
++ /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */
++ insn = ((58 | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1);
++ else if ((insn & (((0x1f << 5) | 0x1f) << 1)) == 341 << 1)
++ /* lwax -> lwa. */
++ insn = (58 << 26) | 2;
++ else
++ return 0;
++ insn |= rtra;
++ return insn;
++}
++
++/* If INSN is an opcode that may be used with an @tprel operand, return
++ the transformed insn for an undefined weak symbol, ie. with the
++ thread pointer REG operand removed. Otherwise return 0. */
++
++unsigned int
++_bfd_elf_amigaos_ppc_at_tprel_transform (unsigned int insn, unsigned int reg)
++{
++ if ((insn & (0x1f << 16)) == reg << 16
++ && ((insn & (0x3f << 26)) == 14u << 26 /* addi */
++ || (insn & (0x3f << 26)) == 15u << 26 /* addis */
++ || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
++ || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
++ || (insn & (0x3f << 26)) == 36u << 26 /* stw */
++ || (insn & (0x3f << 26)) == 38u << 26 /* stb */
++ || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
++ || (insn & (0x3f << 26)) == 42u << 26 /* lha */
++ || (insn & (0x3f << 26)) == 44u << 26 /* sth */
++ || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
++ || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
++ || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
++ || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
++ || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
++ || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
++ || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
++ && (insn & 3) != 1)
++ || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
++ && ((insn & 3) == 0 || (insn & 3) == 3))))
++ {
++ insn &= ~(0x1f << 16);
++ }
++ else if ((insn & (0x1f << 21)) == reg << 21
++ && ((insn & (0x3e << 26)) == 24u << 26 /* ori, oris */
++ || (insn & (0x3e << 26)) == 26u << 26 /* xori,xoris */
++ || (insn & (0x3e << 26)) == 28u << 26 /* andi,andis */))
++ {
++ insn &= ~(0x1f << 21);
++ insn |= (insn & (0x1f << 16)) << 5;
++ if ((insn & (0x3e << 26)) == 26 << 26 /* xori,xoris */)
++ insn -= 2 >> 26; /* convert to ori,oris */
++ }
++ else
++ insn = 0;
++ return insn;
++}
++
++static bfd_boolean
++is_insn_ds_form (unsigned int insn)
++{
++ return ((insn & (0x3f << 26)) == 58u << 26 /* ld,ldu,lwa */
++ || (insn & (0x3f << 26)) == 62u << 26 /* std,stdu,stq */
++ || (insn & (0x3f << 26)) == 57u << 26 /* lfdp */
++ || (insn & (0x3f << 26)) == 61u << 26 /* stfdp */);
++}
++
++static bfd_boolean
++is_insn_dq_form (unsigned int insn)
++{
++ return (insn & (0x3f << 26)) == 56u << 26; /* lq */
++}
++
++/* The RELOCATE_SECTION function is called by the ELF backend linker
++ to handle the relocations for a section.
++
++ The relocs are always passed as Rela structures; if the section
++ actually uses Rel structures, the r_addend field will always be
++ zero.
++
++ This function is responsible for adjust the section contents as
++ necessary, and (if using Rela relocs and generating a
++ relocatable output file) adjusting the reloc addend as
++ necessary.
++
++ This function does not have to worry about setting the reloc
++ address or the reloc symbol index.
++
++ LOCAL_SYMS is a pointer to the swapped in local symbols.
++
++ LOCAL_SECTIONS is an array giving the section in the input file
++ corresponding to the st_shndx field of each local symbol.
++
++ The global hash table entry for the global symbols can be found
++ via elf_sym_hashes (input_bfd).
++
++ When generating relocatable output, this function must handle
++ STB_LOCAL/STT_SECTION symbols specially. The output symbol is
++ going to be the section symbol corresponding to the output
++ section, which means that the addend must be adjusted
++ accordingly. */
++
++static bfd_boolean
++ppc_elf_relocate_section (bfd *output_bfd,
++ struct bfd_link_info *info,
++ bfd *input_bfd,
++ asection *input_section,
++ bfd_byte *contents,
++ Elf_Internal_Rela *relocs,
++ Elf_Internal_Sym *local_syms,
++ asection **local_sections)
++{
++ Elf_Internal_Shdr *symtab_hdr;
++ struct elf_link_hash_entry **sym_hashes;
++ struct ppc_elf_link_hash_table *htab;
++ Elf_Internal_Rela *rel;
++ Elf_Internal_Rela *relend;
++ Elf_Internal_Rela outrel;
++ asection *got2, *sreloc = NULL;
++ bfd_vma *local_got_offsets;
++ bfd_boolean ret = TRUE;
++ bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
++ bfd_boolean is_vxworks_tls;
++
++#ifdef DEBUG
++ _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
++ "%ld relocations%s",
++ input_bfd, input_section,
++ (long) input_section->reloc_count,
++ (info->relocatable) ? " (relocatable)" : "");
++#endif
++
++ got2 = bfd_get_section_by_name (input_bfd, ".got2");
++
++ /* Initialize howto table if not already done. */
++ if (!ppc_elf_howto_table[R_PPC_ADDR32])
++ ppc_elf_howto_init ();
++
++ htab = ppc_elf_hash_table (info);
++ local_got_offsets = elf_local_got_offsets (input_bfd);
++ symtab_hdr = &elf_symtab_hdr (input_bfd);
++ sym_hashes = elf_sym_hashes (input_bfd);
++ /* We have to handle relocations in vxworks .tls_vars sections
++ specially, because the dynamic loader is 'weird'. */
++ is_vxworks_tls = (htab->is_vxworks && info->shared
++ && !strcmp (input_section->output_section->name,
++ ".tls_vars"));
++ rel = relocs;
++ relend = relocs + input_section->reloc_count;
++ for (; rel < relend; rel++)
++ {
++ enum elf_ppc_reloc_type r_type;
++ bfd_vma addend;
++ bfd_reloc_status_type r;
++ Elf_Internal_Sym *sym;
++ asection *sec;
++ struct elf_link_hash_entry *h;
++ const char *sym_name;
++ reloc_howto_type *howto;
++ unsigned long r_symndx;
++ bfd_vma relocation;
++ bfd_vma branch_bit, from;
++ bfd_boolean unresolved_reloc;
++ bfd_boolean warned;
++ unsigned int tls_type, tls_mask, tls_gd;
++ struct plt_entry **ifunc;
++
++ r_type = ELF32_R_TYPE (rel->r_info);
++ sym = NULL;
++ sec = NULL;
++ h = NULL;
++ unresolved_reloc = FALSE;
++ warned = FALSE;
++ r_symndx = ELF32_R_SYM (rel->r_info);
++
++ if (r_symndx < symtab_hdr->sh_info)
++ {
++ sym = local_syms + r_symndx;
++ sec = local_sections[r_symndx];
++ sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
++
++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
++ }
++ else
++ {
++ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
++ r_symndx, symtab_hdr, sym_hashes,
++ h, sec, relocation,
++ unresolved_reloc, warned);
++
++ sym_name = h->root.root.string;
++ }
++
++ if (sec != NULL && discarded_section (sec))
++ {
++ /* For relocs against symbols from removed linkonce sections,
++ or sections discarded by a linker script, we just want the
++ section contents zeroed. Avoid any special processing. */
++ howto = NULL;
++ if (r_type < R_PPC_max)
++ howto = ppc_elf_howto_table[r_type];
++ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
++ rel, 1, relend, howto, 0, contents);
++ }
++
++ if (info->relocatable)
++ {
++ if (got2 != NULL
++ && r_type == R_PPC_PLTREL24
++ && rel->r_addend != 0)
++ {
++ /* R_PPC_PLTREL24 is rather special. If non-zero, the
++ addend specifies the GOT pointer offset within .got2. */
++ rel->r_addend += got2->output_offset;
++ }
++ continue;
++ }
++
++ /* TLS optimizations. Replace instruction sequences and relocs
++ based on information we collected in tls_optimize. We edit
++ RELOCS so that --emit-relocs will output something sensible
++ for the final instruction stream. */
++ tls_mask = 0;
++ tls_gd = 0;
++ if (h != NULL)
++ tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
++ else if (local_got_offsets != NULL)
++ {
++ struct plt_entry **local_plt;
++ char *lgot_masks;
++ local_plt
++ = (struct plt_entry **) (local_got_offsets + symtab_hdr->sh_info);
++ lgot_masks = (char *) (local_plt + symtab_hdr->sh_info);
++ tls_mask = lgot_masks[r_symndx];
++ }
++
++ /* Ensure reloc mapping code below stays sane. */
++ if ((R_PPC_GOT_TLSLD16 & 3) != (R_PPC_GOT_TLSGD16 & 3)
++ || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TLSGD16_LO & 3)
++ || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TLSGD16_HI & 3)
++ || (R_PPC_GOT_TLSLD16_HA & 3) != (R_PPC_GOT_TLSGD16_HA & 3)
++ || (R_PPC_GOT_TLSLD16 & 3) != (R_PPC_GOT_TPREL16 & 3)
++ || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TPREL16_LO & 3)
++ || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TPREL16_HI & 3)
++ || (R_PPC_GOT_TLSLD16_HA & 3) != (R_PPC_GOT_TPREL16_HA & 3))
++ abort ();
++ switch (r_type)
++ {
++ default:
++ break;
++
++ case R_PPC_GOT_TPREL16:
++ case R_PPC_GOT_TPREL16_LO:
++ if ((tls_mask & TLS_TLS) != 0
++ && (tls_mask & TLS_TPREL) == 0)
++ {
++ bfd_vma insn;
++
++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
++ insn &= 31 << 21;
++ insn |= 0x3c020000; /* addis 0,2,0 */
++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
++ r_type = R_PPC_TPREL16_HA;
++ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
++ }
++ break;
++
++ case R_PPC_TLS:
++ if ((tls_mask & TLS_TLS) != 0
++ && (tls_mask & TLS_TPREL) == 0)
++ {
++ bfd_vma insn;
++
++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
++ insn = _bfd_elf_ppc_at_tls_transform (insn, 2);
++ if (insn == 0)
++ abort ();
++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
++ r_type = R_PPC_TPREL16_LO;
++ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
++
++ /* Was PPC_TLS which sits on insn boundary, now
++ PPC_TPREL16_LO which is at low-order half-word. */
++ rel->r_offset += d_offset;
++ }
++ break;
++
++ case R_PPC_GOT_TLSGD16_HI:
++ case R_PPC_GOT_TLSGD16_HA:
++ tls_gd = TLS_TPRELGD;
++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
++ goto tls_gdld_hi;
++ break;
++
++ case R_PPC_GOT_TLSLD16_HI:
++ case R_PPC_GOT_TLSLD16_HA:
++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
++ {
++ tls_gdld_hi:
++ if ((tls_mask & tls_gd) != 0)
++ r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
++ + R_PPC_GOT_TPREL16);
++ else
++ {
++ bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
++ rel->r_offset -= d_offset;
++ r_type = R_PPC_NONE;
++ }
++ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
++ }
++ break;
++
++ case R_PPC_GOT_TLSGD16:
++ case R_PPC_GOT_TLSGD16_LO:
++ tls_gd = TLS_TPRELGD;
++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
++ goto tls_ldgd_opt;
++ break;
++
++ case R_PPC_GOT_TLSLD16:
++ case R_PPC_GOT_TLSLD16_LO:
++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
++ {
++ unsigned int insn1, insn2;
++ bfd_vma offset;
++
++ tls_ldgd_opt:
++ offset = (bfd_vma) -1;
++ /* If not using the newer R_PPC_TLSGD/LD to mark
++ __tls_get_addr calls, we must trust that the call
++ stays with its arg setup insns, ie. that the next
++ reloc is the __tls_get_addr call associated with
++ the current reloc. Edit both insns. */
++ if (input_section->has_tls_get_addr_call
++ && rel + 1 < relend
++ && branch_reloc_hash_match (input_bfd, rel + 1,
++ htab->tls_get_addr))
++ offset = rel[1].r_offset;
++ if ((tls_mask & tls_gd) != 0)
++ {
++ /* IE */
++ insn1 = bfd_get_32 (output_bfd,
++ contents + rel->r_offset - d_offset);
++ insn1 &= (1 << 26) - 1;
++ insn1 |= 32 << 26; /* lwz */
++ if (offset != (bfd_vma) -1)
++ {
++ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
++ insn2 = 0x7c631214; /* add 3,3,2 */
++ bfd_put_32 (output_bfd, insn2, contents + offset);
++ }
++ r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
++ + R_PPC_GOT_TPREL16);
++ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
++ }
++ else
++ {
++ /* LE */
++ insn1 = 0x3c620000; /* addis 3,2,0 */
++ if (tls_gd == 0)
++ {
++ /* Was an LD reloc. */
++ for (r_symndx = 0;
++ r_symndx < symtab_hdr->sh_info;
++ r_symndx++)
++ if (local_sections[r_symndx] == sec)
++ break;
++ if (r_symndx >= symtab_hdr->sh_info)
++ r_symndx = STN_UNDEF;
++ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
++ if (r_symndx != STN_UNDEF)
++ rel->r_addend -= (local_syms[r_symndx].st_value
++ + sec->output_offset
++ + sec->output_section->vma);
++ }
++ r_type = R_PPC_TPREL16_HA;
++ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
++ if (offset != (bfd_vma) -1)
++ {
++ rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
++ rel[1].r_offset = offset + d_offset;
++ rel[1].r_addend = rel->r_addend;
++ insn2 = 0x38630000; /* addi 3,3,0 */
++ bfd_put_32 (output_bfd, insn2, contents + offset);
++ }
++ }
++ bfd_put_32 (output_bfd, insn1,
++ contents + rel->r_offset - d_offset);
++ if (tls_gd == 0)
++ {
++ /* We changed the symbol on an LD reloc. Start over
++ in order to get h, sym, sec etc. right. */
++ rel--;
++ continue;
++ }
++ }
++ break;
++
++ case R_PPC_TLSGD:
++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
++ {
++ unsigned int insn2;
++ bfd_vma offset = rel->r_offset;
++
++ if ((tls_mask & TLS_TPRELGD) != 0)
++ {
++ /* IE */
++ r_type = R_PPC_NONE;
++ insn2 = 0x7c631214; /* add 3,3,2 */
++ }
++ else
++ {
++ /* LE */
++ r_type = R_PPC_TPREL16_LO;
++ rel->r_offset += d_offset;
++ insn2 = 0x38630000; /* addi 3,3,0 */
++ }
++ rel->r_info = ELF32_R_INFO (r_symndx, r_type);
++ bfd_put_32 (output_bfd, insn2, contents + offset);
++ /* Zap the reloc on the _tls_get_addr call too. */
++ BFD_ASSERT (offset == rel[1].r_offset);
++ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
++ }
++ break;
++
++ case R_PPC_TLSLD:
++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
++ {
++ unsigned int insn2;
++
++ for (r_symndx = 0;
++ r_symndx < symtab_hdr->sh_info;
++ r_symndx++)
++ if (local_sections[r_symndx] == sec)
++ break;
++ if (r_symndx >= symtab_hdr->sh_info)
++ r_symndx = STN_UNDEF;
++ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
++ if (r_symndx != STN_UNDEF)
++ rel->r_addend -= (local_syms[r_symndx].st_value
++ + sec->output_offset
++ + sec->output_section->vma);
++
++ rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
++ rel->r_offset += d_offset;
++ insn2 = 0x38630000; /* addi 3,3,0 */
++ bfd_put_32 (output_bfd, insn2,
++ contents + rel->r_offset - d_offset);
++ /* Zap the reloc on the _tls_get_addr call too. */
++ BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset);
++ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
++ rel--;
++ continue;
++ }
++ break;
++ }
++
++ /* Handle other relocations that tweak non-addend part of insn. */
++ branch_bit = 0;
++ switch (r_type)
++ {
++ default:
++ break;
++
++ /* Branch taken prediction relocations. */
++ case R_PPC_ADDR14_BRTAKEN:
++ case R_PPC_REL14_BRTAKEN:
++ branch_bit = BRANCH_PREDICT_BIT;
++ /* Fall thru */
++
++ /* Branch not taken prediction relocations. */
++ case R_PPC_ADDR14_BRNTAKEN:
++ case R_PPC_REL14_BRNTAKEN:
++ {
++ bfd_vma insn;
++
++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
++ insn &= ~BRANCH_PREDICT_BIT;
++ insn |= branch_bit;
++
++ from = (rel->r_offset
++ + input_section->output_offset
++ + input_section->output_section->vma);
++
++ /* Invert 'y' bit if not the default. */
++ if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
++ insn ^= BRANCH_PREDICT_BIT;
++
++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
++ break;
++ }
++ }
++
++ ifunc = NULL;
++ if (!htab->is_vxworks)
++ {
++ struct plt_entry *ent;
++
++ if (h != NULL)
++ {
++ if (h->type == STT_GNU_IFUNC)
++ ifunc = &h->plt.plist;
++ }
++ else if (local_got_offsets != NULL
++ && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
++ {
++ struct plt_entry **local_plt;
++
++ local_plt = (struct plt_entry **) (local_got_offsets
++ + symtab_hdr->sh_info);
++ ifunc = local_plt + r_symndx;
++ }
++
++ ent = NULL;
++ if (ifunc != NULL
++ && (!info->shared
++ || is_branch_reloc (r_type)))
++ {
++ addend = 0;
++ if (r_type == R_PPC_PLTREL24 && info->shared)
++ addend = rel->r_addend;
++ ent = find_plt_ent (ifunc, got2, addend);
++ }
++ if (ent != NULL)
++ {
++ if (h == NULL && (ent->plt.offset & 1) == 0)
++ {
++ Elf_Internal_Rela rela;
++ bfd_byte *loc;
++
++ rela.r_offset = (htab->iplt->output_section->vma
++ + htab->iplt->output_offset
++ + ent->plt.offset);
++ rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
++ rela.r_addend = relocation;
++ loc = htab->reliplt->contents;
++ loc += (htab->reliplt->reloc_count++
++ * sizeof (Elf32_External_Rela));
++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
++
++ ent->plt.offset |= 1;
++ }
++ if (h == NULL && (ent->glink_offset & 1) == 0)
++ {
++ unsigned char *p = ((unsigned char *) htab->glink->contents
++ + ent->glink_offset);
++ write_glink_stub (ent, htab->iplt, p, info);
++ ent->glink_offset |= 1;
++ }
++
++ unresolved_reloc = FALSE;
++ if (htab->plt_type == PLT_NEW
++ || !htab->elf.dynamic_sections_created
++ || h == NULL)
++ relocation = (htab->glink->output_section->vma
++ + htab->glink->output_offset
++ + (ent->glink_offset & ~1));
++ else
++ relocation = (htab->plt->output_section->vma
++ + htab->plt->output_offset
++ + ent->plt.offset);
++ }
++ }
++
++ addend = rel->r_addend;
++ tls_type = 0;
++ howto = NULL;
++ if (r_type < R_PPC_max)
++ howto = ppc_elf_howto_table[r_type];
++ switch (r_type)
++ {
++ default:
++ info->callbacks->einfo
++ (_("%P: %B: unknown relocation type %d for symbol %s\n"),
++ input_bfd, (int) r_type, sym_name);
++
++ bfd_set_error (bfd_error_bad_value);
++ ret = FALSE;
++ continue;
++
++ case R_PPC_NONE:
++ case R_PPC_TLS:
++ case R_PPC_TLSGD:
++ case R_PPC_TLSLD:
++ case R_PPC_EMB_MRKREF:
++ case R_PPC_GNU_VTINHERIT:
++ case R_PPC_GNU_VTENTRY:
++ continue;
++
++ /* GOT16 relocations. Like an ADDR16 using the symbol's
++ address in the GOT as relocation value instead of the
++ symbol's value itself. Also, create a GOT entry for the
++ symbol and put the symbol value there. */
++ case R_PPC_GOT_TLSGD16:
++ case R_PPC_GOT_TLSGD16_LO:
++ case R_PPC_GOT_TLSGD16_HI:
++ case R_PPC_GOT_TLSGD16_HA:
++ tls_type = TLS_TLS | TLS_GD;
++ goto dogot;
++
++ case R_PPC_GOT_TLSLD16:
++ case R_PPC_GOT_TLSLD16_LO:
++ case R_PPC_GOT_TLSLD16_HI:
++ case R_PPC_GOT_TLSLD16_HA:
++ tls_type = TLS_TLS | TLS_LD;
++ goto dogot;
++
++ case R_PPC_GOT_TPREL16:
++ case R_PPC_GOT_TPREL16_LO:
++ case R_PPC_GOT_TPREL16_HI:
++ case R_PPC_GOT_TPREL16_HA:
++ tls_type = TLS_TLS | TLS_TPREL;
++ goto dogot;
++
++ case R_PPC_GOT_DTPREL16:
++ case R_PPC_GOT_DTPREL16_LO:
++ case R_PPC_GOT_DTPREL16_HI:
++ case R_PPC_GOT_DTPREL16_HA:
++ tls_type = TLS_TLS | TLS_DTPREL;
++ goto dogot;
++
++ case R_PPC_GOT16:
++ case R_PPC_GOT16_LO:
++ case R_PPC_GOT16_HI:
++ case R_PPC_GOT16_HA:
++ tls_mask = 0;
++ dogot:
++ {
++ /* Relocation is to the entry for this symbol in the global
++ offset table. */
++ bfd_vma off;
++ bfd_vma *offp;
++ unsigned long indx;
++
++ if (htab->got == NULL)
++ abort ();
++
++ indx = 0;
++ if (tls_type == (TLS_TLS | TLS_LD)
++ && (h == NULL
++ || !h->def_dynamic))
++ offp = &htab->tlsld_got.offset;
++ else if (h != NULL)
++ {
++ bfd_boolean dyn;
++ dyn = htab->elf.dynamic_sections_created;
++ if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
++ || (info->shared
++ && SYMBOL_REFERENCES_LOCAL (info, h)))
++ /* This is actually a static link, or it is a
++ -Bsymbolic link and the symbol is defined
++ locally, or the symbol was forced to be local
++ because of a version file. */
++ ;
++ else
++ {
++ BFD_ASSERT (h->dynindx != -1);
++ indx = h->dynindx;
++ unresolved_reloc = FALSE;
++ }
++ offp = &h->got.offset;
++ }
++ else
++ {
++ if (local_got_offsets == NULL)
++ abort ();
++ offp = &local_got_offsets[r_symndx];
++ }
++
++ /* The offset must always be a multiple of 4. We use the
++ least significant bit to record whether we have already
++ processed this entry. */
++ off = *offp;
++ if ((off & 1) != 0)
++ off &= ~1;
++ else
++ {
++ unsigned int tls_m = (tls_mask
++ & (TLS_LD | TLS_GD | TLS_DTPREL
++ | TLS_TPREL | TLS_TPRELGD));
++
++ if (offp == &htab->tlsld_got.offset)
++ tls_m = TLS_LD;
++ else if (h == NULL
++ || !h->def_dynamic)
++ tls_m &= ~TLS_LD;
++
++ /* We might have multiple got entries for this sym.
++ Initialize them all. */
++ do
++ {
++ int tls_ty = 0;
++
++ if ((tls_m & TLS_LD) != 0)
++ {
++ tls_ty = TLS_TLS | TLS_LD;
++ tls_m &= ~TLS_LD;
++ }
++ else if ((tls_m & TLS_GD) != 0)
++ {
++ tls_ty = TLS_TLS | TLS_GD;
++ tls_m &= ~TLS_GD;
++ }
++ else if ((tls_m & TLS_DTPREL) != 0)
++ {
++ tls_ty = TLS_TLS | TLS_DTPREL;
++ tls_m &= ~TLS_DTPREL;
++ }
++ else if ((tls_m & (TLS_TPREL | TLS_TPRELGD)) != 0)
++ {
++ tls_ty = TLS_TLS | TLS_TPREL;
++ tls_m = 0;
++ }
++
++ /* Generate relocs for the dynamic linker. */
++ if ((info->shared || indx != 0)
++ && (offp == &htab->tlsld_got.offset
++ || h == NULL
++ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
++ || h->root.type != bfd_link_hash_undefweak))
++ {
++ asection *rsec = htab->relgot;
++ bfd_byte * loc;
++
++ outrel.r_offset = (htab->got->output_section->vma
++ + htab->got->output_offset
++ + off);
++ outrel.r_addend = 0;
++ if (tls_ty & (TLS_LD | TLS_GD))
++ {
++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32);
++ if (tls_ty == (TLS_TLS | TLS_GD))
++ {
++ loc = rsec->contents;
++ loc += (rsec->reloc_count++
++ * sizeof (Elf32_External_Rela));
++ bfd_elf32_swap_reloca_out (output_bfd,
++ &outrel, loc);
++ outrel.r_offset += 4;
++ outrel.r_info
++ = ELF32_R_INFO (indx, R_PPC_DTPREL32);
++ }
++ }
++ else if (tls_ty == (TLS_TLS | TLS_DTPREL))
++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32);
++ else if (tls_ty == (TLS_TLS | TLS_TPREL))
++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_TPREL32);
++ else if (indx != 0)
++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT);
++ else if (ifunc != NULL)
++ outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
++ else
++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
++ if (indx == 0 && tls_ty != (TLS_TLS | TLS_LD))
++ {
++ outrel.r_addend += relocation;
++ if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
++ outrel.r_addend -= htab->elf.tls_sec->vma;
++ }
++ loc = rsec->contents;
++ loc += (rsec->reloc_count++
++ * sizeof (Elf32_External_Rela));
++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
++ }
++
++ /* Init the .got section contents if we're not
++ emitting a reloc. */
++ else
++ {
++ bfd_vma value = relocation;
++
++ if (tls_ty == (TLS_TLS | TLS_LD))
++ value = 1;
++ else if (tls_ty != 0)
++ {
++ value -= htab->elf.tls_sec->vma + DTP_OFFSET;
++ if (tls_ty == (TLS_TLS | TLS_TPREL))
++ value += DTP_OFFSET - TP_OFFSET;
++
++ if (tls_ty == (TLS_TLS | TLS_GD))
++ {
++ bfd_put_32 (output_bfd, value,
++ htab->got->contents + off + 4);
++ value = 1;
++ }
++ }
++ bfd_put_32 (output_bfd, value,
++ htab->got->contents + off);
++ }
++
++ off += 4;
++ if (tls_ty & (TLS_LD | TLS_GD))
++ off += 4;
++ }
++ while (tls_m != 0);
++
++ off = *offp;
++ *offp = off | 1;
++ }
++
++ if (off >= (bfd_vma) -2)
++ abort ();
++
++ if ((tls_type & TLS_TLS) != 0)
++ {
++ if (tls_type != (TLS_TLS | TLS_LD))
++ {
++ if ((tls_mask & TLS_LD) != 0
++ && !(h == NULL
++ || !h->def_dynamic))
++ off += 8;
++ if (tls_type != (TLS_TLS | TLS_GD))
++ {
++ if ((tls_mask & TLS_GD) != 0)
++ off += 8;
++ if (tls_type != (TLS_TLS | TLS_DTPREL))
++ {
++ if ((tls_mask & TLS_DTPREL) != 0)
++ off += 4;
++ }
++ }
++ }
++ }
++
++ relocation = (htab->got->output_section->vma
++ + htab->got->output_offset
++ + off
++ - SYM_VAL (htab->elf.hgot));
++
++ /* Addends on got relocations don't make much sense.
++ x+off@got is actually x@got+off, and since the got is
++ generated by a hash table traversal, the value in the
++ got at entry m+n bears little relation to the entry m. */
++ if (addend != 0)
++ info->callbacks->einfo
++ (_("%P: %H: non-zero addend on %s reloc against `%s'\n"),
++ input_bfd, input_section, rel->r_offset,
++ howto->name,
++ sym_name);
++ }
++ break;
++
++ /* Relocations that need no special processing. */
++ case R_PPC_LOCAL24PC:
++ /* It makes no sense to point a local relocation
++ at a symbol not in this object. */
++ if (unresolved_reloc)
++ {
++ if (! (*info->callbacks->undefined_symbol) (info,
++ h->root.root.string,
++ input_bfd,
++ input_section,
++ rel->r_offset,
++ TRUE))
++ return FALSE;
++ continue;
++ }
++ break;
++
++ case R_PPC_DTPREL16:
++ case R_PPC_DTPREL16_LO:
++ case R_PPC_DTPREL16_HI:
++ case R_PPC_DTPREL16_HA:
++ addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
++ break;
++
++ /* Relocations that may need to be propagated if this is a shared
++ object. */
++ case R_PPC_TPREL16:
++ case R_PPC_TPREL16_LO:
++ case R_PPC_TPREL16_HI:
++ case R_PPC_TPREL16_HA:
++ if (h != NULL
++ && h->root.type == bfd_link_hash_undefweak
++ && h->dynindx == -1)
++ {
++ /* Make this relocation against an undefined weak symbol
++ resolve to zero. This is really just a tweak, since
++ code using weak externs ought to check that they are
++ defined before using them. */
++ bfd_byte *p = contents + rel->r_offset - d_offset;
++ unsigned int insn = bfd_get_32 (output_bfd, p);
++ insn = _bfd_elf_amigaos_ppc_at_tprel_transform (insn, 2);
++ if (insn != 0)
++ bfd_put_32 (output_bfd, insn, p);
++ break;
++ }
++ addend -= htab->elf.tls_sec->vma + TP_OFFSET;
++ /* The TPREL16 relocs shouldn't really be used in shared
++ libs as they will result in DT_TEXTREL being set, but
++ support them anyway. */
++ goto dodyn;
++
++ case R_PPC_TPREL32:
++ addend -= htab->elf.tls_sec->vma + TP_OFFSET;
++ goto dodyn;
++
++ case R_PPC_DTPREL32:
++ addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
++ goto dodyn;
++
++ case R_PPC_DTPMOD32:
++ relocation = 1;
++ addend = 0;
++ goto dodyn;
++
++ case R_PPC_REL16:
++ case R_PPC_REL16_LO:
++ case R_PPC_REL16_HI:
++ case R_PPC_REL16_HA:
++ break;
++
++ case R_PPC_REL32:
++ if (h == NULL || h == htab->elf.hgot)
++ break;
++ /* fall through */
++
++ case R_PPC_ADDR32:
++ case R_PPC_ADDR16:
++ case R_PPC_ADDR16_LO:
++ case R_PPC_ADDR16_HI:
++ case R_PPC_ADDR16_HA:
++ case R_PPC_UADDR32:
++ case R_PPC_UADDR16:
++ goto dodyn;
++
++ case R_PPC_VLE_REL8:
++ case R_PPC_VLE_REL15:
++ case R_PPC_VLE_REL24:
++ case R_PPC_REL24:
++ case R_PPC_REL14:
++ case R_PPC_REL14_BRTAKEN:
++ case R_PPC_REL14_BRNTAKEN:
++ /* If these relocations are not to a named symbol, they can be
++ handled right here, no need to bother the dynamic linker. */
++ if (SYMBOL_CALLS_LOCAL (info, h)
++ || h == htab->elf.hgot)
++ break;
++ /* fall through */
++
++ case R_PPC_ADDR24:
++ case R_PPC_ADDR14:
++ case R_PPC_ADDR14_BRTAKEN:
++ case R_PPC_ADDR14_BRNTAKEN:
++ if (h != NULL && !info->shared)
++ break;
++ /* fall through */
++
++ dodyn:
++ if ((input_section->flags & SEC_ALLOC) == 0
++ || is_vxworks_tls)
++ break;
++
++ if ((info->shared
++ && !(h != NULL
++ && ((h->root.type == bfd_link_hash_undefined
++ && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
++ || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
++ || (h->root.type == bfd_link_hash_undefweak
++ && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)))
++ && (must_be_dyn_reloc (info, r_type)
++ || !SYMBOL_CALLS_LOCAL (info, h)))
++ || (ELIMINATE_COPY_RELOCS
++ && !info->shared
++ && h != NULL
++ && h->dynindx != -1
++ && !h->non_got_ref
++ && !h->def_regular))
++ {
++ int skip;
++ bfd_byte * loc;
++#ifdef DEBUG
++ fprintf (stderr, "ppc_elf_relocate_section needs to "
++ "create relocation for %s\n",
++ (h && h->root.root.string
++ ? h->root.root.string : "<unknown>"));
++#endif
++
++ /* When generating a shared object, these relocations
++ are copied into the output file to be resolved at run
++ time. */
++ if (sreloc == NULL)
++ {
++ sreloc = elf_section_data (input_section)->sreloc;
++ if (!htab->elf.dynamic_sections_created)
++ sreloc = htab->reliplt;
++ if (sreloc == NULL)
++ return FALSE;
++ }
++
++ skip = 0;
++ outrel.r_offset = _bfd_elf_section_offset (output_bfd, info,
++ input_section,
++ rel->r_offset);
++ if (outrel.r_offset == (bfd_vma) -1
++ || outrel.r_offset == (bfd_vma) -2)
++ skip = (int) outrel.r_offset;
++ outrel.r_offset += (input_section->output_section->vma
++ + input_section->output_offset);
++
++ if (skip)
++ memset (&outrel, 0, sizeof outrel);
++ else if ((h != NULL
++ && (h->root.type == bfd_link_hash_undefined
++ || h->root.type == bfd_link_hash_undefweak))
++ || !SYMBOL_REFERENCES_LOCAL (info, h))
++ {
++ BFD_ASSERT (h->dynindx != -1);
++ unresolved_reloc = FALSE;
++ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
++ outrel.r_addend = rel->r_addend;
++ }
++ else
++ {
++ outrel.r_addend = relocation + rel->r_addend;
++
++ if (r_type != R_PPC_ADDR32)
++ {
++ long indx = 0;
++
++ if (ifunc != NULL)
++ {
++ /* If we get here when building a static
++ executable, then the libc startup function
++ responsible for applying indirect function
++ relocations is going to complain about
++ the reloc type.
++ If we get here when building a dynamic
++ executable, it will be because we have
++ a text relocation. The dynamic loader
++ will set the text segment writable and
++ non-executable to apply text relocations.
++ So we'll segfault when trying to run the
++ indirection function to resolve the reloc. */
++ info->callbacks->einfo
++ (_("%P: %H: relocation %s for indirect "
++ "function %s unsupported\n"),
++ input_bfd, input_section, rel->r_offset,
++ howto->name,
++ sym_name);
++ ret = FALSE;
++ }
++ else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec))
++ ;
++ else if (sec == NULL || sec->owner == NULL)
++ {
++ bfd_set_error (bfd_error_bad_value);
++ ret = FALSE;
++ }
++ else
++ {
++ asection *osec;
++
++ /* We are turning this relocation into one
++ against a section symbol. It would be
++ proper to subtract the symbol's value,
++ osec->vma, from the emitted reloc addend,
++ but ld.so expects buggy relocs.
++ FIXME: Why not always use a zero index? */
++ osec = sec->output_section;
++ indx = elf_section_data (osec)->dynindx;
++ if (indx == 0)
++ {
++ osec = htab->elf.text_index_section;
++ indx = elf_section_data (osec)->dynindx;
++ }
++ BFD_ASSERT (indx != 0);
++#ifdef DEBUG
++ if (indx == 0)
++ printf ("indx=%ld section=%s flags=%08x name=%s\n",
++ indx, osec->name, osec->flags,
++ h->root.root.string);
++#endif
++ }
++
++ outrel.r_info = ELF32_R_INFO (indx, r_type);
++ }
++ else if (ifunc != NULL)
++ outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
++ else
++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
++ }
++
++ loc = sreloc->contents;
++ loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
++
++ if (skip == -1)
++ continue;
++
++ /* This reloc will be computed at runtime. We clear the memory
++ so that it contains predictable value. */
++ if (! skip
++ && ((input_section->flags & SEC_ALLOC) != 0
++ || ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE))
++ {
++ relocation = howto->pc_relative ? outrel.r_offset : 0;
++ addend = 0;
++ break;
++ }
++ }
++ break;
++
++ case R_PPC_RELAX_PLT:
++ case R_PPC_RELAX_PLTREL24:
++ if (h != NULL)
++ {
++ struct plt_entry *ent;
++ bfd_vma got2_addend = 0;
++
++ if (r_type == R_PPC_RELAX_PLTREL24)
++ {
++ if (info->shared)
++ got2_addend = addend;
++ addend = 0;
++ }
++ ent = find_plt_ent (&h->plt.plist, got2, got2_addend);
++ if (htab->plt_type == PLT_NEW)
++ relocation = (htab->glink->output_section->vma
++ + htab->glink->output_offset
++ + ent->glink_offset);
++ else
++ relocation = (htab->plt->output_section->vma
++ + htab->plt->output_offset
++ + ent->plt.offset);
++ }
++ /* Fall thru */
++
++ case R_PPC_RELAX:
++ if (info->shared)
++ relocation -= (input_section->output_section->vma
++ + input_section->output_offset
++ + rel->r_offset - 4);
++
++ {
++ unsigned long t0;
++ unsigned long t1;
++
++ t0 = bfd_get_32 (output_bfd, contents + rel->r_offset);
++ t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4);
++
++ /* We're clearing the bits for R_PPC_ADDR16_HA
++ and R_PPC_ADDR16_LO here. */
++ t0 &= ~0xffff;
++ t1 &= ~0xffff;
++
++ /* t0 is HA, t1 is LO */
++ relocation += addend;
++ t0 |= ((relocation + 0x8000) >> 16) & 0xffff;
++ t1 |= relocation & 0xffff;
++
++ bfd_put_32 (output_bfd, t0, contents + rel->r_offset);
++ bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4);
++
++ /* Rewrite the reloc and convert one of the trailing nop
++ relocs to describe this relocation. */
++ BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE);
++ /* The relocs are at the bottom 2 bytes */
++ rel[0].r_offset += 2;
++ memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel));
++ rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
++ rel[1].r_offset += 4;
++ rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
++ rel++;
++ }
++ continue;
++
++ /* Indirect .sdata relocation. */
++ case R_PPC_EMB_SDAI16:
++ BFD_ASSERT (htab->sdata[0].section != NULL);
++ if (!is_static_defined (htab->sdata[0].sym))
++ {
++ unresolved_reloc = TRUE;
++ break;
++ }
++ relocation
++ = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[0],
++ h, relocation, rel);
++ addend = 0;
++ break;
++
++ /* Indirect .sdata2 relocation. */
++ case R_PPC_EMB_SDA2I16:
++ BFD_ASSERT (htab->sdata[1].section != NULL);
++ if (!is_static_defined (htab->sdata[1].sym))
++ {
++ unresolved_reloc = TRUE;
++ break;
++ }
++ relocation
++ = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[1],
++ h, relocation, rel);
++ addend = 0;
++ break;
++
++ /* Handle the TOC16 reloc. We want to use the offset within the .got
++ section, not the actual VMA. This is appropriate when generating
++ an embedded ELF object, for which the .got section acts like the
++ AIX .toc section. */
++ case R_PPC_TOC16: /* phony GOT16 relocations */
++ if (sec == NULL || sec->output_section == NULL)
++ {
++ unresolved_reloc = TRUE;
++ break;
++ }
++ BFD_ASSERT (strcmp (bfd_get_section_name (sec->owner, sec),
++ ".got") == 0
++ || strcmp (bfd_get_section_name (sec->owner, sec),
++ ".cgot") == 0);
++
++ addend -= sec->output_section->vma + sec->output_offset + 0x8000;
++ break;
++
++ case R_PPC_PLTREL24:
++ if (h != NULL && ifunc == NULL)
++ {
++ struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
++ info->shared ? addend : 0);
++ if (ent == NULL
++ || htab->plt == NULL)
++ {
++ /* We didn't make a PLT entry for this symbol. This
++ happens when statically linking PIC code, or when
++ using -Bsymbolic. */
++ }
++ else
++ {
++ /* Relocation is to the entry for this symbol in the
++ procedure linkage table. */
++ unresolved_reloc = FALSE;
++ if (htab->plt_type == PLT_NEW)
++ relocation = (htab->glink->output_section->vma
++ + htab->glink->output_offset
++ + ent->glink_offset);
++ else
++ relocation = (htab->plt->output_section->vma
++ + htab->plt->output_offset
++ + ent->plt.offset);
++ }
++ }
++
++ /* R_PPC_PLTREL24 is rather special. If non-zero, the
++ addend specifies the GOT pointer offset within .got2.
++ Don't apply it to the relocation field. */
++ addend = 0;
++ break;
++
++ /* Relocate against _SDA_BASE_. */
++ case R_PPC_SDAREL16:
++ {
++ const char *name;
++ struct elf_link_hash_entry *sda = htab->sdata[0].sym;
++
++ if (sec == NULL
++ || sec->output_section == NULL
++ || !is_static_defined (sda))
++ {
++ unresolved_reloc = TRUE;
++ break;
++ }
++ addend -= SYM_VAL (sda);
++
++ name = bfd_get_section_name (output_bfd, sec->output_section);
++ if (! ((CONST_STRNEQ (name, ".sdata")
++ && (name[6] == 0 || name[6] == '.'))
++ || (CONST_STRNEQ (name, ".sbss")
++ && (name[5] == 0 || name[5] == '.'))))
++ {
++ info->callbacks->einfo
++ (_("%P: %B: the target (%s) of a %s relocation is "
++ "in the wrong output section (%s)\n"),
++ input_bfd,
++ sym_name,
++ howto->name,
++ name);
++ }
++ }
++ break;
++
++ /* Relocate against _SDA2_BASE_. */
++ case R_PPC_EMB_SDA2REL:
++ {
++ const char *name;
++ struct elf_link_hash_entry *sda = htab->sdata[1].sym;
++
++ if (sec == NULL
++ || sec->output_section == NULL
++ || !is_static_defined (sda))
++ {
++ unresolved_reloc = TRUE;
++ break;
++ }
++ addend -= SYM_VAL (sda);
++
++ name = bfd_get_section_name (output_bfd, sec->output_section);
++ if (! (CONST_STRNEQ (name, ".sdata2")
++ || CONST_STRNEQ (name, ".sbss2")))
++ {
++ info->callbacks->einfo
++ (_("%P: %B: the target (%s) of a %s relocation is "
++ "in the wrong output section (%s)\n"),
++ input_bfd,
++ sym_name,
++ howto->name,
++ name);
++ }
++ }
++ break;
++#if 0
++ case R_PPC_AMIGAOS_BREL:
++ case R_PPC_AMIGAOS_BREL_HI:
++ case R_PPC_AMIGAOS_BREL_LO:
++ case R_PPC_AMIGAOS_BREL_HA:
++ {
++ if (data_section == NULL)
++ data_section = bfd_get_section_by_name (output_bfd, ".data");
++
++ if (sec)
++ {
++ const char *name = bfd_get_section_name (abfd, sec->output_section);
++ if (strcmp (name, ".sdata") != 0
++ && strcmp (name, ".sbss") != 0
++ && strcmp (name, ".data") != 0
++ && strcmp (name, ".bss") != 0
++ && strncmp (name, ".ctors", 6) != 0
++ && strncmp (name, ".dtors", 6) != 0)
++ {
++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
++ input_bfd,
++ sym_name,
++ howto->name,
++ name);
++ }
++ }
++
++ addend = addend - data_section->vma;
++
++ if (r_type == R_PPC_AMIGAOS_BREL_HA)
++ addend += ((relocation + addend) & 0x8000) << 1;
++
++ }
++ break;
++#endif
++ case R_PPC_VLE_LO16A:
++ relocation = (relocation + addend) & 0xffff;
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ relocation, split16a_type);
++ continue;
++
++ case R_PPC_VLE_LO16D:
++ relocation = (relocation + addend) & 0xffff;
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ relocation, split16d_type);
++ continue;
++
++ case R_PPC_VLE_HI16A:
++ relocation = ((relocation + addend) >> 16) & 0xffff;
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ relocation, split16a_type);
++ continue;
++
++ case R_PPC_VLE_HI16D:
++ relocation = ((relocation + addend) >> 16) & 0xffff;
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ relocation, split16d_type);
++ continue;
++
++ case R_PPC_VLE_HA16A:
++ {
++ bfd_vma value = relocation + addend;
++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ value, split16a_type);
++ }
++ continue;
++
++ case R_PPC_VLE_HA16D:
++ {
++ bfd_vma value = relocation + addend;
++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ value, split16d_type);
++ }
++ continue;
++
++ /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */
++ case R_PPC_EMB_SDA21:
++ case R_PPC_VLE_SDA21:
++ case R_PPC_EMB_RELSDA:
++ case R_PPC_VLE_SDA21_LO:
++ {
++ const char *name;
++ int reg;
++ struct elf_link_hash_entry *sda = NULL;
++
++ if (sec == NULL || sec->output_section == NULL)
++ {
++ unresolved_reloc = TRUE;
++ break;
++ }
++
++ name = bfd_get_section_name (output_bfd, sec->output_section);
++ if (((CONST_STRNEQ (name, ".sdata")
++ && (name[6] == 0 || name[6] == '.'))
++ || (CONST_STRNEQ (name, ".sbss")
++ && (name[5] == 0 || name[5] == '.'))))
++ {
++ reg = 13;
++ sda = htab->sdata[0].sym;
++ }
++ else if (CONST_STRNEQ (name, ".sdata2")
++ || CONST_STRNEQ (name, ".sbss2"))
++ {
++ reg = 2;
++ sda = htab->sdata[1].sym;
++ }
++ else if (strcmp (name, ".PPC.EMB.sdata0") == 0
++ || strcmp (name, ".PPC.EMB.sbss0") == 0)
++ {
++ reg = 0;
++ }
++ else
++ {
++ info->callbacks->einfo
++ (_("%P: %B: the target (%s) of a %s relocation is "
++ "in the wrong output section (%s)\n"),
++ input_bfd,
++ sym_name,
++ howto->name,
++ name);
++
++ bfd_set_error (bfd_error_bad_value);
++ ret = FALSE;
++ continue;
++ }
++
++ if (sda != NULL)
++ {
++ if (!is_static_defined (sda))
++ {
++ unresolved_reloc = TRUE;
++ break;
++ }
++ addend -= SYM_VAL (sda);
++ }
++
++ if (reg == 0
++ && (r_type == R_PPC_VLE_SDA21
++ || r_type == R_PPC_VLE_SDA21_LO))
++ {
++ /* Use the split20 format. */
++ bfd_vma insn, bits12to15, bits21to31;
++ bfd_vma value = (relocation + rel->r_offset) & 0xffff;
++ /* Propagate sign bit, if necessary. */
++ insn = (value & 0x8000) ? 0x70107800 : 0x70000000;
++ bits12to15 = value & 0x700;
++ bits21to31 = value & 0x7ff;
++ insn |= bits12to15;
++ insn |= bits21to31;
++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
++ continue;
++ }
++ else if (r_type == R_PPC_EMB_SDA21
++ || r_type == R_PPC_VLE_SDA21
++ || r_type == R_PPC_VLE_SDA21_LO)
++ {
++ bfd_vma insn; /* Fill in register field. */
++
++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
++ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
++ }
++ }
++ break;
++
++ case R_PPC_VLE_SDAREL_LO16A:
++ case R_PPC_VLE_SDAREL_LO16D:
++ case R_PPC_VLE_SDAREL_HI16A:
++ case R_PPC_VLE_SDAREL_HI16D:
++ case R_PPC_VLE_SDAREL_HA16A:
++ case R_PPC_VLE_SDAREL_HA16D:
++ {
++ bfd_vma value;
++ const char *name;
++ //int reg;
++ struct elf_link_hash_entry *sda = NULL;
++
++ if (sec == NULL || sec->output_section == NULL)
++ {
++ unresolved_reloc = TRUE;
++ break;
++ }
++
++ name = bfd_get_section_name (output_bfd, sec->output_section);
++ if (((CONST_STRNEQ (name, ".sdata")
++ && (name[6] == 0 || name[6] == '.'))
++ || (CONST_STRNEQ (name, ".sbss")
++ && (name[5] == 0 || name[5] == '.'))))
++ {
++ //reg = 13;
++ sda = htab->sdata[0].sym;
++ }
++ else if (CONST_STRNEQ (name, ".sdata2")
++ || CONST_STRNEQ (name, ".sbss2"))
++ {
++ //reg = 2;
++ sda = htab->sdata[1].sym;
++ }
++ else
++ {
++ (*_bfd_error_handler)
++ (_("%B: the target (%s) of a %s relocation is "
++ "in the wrong output section (%s)"),
++ input_bfd,
++ sym_name,
++ howto->name,
++ name);
++
++ bfd_set_error (bfd_error_bad_value);
++ ret = FALSE;
++ continue;
++ }
++
++ if (sda != NULL)
++ {
++ if (!is_static_defined (sda))
++ {
++ unresolved_reloc = TRUE;
++ break;
++ }
++ }
++
++ value = sda->root.u.def.section->output_section->vma
++ + sda->root.u.def.section->output_offset;
++
++ if (r_type == R_PPC_VLE_SDAREL_LO16A)
++ {
++ value = (value + addend) & 0xffff;
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ value, split16a_type);
++ }
++ else if (r_type == R_PPC_VLE_SDAREL_LO16D)
++ {
++ value = (value + addend) & 0xffff;
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ value, split16d_type);
++ }
++ else if (r_type == R_PPC_VLE_SDAREL_HI16A)
++ {
++ value = ((value + addend) >> 16) & 0xffff;
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ value, split16a_type);
++ }
++ else if (r_type == R_PPC_VLE_SDAREL_HI16D)
++ {
++ value = ((value + addend) >> 16) & 0xffff;
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ value, split16d_type);
++ }
++ else if (r_type == R_PPC_VLE_SDAREL_HA16A)
++ {
++ value += addend;
++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ value, split16a_type);
++ }
++ else if (r_type == R_PPC_VLE_SDAREL_HA16D)
++ {
++ value += addend;
++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
++ value, split16d_type);
++ }
++ }
++ continue;
++
++ /* Relocate against the beginning of the section. */
++ case R_PPC_SECTOFF:
++ case R_PPC_SECTOFF_LO:
++ case R_PPC_SECTOFF_HI:
++ case R_PPC_SECTOFF_HA:
++ if (sec == NULL || sec->output_section == NULL)
++ {
++ unresolved_reloc = TRUE;
++ break;
++ }
++ addend -= sec->output_section->vma;
++ break;
++
++ /* Negative relocations. */
++ case R_PPC_EMB_NADDR32:
++ case R_PPC_EMB_NADDR16:
++ case R_PPC_EMB_NADDR16_LO:
++ case R_PPC_EMB_NADDR16_HI:
++ case R_PPC_EMB_NADDR16_HA:
++ addend -= 2 * relocation;
++ break;
++
++ case R_PPC_COPY:
++ case R_PPC_GLOB_DAT:
++ case R_PPC_JMP_SLOT:
++ case R_PPC_RELATIVE:
++ case R_PPC_IRELATIVE:
++ case R_PPC_PLT32:
++ case R_PPC_PLTREL32:
++ case R_PPC_PLT16_LO:
++ case R_PPC_PLT16_HI:
++ case R_PPC_PLT16_HA:
++ case R_PPC_ADDR30:
++ case R_PPC_EMB_RELSEC16:
++ case R_PPC_EMB_RELST_LO:
++ case R_PPC_EMB_RELST_HI:
++ case R_PPC_EMB_RELST_HA:
++ case R_PPC_EMB_BIT_FLD:
++ info->callbacks->einfo
++ (_("%P: %B: relocation %s is not yet supported for symbol %s\n"),
++ input_bfd,
++ howto->name,
++ sym_name);
++
++ bfd_set_error (bfd_error_invalid_operation);
++ ret = FALSE;
++ continue;
++ }
++
++ /* Do any further special processing. */
++ switch (r_type)
++ {
++ default:
++ break;
++
++ case R_PPC_ADDR16_HA:
++ case R_PPC_REL16_HA:
++ case R_PPC_SECTOFF_HA:
++ case R_PPC_TPREL16_HA:
++ case R_PPC_DTPREL16_HA:
++ case R_PPC_EMB_NADDR16_HA:
++ case R_PPC_EMB_RELST_HA:
++ /* It's just possible that this symbol is a weak symbol
++ that's not actually defined anywhere. In that case,
++ 'sec' would be NULL, and we should leave the symbol
++ alone (it will be set to zero elsewhere in the link). */
++ if (sec == NULL)
++ break;
++ /* Fall thru */
++
++ case R_PPC_PLT16_HA:
++ case R_PPC_GOT16_HA:
++ case R_PPC_GOT_TLSGD16_HA:
++ case R_PPC_GOT_TLSLD16_HA:
++ case R_PPC_GOT_TPREL16_HA:
++ case R_PPC_GOT_DTPREL16_HA:
++ /* Add 0x10000 if sign bit in 0:15 is set.
++ Bits 0:15 are not used. */
++ addend += 0x8000;
++ break;
++
++ case R_PPC_ADDR16:
++ case R_PPC_ADDR16_LO:
++ case R_PPC_GOT16:
++ case R_PPC_GOT16_LO:
++ case R_PPC_SDAREL16:
++ case R_PPC_SECTOFF:
++ case R_PPC_SECTOFF_LO:
++ case R_PPC_DTPREL16:
++ case R_PPC_DTPREL16_LO:
++ case R_PPC_TPREL16:
++ case R_PPC_TPREL16_LO:
++ case R_PPC_GOT_TLSGD16:
++ case R_PPC_GOT_TLSGD16_LO:
++ case R_PPC_GOT_TLSLD16:
++ case R_PPC_GOT_TLSLD16_LO:
++ case R_PPC_GOT_DTPREL16:
++ case R_PPC_GOT_DTPREL16_LO:
++ case R_PPC_GOT_TPREL16:
++ case R_PPC_GOT_TPREL16_LO:
++ {
++ /* The 32-bit ABI lacks proper relocations to deal with
++ certain 64-bit instructions. Prevent damage to bits
++ that make up part of the insn opcode. */
++ unsigned int insn, mask, lobit;
++
++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
++ mask = 0;
++ if (is_insn_ds_form (insn))
++ mask = 3;
++ else if (is_insn_dq_form (insn))
++ mask = 15;
++ else
++ break;
++ lobit = mask & (relocation + addend);
++ if (lobit != 0)
++ {
++ addend -= lobit;
++ info->callbacks->einfo
++ (_("%P: %H: error: %s against `%s' not a multiple of %u\n"),
++ input_bfd, input_section, rel->r_offset,
++ howto->name, sym_name, mask + 1);
++ bfd_set_error (bfd_error_bad_value);
++ ret = FALSE;
++ }
++ addend += insn & mask;
++ }
++ break;
++ }
++
++#ifdef DEBUG
++ fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, "
++ "offset = %ld, addend = %ld\n",
++ howto->name,
++ (int) r_type,
++ sym_name,
++ r_symndx,
++ (long) rel->r_offset,
++ (long) addend);
++#endif
++
++ if (unresolved_reloc
++ && !((input_section->flags & SEC_DEBUGGING) != 0
++ && h->def_dynamic)
++ && _bfd_elf_section_offset (output_bfd, info, input_section,
++ rel->r_offset) != (bfd_vma) -1)
++ {
++ info->callbacks->einfo
++ (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"),
++ input_bfd, input_section, rel->r_offset,
++ howto->name,
++ sym_name);
++ ret = FALSE;
++ }
++
++ r = _bfd_final_link_relocate (howto,
++ input_bfd,
++ input_section,
++ contents,
++ rel->r_offset,
++ relocation,
++ addend);
++
++#ifdef DEBUG
++ fprintf (stderr, "%p %p %p\n", (void *)rel->r_offset, (void *)relocation, (void *)addend);
++#endif
++ if (r != bfd_reloc_ok)
++ {
++ if (r == bfd_reloc_overflow)
++ {
++ if (warned)
++ continue;
++ if (h != NULL
++ && h->root.type == bfd_link_hash_undefweak
++ && howto->pc_relative)
++ {
++ /* Assume this is a call protected by other code that
++ detect the symbol is undefined. If this is the case,
++ we can safely ignore the overflow. If not, the
++ program is hosed anyway, and a little warning isn't
++ going to help. */
++
++ continue;
++ }
++
++ if (! (*info->callbacks->reloc_overflow) (info,
++ (h ? &h->root : NULL),
++ sym_name,
++ howto->name,
++ rel->r_addend,
++ input_bfd,
++ input_section,
++ rel->r_offset))
++ return FALSE;
++ }
++ else
++ {
++ info->callbacks->einfo
++ (_("%P: %H: %s reloc against `%s': error %d\n"),
++ input_bfd, input_section, rel->r_offset,
++ howto->name, sym_name, (int) r);
++ ret = FALSE;
++ }
++ }
++ }
++
++#ifdef DEBUG
++ fprintf (stderr, "\n");
++#endif
++
++ return ret;
++}
++
++/* Finish up dynamic symbol handling. We set the contents of various
++ dynamic sections here. */
++
++static bfd_boolean
++ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
++ struct bfd_link_info *info,
++ struct elf_link_hash_entry *h,
++ Elf_Internal_Sym *sym)
++{
++ struct ppc_elf_link_hash_table *htab;
++ struct plt_entry *ent;
++ bfd_boolean doneone;
++
++#ifdef DEBUG
++ fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
++ h->root.root.string);
++#endif
++
++ htab = ppc_elf_hash_table (info);
++ BFD_ASSERT (htab->elf.dynobj != NULL);
++
++ doneone = FALSE;
++ for (ent = h->plt.plist; ent != NULL; ent = ent->next)
++ if (ent->plt.offset != (bfd_vma) -1)
++ {
++ if (!doneone)
++ {
++ Elf_Internal_Rela rela;
++ bfd_byte *loc;
++ bfd_vma reloc_index;
++
++ if (htab->plt_type == PLT_NEW
++ || !htab->elf.dynamic_sections_created
++ || h->dynindx == -1)
++ reloc_index = ent->plt.offset / 4;
++ else
++ {
++ reloc_index = ((ent->plt.offset - htab->plt_initial_entry_size)
++ / htab->plt_slot_size);
++ if (reloc_index > PLT_NUM_SINGLE_ENTRIES
++ && htab->plt_type == PLT_OLD)
++ reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
++ }
++
++ /* This symbol has an entry in the procedure linkage table.
++ Set it up. */
++ if (htab->plt_type == PLT_VXWORKS
++ && htab->elf.dynamic_sections_created
++ && h->dynindx != -1)
++ {
++ bfd_vma got_offset;
++ const bfd_vma *plt_entry;
++
++ /* The first three entries in .got.plt are reserved. */
++ got_offset = (reloc_index + 3) * 4;
++
++ /* Use the right PLT. */
++ plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry
++ : ppc_elf_vxworks_plt_entry;
++
++ /* Fill in the .plt on VxWorks. */
++ if (info->shared)
++ {
++ bfd_put_32 (output_bfd,
++ plt_entry[0] | PPC_HA (got_offset),
++ htab->plt->contents + ent->plt.offset + 0);
++ bfd_put_32 (output_bfd,
++ plt_entry[1] | PPC_LO (got_offset),
++ htab->plt->contents + ent->plt.offset + 4);
++ }
++ else
++ {
++ bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot);
++
++ bfd_put_32 (output_bfd,
++ plt_entry[0] | PPC_HA (got_loc),
++ htab->plt->contents + ent->plt.offset + 0);
++ bfd_put_32 (output_bfd,
++ plt_entry[1] | PPC_LO (got_loc),
++ htab->plt->contents + ent->plt.offset + 4);
++ }
++
++ bfd_put_32 (output_bfd, plt_entry[2],
++ htab->plt->contents + ent->plt.offset + 8);
++ bfd_put_32 (output_bfd, plt_entry[3],
++ htab->plt->contents + ent->plt.offset + 12);
++
++ /* This instruction is an immediate load. The value loaded is
++ the byte offset of the R_PPC_JMP_SLOT relocation from the
++ start of the .rela.plt section. The value is stored in the
++ low-order 16 bits of the load instruction. */
++ /* NOTE: It appears that this is now an index rather than a
++ prescaled offset. */
++ bfd_put_32 (output_bfd,
++ plt_entry[4] | reloc_index,
++ htab->plt->contents + ent->plt.offset + 16);
++ /* This instruction is a PC-relative branch whose target is
++ the start of the PLT section. The address of this branch
++ instruction is 20 bytes beyond the start of this PLT entry.
++ The address is encoded in bits 6-29, inclusive. The value
++ stored is right-shifted by two bits, permitting a 26-bit
++ offset. */
++ bfd_put_32 (output_bfd,
++ (plt_entry[5]
++ | (-(ent->plt.offset + 20) & 0x03fffffc)),
++ htab->plt->contents + ent->plt.offset + 20);
++ bfd_put_32 (output_bfd, plt_entry[6],
++ htab->plt->contents + ent->plt.offset + 24);
++ bfd_put_32 (output_bfd, plt_entry[7],
++ htab->plt->contents + ent->plt.offset + 28);
++
++ /* Fill in the GOT entry corresponding to this PLT slot with
++ the address immediately after the "bctr" instruction
++ in this PLT entry. */
++ bfd_put_32 (output_bfd, (htab->plt->output_section->vma
++ + htab->plt->output_offset
++ + ent->plt.offset + 16),
++ htab->sgotplt->contents + got_offset);
++
++ if (!info->shared)
++ {
++ /* Fill in a couple of entries in .rela.plt.unloaded. */
++ loc = htab->srelplt2->contents
++ + ((VXWORKS_PLTRESOLVE_RELOCS + reloc_index
++ * VXWORKS_PLT_NON_JMP_SLOT_RELOCS)
++ * sizeof (Elf32_External_Rela));
++
++ /* Provide the @ha relocation for the first instruction. */
++ rela.r_offset = (htab->plt->output_section->vma
++ + htab->plt->output_offset
++ + ent->plt.offset + 2);
++ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
++ R_PPC_ADDR16_HA);
++ rela.r_addend = got_offset;
++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
++ loc += sizeof (Elf32_External_Rela);
++
++ /* Provide the @l relocation for the second instruction. */
++ rela.r_offset = (htab->plt->output_section->vma
++ + htab->plt->output_offset
++ + ent->plt.offset + 6);
++ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
++ R_PPC_ADDR16_LO);
++ rela.r_addend = got_offset;
++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
++ loc += sizeof (Elf32_External_Rela);
++
++ /* Provide a relocation for the GOT entry corresponding to this
++ PLT slot. Point it at the middle of the .plt entry. */
++ rela.r_offset = (htab->sgotplt->output_section->vma
++ + htab->sgotplt->output_offset
++ + got_offset);
++ rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
++ R_PPC_ADDR32);
++ rela.r_addend = ent->plt.offset + 16;
++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
++ }
++
++ /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT.
++ In particular, the offset for the relocation is not the
++ address of the PLT entry for this function, as specified
++ by the ABI. Instead, the offset is set to the address of
++ the GOT slot for this function. See EABI 4.4.4.1. */
++ rela.r_offset = (htab->sgotplt->output_section->vma
++ + htab->sgotplt->output_offset
++ + got_offset);
++
++ }
++ else
++ {
++ asection *splt = htab->plt;
++ if (!htab->elf.dynamic_sections_created
++ || h->dynindx == -1)
++ splt = htab->iplt;
++
++ rela.r_offset = (splt->output_section->vma
++ + splt->output_offset
++ + ent->plt.offset);
++#ifdef DEBUG
++ fprintf (stderr, " r_offset = %p ", (void *)rela.r_offset);
++#endif
++ if (htab->plt_type == PLT_OLD
++ || !htab->elf.dynamic_sections_created
++ || h->dynindx == -1)
++ {
++ /* We don't need to fill in the .plt. The ppc dynamic
++ linker will fill it in. */
++#ifdef DEBUG
++ fprintf (stderr, " not filling in .plt ");
++#endif
++ }
++ else
++ {
++ bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
++ + htab->glink->output_section->vma
++ + htab->glink->output_offset);
++ bfd_put_32 (output_bfd, val,
++ splt->contents + ent->plt.offset);
++ }
++ }
++
++ /* Fill in the entry in the .rela.plt section. */
++ rela.r_addend = 0;
++ if (!htab->elf.dynamic_sections_created
++ || h->dynindx == -1)
++ {
++ BFD_ASSERT (h->type == STT_GNU_IFUNC
++ && h->def_regular
++ && (h->root.type == bfd_link_hash_defined
++ || h->root.type == bfd_link_hash_defweak));
++ rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
++ rela.r_addend = SYM_VAL (h);
++ }
++ else
++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
++
++ if (!htab->elf.dynamic_sections_created
++ || h->dynindx == -1)
++ loc = (htab->reliplt->contents
++ + (htab->reliplt->reloc_count++
++ * sizeof (Elf32_External_Rela)));
++ else
++ loc = (htab->relplt->contents
++ + reloc_index * sizeof (Elf32_External_Rela));
++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
++
++#ifdef DEBUG
++ fprintf (stderr, " r_offset = %p r_addednd = %p, r_info = 0x%08x, h->def_regular = %d", (void *)rela.r_offset, (void *)rela.r_addend, (unsigned int)rela.r_info, (int)h->def_regular);
++#endif
++ if (!h->def_regular)
++ {
++ /* Mark the symbol as undefined, rather than as
++ defined in the .plt section. Leave the value if
++ there were any relocations where pointer equality
++ matters (this is a clue for the dynamic linker, to
++ make function pointer comparisons work between an
++ application and shared library), otherwise set it
++ to zero. */
++ sym->st_shndx = SHN_UNDEF;
++ if (!h->pointer_equality_needed)
++ {
++ /* THF: This is peculiar. The compiler generates a R_PPC_REL24 for externally referenced
++ * symbols impoted from libc.so. Relocation in elf.library requires the symbol to have it's .plt
++ * stub value, but the linker specifically clears the value to 0, resulting in run-time
++ * errors when the binary tries to call libc functions.
++ */
++ // sym->st_value = 0;
++ }
++ else if (!h->ref_regular_nonweak)
++ {
++ /* This breaks function pointer comparisons, but
++ that is better than breaking tests for a NULL
++ function pointer. */
++ sym->st_value = 0;
++ }
++ }
++ else if (h->type == STT_GNU_IFUNC
++ && !info->shared)
++ {
++ /* Set the value of ifunc symbols in a non-pie
++ executable to the glink entry. This is to avoid
++ text relocations. We can't do this for ifunc in
++ allocate_dynrelocs, as we do for normal dynamic
++ function symbols with plt entries, because we need
++ to keep the original value around for the ifunc
++ relocation. */
++ sym->st_shndx = (_bfd_elf_section_from_bfd_section
++ (output_bfd, htab->glink->output_section));
++ sym->st_value = (ent->glink_offset
++ + htab->glink->output_offset
++ + htab->glink->output_section->vma);
++ }
++ doneone = TRUE;
++ }
++
++ if (htab->plt_type == PLT_NEW
++ || !htab->elf.dynamic_sections_created
++ || h->dynindx == -1)
++ {
++ unsigned char *p;
++ asection *splt = htab->plt;
++ if (!htab->elf.dynamic_sections_created
++ || h->dynindx == -1)
++ splt = htab->iplt;
++
++ p = (unsigned char *) htab->glink->contents + ent->glink_offset;
++
++ if (h == htab->tls_get_addr && !htab->no_tls_get_addr_opt)
++ {
++ bfd_put_32 (output_bfd, LWZ_11_3, p);
++ p += 4;
++ bfd_put_32 (output_bfd, LWZ_12_3 + 4, p);
++ p += 4;
++ bfd_put_32 (output_bfd, MR_0_3, p);
++ p += 4;
++ bfd_put_32 (output_bfd, CMPWI_11_0, p);
++ p += 4;
++ bfd_put_32 (output_bfd, ADD_3_12_2, p);
++ p += 4;
++ bfd_put_32 (output_bfd, BEQLR, p);
++ p += 4;
++ bfd_put_32 (output_bfd, MR_3_0, p);
++ p += 4;
++ bfd_put_32 (output_bfd, NOP, p);
++ p += 4;
++ }
++
++ write_glink_stub (ent, splt, p, info);
++
++ if (!info->shared)
++ /* We only need one non-PIC glink stub. */
++ break;
++ }
++ else
++ break;
++ }
++
++ if (h->needs_copy)
++ {
++ asection *s;
++ Elf_Internal_Rela rela;
++ bfd_byte *loc;
++
++ /* This symbols needs a copy reloc. Set it up. */
++
++#ifdef DEBUG
++ fprintf (stderr, ", copy");
++#endif
++
++ BFD_ASSERT (h->dynindx != -1);
++
++ if (ppc_elf_hash_entry (h)->has_sda_refs)
++ s = htab->relsbss;
++ else
++ s = htab->relbss;
++ BFD_ASSERT (s != NULL);
++
++ rela.r_offset = SYM_VAL (h);
++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY);
++ rela.r_addend = 0;
++ loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
++ }
++
++#ifdef DEBUG
++ fprintf (stderr, " SYM_VAL(%p) ", (void *)SYM_VAL(h));
++#endif
++#ifdef DEBUG
++ fprintf (stderr, "\n");
++#endif
++
++ return TRUE;
++}
++
++static enum elf_reloc_type_class
++ppc_elf_reloc_type_class (const Elf_Internal_Rela *rela)
++{
++ switch (ELF32_R_TYPE (rela->r_info))
++ {
++ case R_PPC_RELATIVE:
++ return reloc_class_relative;
++ case R_PPC_REL24:
++ case R_PPC_ADDR24:
++ case R_PPC_JMP_SLOT:
++ return reloc_class_plt;
++ case R_PPC_COPY:
++ return reloc_class_copy;
++ default:
++ return reloc_class_normal;
++ }
++}
++
++/* Finish up the dynamic sections. */
++
++static bfd_boolean
++ppc_elf_finish_dynamic_sections (bfd *output_bfd,
++ struct bfd_link_info *info)
++{
++ asection *sdyn;
++ asection *splt;
++ struct ppc_elf_link_hash_table *htab;
++ bfd_vma got;
++ bfd *dynobj;
++ bfd_boolean ret = TRUE;
++
++#ifdef DEBUG
++ fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n");
++#endif
++
++ htab = ppc_elf_hash_table (info);
++ dynobj = elf_hash_table (info)->dynobj;
++ sdyn = bfd_get_linker_section (dynobj, ".dynamic");
++ if (htab->is_vxworks)
++ splt = bfd_get_linker_section (dynobj, ".plt");
++ else
++ splt = NULL;
++
++ got = 0;
++ if (htab->elf.hgot != NULL)
++ got = SYM_VAL (htab->elf.hgot);
++
++ if (htab->elf.dynamic_sections_created)
++ {
++ Elf32_External_Dyn *dyncon, *dynconend;
++
++ BFD_ASSERT (htab->plt != NULL && sdyn != NULL);
++
++ dyncon = (Elf32_External_Dyn *) sdyn->contents;
++ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
++ for (; dyncon < dynconend; dyncon++)
++ {
++ Elf_Internal_Dyn dyn;
++ asection *s;
++
++ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
++
++ switch (dyn.d_tag)
++ {
++ case DT_PLTGOT:
++ if (htab->is_vxworks)
++ s = htab->sgotplt;
++ else
++ s = htab->plt;
++ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
++ break;
++
++ case DT_PLTRELSZ:
++ dyn.d_un.d_val = htab->relplt->size;
++ break;
++
++ case DT_JMPREL:
++ s = htab->relplt;
++ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
++ break;
++
++ case DT_PPC_GOT:
++ dyn.d_un.d_ptr = got;
++ break;
++
++ case DT_RELASZ:
++ if (htab->is_vxworks)
++ {
++ if (htab->relplt)
++ dyn.d_un.d_ptr -= htab->relplt->size;
++ break;
++ }
++ continue;
++
++ default:
++ if (htab->is_vxworks
++ && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
++ break;
++ continue;
++ }
++
++ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
++ }
++ }
++
++ if (htab->got != NULL)
++ {
++ if (htab->elf.hgot->root.u.def.section == htab->got
++ || htab->elf.hgot->root.u.def.section == htab->sgotplt)
++ {
++ unsigned char *p = htab->elf.hgot->root.u.def.section->contents;
++
++ p += htab->elf.hgot->root.u.def.value;
++ if (htab->plt_type == PLT_OLD)
++ {
++ /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4
++ so that a function can easily find the address of
++ _GLOBAL_OFFSET_TABLE_. */
++ BFD_ASSERT (htab->elf.hgot->root.u.def.value - 4
++ < htab->elf.hgot->root.u.def.section->size);
++ bfd_put_32 (output_bfd, 0x4e800021, p - 4);
++ }
++
++ if (sdyn != NULL)
++ {
++ bfd_vma val = sdyn->output_section->vma + sdyn->output_offset;
++ BFD_ASSERT (htab->elf.hgot->root.u.def.value
++ < htab->elf.hgot->root.u.def.section->size);
++ bfd_put_32 (output_bfd, val, p);
++ }
++ }
++ else
++ {
++ info->callbacks->einfo (_("%P: %s not defined in linker created %s\n"),
++ htab->elf.hgot->root.root.string,
++ (htab->sgotplt != NULL
++ ? htab->sgotplt->name : htab->got->name));
++ bfd_set_error (bfd_error_bad_value);
++ ret = FALSE;
++ }
++
++ elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4;
++ }
++
++ /* Fill in the first entry in the VxWorks procedure linkage table. */
++ if (splt && splt->size > 0)
++ {
++ /* Use the right PLT. */
++ const bfd_vma *plt_entry = (info->shared
++ ? ppc_elf_vxworks_pic_plt0_entry
++ : ppc_elf_vxworks_plt0_entry);
++
++ if (!info->shared)
++ {
++ bfd_vma got_value = SYM_VAL (htab->elf.hgot);
++
++ bfd_put_32 (output_bfd, plt_entry[0] | PPC_HA (got_value),
++ splt->contents + 0);
++ bfd_put_32 (output_bfd, plt_entry[1] | PPC_LO (got_value),
++ splt->contents + 4);
++ }
++ else
++ {
++ bfd_put_32 (output_bfd, plt_entry[0], splt->contents + 0);
++ bfd_put_32 (output_bfd, plt_entry[1], splt->contents + 4);
++ }
++ bfd_put_32 (output_bfd, plt_entry[2], splt->contents + 8);
++ bfd_put_32 (output_bfd, plt_entry[3], splt->contents + 12);
++ bfd_put_32 (output_bfd, plt_entry[4], splt->contents + 16);
++ bfd_put_32 (output_bfd, plt_entry[5], splt->contents + 20);
++ bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24);
++ bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28);
++
++ if (! info->shared)
++ {
++ Elf_Internal_Rela rela;
++ bfd_byte *loc;
++
++ loc = htab->srelplt2->contents;
++
++ /* Output the @ha relocation for the first instruction. */
++ rela.r_offset = (htab->plt->output_section->vma
++ + htab->plt->output_offset
++ + 2);
++ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA);
++ rela.r_addend = 0;
++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
++ loc += sizeof (Elf32_External_Rela);
++
++ /* Output the @l relocation for the second instruction. */
++ rela.r_offset = (htab->plt->output_section->vma
++ + htab->plt->output_offset
++ + 6);
++ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO);
++ rela.r_addend = 0;
++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
++ loc += sizeof (Elf32_External_Rela);
++
++ /* Fix up the remaining relocations. They may have the wrong
++ symbol index for _G_O_T_ or _P_L_T_ depending on the order
++ in which symbols were output. */
++ while (loc < htab->srelplt2->contents + htab->srelplt2->size)
++ {
++ Elf_Internal_Rela rel;
++
++ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
++ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA);
++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
++ loc += sizeof (Elf32_External_Rela);
++
++ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
++ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO);
++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
++ loc += sizeof (Elf32_External_Rela);
++
++ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
++ rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_PPC_ADDR32);
++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
++ loc += sizeof (Elf32_External_Rela);
++ }
++ }
++ }
++
++ if (htab->glink != NULL
++ && htab->glink->contents != NULL
++ && htab->elf.dynamic_sections_created)
++ {
++ unsigned char *p;
++ unsigned char *endp;
++ bfd_vma res0;
++ unsigned int i;
++
++ /*
++ * PIC glink code is the following:
++ *
++ * # ith PLT code stub.
++ * addis 11,30,(plt+(i-1)*4-got)@ha
++ * lwz 11,(plt+(i-1)*4-got)@l(11)
++ * mtctr 11
++ * bctr
++ *
++ * # A table of branches, one for each plt entry.
++ * # The idea is that the plt call stub loads ctr and r11 with these
++ * # addresses, so (r11 - res_0) gives the plt index * 4.
++ * res_0: b PLTresolve
++ * res_1: b PLTresolve
++ * .
++ * # Some number of entries towards the end can be nops
++ * res_n_m3: nop
++ * res_n_m2: nop
++ * res_n_m1:
++ *
++ * PLTresolve:
++ * addis 11,11,(1f-res_0)@ha
++ * mflr 0
++ * bcl 20,31,1f
++ * 1: addi 11,11,(1b-res_0)@l
++ * mflr 12
++ * mtlr 0
++ * sub 11,11,12 # r11 = index * 4
++ * addis 12,12,(got+4-1b)@ha
++ * lwz 0,(got+4-1b)@l(12) # got[1] address of dl_runtime_resolve
++ * lwz 12,(got+8-1b)@l(12) # got[2] contains the map address
++ * mtctr 0
++ * add 0,11,11
++ * add 11,0,11 # r11 = index * 12 = reloc offset.
++ * bctr
++ */
++ static const unsigned int pic_plt_resolve[] =
++ {
++ ADDIS_11_11,
++ MFLR_0,
++ BCL_20_31,
++ ADDI_11_11,
++ MFLR_12,
++ MTLR_0,
++ SUB_11_11_12,
++ ADDIS_12_12,
++ LWZ_0_12,
++ LWZ_12_12,
++ MTCTR_0,
++ ADD_0_11_11,
++ ADD_11_0_11,
++ BCTR,
++ NOP,
++ NOP
++ };
++
++ /*
++ * Non-PIC glink code is a little simpler.
++ *
++ * # ith PLT code stub.
++ * lis 11,(plt+(i-1)*4)@ha
++ * lwz 11,(plt+(i-1)*4)@l(11)
++ * mtctr 11
++ * bctr
++ *
++ * The branch table is the same, then comes
++ *
++ * PLTresolve:
++ * lis 12,(got+4)@ha
++ * addis 11,11,(-res_0)@ha
++ * lwz 0,(got+4)@l(12) # got[1] address of dl_runtime_resolve
++ * addi 11,11,(-res_0)@l # r11 = index * 4
++ * mtctr 0
++ * add 0,11,11
++ * lwz 12,(got+8)@l(12) # got[2] contains the map address
++ * add 11,0,11 # r11 = index * 12 = reloc offset.
++ * bctr
++ */
++ static const unsigned int plt_resolve[] =
++ {
++ LIS_12,
++ ADDIS_11_11,
++ LWZ_0_12,
++ ADDI_11_11,
++ MTCTR_0,
++ ADD_0_11_11,
++ LWZ_12_12,
++ ADD_11_0_11,
++ BCTR,
++ NOP,
++ NOP,
++ NOP,
++ NOP,
++ NOP,
++ NOP,
++ NOP
++ };
++
++ if (ARRAY_SIZE (pic_plt_resolve) != GLINK_PLTRESOLVE / 4)
++ abort ();
++ if (ARRAY_SIZE (plt_resolve) != GLINK_PLTRESOLVE / 4)
++ abort ();
++
++ /* Build the branch table, one for each plt entry (less one),
++ and perhaps some padding. */
++ p = htab->glink->contents;
++ p += htab->glink_pltresolve;
++ endp = htab->glink->contents;
++ endp += htab->glink->size - GLINK_PLTRESOLVE;
++ while (p < endp - 8 * 4)
++ {
++ bfd_put_32 (output_bfd, B + endp - p, p);
++ p += 4;
++ }
++ while (p < endp)
++ {
++ bfd_put_32 (output_bfd, NOP, p);
++ p += 4;
++ }
++
++ res0 = (htab->glink_pltresolve
++ + htab->glink->output_section->vma
++ + htab->glink->output_offset);
++
++ /* Last comes the PLTresolve stub. */
++ if (info->shared)
++ {
++ bfd_vma bcl;
++
++ for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++)
++ {
++ bfd_put_32 (output_bfd, pic_plt_resolve[i], p);
++ p += 4;
++ }
++ p -= 4 * ARRAY_SIZE (pic_plt_resolve);
++
++ bcl = (htab->glink->size - GLINK_PLTRESOLVE + 3*4
++ + htab->glink->output_section->vma
++ + htab->glink->output_offset);
++
++ bfd_put_32 (output_bfd,
++ ADDIS_11_11 + PPC_HA (bcl - res0), p + 0*4);
++ bfd_put_32 (output_bfd,
++ ADDI_11_11 + PPC_LO (bcl - res0), p + 3*4);
++ bfd_put_32 (output_bfd,
++ ADDIS_12_12 + PPC_HA (got + 4 - bcl), p + 7*4);
++ if (PPC_HA (got + 4 - bcl) == PPC_HA (got + 8 - bcl))
++ {
++ bfd_put_32 (output_bfd,
++ LWZ_0_12 + PPC_LO (got + 4 - bcl), p + 8*4);
++ bfd_put_32 (output_bfd,
++ LWZ_12_12 + PPC_LO (got + 8 - bcl), p + 9*4);
++ }
++ else
++ {
++ bfd_put_32 (output_bfd,
++ LWZU_0_12 + PPC_LO (got + 4 - bcl), p + 8*4);
++ bfd_put_32 (output_bfd,
++ LWZ_12_12 + 4, p + 9*4);
++ }
++ }
++ else
++ {
++ for (i = 0; i < ARRAY_SIZE (plt_resolve); i++)
++ {
++ bfd_put_32 (output_bfd, plt_resolve[i], p);
++ p += 4;
++ }
++ p -= 4 * ARRAY_SIZE (plt_resolve);
++
++ bfd_put_32 (output_bfd,
++ LIS_12 + PPC_HA (got + 4), p + 0*4);
++ bfd_put_32 (output_bfd,
++ ADDIS_11_11 + PPC_HA (-res0), p + 1*4);
++ bfd_put_32 (output_bfd,
++ ADDI_11_11 + PPC_LO (-res0), p + 3*4);
++ if (PPC_HA (got + 4) == PPC_HA (got + 8))
++ {
++ bfd_put_32 (output_bfd,
++ LWZ_0_12 + PPC_LO (got + 4), p + 2*4);
++ bfd_put_32 (output_bfd,
++ LWZ_12_12 + PPC_LO (got + 8), p + 6*4);
++ }
++ else
++ {
++ bfd_put_32 (output_bfd,
++ LWZU_0_12 + PPC_LO (got + 4), p + 2*4);
++ bfd_put_32 (output_bfd,
++ LWZ_12_12 + 4, p + 6*4);
++ }
++ }
++ }
++
++ if (htab->glink_eh_frame != NULL
++ && htab->glink_eh_frame->contents != NULL)
++ {
++ unsigned char *p = htab->glink_eh_frame->contents;
++ bfd_vma val;
++
++ p += sizeof (glink_eh_frame_cie);
++ /* FDE length. */
++ p += 4;
++ /* CIE pointer. */
++ p += 4;
++ /* Offset to .glink. */
++ val = (htab->glink->output_section->vma
++ + htab->glink->output_offset);
++ val -= (htab->glink_eh_frame->output_section->vma
++ + htab->glink_eh_frame->output_offset);
++ val -= p - htab->glink_eh_frame->contents;
++ bfd_put_32 (htab->elf.dynobj, val, p);
++
++ if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
++ && !_bfd_elf_write_section_eh_frame (output_bfd, info,
++ htab->glink_eh_frame,
++ htab->glink_eh_frame->contents))
++ return FALSE;
++ }
++
++ return ret;
++}
++
++#define TARGET_BIG_SYM bfd_elf32_amigaos_vec
++#define TARGET_BIG_NAME "elf32-amigaos"
++#define ELF_ARCH bfd_arch_powerpc
++#define ELF_TARGET_ID PPC32_ELF_DATA
++#define ELF_MACHINE_CODE EM_PPC
++#ifdef __QNXTARGET__
++#define ELF_MAXPAGESIZE 0x1000
++#else
++#define ELF_MAXPAGESIZE 0x10000
++#endif
++#define ELF_MINPAGESIZE 0x1000
++#define ELF_COMMONPAGESIZE 0x1000
++#define elf_info_to_howto ppc_elf_info_to_howto
++
++#ifdef EM_CYGNUS_POWERPC
++#define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC
++#endif
++
++#ifdef EM_PPC_OLD
++#define ELF_MACHINE_ALT2 EM_PPC_OLD
++#endif
++
++#define elf_backend_plt_not_loaded 1
++#define elf_backend_can_gc_sections 1
++#define elf_backend_can_refcount 1
++#define elf_backend_rela_normal 1
++
++#define bfd_elf32_mkobject ppc_elf_mkobject
++#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data
++#define bfd_elf32_bfd_relax_section ppc_elf_relax_section
++#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup
++#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup
++#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags
++#define bfd_elf32_bfd_link_hash_table_create ppc_elf_link_hash_table_create
++#define bfd_elf32_get_synthetic_symtab ppc_elf_get_synthetic_symtab
++
++#define elf_backend_object_p ppc_elf_object_p
++#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook
++#define elf_backend_gc_sweep_hook ppc_elf_gc_sweep_hook
++#define elf_backend_section_from_shdr ppc_elf_section_from_shdr
++#define elf_backend_relocate_section ppc_elf_relocate_section
++#define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections
++#define elf_backend_check_relocs ppc_elf_check_relocs
++#define elf_backend_copy_indirect_symbol ppc_elf_copy_indirect_symbol
++#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol
++#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook
++#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections
++#define elf_backend_hash_symbol ppc_elf_hash_symbol
++#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol
++#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections
++#define elf_backend_fake_sections ppc_elf_fake_sections
++#define elf_backend_additional_program_headers ppc_elf_additional_program_headers
++#define elf_backend_modify_segment_map ppc_elf_amigaos_modify_segment_map
++#define elf_backend_grok_prstatus ppc_elf_grok_prstatus
++#define elf_backend_grok_psinfo ppc_elf_grok_psinfo
++#define elf_backend_write_core_note ppc_elf_write_core_note
++#define elf_backend_reloc_type_class ppc_elf_reloc_type_class
++#define elf_backend_begin_write_processing ppc_elf_amigaos_begin_write_processing
++#define elf_backend_final_write_processing ppc_elf_amigaos_final_write_processing
++#define elf_backend_write_section ppc_elf_amigaos_write_section
++#define elf_backend_get_sec_type_attr ppc_elf_get_sec_type_attr
++#define elf_backend_plt_sym_val ppc_elf_plt_sym_val
++#define elf_backend_action_discarded ppc_elf_action_discarded
++#define elf_backend_init_index_section _bfd_elf_init_1_index_section
++#define elf_backend_post_process_headers _bfd_elf_set_osabi
++#define elf_backend_lookup_section_flags_hook ppc_elf_lookup_section_flags
++#define elf_backend_section_processing ppc_elf_amigaos_section_processing
++
++#include "elf32-target.h"
+--- /dev/null 2015-09-06 08:42:34.091999986 +0100
++++ ld/emultempl/amigaos.em 2016-01-03 01:46:50.647001071 +0000
+@@ -0,0 +1,2513 @@
++# This shell script emits a C file. -*- C -*-
++# It does some substitutions.
++# This file is now misnamed, because it supports both 32 bit and 64 bit
++# ELF emulations.
++test -z "${ELFSIZE}" && ELFSIZE=32
++if [ -z "$MACHINE" ]; then
++ OUTPUT_ARCH=${ARCH}
++else
++ OUTPUT_ARCH=${ARCH}:${MACHINE}
++fi
++fragment <<EOF
++/* This file is is generated by a shell script. DO NOT EDIT! */
++
++/* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME}
++ Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
++ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
++ Free Software Foundation, Inc.
++ Written by Steve Chamberlain <sac@cygnus.com>
++ ELF support by Ian Lance Taylor <ian@cygnus.com>
++
++ This file is part of the GNU Binutils.
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
++ MA 02110-1301, USA. */
++
++#define TARGET_IS_${EMULATION_NAME}
++
++#include "sysdep.h"
++#include "bfd.h"
++#include "libiberty.h"
++#include "filenames.h"
++#include "safe-ctype.h"
++#include "getopt.h"
++#include "md5.h"
++#include "sha1.h"
++#include <fcntl.h>
++
++#include "bfdlink.h"
++
++#include "ld.h"
++#include "ldmain.h"
++#include "ldmisc.h"
++#include "ldexp.h"
++#include "ldlang.h"
++#include "ldfile.h"
++#include "ldemul.h"
++#include <ldgram.h>
++#include "elf/common.h"
++#include "elf-bfd.h"
++#include "filenames.h"
++
++/* Declare functions used by various EXTRA_EM_FILEs. */
++static void gld${EMULATION_NAME}_before_parse (void);
++static void gld${EMULATION_NAME}_after_open (void);
++static void gld${EMULATION_NAME}_before_allocation (void);
++static void gld${EMULATION_NAME}_after_allocation (void);
++static lang_output_section_statement_type *gld${EMULATION_NAME}_place_orphan
++ (asection *, const char *, int);
++EOF
++
++if [ "x${USE_LIBPATH}" = xyes ] ; then
++ case ${target} in
++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*)
++ fragment <<EOF
++#ifdef HAVE_GLOB
++#include <glob.h>
++#endif
++EOF
++ ;;
++ esac
++fi
++
++# Import any needed special functions and/or overrides.
++#
++source_em ${srcdir}/emultempl/elf-generic.em
++if test -n "$EXTRA_EM_FILE" ; then
++ source_em ${srcdir}/emultempl/${EXTRA_EM_FILE}.em
++fi
++
++# Functions in this file can be overridden by setting the LDEMUL_* shell
++# variables. If the name of the overriding function is the same as is
++# defined in this file, then don't output this file's version.
++# If a different overriding name is given then output the standard function
++# as presumably it is called from the overriding function.
++#
++if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then
++fragment <<EOF
++
++static void
++gld${EMULATION_NAME}_before_parse (void)
++{
++ ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`);
++ input_flags.dynamic = ${DYNAMIC_LINK-TRUE};
++ config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`;
++ config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then echo TRUE ; else echo FALSE ; fi`;
++}
++
++EOF
++fi
++
++if test x"$LDEMUL_RECOGNIZED_FILE" != xgld"${EMULATION_NAME}"_load_symbols; then
++fragment <<EOF
++/* Handle the generation of DT_NEEDED tags. */
++
++static bfd_boolean
++gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry)
++{
++ int link_class = 0;
++
++ /* Tell the ELF linker that we don't want the output file to have a
++ DT_NEEDED entry for this file, unless it is used to resolve
++ references in a regular object. */
++ if (entry->flags.add_DT_NEEDED_for_regular)
++ link_class = DYN_AS_NEEDED;
++
++ /* Tell the ELF linker that we don't want the output file to have a
++ DT_NEEDED entry for any dynamic library in DT_NEEDED tags from
++ this file at all. */
++ if (!entry->flags.add_DT_NEEDED_for_dynamic)
++ link_class |= DYN_NO_ADD_NEEDED;
++
++ if (entry->flags.just_syms
++ && (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) != 0)
++ einfo (_("%P%F: --just-symbols may not be used on DSO: %B\n"),
++ entry->the_bfd);
++
++ if (link_class == 0
++ || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0)
++ return FALSE;
++
++ bfd_elf_set_dyn_lib_class (entry->the_bfd,
++ (enum dynamic_lib_link_class) link_class);
++
++ /* Continue on with normal load_symbols processing. */
++ return FALSE;
++}
++EOF
++fi
++
++fragment <<EOF
++
++/* These variables are required to pass information back and forth
++ between after_open and check_needed and stat_needed and vercheck. */
++
++static struct bfd_link_needed_list *global_needed;
++static struct stat global_stat;
++static lang_input_statement_type *global_found;
++static struct bfd_link_needed_list *global_vercheck_needed;
++static bfd_boolean global_vercheck_failed;
++
++/* These variables are used to implement target options */
++
++static char *audit; /* colon (typically) separated list of libs */
++static char *depaudit; /* colon (typically) separated list of libs */
++
++/* On Linux, it's possible to have different versions of the same
++ shared library linked against different versions of libc. The
++ dynamic linker somehow tags which libc version to use in
++ /etc/ld.so.cache, and, based on the libc that it sees in the
++ executable, chooses which version of the shared library to use.
++
++ We try to do a similar check here by checking whether this shared
++ library needs any other shared libraries which may conflict with
++ libraries we have already included in the link. If it does, we
++ skip it, and try to find another shared library farther on down the
++ link path.
++
++ This is called via lang_for_each_input_file.
++ GLOBAL_VERCHECK_NEEDED is the list of objects needed by the object
++ which we are checking. This sets GLOBAL_VERCHECK_FAILED if we find
++ a conflicting version. */
++
++static void
++gld${EMULATION_NAME}_vercheck (lang_input_statement_type *s)
++{
++ const char *soname;
++ struct bfd_link_needed_list *l;
++
++ if (global_vercheck_failed)
++ return;
++ if (s->the_bfd == NULL
++ || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0)
++ return;
++
++ soname = bfd_elf_get_dt_soname (s->the_bfd);
++ if (soname == NULL)
++ soname = lbasename (bfd_get_filename (s->the_bfd));
++
++ for (l = global_vercheck_needed; l != NULL; l = l->next)
++ {
++ const char *suffix;
++
++ if (filename_cmp (soname, l->name) == 0)
++ {
++ /* Probably can't happen, but it's an easy check. */
++ continue;
++ }
++
++ if (strchr (l->name, '/') != NULL)
++ continue;
++
++ suffix = strstr (l->name, ".so.");
++ if (suffix == NULL)
++ continue;
++
++ suffix += sizeof ".so." - 1;
++
++ if (filename_ncmp (soname, l->name, suffix - l->name) == 0)
++ {
++ /* Here we know that S is a dynamic object FOO.SO.VER1, and
++ the object we are considering needs a dynamic object
++ FOO.SO.VER2, and VER1 and VER2 are different. This
++ appears to be a version mismatch, so we tell the caller
++ to try a different version of this library. */
++ global_vercheck_failed = TRUE;
++ return;
++ }
++ }
++}
++
++
++/* See if an input file matches a DT_NEEDED entry by running stat on
++ the file. */
++
++static void
++gld${EMULATION_NAME}_stat_needed (lang_input_statement_type *s)
++{
++ struct stat st;
++ const char *suffix;
++ const char *soname;
++
++ if (global_found != NULL)
++ return;
++ if (s->the_bfd == NULL)
++ return;
++
++ /* If this input file was an as-needed entry, and wasn't found to be
++ needed at the stage it was linked, then don't say we have loaded it. */
++ if ((bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0)
++ return;
++
++ if (bfd_stat (s->the_bfd, &st) != 0)
++ {
++ einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd);
++ return;
++ }
++
++ /* Some operating systems, e.g. Windows, do not provide a meaningful
++ st_ino; they always set it to zero. (Windows does provide a
++ meaningful st_dev.) Do not indicate a duplicate library in that
++ case. While there is no guarantee that a system that provides
++ meaningful inode numbers will never set st_ino to zero, this is
++ merely an optimization, so we do not need to worry about false
++ negatives. */
++ if (st.st_dev == global_stat.st_dev
++ && st.st_ino == global_stat.st_ino
++ && st.st_ino != 0)
++ {
++ global_found = s;
++ return;
++ }
++
++ /* We issue a warning if it looks like we are including two
++ different versions of the same shared library. For example,
++ there may be a problem if -lc picks up libc.so.6 but some other
++ shared library has a DT_NEEDED entry of libc.so.5. This is a
++ heuristic test, and it will only work if the name looks like
++ NAME.so.VERSION. FIXME: Depending on file names is error-prone.
++ If we really want to issue warnings about mixing version numbers
++ of shared libraries, we need to find a better way. */
++
++ if (strchr (global_needed->name, '/') != NULL)
++ return;
++ suffix = strstr (global_needed->name, ".so.");
++ if (suffix == NULL)
++ return;
++ suffix += sizeof ".so." - 1;
++
++ soname = bfd_elf_get_dt_soname (s->the_bfd);
++ if (soname == NULL)
++ soname = lbasename (s->filename);
++
++ if (filename_ncmp (soname, global_needed->name, suffix - global_needed->name) == 0)
++ einfo ("%P: warning: %s, needed by %B, may conflict with %s\n",
++ global_needed->name, global_needed->by, soname);
++}
++
++struct dt_needed
++{
++ bfd *by;
++ const char *name;
++};
++
++/* This function is called for each possible name for a dynamic object
++ named by a DT_NEEDED entry. The FORCE parameter indicates whether
++ to skip the check for a conflicting version. */
++
++static bfd_boolean
++gld${EMULATION_NAME}_try_needed (struct dt_needed *needed,
++ int force)
++{
++ bfd *abfd;
++ const char *name = needed->name;
++ const char *soname;
++ int link_class;
++
++ abfd = bfd_openr (name, bfd_get_target (link_info.output_bfd));
++ if (abfd == NULL)
++ return FALSE;
++
++ /* Linker needs to decompress sections. */
++ abfd->flags |= BFD_DECOMPRESS;
++
++ if (! bfd_check_format (abfd, bfd_object))
++ {
++ bfd_close (abfd);
++ return FALSE;
++ }
++ if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0)
++ {
++ bfd_close (abfd);
++ return FALSE;
++ }
++
++ /* For DT_NEEDED, they have to match. */
++ if (abfd->xvec != link_info.output_bfd->xvec)
++ {
++ bfd_close (abfd);
++ return FALSE;
++ }
++
++ /* Check whether this object would include any conflicting library
++ versions. If FORCE is set, then we skip this check; we use this
++ the second time around, if we couldn't find any compatible
++ instance of the shared library. */
++
++ if (! force)
++ {
++ struct bfd_link_needed_list *needs;
++
++ if (! bfd_elf_get_bfd_needed_list (abfd, &needs))
++ einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd);
++
++ if (needs != NULL)
++ {
++ global_vercheck_needed = needs;
++ global_vercheck_failed = FALSE;
++ lang_for_each_input_file (gld${EMULATION_NAME}_vercheck);
++ if (global_vercheck_failed)
++ {
++ bfd_close (abfd);
++ /* Return FALSE to force the caller to move on to try
++ another file on the search path. */
++ return FALSE;
++ }
++
++ /* But wait! It gets much worse. On Linux, if a shared
++ library does not use libc at all, we are supposed to skip
++ it the first time around in case we encounter a shared
++ library later on with the same name which does use the
++ version of libc that we want. This is much too horrible
++ to use on any system other than Linux. */
++
++EOF
++case ${target} in
++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*)
++ fragment <<EOF
++ {
++ struct bfd_link_needed_list *l;
++
++ for (l = needs; l != NULL; l = l->next)
++ if (CONST_STRNEQ (l->name, "libc.so"))
++ break;
++ if (l == NULL)
++ {
++ bfd_close (abfd);
++ return FALSE;
++ }
++ }
++
++EOF
++ ;;
++esac
++fragment <<EOF
++ }
++ }
++
++ /* We've found a dynamic object matching the DT_NEEDED entry. */
++
++ /* We have already checked that there is no other input file of the
++ same name. We must now check again that we are not including the
++ same file twice. We need to do this because on many systems
++ libc.so is a symlink to, e.g., libc.so.1. The SONAME entry will
++ reference libc.so.1. If we have already included libc.so, we
++ don't want to include libc.so.1 if they are the same file, and we
++ can only check that using stat. */
++
++ if (bfd_stat (abfd, &global_stat) != 0)
++ einfo ("%F%P:%B: bfd_stat failed: %E\n", abfd);
++
++ /* First strip off everything before the last '/'. */
++ soname = lbasename (abfd->filename);
++
++ if (verbose)
++ info_msg (_("found %s at %s\n"), soname, name);
++
++ global_found = NULL;
++ lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed);
++ if (global_found != NULL)
++ {
++ /* Return TRUE to indicate that we found the file, even though
++ we aren't going to do anything with it. */
++ return TRUE;
++ }
++
++ /* Specify the soname to use. */
++ bfd_elf_set_dt_needed_name (abfd, soname);
++
++ /* Tell the ELF linker that we don't want the output file to have a
++ DT_NEEDED entry for this file, unless it is used to resolve
++ references in a regular object. */
++ link_class = DYN_DT_NEEDED;
++
++ /* Tell the ELF linker that we don't want the output file to have a
++ DT_NEEDED entry for this file at all if the entry is from a file
++ with DYN_NO_ADD_NEEDED. */
++ if (needed->by != NULL
++ && (bfd_elf_get_dyn_lib_class (needed->by) & DYN_NO_ADD_NEEDED) != 0)
++ link_class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED;
++
++ bfd_elf_set_dyn_lib_class (abfd, (enum dynamic_lib_link_class) link_class);
++
++ /* Add this file into the symbol table. */
++ if (! bfd_link_add_symbols (abfd, &link_info))
++ einfo ("%F%B: could not read symbols: %E\n", abfd);
++
++ return TRUE;
++}
++
++
++/* Search for a needed file in a path. */
++
++static bfd_boolean
++gld${EMULATION_NAME}_search_needed (const char *path,
++ struct dt_needed *n, int force)
++{
++ const char *s;
++ const char *name = n->name;
++ size_t len;
++ struct dt_needed needed;
++
++ if (name[0] == '/')
++ return gld${EMULATION_NAME}_try_needed (n, force);
++
++ if (path == NULL || *path == '\0')
++ return FALSE;
++
++ needed.by = n->by;
++ needed.name = n->name;
++
++ len = strlen (name);
++ while (1)
++ {
++ char *filename, *sset;
++
++ s = strchr (path, config.rpath_separator);
++ if (s == NULL)
++ s = path + strlen (path);
++
++#if HAVE_DOS_BASED_FILE_SYSTEM
++ /* Assume a match on the second char is part of drive specifier. */
++ else if (config.rpath_separator == ':'
++ && s == path + 1
++ && ISALPHA (*path))
++ {
++ s = strchr (s + 1, config.rpath_separator);
++ if (s == NULL)
++ s = path + strlen (path);
++ }
++#endif
++ filename = (char *) xmalloc (s - path + len + 2);
++ if (s == path)
++ sset = filename;
++ else
++ {
++ memcpy (filename, path, s - path);
++ filename[s - path] = '/';
++ sset = filename + (s - path) + 1;
++ }
++ strcpy (sset, name);
++
++ needed.name = filename;
++ if (gld${EMULATION_NAME}_try_needed (&needed, force))
++ return TRUE;
++
++ free (filename);
++
++ if (*s == '\0')
++ break;
++ path = s + 1;
++ }
++
++ return FALSE;
++}
++
++EOF
++if [ "x${USE_LIBPATH}" = xyes ] ; then
++ fragment <<EOF
++
++/* Add the sysroot to every entry in a path separated by
++ config.rpath_separator. */
++
++static char *
++gld${EMULATION_NAME}_add_sysroot (const char *path)
++{
++ int len, colons, i;
++ char *ret, *p;
++
++ len = strlen (path);
++ colons = 0;
++ i = 0;
++ while (path[i])
++ if (path[i++] == config.rpath_separator)
++ colons++;
++
++ if (path[i])
++ colons++;
++
++ len = len + (colons + 1) * strlen (ld_sysroot);
++ ret = xmalloc (len + 1);
++ strcpy (ret, ld_sysroot);
++ p = ret + strlen (ret);
++ i = 0;
++ while (path[i])
++ if (path[i] == config.rpath_separator)
++ {
++ *p++ = path[i++];
++ strcpy (p, ld_sysroot);
++ p = p + strlen (p);
++ }
++ else
++ *p++ = path[i++];
++
++ *p = 0;
++ return ret;
++}
++
++EOF
++ case ${target} in
++ *-*-freebsd* | *-*-dragonfly*)
++ fragment <<EOF
++/* Read the system search path the FreeBSD way rather than the Linux way. */
++#ifdef HAVE_ELF_HINTS_H
++#include <elf-hints.h>
++#else
++#include "elf-hints-local.h"
++#endif
++
++static bfd_boolean
++gld${EMULATION_NAME}_check_ld_elf_hints (const struct bfd_link_needed_list *l,
++ int force)
++{
++ static bfd_boolean initialized;
++ static char *ld_elf_hints;
++ struct dt_needed needed;
++
++ if (!initialized)
++ {
++ FILE *f;
++ char *tmppath;
++
++ tmppath = concat (ld_sysroot, _PATH_ELF_HINTS, (const char *) NULL);
++ f = fopen (tmppath, FOPEN_RB);
++ free (tmppath);
++ if (f != NULL)
++ {
++ struct elfhints_hdr hdr;
++
++ if (fread (&hdr, 1, sizeof (hdr), f) == sizeof (hdr)
++ && hdr.magic == ELFHINTS_MAGIC
++ && hdr.version == 1)
++ {
++ if (fseek (f, hdr.strtab + hdr.dirlist, SEEK_SET) != -1)
++ {
++ char *b;
++
++ b = xmalloc (hdr.dirlistlen + 1);
++ if (fread (b, 1, hdr.dirlistlen + 1, f) ==
++ hdr.dirlistlen + 1)
++ ld_elf_hints = gld${EMULATION_NAME}_add_sysroot (b);
++
++ free (b);
++ }
++ }
++ fclose (f);
++ }
++
++ initialized = TRUE;
++ }
++
++ if (ld_elf_hints == NULL)
++ return FALSE;
++
++ needed.by = l->by;
++ needed.name = l->name;
++ return gld${EMULATION_NAME}_search_needed (ld_elf_hints, &needed, force);
++}
++EOF
++ # FreeBSD
++ ;;
++
++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*)
++ fragment <<EOF
++/* For a native linker, check the file /etc/ld.so.conf for directories
++ in which we may find shared libraries. /etc/ld.so.conf is really
++ only meaningful on Linux. */
++
++struct gld${EMULATION_NAME}_ld_so_conf
++{
++ char *path;
++ size_t len, alloc;
++};
++
++static bfd_boolean
++gld${EMULATION_NAME}_parse_ld_so_conf
++ (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename);
++
++static void
++gld${EMULATION_NAME}_parse_ld_so_conf_include
++ (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename,
++ const char *pattern)
++{
++ char *newp = NULL;
++#ifdef HAVE_GLOB
++ glob_t gl;
++#endif
++
++ if (pattern[0] != '/')
++ {
++ char *p = strrchr (filename, '/');
++ size_t patlen = strlen (pattern) + 1;
++
++ newp = xmalloc (p - filename + 1 + patlen);
++ memcpy (newp, filename, p - filename + 1);
++ memcpy (newp + (p - filename + 1), pattern, patlen);
++ pattern = newp;
++ }
++
++#ifdef HAVE_GLOB
++ if (glob (pattern, 0, NULL, &gl) == 0)
++ {
++ size_t i;
++
++ for (i = 0; i < gl.gl_pathc; ++i)
++ gld${EMULATION_NAME}_parse_ld_so_conf (info, gl.gl_pathv[i]);
++ globfree (&gl);
++ }
++#else
++ /* If we do not have glob, treat the pattern as a literal filename. */
++ gld${EMULATION_NAME}_parse_ld_so_conf (info, pattern);
++#endif
++
++ if (newp)
++ free (newp);
++}
++
++static bfd_boolean
++gld${EMULATION_NAME}_parse_ld_so_conf
++ (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename)
++{
++ FILE *f = fopen (filename, FOPEN_RT);
++ char *line;
++ size_t linelen;
++
++ if (f == NULL)
++ return FALSE;
++
++ linelen = 256;
++ line = xmalloc (linelen);
++ do
++ {
++ char *p = line, *q;
++
++ /* Normally this would use getline(3), but we need to be portable. */
++ while ((q = fgets (p, linelen - (p - line), f)) != NULL
++ && strlen (q) == linelen - (p - line) - 1
++ && line[linelen - 2] != '\n')
++ {
++ line = xrealloc (line, 2 * linelen);
++ p = line + linelen - 1;
++ linelen += linelen;
++ }
++
++ if (q == NULL && p == line)
++ break;
++
++ p = strchr (line, '\n');
++ if (p)
++ *p = '\0';
++
++ /* Because the file format does not know any form of quoting we
++ can search forward for the next '#' character and if found
++ make it terminating the line. */
++ p = strchr (line, '#');
++ if (p)
++ *p = '\0';
++
++ /* Remove leading whitespace. NUL is no whitespace character. */
++ p = line;
++ while (*p == ' ' || *p == '\f' || *p == '\r' || *p == '\t' || *p == '\v')
++ ++p;
++
++ /* If the line is blank it is ignored. */
++ if (p[0] == '\0')
++ continue;
++
++ if (CONST_STRNEQ (p, "include") && (p[7] == ' ' || p[7] == '\t'))
++ {
++ char *dir, c;
++ p += 8;
++ do
++ {
++ while (*p == ' ' || *p == '\t')
++ ++p;
++
++ if (*p == '\0')
++ break;
++
++ dir = p;
++
++ while (*p != ' ' && *p != '\t' && *p)
++ ++p;
++
++ c = *p;
++ *p++ = '\0';
++ if (dir[0] != '\0')
++ gld${EMULATION_NAME}_parse_ld_so_conf_include (info, filename,
++ dir);
++ }
++ while (c != '\0');
++ }
++ else
++ {
++ char *dir = p;
++ while (*p && *p != '=' && *p != ' ' && *p != '\t' && *p != '\f'
++ && *p != '\r' && *p != '\v')
++ ++p;
++
++ while (p != dir && p[-1] == '/')
++ --p;
++ if (info->path == NULL)
++ {
++ info->alloc = p - dir + 1 + 256;
++ info->path = xmalloc (info->alloc);
++ info->len = 0;
++ }
++ else
++ {
++ if (info->len + 1 + (p - dir) >= info->alloc)
++ {
++ info->alloc += p - dir + 256;
++ info->path = xrealloc (info->path, info->alloc);
++ }
++ info->path[info->len++] = config.rpath_separator;
++ }
++ memcpy (info->path + info->len, dir, p - dir);
++ info->len += p - dir;
++ info->path[info->len] = '\0';
++ }
++ }
++ while (! feof (f));
++ free (line);
++ fclose (f);
++ return TRUE;
++}
++
++static bfd_boolean
++gld${EMULATION_NAME}_check_ld_so_conf (const struct bfd_link_needed_list *l,
++ int force)
++{
++ static bfd_boolean initialized;
++ static char *ld_so_conf;
++ struct dt_needed needed;
++
++ if (! initialized)
++ {
++ char *tmppath;
++ struct gld${EMULATION_NAME}_ld_so_conf info;
++
++ info.path = NULL;
++ info.len = info.alloc = 0;
++ tmppath = concat (ld_sysroot, "${prefix}/etc/ld.so.conf",
++ (const char *) NULL);
++ if (!gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath))
++ {
++ free (tmppath);
++ tmppath = concat (ld_sysroot, "/etc/ld.so.conf",
++ (const char *) NULL);
++ gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath);
++ }
++ free (tmppath);
++
++ if (info.path)
++ {
++ char *d = gld${EMULATION_NAME}_add_sysroot (info.path);
++ free (info.path);
++ ld_so_conf = d;
++ }
++ initialized = TRUE;
++ }
++
++ if (ld_so_conf == NULL)
++ return FALSE;
++
++
++ needed.by = l->by;
++ needed.name = l->name;
++ return gld${EMULATION_NAME}_search_needed (ld_so_conf, &needed, force);
++}
++
++EOF
++ # Linux
++ ;;
++ esac
++fi
++fragment <<EOF
++
++/* See if an input file matches a DT_NEEDED entry by name. */
++
++static void
++gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s)
++{
++ const char *soname;
++
++ /* Stop looking if we've found a loaded lib. */
++ if (global_found != NULL
++ && (bfd_elf_get_dyn_lib_class (global_found->the_bfd)
++ & DYN_AS_NEEDED) == 0)
++ return;
++
++ if (s->filename == NULL || s->the_bfd == NULL)
++ return;
++
++ /* Don't look for a second non-loaded as-needed lib. */
++ if (global_found != NULL
++ && (bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0)
++ return;
++
++ if (filename_cmp (s->filename, global_needed->name) == 0)
++ {
++ global_found = s;
++ return;
++ }
++
++ if (s->flags.search_dirs)
++ {
++ const char *f = strrchr (s->filename, '/');
++ if (f != NULL
++ && filename_cmp (f + 1, global_needed->name) == 0)
++ {
++ global_found = s;
++ return;
++ }
++ }
++
++ soname = bfd_elf_get_dt_soname (s->the_bfd);
++ if (soname != NULL
++ && filename_cmp (soname, global_needed->name) == 0)
++ {
++ global_found = s;
++ return;
++ }
++}
++
++EOF
++
++if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then
++fragment <<EOF
++
++static bfd_size_type
++gld${EMULATION_NAME}_id_note_section_size (bfd *abfd,
++ struct bfd_link_info *linfo)
++{
++ const char *style = linfo->emit_note_gnu_build_id;
++ bfd_size_type size;
++
++ abfd = abfd;
++
++ size = offsetof (Elf_External_Note, name[sizeof "GNU"]);
++ size = (size + 3) & -(bfd_size_type) 4;
++
++ if (!strcmp (style, "md5") || !strcmp (style, "uuid"))
++ size += 128 / 8;
++ else if (!strcmp (style, "sha1"))
++ size += 160 / 8;
++ else if (!strncmp (style, "0x", 2))
++ {
++ /* ID is in string form (hex). Convert to bits. */
++ const char *id = style + 2;
++ do
++ {
++ if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
++ {
++ ++size;
++ id += 2;
++ }
++ else if (*id == '-' || *id == ':')
++ ++id;
++ else
++ {
++ size = 0;
++ break;
++ }
++ } while (*id != '\0');
++ }
++ else
++ size = 0;
++
++ return size;
++}
++
++static unsigned char
++read_hex (const char xdigit)
++{
++ if (ISDIGIT (xdigit))
++ return xdigit - '0';
++ if (ISUPPER (xdigit))
++ return xdigit - 'A' + 0xa;
++ if (ISLOWER (xdigit))
++ return xdigit - 'a' + 0xa;
++ abort ();
++ return 0;
++}
++
++struct build_id_info
++{
++ const char *style;
++ asection *sec;
++};
++
++static bfd_boolean
++gld${EMULATION_NAME}_write_build_id_section (bfd *abfd)
++{
++ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
++ struct build_id_info *info = (struct build_id_info *)
++ elf_tdata (abfd)->after_write_object_contents_info;
++ asection *asec;
++ Elf_Internal_Shdr *i_shdr;
++ unsigned char *contents, *id_bits;
++ bfd_size_type size;
++ Elf_External_Note *e_note;
++
++ asec = info->sec;
++ if (bfd_is_abs_section (asec->output_section))
++ {
++ einfo (_("%P: warning: .note.gnu.build-id section discarded,"
++ " --build-id ignored.\n"));
++ return TRUE;
++ }
++ i_shdr = &elf_section_data (asec->output_section)->this_hdr;
++
++ if (i_shdr->contents == NULL)
++ {
++ if (asec->contents == NULL)
++ asec->contents = (unsigned char *) xmalloc (asec->size);
++ contents = asec->contents;
++ }
++ else
++ contents = i_shdr->contents + asec->output_offset;
++
++ e_note = (Elf_External_Note *) contents;
++ size = offsetof (Elf_External_Note, name[sizeof "GNU"]);
++ size = (size + 3) & -(bfd_size_type) 4;
++ id_bits = contents + size;
++ size = asec->size - size;
++
++ bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz);
++ bfd_h_put_32 (abfd, size, &e_note->descsz);
++ bfd_h_put_32 (abfd, NT_GNU_BUILD_ID, &e_note->type);
++ memcpy (e_note->name, "GNU", sizeof "GNU");
++
++ if (!strcmp (info->style, "md5"))
++ {
++ struct md5_ctx ctx;
++ md5_init_ctx (&ctx);
++ if (bed->s->checksum_contents (abfd,
++ (void (*) (const void *, size_t, void *))
++ &md5_process_bytes,
++ &ctx))
++ md5_finish_ctx (&ctx, id_bits);
++ else
++ return FALSE;
++ }
++ else if (!strcmp (info->style, "sha1"))
++ {
++ struct sha1_ctx ctx;
++ sha1_init_ctx (&ctx);
++ if (bed->s->checksum_contents (abfd,
++ (void (*) (const void *, size_t, void *))
++ &sha1_process_bytes,
++ &ctx))
++ sha1_finish_ctx (&ctx, id_bits);
++ else
++ return FALSE;
++ }
++ else if (!strcmp (info->style, "uuid"))
++ {
++ int n;
++ int fd = open ("/dev/urandom", O_RDONLY);
++ if (fd < 0)
++ return FALSE;
++ n = read (fd, id_bits, size);
++ close (fd);
++ if (n < (int) size)
++ return FALSE;
++ }
++ else if (!strncmp (info->style, "0x", 2))
++ {
++ /* ID is in string form (hex). Convert to bits. */
++ const char *id = info->style + 2;
++ size_t n = 0;
++ do
++ {
++ if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
++ {
++ id_bits[n] = read_hex (*id++) << 4;
++ id_bits[n++] |= read_hex (*id++);
++ }
++ else if (*id == '-' || *id == ':')
++ ++id;
++ else
++ abort (); /* Should have been validated earlier. */
++ } while (*id != '\0');
++ }
++ else
++ abort (); /* Should have been validated earlier. */
++
++ size = asec->size;
++ return (bfd_seek (abfd,
++ i_shdr->sh_offset + asec->output_offset, SEEK_SET) == 0
++ && bfd_bwrite (contents, size, abfd) == size);
++}
++
++
++/* This is called after all the input files have been opened. */
++
++static void
++gld${EMULATION_NAME}_after_open (void)
++{
++ struct bfd_link_needed_list *needed, *l;
++ struct elf_link_hash_table *htab;
++
++ after_open_default ();
++
++ htab = elf_hash_table (&link_info);
++ if (!is_elf_hash_table (htab))
++ return;
++
++ if (link_info.emit_note_gnu_build_id)
++ {
++ bfd *abfd;
++ asection *s;
++ bfd_size_type size;
++
++ /* Find an ELF input. */
++ for (abfd = link_info.input_bfds;
++ abfd != (bfd *) NULL; abfd = abfd->link_next)
++ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
++ break;
++
++ if (abfd == NULL)
++ {
++ /* PR 10555: If there are no input files do not
++ try to create a .note.gnu-build-id section. */
++ free (link_info.emit_note_gnu_build_id);
++ link_info.emit_note_gnu_build_id = NULL;
++ }
++ else
++ {
++ size = gld${EMULATION_NAME}_id_note_section_size (abfd, &link_info);
++ if (size == 0)
++ {
++ einfo ("%P: warning: unrecognized --build-id style ignored.\n");
++ free (link_info.emit_note_gnu_build_id);
++ link_info.emit_note_gnu_build_id = NULL;
++ }
++ else
++ {
++ s = bfd_make_section_with_flags (abfd, ".note.gnu.build-id",
++ SEC_ALLOC | SEC_LOAD
++ | SEC_IN_MEMORY | SEC_LINKER_CREATED
++ | SEC_READONLY | SEC_DATA);
++ if (s != NULL && bfd_set_section_alignment (abfd, s, 2))
++ {
++ struct elf_obj_tdata *t = elf_tdata (link_info.output_bfd);
++ struct build_id_info *b =
++ (struct build_id_info *) xmalloc (sizeof *b);
++
++ b->style = link_info.emit_note_gnu_build_id;
++ b->sec = s;
++ elf_section_type (s) = SHT_NOTE;
++ s->size = size;
++ t->after_write_object_contents
++ = &gld${EMULATION_NAME}_write_build_id_section;
++ t->after_write_object_contents_info = b;
++ }
++ else
++ {
++ einfo ("%P: warning: Cannot create .note.gnu.build-id section,"
++ " --build-id ignored.\n");
++ free (link_info.emit_note_gnu_build_id);
++ link_info.emit_note_gnu_build_id = NULL;
++ }
++ }
++ }
++ }
++
++ if (link_info.relocatable)
++ return;
++
++ if (link_info.eh_frame_hdr
++ && !link_info.traditional_format)
++ {
++ bfd *abfd, *elfbfd = NULL;
++ bfd_boolean warn_eh_frame = FALSE;
++ asection *s;
++
++ for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next)
++ {
++ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
++ elfbfd = abfd;
++ if (!warn_eh_frame)
++ {
++ s = bfd_get_section_by_name (abfd, ".eh_frame");
++ while (s != NULL
++ && (s->size <= 8
++ || bfd_is_abs_section (s->output_section)))
++ s = bfd_get_next_section_by_name (s);
++ warn_eh_frame = s != NULL;
++ }
++ if (elfbfd && warn_eh_frame)
++ break;
++ }
++ if (elfbfd)
++ {
++ const struct elf_backend_data *bed;
++
++ bed = get_elf_backend_data (elfbfd);
++ s = bfd_make_section_with_flags (elfbfd, ".eh_frame_hdr",
++ bed->dynamic_sec_flags
++ | SEC_READONLY);
++ if (s != NULL
++ && bfd_set_section_alignment (elfbfd, s, 2))
++ {
++ htab->eh_info.hdr_sec = s;
++ warn_eh_frame = FALSE;
++ }
++ }
++ if (warn_eh_frame)
++ einfo ("%P: warning: Cannot create .eh_frame_hdr section,"
++ " --eh-frame-hdr ignored.\n");
++ }
++
++ /* Get the list of files which appear in DT_NEEDED entries in
++ dynamic objects included in the link (often there will be none).
++ For each such file, we want to track down the corresponding
++ library, and include the symbol table in the link. This is what
++ the runtime dynamic linker will do. Tracking the files down here
++ permits one dynamic object to include another without requiring
++ special action by the person doing the link. Note that the
++ needed list can actually grow while we are stepping through this
++ loop. */
++ needed = bfd_elf_get_needed_list (link_info.output_bfd, &link_info);
++ for (l = needed; l != NULL; l = l->next)
++ {
++ struct bfd_link_needed_list *ll;
++ struct dt_needed n, nn;
++ int force;
++
++ /* If the lib that needs this one was --as-needed and wasn't
++ found to be needed, then this lib isn't needed either. Skip
++ the lib when creating a shared object unless we are copying
++ DT_NEEDED entres. */
++ if (l->by != NULL
++ && ((bfd_elf_get_dyn_lib_class (l->by) & DYN_AS_NEEDED) != 0
++ || (!link_info.executable
++ && bfd_elf_get_dyn_lib_class (l->by) & DYN_NO_ADD_NEEDED) != 0))
++ continue;
++
++ /* If we've already seen this file, skip it. */
++ for (ll = needed; ll != l; ll = ll->next)
++ if ((ll->by == NULL
++ || (bfd_elf_get_dyn_lib_class (ll->by) & DYN_AS_NEEDED) == 0)
++ && strcmp (ll->name, l->name) == 0)
++ break;
++ if (ll != l)
++ continue;
++
++ /* See if this file was included in the link explicitly. */
++ global_needed = l;
++ global_found = NULL;
++ lang_for_each_input_file (gld${EMULATION_NAME}_check_needed);
++ if (global_found != NULL
++ && (bfd_elf_get_dyn_lib_class (global_found->the_bfd)
++ & DYN_AS_NEEDED) == 0)
++ continue;
++
++ n.by = l->by;
++ n.name = l->name;
++ nn.by = l->by;
++ if (verbose)
++ info_msg (_("%s needed by %B\n"), l->name, l->by);
++
++ /* As-needed libs specified on the command line (or linker script)
++ take priority over libs found in search dirs. */
++ if (global_found != NULL)
++ {
++ nn.name = global_found->filename;
++ if (gld${EMULATION_NAME}_try_needed (&nn, TRUE))
++ continue;
++ }
++
++ /* We need to find this file and include the symbol table. We
++ want to search for the file in the same way that the dynamic
++ linker will search. That means that we want to use
++ rpath_link, rpath, then the environment variable
++ LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH
++ entries (native only), then the linker script LIB_SEARCH_DIRS.
++ We do not search using the -L arguments.
++
++ We search twice. The first time, we skip objects which may
++ introduce version mismatches. The second time, we force
++ their use. See gld${EMULATION_NAME}_vercheck comment. */
++ for (force = 0; force < 2; force++)
++ {
++ size_t len;
++ search_dirs_type *search;
++EOF
++if [ "x${NATIVE}" = xyes ] ; then
++fragment <<EOF
++ const char *lib_path;
++EOF
++fi
++if [ "x${USE_LIBPATH}" = xyes ] ; then
++fragment <<EOF
++ struct bfd_link_needed_list *rp;
++ int found;
++EOF
++fi
++fragment <<EOF
++
++ if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
++ &n, force))
++ break;
++EOF
++if [ "x${USE_LIBPATH}" = xyes ] ; then
++fragment <<EOF
++ if (gld${EMULATION_NAME}_search_needed (command_line.rpath,
++ &n, force))
++ break;
++EOF
++fi
++if [ "x${NATIVE}" = xyes ] ; then
++fragment <<EOF
++ if (command_line.rpath_link == NULL
++ && command_line.rpath == NULL)
++ {
++ lib_path = (const char *) getenv ("LD_RUN_PATH");
++ if (gld${EMULATION_NAME}_search_needed (lib_path, &n,
++ force))
++ break;
++ }
++ lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
++ if (gld${EMULATION_NAME}_search_needed (lib_path, &n, force))
++ break;
++EOF
++fi
++if [ "x${USE_LIBPATH}" = xyes ] ; then
++fragment <<EOF
++ found = 0;
++ rp = bfd_elf_get_runpath_list (link_info.output_bfd, &link_info);
++ for (; !found && rp != NULL; rp = rp->next)
++ {
++ char *tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name);
++ found = (rp->by == l->by
++ && gld${EMULATION_NAME}_search_needed (tmpname,
++ &n,
++ force));
++ free (tmpname);
++ }
++ if (found)
++ break;
++
++EOF
++fi
++if [ "x${USE_LIBPATH}" = xyes ] ; then
++ case ${target} in
++ *-*-freebsd* | *-*-dragonfly*)
++ fragment <<EOF
++ if (gld${EMULATION_NAME}_check_ld_elf_hints (l, force))
++ break;
++EOF
++ # FreeBSD
++ ;;
++
++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*)
++ # Linux
++ fragment <<EOF
++ if (gld${EMULATION_NAME}_check_ld_so_conf (l, force))
++ break;
++
++EOF
++ ;;
++ esac
++fi
++fragment <<EOF
++ len = strlen (l->name);
++ for (search = search_head; search != NULL; search = search->next)
++ {
++ char *filename;
++
++ if (search->cmdline)
++ continue;
++ filename = (char *) xmalloc (strlen (search->name) + len + 2);
++ sprintf (filename, "%s/%s", search->name, l->name);
++ nn.name = filename;
++ if (gld${EMULATION_NAME}_try_needed (&nn, force))
++ break;
++ free (filename);
++ }
++ if (search != NULL)
++ break;
++EOF
++fragment <<EOF
++ }
++
++ if (force < 2)
++ continue;
++
++ einfo ("%P: warning: %s, needed by %B, not found (try using -rpath or -rpath-link)\n",
++ l->name, l->by);
++ }
++}
++
++EOF
++fi
++
++fragment <<EOF
++
++/* Look through an expression for an assignment statement. */
++
++static void
++gld${EMULATION_NAME}_find_exp_assignment (etree_type *exp)
++{
++ bfd_boolean provide = FALSE;
++
++ switch (exp->type.node_class)
++ {
++ case etree_provide:
++ case etree_provided:
++ provide = TRUE;
++ /* Fall thru */
++ case etree_assign:
++ /* We call record_link_assignment even if the symbol is defined.
++ This is because if it is defined by a dynamic object, we
++ actually want to use the value defined by the linker script,
++ not the value from the dynamic object (because we are setting
++ symbols like etext). If the symbol is defined by a regular
++ object, then, as it happens, calling record_link_assignment
++ will do no harm. */
++ if (strcmp (exp->assign.dst, ".") != 0)
++ {
++ if (!bfd_elf_record_link_assignment (link_info.output_bfd,
++ &link_info,
++ exp->assign.dst, provide,
++ exp->assign.hidden))
++ einfo ("%P%F: failed to record assignment to %s: %E\n",
++ exp->assign.dst);
++ }
++ gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src);
++ break;
++
++ case etree_binary:
++ gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs);
++ gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs);
++ break;
++
++ case etree_trinary:
++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond);
++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs);
++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs);
++ break;
++
++ case etree_unary:
++ gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child);
++ break;
++
++ default:
++ break;
++ }
++}
++
++
++/* This is called by the before_allocation routine via
++ lang_for_each_statement. It locates any assignment statements, and
++ tells the ELF backend about them, in case they are assignments to
++ symbols which are referred to by dynamic objects. */
++
++static void
++gld${EMULATION_NAME}_find_statement_assignment (lang_statement_union_type *s)
++{
++ if (s->header.type == lang_assignment_statement_enum)
++ gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
++}
++
++EOF
++
++if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then
++ if test x"${ELF_INTERPRETER_NAME+set}" = xset; then
++ ELF_INTERPRETER_SET_DEFAULT="
++ if (sinterp != NULL)
++ {
++ sinterp->contents = (unsigned char *) ${ELF_INTERPRETER_NAME};
++ sinterp->size = strlen ((char *) sinterp->contents) + 1;
++ }
++
++"
++ else
++ ELF_INTERPRETER_SET_DEFAULT=
++ fi
++fragment <<EOF
++
++/* used by before_allocation and handle_option. */
++static void
++gld${EMULATION_NAME}_append_to_separated_string (char **to, char *op_arg)
++{
++ if (*to == NULL)
++ *to = xstrdup (op_arg);
++ else
++ {
++ size_t to_len = strlen (*to);
++ size_t op_arg_len = strlen (op_arg);
++ char *buf;
++ char *cp = *to;
++
++ /* First see whether OPTARG is already in the path. */
++ do
++ {
++ if (strncmp (op_arg, cp, op_arg_len) == 0
++ && (cp[op_arg_len] == 0
++ || cp[op_arg_len] == config.rpath_separator))
++ /* We found it. */
++ break;
++
++ /* Not yet found. */
++ cp = strchr (cp, config.rpath_separator);
++ if (cp != NULL)
++ ++cp;
++ }
++ while (cp != NULL);
++
++ if (cp == NULL)
++ {
++ buf = xmalloc (to_len + op_arg_len + 2);
++ sprintf (buf, "%s%c%s", *to,
++ config.rpath_separator, op_arg);
++ free (*to);
++ *to = buf;
++ }
++ }
++}
++
++/* This is called after the sections have been attached to output
++ sections, but before any sizes or addresses have been set. */
++
++static void
++gld${EMULATION_NAME}_before_allocation (void)
++{
++ const char *rpath;
++ asection *sinterp;
++ bfd *abfd;
++
++ if (link_info.hash->type == bfd_link_elf_hash_table)
++ _bfd_elf_tls_setup (link_info.output_bfd, &link_info);
++
++ /* If we are going to make any variable assignments, we need to let
++ the ELF backend know about them in case the variables are
++ referred to by dynamic objects. */
++ lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment);
++
++ /* Let the ELF backend work out the sizes of any sections required
++ by dynamic linking. */
++ rpath = command_line.rpath;
++ if (rpath == NULL)
++ rpath = (const char *) getenv ("LD_RUN_PATH");
++
++ for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next)
++ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
++ {
++ const char *audit_libs = elf_dt_audit (abfd);
++
++ /* If the input bfd contains an audit entry, we need to add it as
++ a dep audit entry. */
++ if (audit_libs && *audit_libs != '\0')
++ {
++ char *cp = xstrdup (audit_libs);
++ do
++ {
++ int more = 0;
++ char *cp2 = strchr (cp, config.rpath_separator);
++
++ if (cp2)
++ {
++ *cp2 = '\0';
++ more = 1;
++ }
++
++ if (cp != NULL && *cp != '\0')
++ gld${EMULATION_NAME}_append_to_separated_string (&depaudit, cp);
++
++ cp = more ? ++cp2 : NULL;
++ }
++ while (cp != NULL);
++ }
++ }
++
++ if (! (bfd_elf_size_dynamic_sections
++ (link_info.output_bfd, command_line.soname, rpath,
++ command_line.filter_shlib, audit, depaudit,
++ (const char * const *) command_line.auxiliary_filters,
++ &link_info, &sinterp)))
++ einfo ("%P%F: failed to set dynamic section sizes: %E\n");
++
++${ELF_INTERPRETER_SET_DEFAULT}
++ /* Let the user override the dynamic linker we are using. */
++ if (command_line.interpreter != NULL
++ && sinterp != NULL)
++ {
++ sinterp->contents = (bfd_byte *) command_line.interpreter;
++ sinterp->size = strlen (command_line.interpreter) + 1;
++ }
++
++ /* Look for any sections named .gnu.warning. As a GNU extensions,
++ we treat such sections as containing warning messages. We print
++ out the warning message, and then zero out the section size so
++ that it does not get copied into the output file. */
++
++ {
++ LANG_FOR_EACH_INPUT_STATEMENT (is)
++ {
++ asection *s;
++ bfd_size_type sz;
++ char *msg;
++ bfd_boolean ret;
++
++ if (is->flags.just_syms)
++ continue;
++
++ s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning");
++ if (s == NULL)
++ continue;
++
++ sz = s->size;
++ msg = (char *) xmalloc ((size_t) (sz + 1));
++ if (! bfd_get_section_contents (is->the_bfd, s, msg,
++ (file_ptr) 0, sz))
++ einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n",
++ is->the_bfd);
++ msg[sz] = '\0';
++ ret = link_info.callbacks->warning (&link_info, msg,
++ (const char *) NULL,
++ is->the_bfd, (asection *) NULL,
++ (bfd_vma) 0);
++ ASSERT (ret);
++ free (msg);
++
++ /* Clobber the section size, so that we don't waste space
++ copying the warning into the output file. If we've already
++ sized the output section, adjust its size. The adjustment
++ is on rawsize because targets that size sections early will
++ have called lang_reset_memory_regions after sizing. */
++ if (s->output_section != NULL
++ && s->output_section->rawsize >= s->size)
++ s->output_section->rawsize -= s->size;
++
++ s->size = 0;
++
++ /* Also set SEC_EXCLUDE, so that local symbols defined in the
++ warning section don't get copied to the output. */
++ s->flags |= SEC_EXCLUDE | SEC_KEEP;
++ }
++ }
++
++ before_allocation_default ();
++
++ if (!bfd_elf_size_dynsym_hash_dynstr (link_info.output_bfd, &link_info))
++ einfo ("%P%F: failed to set dynamic section sizes: %E\n");
++}
++
++EOF
++fi
++
++if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then
++fragment <<EOF
++
++/* Try to open a dynamic archive. This is where we know that ELF
++ dynamic libraries have an extension of .so (or .sl on oddball systems
++ like hpux). */
++
++static bfd_boolean
++gld${EMULATION_NAME}_open_dynamic_archive
++ (const char *arch, search_dirs_type *search, lang_input_statement_type *entry)
++{
++ const char *filename;
++ char *string;
++
++ if (! entry->flags.maybe_archive)
++ return FALSE;
++
++ filename = entry->filename;
++
++ /* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION
++ is defined, but it does not seem worth the headache to optimize
++ away those two bytes of space. */
++ string = (char *) xmalloc (strlen (search->name)
++ + strlen (filename)
++ + strlen (arch)
++#ifdef EXTRA_SHLIB_EXTENSION
++ + strlen (EXTRA_SHLIB_EXTENSION)
++#endif
++ + sizeof "/lib.so");
++
++ sprintf (string, "%s/lib%s%s.so", search->name, filename, arch);
++
++#ifdef EXTRA_SHLIB_EXTENSION
++ /* Try the .so extension first. If that fails build a new filename
++ using EXTRA_SHLIB_EXTENSION. */
++ if (! ldfile_try_open_bfd (string, entry))
++ {
++ sprintf (string, "%s/lib%s%s%s", search->name,
++ filename, arch, EXTRA_SHLIB_EXTENSION);
++#endif
++
++ if (! ldfile_try_open_bfd (string, entry))
++ {
++ free (string);
++ return FALSE;
++ }
++#ifdef EXTRA_SHLIB_EXTENSION
++ }
++#endif
++
++ entry->filename = string;
++
++ /* We have found a dynamic object to include in the link. The ELF
++ backend linker will create a DT_NEEDED entry in the .dynamic
++ section naming this file. If this file includes a DT_SONAME
++ entry, it will be used. Otherwise, the ELF linker will just use
++ the name of the file. For an archive found by searching, like
++ this one, the DT_NEEDED entry should consist of just the name of
++ the file, without the path information used to find it. Note
++ that we only need to do this if we have a dynamic object; an
++ archive will never be referenced by a DT_NEEDED entry.
++
++ FIXME: This approach--using bfd_elf_set_dt_needed_name--is not
++ very pretty. I haven't been able to think of anything that is
++ pretty, though. */
++ if (bfd_check_format (entry->the_bfd, bfd_object)
++ && (entry->the_bfd->flags & DYNAMIC) != 0)
++ {
++ ASSERT (entry->flags.maybe_archive && entry->flags.search_dirs);
++
++ /* Rather than duplicating the logic above. Just use the
++ filename we recorded earlier. */
++
++ filename = lbasename (entry->filename);
++ bfd_elf_set_dt_needed_name (entry->the_bfd, filename);
++ }
++
++ return TRUE;
++}
++
++EOF
++fi
++
++if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
++fragment <<EOF
++
++/* A variant of lang_output_section_find used by place_orphan. */
++
++static lang_output_section_statement_type *
++output_rel_find (asection *sec, int isdyn)
++{
++ lang_output_section_statement_type *lookup;
++ lang_output_section_statement_type *last = NULL;
++ lang_output_section_statement_type *last_alloc = NULL;
++ lang_output_section_statement_type *last_ro_alloc = NULL;
++ lang_output_section_statement_type *last_rel = NULL;
++ lang_output_section_statement_type *last_rel_alloc = NULL;
++ int rela = sec->name[4] == 'a';
++
++ for (lookup = &lang_output_section_statement.head->output_section_statement;
++ lookup != NULL;
++ lookup = lookup->next)
++ {
++ if (lookup->constraint >= 0
++ && CONST_STRNEQ (lookup->name, ".rel"))
++ {
++ int lookrela = lookup->name[4] == 'a';
++
++ /* .rel.dyn must come before all other reloc sections, to suit
++ GNU ld.so. */
++ if (isdyn)
++ break;
++
++ /* Don't place after .rel.plt as doing so results in wrong
++ dynamic tags. */
++ if (strcmp (".plt", lookup->name + 4 + lookrela) == 0)
++ break;
++
++ if (rela == lookrela || last_rel == NULL)
++ last_rel = lookup;
++ if ((rela == lookrela || last_rel_alloc == NULL)
++ && lookup->bfd_section != NULL
++ && (lookup->bfd_section->flags & SEC_ALLOC) != 0)
++ last_rel_alloc = lookup;
++ }
++
++ last = lookup;
++ if (lookup->bfd_section != NULL
++ && (lookup->bfd_section->flags & SEC_ALLOC) != 0)
++ {
++ last_alloc = lookup;
++ if ((lookup->bfd_section->flags & SEC_READONLY) != 0)
++ last_ro_alloc = lookup;
++ }
++ }
++
++ if (last_rel_alloc)
++ return last_rel_alloc;
++
++ if (last_rel)
++ return last_rel;
++
++ if (last_ro_alloc)
++ return last_ro_alloc;
++
++ if (last_alloc)
++ return last_alloc;
++
++ return last;
++}
++
++/* Place an orphan section. We use this to put random SHF_ALLOC
++ sections in the right segment. */
++
++static lang_output_section_statement_type *
++gld${EMULATION_NAME}_place_orphan (asection *s,
++ const char *secname,
++ int constraint)
++{
++ static struct orphan_save hold[] =
++ {
++ { ".text",
++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE,
++ 0, 0, 0, 0 },
++ { ".rodata",
++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
++ 0, 0, 0, 0 },
++ { ".data",
++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA,
++ 0, 0, 0, 0 },
++ { ".bss",
++ SEC_ALLOC,
++ 0, 0, 0, 0 },
++ { 0,
++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
++ 0, 0, 0, 0 },
++ { ".interp",
++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
++ 0, 0, 0, 0 },
++ { ".sdata",
++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA,
++ 0, 0, 0, 0 },
++ { ".comment",
++ SEC_HAS_CONTENTS,
++ 0, 0, 0, 0 },
++ };
++ enum orphan_save_index
++ {
++ orphan_text = 0,
++ orphan_rodata,
++ orphan_data,
++ orphan_bss,
++ orphan_rel,
++ orphan_interp,
++ orphan_sdata,
++ orphan_nonalloc
++ };
++ static int orphan_init_done = 0;
++ struct orphan_save *place;
++ lang_output_section_statement_type *after;
++ lang_output_section_statement_type *os;
++ lang_output_section_statement_type *match_by_name = NULL;
++ int isdyn = 0;
++ int iself = s->owner->xvec->flavour == bfd_target_elf_flavour;
++ unsigned int sh_type = iself ? elf_section_type (s) : SHT_NULL;
++
++ if (! link_info.relocatable
++ && link_info.combreloc
++ && (s->flags & SEC_ALLOC))
++ {
++ if (iself)
++ switch (sh_type)
++ {
++ case SHT_RELA:
++ secname = ".rela.dyn";
++ isdyn = 1;
++ break;
++ case SHT_REL:
++ secname = ".rel.dyn";
++ isdyn = 1;
++ break;
++ default:
++ break;
++ }
++ else if (CONST_STRNEQ (secname, ".rel"))
++ {
++ secname = secname[4] == 'a' ? ".rela.dyn" : ".rel.dyn";
++ isdyn = 1;
++ }
++ }
++
++ /* Look through the script to see where to place this section. */
++ if (constraint == 0)
++ for (os = lang_output_section_find (secname);
++ os != NULL;
++ os = next_matching_output_section_statement (os, 0))
++ {
++ /* If we don't match an existing output section, tell
++ lang_insert_orphan to create a new output section. */
++ constraint = SPECIAL;
++
++ if (os->bfd_section != NULL
++ && (os->bfd_section->flags == 0
++ || (_bfd_elf_match_sections_by_type (link_info.output_bfd,
++ os->bfd_section,
++ s->owner, s)
++ && ((s->flags ^ os->bfd_section->flags)
++ & (SEC_LOAD | SEC_ALLOC)) == 0)))
++ {
++ /* We already have an output section statement with this
++ name, and its bfd section has compatible flags.
++ If the section already exists but does not have any flags
++ set, then it has been created by the linker, probably as a
++ result of a --section-start command line switch. */
++ lang_add_section (&os->children, s, NULL, os);
++ return os;
++ }
++
++ /* Save unused output sections in case we can match them
++ against orphans later. */
++ if (os->bfd_section == NULL)
++ match_by_name = os;
++ }
++
++ /* If we didn't match an active output section, see if we matched an
++ unused one and use that. */
++ if (match_by_name)
++ {
++ lang_add_section (&match_by_name->children, s, NULL, match_by_name);
++ return match_by_name;
++ }
++
++ if (!orphan_init_done)
++ {
++ struct orphan_save *ho;
++
++ for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho)
++ if (ho->name != NULL)
++ {
++ ho->os = lang_output_section_find (ho->name);
++ if (ho->os != NULL && ho->os->flags == 0)
++ ho->os->flags = ho->flags;
++ }
++ orphan_init_done = 1;
++ }
++
++ /* If this is a final link, then always put .gnu.warning.SYMBOL
++ sections into the .text section to get them out of the way. */
++ if (link_info.executable
++ && ! link_info.relocatable
++ && CONST_STRNEQ (s->name, ".gnu.warning.")
++ && hold[orphan_text].os != NULL)
++ {
++ os = hold[orphan_text].os;
++ lang_add_section (&os->children, s, NULL, os);
++ return os;
++ }
++
++ /* Decide which segment the section should go in based on the
++ section name and section flags. We put loadable .note sections
++ right after the .interp section, so that the PT_NOTE segment is
++ stored right after the program headers where the OS can read it
++ in the first page. */
++
++ place = NULL;
++ if ((s->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
++ place = &hold[orphan_nonalloc];
++ else if ((s->flags & SEC_ALLOC) == 0)
++ ;
++ else if ((s->flags & SEC_LOAD) != 0
++ && ((iself && sh_type == SHT_NOTE)
++ || (!iself && CONST_STRNEQ (secname, ".note"))))
++ place = &hold[orphan_interp];
++ else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) == 0)
++ place = &hold[orphan_bss];
++ else if ((s->flags & SEC_SMALL_DATA) != 0)
++ place = &hold[orphan_sdata];
++ else if ((s->flags & SEC_READONLY) == 0)
++ place = &hold[orphan_data];
++ else if (((iself && (sh_type == SHT_RELA || sh_type == SHT_REL))
++ || (!iself && CONST_STRNEQ (secname, ".rel")))
++ && (s->flags & SEC_LOAD) != 0)
++ place = &hold[orphan_rel];
++ else if ((s->flags & SEC_CODE) == 0)
++ place = &hold[orphan_rodata];
++ else
++ place = &hold[orphan_text];
++
++ after = NULL;
++ if (place != NULL)
++ {
++ if (place->os == NULL)
++ {
++ if (place->name != NULL)
++ place->os = lang_output_section_find (place->name);
++ else
++ place->os = output_rel_find (s, isdyn);
++ }
++ after = place->os;
++ if (after == NULL)
++ after = lang_output_section_find_by_flags
++ (s, &place->os, _bfd_elf_match_sections_by_type);
++ if (after == NULL)
++ /* *ABS* is always the first output section statement. */
++ after = &lang_output_section_statement.head->output_section_statement;
++ }
++
++ return lang_insert_orphan (s, secname, constraint, after, place, NULL, NULL);
++}
++EOF
++fi
++
++if test x"$LDEMUL_AFTER_ALLOCATION" != xgld"$EMULATION_NAME"_after_allocation; then
++fragment <<EOF
++
++static void
++gld${EMULATION_NAME}_after_allocation (void)
++{
++ bfd_boolean need_layout = bfd_elf_discard_info (link_info.output_bfd,
++ &link_info);
++ gld${EMULATION_NAME}_map_segments (need_layout);
++}
++EOF
++fi
++
++if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then
++fragment <<EOF
++
++static char *
++gld${EMULATION_NAME}_get_script (int *isfile)
++EOF
++
++if test -n "$COMPILE_IN"
++then
++# Scripts compiled in.
++
++# sed commands to quote an ld script as a C string.
++sc="-f stringify.sed"
++
++fragment <<EOF
++{
++ *isfile = 0;
++
++ if (link_info.relocatable && config.build_constructors)
++ return
++EOF
++sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c
++echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c
++echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c
++if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else
++echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c
++fi
++if test -n "$GENERATE_PIE_SCRIPT" ; then
++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
++echo ' ; else if (link_info.pie && link_info.combreloc' >> e${EMULATION_NAME}.c
++echo ' && link_info.relro' >> e${EMULATION_NAME}.c
++echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c
++echo ' ; else if (link_info.pie && link_info.combreloc) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c
++fi
++echo ' ; else if (link_info.pie) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xd >> e${EMULATION_NAME}.c
++fi
++if test -n "$GENERATE_SHLIB_SCRIPT" ; then
++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
++echo ' ; else if (link_info.shared && link_info.combreloc' >> e${EMULATION_NAME}.c
++echo ' && link_info.relro' >> e${EMULATION_NAME}.c
++echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c
++echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c
++fi
++echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c
++fi
++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
++echo ' ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c
++echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c
++echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c
++fi
++echo ' ; else return' >> e${EMULATION_NAME}.c
++sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c
++echo '; }' >> e${EMULATION_NAME}.c
++
++else
++# Scripts read from the filesystem.
++
++fragment <<EOF
++{
++ *isfile = 1;
++
++ if (link_info.relocatable && config.build_constructors)
++ return "ldscripts/${EMULATION_NAME}.xu";
++ else if (link_info.relocatable)
++ return "ldscripts/${EMULATION_NAME}.xr";
++ else if (!config.text_read_only)
++ return "ldscripts/${EMULATION_NAME}.xbn";
++EOF
++if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then :
++else
++fragment <<EOF
++ else if (!config.magic_demand_paged)
++ return "ldscripts/${EMULATION_NAME}.xn";
++EOF
++fi
++if test -n "$GENERATE_PIE_SCRIPT" ; then
++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
++fragment <<EOF
++ else if (link_info.pie && link_info.combreloc
++ && link_info.relro && (link_info.flags & DF_BIND_NOW))
++ return "ldscripts/${EMULATION_NAME}.xdw";
++ else if (link_info.pie && link_info.combreloc)
++ return "ldscripts/${EMULATION_NAME}.xdc";
++EOF
++fi
++fragment <<EOF
++ else if (link_info.pie)
++ return "ldscripts/${EMULATION_NAME}.xd";
++EOF
++fi
++if test -n "$GENERATE_SHLIB_SCRIPT" ; then
++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
++fragment <<EOF
++ else if (link_info.shared && link_info.combreloc
++ && link_info.relro && (link_info.flags & DF_BIND_NOW))
++ return "ldscripts/${EMULATION_NAME}.xsw";
++ else if (link_info.shared && link_info.combreloc)
++ return "ldscripts/${EMULATION_NAME}.xsc";
++EOF
++fi
++fragment <<EOF
++ else if (link_info.shared)
++ return "ldscripts/${EMULATION_NAME}.xs";
++EOF
++fi
++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
++fragment <<EOF
++ else if (link_info.combreloc && link_info.relro
++ && (link_info.flags & DF_BIND_NOW))
++ return "ldscripts/${EMULATION_NAME}.xw";
++ else if (link_info.combreloc)
++ return "ldscripts/${EMULATION_NAME}.xc";
++EOF
++fi
++fragment <<EOF
++ else
++ return "ldscripts/${EMULATION_NAME}.x";
++}
++
++EOF
++fi
++fi
++
++if test -n "$PARSE_AND_LIST_PROLOGUE" ; then
++fragment <<EOF
++ $PARSE_AND_LIST_PROLOGUE
++EOF
++fi
++
++fragment <<EOF
++
++#define OPTION_DISABLE_NEW_DTAGS (400)
++#define OPTION_ENABLE_NEW_DTAGS (OPTION_DISABLE_NEW_DTAGS + 1)
++#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1)
++#define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1)
++#define OPTION_EXCLUDE_LIBS (OPTION_EH_FRAME_HDR + 1)
++#define OPTION_HASH_STYLE (OPTION_EXCLUDE_LIBS + 1)
++#define OPTION_BUILD_ID (OPTION_HASH_STYLE + 1)
++#define OPTION_AUDIT (OPTION_BUILD_ID + 1)
++
++static void
++gld${EMULATION_NAME}_add_options
++ (int ns, char **shortopts, int nl, struct option **longopts,
++ int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED)
++{
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ static const char xtra_short[] = "${PARSE_AND_LIST_SHORTOPTS}z:P:";
++EOF
++else
++fragment <<EOF
++ static const char xtra_short[] = "${PARSE_AND_LIST_SHORTOPTS}z:";
++EOF
++fi
++fragment <<EOF
++ static const struct option xtra_long[] = {
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ {"audit", required_argument, NULL, OPTION_AUDIT},
++ {"Bgroup", no_argument, NULL, OPTION_GROUP},
++EOF
++fi
++fragment <<EOF
++ {"build-id", optional_argument, NULL, OPTION_BUILD_ID},
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ {"depaudit", required_argument, NULL, 'P'},
++ {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
++ {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
++ {"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR},
++ {"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS},
++ {"hash-style", required_argument, NULL, OPTION_HASH_STYLE},
++EOF
++fi
++if test -n "$PARSE_AND_LIST_LONGOPTS" ; then
++fragment <<EOF
++ $PARSE_AND_LIST_LONGOPTS
++EOF
++fi
++fragment <<EOF
++ {NULL, no_argument, NULL, 0}
++ };
++
++ *shortopts = (char *) xrealloc (*shortopts, ns + sizeof (xtra_short));
++ memcpy (*shortopts + ns, &xtra_short, sizeof (xtra_short));
++ *longopts = (struct option *)
++ xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long));
++ memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long));
++}
++
++#define DEFAULT_BUILD_ID_STYLE "sha1"
++
++static bfd_boolean
++gld${EMULATION_NAME}_handle_option (int optc)
++{
++ switch (optc)
++ {
++ default:
++ return FALSE;
++
++ case OPTION_BUILD_ID:
++ if (link_info.emit_note_gnu_build_id != NULL)
++ {
++ free (link_info.emit_note_gnu_build_id);
++ link_info.emit_note_gnu_build_id = NULL;
++ }
++ if (optarg == NULL)
++ optarg = DEFAULT_BUILD_ID_STYLE;
++ if (strcmp (optarg, "none"))
++ link_info.emit_note_gnu_build_id = xstrdup (optarg);
++ break;
++
++EOF
++
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ case OPTION_AUDIT:
++ gld${EMULATION_NAME}_append_to_separated_string (&audit, optarg);
++ break;
++
++ case 'P':
++ gld${EMULATION_NAME}_append_to_separated_string (&depaudit, optarg);
++ break;
++
++ case OPTION_DISABLE_NEW_DTAGS:
++ link_info.new_dtags = FALSE;
++ break;
++
++ case OPTION_ENABLE_NEW_DTAGS:
++ link_info.new_dtags = TRUE;
++ break;
++
++ case OPTION_EH_FRAME_HDR:
++ link_info.eh_frame_hdr = TRUE;
++ break;
++
++ case OPTION_GROUP:
++ link_info.flags_1 |= (bfd_vma) DF_1_GROUP;
++ /* Groups must be self-contained. */
++ link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR;
++ link_info.unresolved_syms_in_shared_libs = RM_GENERATE_ERROR;
++ break;
++
++ case OPTION_EXCLUDE_LIBS:
++ add_excluded_libs (optarg);
++ break;
++
++ case OPTION_HASH_STYLE:
++ link_info.emit_hash = FALSE;
++ link_info.emit_gnu_hash = FALSE;
++ if (strcmp (optarg, "sysv") == 0)
++ link_info.emit_hash = TRUE;
++ else if (strcmp (optarg, "gnu") == 0)
++ link_info.emit_gnu_hash = TRUE;
++ else if (strcmp (optarg, "both") == 0)
++ {
++ link_info.emit_hash = TRUE;
++ link_info.emit_gnu_hash = TRUE;
++ }
++ else
++ einfo (_("%P%F: invalid hash style \`%s'\n"), optarg);
++ break;
++
++EOF
++fi
++fragment <<EOF
++ case 'z':
++ if (strcmp (optarg, "defs") == 0)
++ link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR;
++ else if (strcmp (optarg, "muldefs") == 0)
++ link_info.allow_multiple_definition = TRUE;
++ else if (CONST_STRNEQ (optarg, "max-page-size="))
++ {
++ char *end;
++
++ config.maxpagesize = strtoul (optarg + 14, &end, 0);
++ if (*end || (config.maxpagesize & (config.maxpagesize - 1)) != 0)
++ einfo (_("%P%F: invalid maxium page size \`%s'\n"),
++ optarg + 14);
++ }
++ else if (CONST_STRNEQ (optarg, "common-page-size="))
++ {
++ char *end;
++ config.commonpagesize = strtoul (optarg + 17, &end, 0);
++ if (*end
++ || (config.commonpagesize & (config.commonpagesize - 1)) != 0)
++ einfo (_("%P%F: invalid common page size \`%s'\n"),
++ optarg + 17);
++ }
++ else if (strcmp (optarg, "execstack") == 0)
++ {
++ link_info.execstack = TRUE;
++ link_info.noexecstack = FALSE;
++ }
++ else if (strcmp (optarg, "noexecstack") == 0)
++ {
++ link_info.noexecstack = TRUE;
++ link_info.execstack = FALSE;
++ }
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ else if (strcmp (optarg, "initfirst") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST;
++ else if (strcmp (optarg, "interpose") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_INTERPOSE;
++ else if (strcmp (optarg, "loadfltr") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_LOADFLTR;
++ else if (strcmp (optarg, "nodefaultlib") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_NODEFLIB;
++ else if (strcmp (optarg, "nodelete") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_NODELETE;
++ else if (strcmp (optarg, "nodlopen") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_NOOPEN;
++ else if (strcmp (optarg, "nodump") == 0)
++ link_info.flags_1 |= (bfd_vma) DF_1_NODUMP;
++ else if (strcmp (optarg, "now") == 0)
++ {
++ link_info.flags |= (bfd_vma) DF_BIND_NOW;
++ link_info.flags_1 |= (bfd_vma) DF_1_NOW;
++ }
++ else if (strcmp (optarg, "lazy") == 0)
++ {
++ link_info.flags &= ~(bfd_vma) DF_BIND_NOW;
++ link_info.flags_1 &= ~(bfd_vma) DF_1_NOW;
++ }
++ else if (strcmp (optarg, "origin") == 0)
++ {
++ link_info.flags |= (bfd_vma) DF_ORIGIN;
++ link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN;
++ }
++ else if (strcmp (optarg, "combreloc") == 0)
++ link_info.combreloc = TRUE;
++ else if (strcmp (optarg, "nocombreloc") == 0)
++ link_info.combreloc = FALSE;
++ else if (strcmp (optarg, "nocopyreloc") == 0)
++ link_info.nocopyreloc = TRUE;
++ else if (strcmp (optarg, "relro") == 0)
++ link_info.relro = TRUE;
++ else if (strcmp (optarg, "norelro") == 0)
++ link_info.relro = FALSE;
++ else if (strcmp (optarg, "text") == 0)
++ link_info.error_textrel = TRUE;
++ else if (strcmp (optarg, "notext") == 0)
++ link_info.error_textrel = FALSE;
++ else if (strcmp (optarg, "textoff") == 0)
++ link_info.error_textrel = FALSE;
++EOF
++fi
++
++fragment <<EOF
++ else
++ einfo (_("%P: warning: -z %s ignored.\n"), optarg);
++ break;
++EOF
++
++if test -n "$PARSE_AND_LIST_ARGS_CASES" ; then
++fragment <<EOF
++ $PARSE_AND_LIST_ARGS_CASES
++EOF
++fi
++
++fragment <<EOF
++ }
++
++ return TRUE;
++}
++
++EOF
++
++if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then
++fragment <<EOF
++
++static void
++gld${EMULATION_NAME}_list_options (FILE * file)
++{
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ fprintf (file, _("\
++ --audit=AUDITLIB Specify a library to use for auditing\n"));
++ fprintf (file, _("\
++ -Bgroup Selects group name lookup rules for DSO\n"));
++EOF
++fi
++fragment <<EOF
++ fprintf (file, _("\
++ --build-id[=STYLE] Generate build ID note\n"));
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ fprintf (file, _("\
++ -P AUDITLIB, --depaudit=AUDITLIB\n" "\
++ Specify a library to use for auditing dependencies\n"));
++ fprintf (file, _("\
++ --disable-new-dtags Disable new dynamic tags\n"));
++ fprintf (file, _("\
++ --enable-new-dtags Enable new dynamic tags\n"));
++ fprintf (file, _("\
++ --eh-frame-hdr Create .eh_frame_hdr section\n"));
++ fprintf (file, _("\
++ --exclude-libs=LIBS Make all symbols in LIBS hidden\n"));
++ fprintf (file, _("\
++ --hash-style=STYLE Set hash style to sysv, gnu or both\n"));
++ fprintf (file, _("\
++ -z combreloc Merge dynamic relocs into one section and sort\n"));
++EOF
++fi
++
++fragment <<EOF
++ fprintf (file, _("\
++ -z common-page-size=SIZE Set common page size to SIZE\n"));
++ fprintf (file, _("\
++ -z defs Report unresolved symbols in object files.\n"));
++ fprintf (file, _("\
++ -z execstack Mark executable as requiring executable stack\n"));
++EOF
++
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ fprintf (file, _("\
++ -z initfirst Mark DSO to be initialized first at runtime\n"));
++ fprintf (file, _("\
++ -z interpose Mark object to interpose all DSOs but executable\n"));
++ fprintf (file, _("\
++ -z lazy Mark object lazy runtime binding (default)\n"));
++ fprintf (file, _("\
++ -z loadfltr Mark object requiring immediate process\n"));
++EOF
++fi
++
++fragment <<EOF
++ fprintf (file, _("\
++ -z max-page-size=SIZE Set maximum page size to SIZE\n"));
++ fprintf (file, _("\
++ -z muldefs Allow multiple definitions\n"));
++EOF
++
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ fprintf (file, _("\
++ -z nocombreloc Don't merge dynamic relocs into one section\n"));
++ fprintf (file, _("\
++ -z nocopyreloc Don't create copy relocs\n"));
++ fprintf (file, _("\
++ -z nodefaultlib Mark object not to use default search paths\n"));
++ fprintf (file, _("\
++ -z nodelete Mark DSO non-deletable at runtime\n"));
++ fprintf (file, _("\
++ -z nodlopen Mark DSO not available to dlopen\n"));
++ fprintf (file, _("\
++ -z nodump Mark DSO not available to dldump\n"));
++EOF
++fi
++fragment <<EOF
++ fprintf (file, _("\
++ -z noexecstack Mark executable as not requiring executable stack\n"));
++EOF
++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
++fragment <<EOF
++ fprintf (file, _("\
++ -z norelro Don't create RELRO program header\n"));
++ fprintf (file, _("\
++ -z now Mark object non-lazy runtime binding\n"));
++ fprintf (file, _("\
++ -z origin Mark object requiring immediate \$ORIGIN\n\
++ processing at runtime\n"));
++ fprintf (file, _("\
++ -z relro Create RELRO program header\n"));
++EOF
++fi
++
++if test -n "$PARSE_AND_LIST_OPTIONS" ; then
++fragment <<EOF
++ $PARSE_AND_LIST_OPTIONS
++EOF
++fi
++
++fragment <<EOF
++}
++EOF
++
++if test -n "$PARSE_AND_LIST_EPILOGUE" ; then
++fragment <<EOF
++ $PARSE_AND_LIST_EPILOGUE
++EOF
++fi
++fi
++
++fragment <<EOF
++
++struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
++{
++ ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
++ ${LDEMUL_SYSLIB-syslib_default},
++ ${LDEMUL_HLL-hll_default},
++ ${LDEMUL_AFTER_PARSE-after_parse_default},
++ ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open},
++ ${LDEMUL_AFTER_ALLOCATION-gld${EMULATION_NAME}_after_allocation},
++ ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
++ ${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
++ ${LDEMUL_BEFORE_ALLOCATION-gld${EMULATION_NAME}_before_allocation},
++ ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script},
++ "${EMULATION_NAME}",
++ "${OUTPUT_FORMAT}",
++ ${LDEMUL_FINISH-finish_default},
++ ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
++ ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-gld${EMULATION_NAME}_open_dynamic_archive},
++ ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
++ ${LDEMUL_SET_SYMBOLS-NULL},
++ ${LDEMUL_PARSE_ARGS-NULL},
++ gld${EMULATION_NAME}_add_options,
++ gld${EMULATION_NAME}_handle_option,
++ ${LDEMUL_UNRECOGNIZED_FILE-NULL},
++ ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options},
++ ${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols},
++ ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
++ ${LDEMUL_NEW_VERS_PATTERN-NULL}
++};
++EOF
+--- /dev/null 2015-09-06 08:42:34.091999986 +0100
++++ ld/scripttempl/amigaos.sc 2016-01-03 01:46:50.663001071 +0000
+@@ -0,0 +1,527 @@
++#
++# 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) }
++
++ /* 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${RELOCATING+ .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) }
++
++ /* DWARF 3 */
++ .debug_pubtypes 0 : { *(.debug_pubtypes) }
++ .debug_ranges 0 : { *(.debug_ranges) }
++
++ ${TINY_DATA_SECTION}
++ ${TINY_BSS_SECTION}
++
++ ${STACK_ADDR+${STACK}}
++ ${ATTRS_SECTIONS}
++ ${OTHER_SECTIONS}
++ ${RELOCATING+${OTHER_SYMBOLS}}
++ ${RELOCATING+${DISCARDED}}
++}
++EOF
diff --git a/ppc-amigaos/recipes/patches/binutils/remove_unused.p b/ppc-amigaos/recipes/patches/binutils/remove_unused.p
deleted file mode 100644
index dea60e9..0000000
--- a/ppc-amigaos/recipes/patches/binutils/remove_unused.p
+++ /dev/null
@@ -1,406 +0,0 @@
---- bfd/elf32-ppc.c.old 2014-01-04 16:37:47.404630311 +0000
-+++ bfd/elf32-ppc.c 2014-01-04 16:38:30.333547584 +0000
-@@ -4147,7 +4147,6 @@
- }
- else
- {
-- Elf_Internal_Sym *sym;
- bfd_signed_vma *lgot_refs;
- char *lgot_masks;
-
-@@ -4165,7 +4164,6 @@
- return FALSE;
- }
- }
-- sym = locsyms + r_symndx;
- lgot_refs = elf_local_got_refcounts (ibfd);
- if (lgot_refs == NULL)
- abort ();
---- bfd/elf.c.old 2014-01-04 16:30:59.089704808 +0000
-+++ bfd/elf.c 2014-01-04 16:34:48.929678864 +0000
-@@ -4649,13 +4649,10 @@
- prep_headers (bfd *abfd)
- {
- Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */
-- Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
-- Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */
- struct elf_strtab_hash *shstrtab;
- const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-
- i_ehdrp = elf_elfheader (abfd);
-- i_shdrp = elf_elfsections (abfd);
-
- shstrtab = _bfd_elf_strtab_init ();
- if (shstrtab == NULL)
-@@ -4719,7 +4716,6 @@
- else
- {
- i_ehdrp->e_phentsize = 0;
-- i_phdrp = 0;
- i_ehdrp->e_phoff = 0;
- }
-
-@@ -4767,7 +4763,6 @@
- _bfd_elf_write_object_contents (bfd *abfd)
- {
- const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-- Elf_Internal_Ehdr *i_ehdrp;
- Elf_Internal_Shdr **i_shdrp;
- bfd_boolean failed;
- unsigned int count, num_sec;
-@@ -4777,7 +4772,6 @@
- return FALSE;
-
- i_shdrp = elf_elfsections (abfd);
-- i_ehdrp = elf_elfheader (abfd);
-
- failed = FALSE;
- bfd_map_over_sections (abfd, bed->s->write_relocs, &failed);
---- binutils/dwarf.c.old 2014-01-04 16:44:22.393068874 +0000
-+++ binutils/dwarf.c 2014-01-04 16:45:12.317387306 +0000
-@@ -1589,7 +1589,6 @@
- {
- DWARF2_Internal_CompUnit compunit;
- unsigned char *hdrptr;
-- unsigned char *cu_abbrev_offset_ptr;
- unsigned char *tags;
- int level;
- unsigned long cu_offset;
-@@ -1619,7 +1618,6 @@
-
- cu_offset = start - section_begin;
-
-- cu_abbrev_offset_ptr = hdrptr;
- compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
- hdrptr += offset_size;
-
-@@ -2655,7 +2653,6 @@
- void *file ATTRIBUTE_UNUSED)
- {
- unsigned char *start = section->start;
-- unsigned char *section_end;
- unsigned long bytes;
- unsigned char *section_begin = start;
- unsigned int num_range_list = 0;
-@@ -2668,7 +2665,6 @@
- unsigned char *next;
-
- bytes = section->size;
-- section_end = start + bytes;
-
- if (bytes == 0)
- {
---- binutils/ieee.c.old 2014-01-04 17:04:36.896761373 +0000
-+++ binutils/ieee.c 2014-01-04 17:05:14.355010533 +0000
-@@ -4815,7 +4815,6 @@
- const char *backslash;
- #endif
- char *c, *s;
-- unsigned int nindx;
-
- if (info->filename != NULL)
- {
-@@ -4863,7 +4862,6 @@
- || ! ieee_write_id (info, info->modname))
- return FALSE;
-
-- nindx = info->name_indx;
- ++info->name_indx;
- if (! ieee_change_buffer (info, &info->vars)
- || ! ieee_write_byte (info, (int) ieee_bb_record_enum)
-@@ -5679,11 +5677,6 @@
- static bfd_boolean
- ieee_offset_type (void *p)
- {
-- struct ieee_handle *info = (struct ieee_handle *) p;
-- unsigned int targetindx, baseindx;
--
-- targetindx = ieee_pop_type (info);
-- baseindx = ieee_pop_type (info);
-
- /* FIXME: The MRI C++ compiler does not appear to generate any
- useful type information about an offset type. It just records a
---- binutils/objdump.c.old 2014-01-04 16:41:33.090584888 +0000
-+++ binutils/objdump.c 2014-01-04 16:42:05.046153323 +0000
-@@ -1315,7 +1315,6 @@
- struct objdump_disasm_info *aux;
- asection *section;
- int octets_per_line;
-- bfd_boolean done_dot;
- int skip_addr_chars;
- bfd_vma addr_offset;
- unsigned int opb = info->octets_per_byte;
-@@ -1361,7 +1360,6 @@
-
- info->insn_info_valid = 0;
-
-- done_dot = FALSE;
- addr_offset = start_offset;
- while (addr_offset < stop_offset)
- {
-@@ -1402,8 +1400,6 @@
- int bpc = 0;
- int pb = 0;
-
-- done_dot = FALSE;
--
- if (with_line_numbers || with_source_code)
- show_line (aux->abfd, section, addr_offset);
-
---- binutils/rddbg.c.old 2014-01-04 16:48:10.560218033 +0000
-+++ binutils/rddbg.c 2014-01-04 16:48:33.511437185 +0000
-@@ -163,7 +163,6 @@
- {
- unsigned int strx;
- int type;
-- int other;
- int desc;
- bfd_vma value;
-
-@@ -171,7 +170,6 @@
-
- strx = bfd_get_32 (abfd, stab);
- type = bfd_get_8 (abfd, stab + 4);
-- other = bfd_get_8 (abfd, stab + 5);
- desc = bfd_get_16 (abfd, stab + 6);
- value = bfd_get_32 (abfd, stab + 8);
-
---- binutils/stabs.c.old 2014-01-04 16:51:23.478216204 +0000
-+++ binutils/stabs.c 2014-01-04 16:54:20.752581129 +0000
-@@ -685,7 +685,7 @@
- debug_type dtype;
- bfd_boolean synonym;
- bfd_boolean self_crossref;
-- unsigned int lineno;
- debug_type *slot;
-+ (void) desc;
-
- p = strchr (string, ':');
-@@ -703,14 +703,6 @@
- }
- }
-
-- /* GCC 2.x puts the line number in desc. SunOS apparently puts in
-- the number of bytes occupied by a type or object, which we
-- ignore. */
-- if (info->gcc_compiled >= 2)
-- lineno = desc;
-- else
-- lineno = 0;
--
- /* FIXME: Sometimes the special C++ names start with '.'. */
- name = NULL;
- if (string[0] == '$')
-@@ -2006,7 +1998,6 @@
- const char *tagname, const char **pp,
- bfd_boolean structp, const int *typenums)
- {
-- const char *orig;
- bfd_vma size;
- debug_baseclass *baseclasses;
- debug_field *fields;
-@@ -2015,8 +2006,6 @@
- debug_type vptrbase;
- bfd_boolean ownvptr;
-
-- orig = *pp;
--
- /* Get the size. */
- size = parse_number (pp, (bfd_boolean *) NULL);
-
-@@ -4645,7 +4634,7 @@
- case 'M':
- case 'O':
- {
-- bfd_boolean memberp, constp, volatilep;
-+ bfd_boolean memberp;
- debug_type class_type = DEBUG_TYPE_NULL;
- debug_type *args;
- bfd_boolean varargs;
-@@ -4653,8 +4642,6 @@
- const char *name;
-
- memberp = **pp == 'M';
-- constp = FALSE;
-- volatilep = FALSE;
- args = NULL;
- varargs = FALSE;
-
-@@ -4698,12 +4685,10 @@
- {
- if (**pp == 'C')
- {
-- constp = TRUE;
- ++*pp;
- }
- else if (**pp == 'V')
- {
-- volatilep = TRUE;
- ++*pp;
- }
- if (**pp != 'F')
-@@ -4764,9 +4749,6 @@
-
- case 'Q':
- {
-- const char *hold;
--
-- hold = *pp;
- if (! stab_demangle_qualified (minfo, pp, ptype))
- return FALSE;
- }
---- gas/as.c.old 2014-01-04 17:13:31.225076310 +0000
-+++ gas/as.c 2014-01-04 17:18:37.674379984 +0000
-@@ -1060,7 +1060,6 @@
- {
- segT s;
- char *p;
-- addressT addr;
- offsetT size;
- const char *name;
-
-@@ -1074,7 +1073,6 @@
- elf_section_type (s)
- = get_elf_backend_data (stdoutput)->obj_attrs_section_type;
- bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA);
-- addr = frag_now_fix ();
- p = frag_more (size);
- bfd_elf_set_obj_attr_contents (stdoutput, (bfd_byte *)p, size);
- }
---- gas/listing.c.old 2014-01-04 17:21:13.406248415 +0000
-+++ gas/listing.c 2014-01-04 17:21:51.156643142 +0000
-@@ -937,7 +937,6 @@
- {
- list_info_type *list = head;
- file_info_type *current_hll_file = (file_info_type *) NULL;
-- char *message;
- char *buffer;
- char *p;
- int show_listing = 1;
-@@ -1002,8 +1001,6 @@
- {
- /* Scan down the list and print all the stuff which can be done
- with this line (or lines). */
-- message = 0;
--
- if (list->hll_file)
- current_hll_file = list->hll_file;
-
---- gas/read.c.old 2014-01-04 17:24:32.839414940 +0000
-+++ gas/read.c 2014-01-04 17:46:41.158558836 +0000
-@@ -2575,10 +2575,15 @@
- void
- s_mri (int ignore ATTRIBUTE_UNUSED)
- {
-- int on, old_flag;
-+ int on;
-+#ifdef MRI_MODE_CHANGE
-+ int old_flag;
-+#endif
-
- on = get_absolute_expression ();
-+#ifdef MRI_MODE_CHANGE
- old_flag = flag_mri;
-+#endif
- if (on != 0)
- {
- flag_mri = 1;
-@@ -4683,11 +4688,9 @@
- sizeof_uleb128 (valueT value)
- {
- register int size = 0;
-- register unsigned byte;
-
- do
- {
-- byte = (value & 0x7f);
- value >>= 7;
- size += 1;
- }
-@@ -5644,16 +5647,15 @@
- SKIP_WHITESPACE ();
- if (*input_line_pointer != ',')
- {
-- int res;
- if (default_prefix)
-- res = asprintf (&label, "%s%s", default_prefix, name);
-+ (void) asprintf (&label, "%s%s", default_prefix, name);
- else
- {
- char leading_char = bfd_get_symbol_leading_char (stdoutput);
- /* Missing entry point, use function's name with the leading
- char prepended. */
- if (leading_char)
-- res = asprintf (&label, "%c%s", leading_char, name);
-+ (void) asprintf (&label, "%c%s", leading_char, name);
- else
- label = name;
- }
---- gas/stabs.c.old 2014-01-04 17:59:17.491017224 +0000
-+++ gas/stabs.c 2014-01-04 18:00:01.744605487 +0000
-@@ -658,7 +658,6 @@
- char *buf;
- char *file;
- unsigned int lineno;
-- int res;
-
- if (! void_emitted_p)
- {
-@@ -668,7 +667,7 @@
- }
-
- as_where (&file, &lineno);
-- res = asprintf (&buf, "\"%s:F1\",%d,0,%d,%s",
-+ (void) asprintf (&buf, "\"%s:F1\",%d,0,%d,%s",
- funcname, N_FUN, lineno + 1, startlabname);
- input_line_pointer = buf;
- s_stab ('s');
-@@ -689,13 +688,12 @@
- char *hold = input_line_pointer;
- char *buf;
- char sym[30];
-- int res;
-
- sprintf (sym, "%sendfunc%d", FAKE_LABEL_NAME, label_count);
- ++label_count;
- colon (sym);
-
-- res = asprintf (&buf, "\"\",%d,0,0,%s-%s", N_FUN, sym, startlabname);
-+ (void) asprintf (&buf, "\"\",%d,0,0,%s-%s", N_FUN, sym, startlabname);
- input_line_pointer = buf;
- s_stab ('s');
- free (buf);
---- include/elf/ppc.h.old 2014-01-04 16:07:28.062263958 +0000
-+++ include/elf/ppc.h 2014-01-04 16:08:56.781487163 +0000
-@@ -133,10 +133,10 @@
- RELOC_NUMBER (R_PPC_AMIGAOS_BREL_HA, 213)
-
- /* Fake relocations for branch stubs, only used internally by ld. */
--#define R_PPC_RELAX32 245
--#define R_PPC_RELAX32PC 246
--#define R_PPC_RELAX32_PLT 247
--#define R_PPC_RELAX32PC_PLT 248
-+ FAKE_RELOC(R_PPC_RELAX32, 245)
-+ FAKE_RELOC(R_PPC_RELAX32PC, 246)
-+ FAKE_RELOC(R_PPC_RELAX32_PLT, 247)
-+ FAKE_RELOC(R_PPC_RELAX32PC_PLT, 248)
-
- /* These are GNU extensions used in PIC code sequences. */
- RELOC_NUMBER (R_PPC_REL16, 249)
---- ld/ldlang.c.old 2014-01-04 18:03:19.264793435 +0000
-+++ ld/ldlang.c 2014-01-04 18:04:28.794701467 +0000
-@@ -2141,14 +2141,12 @@
- lang_input_statement_type *file,
- asection *section)
- {
-- const char *section_name;
- lang_statement_union_type *l;
-
- if (!wild->filenames_sorted
- && (sec == NULL || sec->spec.sorted == none))
- return NULL;
-
-- section_name = bfd_get_section_name (file->the_bfd, section);
- for (l = wild->children.head; l != NULL; l = l->header.next)
- {
- lang_input_section_type *ls;
diff --git a/ppc-amigaos/recipes/patches/gcc/0001-Changes-for-AmigaOS-version-of-gcc.p b/ppc-amigaos/recipes/patches/gcc/0001-Changes-for-AmigaOS-version-of-gcc.p
new file mode 100644
index 0000000..98441d3
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/gcc/0001-Changes-for-AmigaOS-version-of-gcc.p
@@ -0,0 +1,5166 @@
+From eecb39df390b5b8cd36a8a417f61d4afba24c187 Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Tue, 17 Feb 2015 20:25:55 +0100
+Subject: [PATCH 1/6] Changes for AmigaOS version of gcc.
+
+---
+ fixincludes/configure | 1 +
+ fixincludes/configure.ac | 1 +
+ gcc/Makefile.in | 1 +
+ gcc/c-family/c-common.c | 26 +
+ gcc/c/c-typeck.c | 25 +
+ gcc/config.gcc | 8 +
+ gcc/config.host | 6 +
+ gcc/config/rs6000/amigaos-protos.h | 41 +
+ gcc/config/rs6000/amigaos.c | 466 +++++++++
+ gcc/config/rs6000/amigaos.h | 431 ++++++++
+ gcc/config/rs6000/amigaos.opt | 37 +
+ gcc/config/rs6000/rs6000-builtin.def | 7 +
+ gcc/config/rs6000/rs6000.c | 176 +++-
+ gcc/config/rs6000/rs6000.h | 3 +
+ gcc/config/rs6000/rs6000.md | 27 +-
+ gcc/config/rs6000/t-amigaos | 20 +
+ gcc/cp/typeck.c | 16 +
+ gcc/doc/extend.texi | 167 +++
+ gcc/doc/invoke.texi | 136 +++
+ gcc/expr.c | 1 -
+ gcc/gcc.c | 12 +-
+ gcc/prefix.c | 2 +-
+ intl/dcigettext.c | 2 +
+ libcpp/line-map.c | 3 +
+ libgcc/config.host | 3 +
+ libgcc/config/rs6000/t-amigaos | 45 +
+ libiberty/Makefile.in | 9 +
+ libiberty/basename.c | 21 +-
+ libiberty/configure | 1 +
+ libiberty/configure.ac | 1 +
+ libiberty/lrealpath.c | 3 +-
+ libiberty/make-relative-prefix.c | 37 +-
+ libiberty/make-temp-file.c | 27 +-
+ libiberty/pex-amigaos.c | 325 ++++++
+ libstdc++-v3/configure | 1852 ++++++++++++++++++++++++++++++++-
+ libstdc++-v3/configure.ac | 3 +
+ libstdc++-v3/crossconfig.m4 | 8 +
+ libstdc++-v3/include/c_global/cstddef | 3 +
+ libstdc++-v3/include/c_std/cstddef | 3 +
+ 39 files changed, 3879 insertions(+), 77 deletions(-)
+ create mode 100644 gcc/config/rs6000/amigaos-protos.h
+ create mode 100644 gcc/config/rs6000/amigaos.c
+ create mode 100644 gcc/config/rs6000/amigaos.h
+ create mode 100644 gcc/config/rs6000/amigaos.opt
+ create mode 100644 gcc/config/rs6000/t-amigaos
+ create mode 100644 libgcc/config/rs6000/t-amigaos
+ create mode 100644 libiberty/pex-amigaos.c
+
+diff --git a/fixincludes/configure b/fixincludes/configure
+index 4836cd886537e9cdf73ef2bb064bfa581fc1068a..6bee1a37ee30a1c12a8f41f05c21d956d1be1a09 100755
+--- fixincludes/configure
++++ fixincludes/configure
+@@ -4712,12 +4712,13 @@ else
+ fi
+ else
+ case $host in
+ i?86-*-msdosdjgpp* | \
+ i?86-*-mingw32* | \
+ x86_64-*-mingw32* | \
++ *-*-amigaos* | \
+ *-*-beos* | \
+ *-*-*vms*)
+ TARGET=twoprocess
+ ;;
+
+ * )
+diff --git a/fixincludes/configure.ac b/fixincludes/configure.ac
+index f8f352fb7153445782727eb3311d4305f33fa260..66a501d80528fdd50b4cd2f9f3282e3c562bf2e2 100644
+--- fixincludes/configure.ac
++++ fixincludes/configure.ac
+@@ -50,12 +50,13 @@ else
+ TARGET=oneprocess
+ fi],
+ [case $host in
+ i?86-*-msdosdjgpp* | \
+ i?86-*-mingw32* | \
+ x86_64-*-mingw32* | \
++ *-*-amigaos* | \
+ *-*-beos* | \
+ *-*-*vms*)
+ TARGET=twoprocess
+ ;;
+
+ * )
+diff --git a/gcc/Makefile.in b/gcc/Makefile.in
+index 07c6f0af71749b653c16ef7843a191e0bd9aa95d..c464690a51e62c8ba92fa3543dccb70488bd12f9 100644
+--- gcc/Makefile.in
++++ gcc/Makefile.in
+@@ -1972,12 +1972,13 @@ default-c.o: config/default-c.c
+ CFLAGS-prefix.o += -DPREFIX=\"$(prefix)\" -DBASEVER=$(BASEVER_s)
+ prefix.o: $(BASEVER)
+
+ # Language-independent files.
+
+ DRIVER_DEFINES = \
++ -DEXEC_PREFIX=\"$(exec_prefix)/\" \
+ -DSTANDARD_STARTFILE_PREFIX=\"$(unlibsubdir)/\" \
+ -DSTANDARD_EXEC_PREFIX=\"$(libdir)/gcc/\" \
+ -DSTANDARD_LIBEXEC_PREFIX=\"$(libexecdir)/gcc/\" \
+ -DDEFAULT_TARGET_VERSION=\"$(version)\" \
+ -DDEFAULT_REAL_TARGET_MACHINE=\"$(real_target_noncanonical)\" \
+ -DDEFAULT_TARGET_MACHINE=\"$(target_noncanonical)\" \
+diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
+index 117f89c023842aa8ea10a6a94088f4095246d9e3..4e1bbf417e6b774bdaa6c01dccef933fc73505ea 100644
+--- gcc/c-family/c-common.c
++++ gcc/c-family/c-common.c
+@@ -381,12 +381,13 @@ static tree handle_vector_size_attribute (tree *, tree, tree, int,
+ bool *);
+ static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
+ bool *);
++static tree handle_libcall_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_alloc_align_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_target_attribute (tree *, tree, tree, int, bool *);
+@@ -755,12 +756,17 @@ const struct attribute_spec c_common_attribute_table[] =
+ handle_nothrow_attribute, false },
+ { "may_alias", 0, 0, false, true, false, NULL, false },
+ { "cleanup", 1, 1, true, false, false,
+ handle_cleanup_attribute, false },
+ { "warn_unused_result", 0, 0, false, true, true,
+ handle_warn_unused_result_attribute, false },
++ { "libcall", 0, 0, false, true, true,
++ handle_libcall_attribute, false },
++ /* Similiar to libcall but doesn't imply linearvarargs. Can be handled as libcall here. */
++ { "libcall2", 0, 0, false, true, true,
++ handle_libcall_attribute, false },
+ { "sentinel", 0, 1, false, true, true,
+ handle_sentinel_attribute, false },
+ /* For internal use (marking of builtins) only. The name contains space
+ to prevent its usage in source code. */
+ { "type generic", 0, 0, false, true, true,
+ handle_type_generic_attribute, false },
+@@ -9218,12 +9224,32 @@ handle_warn_unused_result_attribute (tree *node, tree name,
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+ }
+
++/* Handle a "libcall" attribute. No special handling. */
++
++static tree
++handle_libcall_attribute (tree *node, tree name,
++ tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED,
++ bool *no_add_attrs)
++{
++ if (TREE_CODE (*node) != FUNCTION_TYPE
++ && TREE_CODE (*node) != METHOD_TYPE
++ && TREE_CODE (*node) != FIELD_DECL
++ && TREE_CODE (*node) != TYPE_DECL)
++ {
++ warning (OPT_Wattributes,"%qs attribute only applies to functions",
++ IDENTIFIER_POINTER (name));
++ *no_add_attrs = true;
++ }
++
++ return NULL_TREE;
++}
++
+ /* Handle a "sentinel" attribute. */
+
+ static tree
+ handle_sentinel_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+ {
+diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
+index ffba66bb6c4cf935bc86fc3896fadcc5e40023a7..a98622b16f546b88eb7fdce9ca7631c3ca37470a 100644
+--- gcc/c/c-typeck.c
++++ gcc/c/c-typeck.c
+@@ -2888,12 +2888,14 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
+ tree fntype, fundecl = 0;
+ tree name = NULL_TREE, result;
+ tree tem;
+ int nargs;
+ tree *argarray;
+
++ vec<tree, va_gc> *new_params = NULL;
++ vec<tree, va_gc> *new_origtypes = NULL;
+
+ /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
+ STRIP_TYPE_NOPS (function);
+
+ /* Convert anything with function type to a pointer-to-function. */
+ if (TREE_CODE (function) == FUNCTION_DECL)
+@@ -2950,12 +2952,35 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
+ if (fundecl && TREE_THIS_VOLATILE (fundecl))
+ current_function_returns_abnormally = 1;
+
+ /* fntype now gets the type of function pointed to. */
+ fntype = TREE_TYPE (fntype);
+
++ if (lookup_attribute ("libcall", TYPE_ATTRIBUTES (fntype)) ||
++ lookup_attribute ("libcall2", TYPE_ATTRIBUTES (fntype)))
++ {
++ if (TREE_CODE (function) == COMPONENT_REF && lvalue_p (function))
++ {
++ /* We copy the involved vectors here, as adding an element may
++ * free the original pointer, but we are not the owner of those.
++ *
++ * FIXME: At the moment, we don't free the memory allocated here
++ * If it is freed at the exit of the function via VEC_free() in
++ * some cases a segfault occurs */
++ params = new_params = vec_safe_copy(params);
++ origtypes = new_origtypes = vec_safe_copy(origtypes);
++
++ /* Type of 0 operand of a component ref is always a dereferenced object but
++ * we need to pass the address of this object */
++ vec_safe_insert(params,0,
++ build1(ADDR_EXPR, build_pointer_type (TREE_TYPE (TREE_OPERAND (function, 0))),
++ TREE_OPERAND (function, 0)));
++ vec_safe_insert(origtypes,0,(tree)NULL);
++ }
++ }
++
+ /* Convert the parameters to the types declared in the
+ function prototype, or apply default promotions. */
+
+ nargs = convert_arguments (loc, arg_loc, TYPE_ARG_TYPES (fntype), params,
+ origtypes, function, fundecl);
+ if (nargs < 0)
+diff --git a/gcc/config.gcc b/gcc/config.gcc
+index c835734128b0aef5a0b558ccd7ad24fd17bb9bee..6fcd952f5235f04160e5de45aff781993bf120a1 100644
+--- gcc/config.gcc
++++ gcc/config.gcc
+@@ -2245,12 +2245,20 @@ nvptx-*)
+ fi
+ ;;
+ pdp11-*-*)
+ tm_file="${tm_file} newlib-stdint.h"
+ use_gcc_stdint=wrap
+ ;;
++powerpc-*-amigaos*)
++ tm_file="${tm_file} dbxelf.h elfos.h rs6000/sysv4.h rs6000/amigaos.h"
++ tm_p_file="${tm_p_file} rs6000/amigaos-protos.h"
++ extra_options="${extra_options} rs6000/sysv4.opt rs6000/amigaos.opt"
++ tmake_file="rs6000/t-amigaos"
++ extra_objs=amigaos.o
++ use_collect2=no
++ ;;
+ # port not yet contributed
+ #powerpc-*-openbsd*)
+ # tmake_file="${tmake_file} rs6000/t-fprules"
+ # extra_headers=
+ # ;;
+ powerpc-*-darwin*)
+diff --git a/gcc/config.host b/gcc/config.host
+index b0f5940c26379ebc75e0ca462cbb2cb01dabd2fa..51675e166b9833d327ec43fcca67d6a2b3560068 100644
+--- gcc/config.host
++++ gcc/config.host
+@@ -242,12 +242,18 @@ case ${host} in
+ exit 1
+ ;;
+ i[34567]86-*-darwin* | x86_64-*-darwin*)
+ out_host_hook_obj="${out_host_hook_obj} host-i386-darwin.o"
+ host_xmake_file="${host_xmake_file} i386/x-darwin"
+ ;;
++ powerpc-*-amigaos*) # AmigaOS 4
++ prefix=/gcc
++ local_prefix=/gcc
++ host_can_use_collect2=no
++ host_xm_defines=HOST_LACKS_INODE_NUMBERS
++ ;;
+ powerpc-*-beos*)
+ host_can_use_collect2=no
+ ;;
+ powerpc-*-darwin*)
+ out_host_hook_obj="${out_host_hook_obj} host-ppc-darwin.o"
+ host_xmake_file="${host_xmake_file} rs6000/x-darwin"
+diff --git a/gcc/config/rs6000/amigaos-protos.h b/gcc/config/rs6000/amigaos-protos.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..eb5f8fc5f3d546b8d8e1cdd8118a3085079df50e
+--- /dev/null
++++ gcc/config/rs6000/amigaos-protos.h
+@@ -0,0 +1,41 @@
++/* Prototypes.
++ Copyright (C) 2003 Free Software Foundation, Inc.
++
++ This file is part of GCC.
++
++ GCC 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.
++
++ GCC 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 GCC; see the file COPYING. If not, write to the
++ Free Software Foundation, 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA. */
++
++
++//#ifdef RTX_CODE
++//#ifdef TREE_CODE
++
++extern void amigaos_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, int, int);
++extern void amigaos_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
++extern struct rtx_def *amigaos_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
++extern void amigaos_expand_builtin_va_start (tree valist, rtx nextarg);
++extern struct rtx_def *amigaos_expand_builtin_saveregs (void);
++extern void amigaos_init_builtins (void);
++extern rtx amigaos_expand_builtin (tree, rtx, rtx, enum machine_mode, int, bool*);
++extern tree amigaos_handle_linearvarargs_attribute (tree *, tree, tree, int, bool*);
++extern tree amigaos_handle_baserel_restore_attribute (tree *, tree, tree, int, bool*);
++extern tree amigaos_handle_force_no_baserel_attribute (tree *, tree, tree, int, bool*);
++extern tree amigaos_handle_check68kfuncptr_attribute (tree *, tree, tree, int, bool*);
++extern rtx amigaos_legitimize_baserel_address (rtx addr);
++extern int amigaos_baserel_operand(rtx x);
++extern int amigaos_not_baserel_tree_p(tree decl);
++
++//#endif /* TREE_CODE */
++//#endif /* RTX_CODE */
+diff --git a/gcc/config/rs6000/amigaos.c b/gcc/config/rs6000/amigaos.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..0f575a38e4dc4aac0b454c56bf62f625c0f7eb9c
+--- /dev/null
++++ gcc/config/rs6000/amigaos.c
+@@ -0,0 +1,466 @@
++/* Subroutines used for code generation on Amiga OS 4
++ Copyright (C) 2003 Free Software Foundation, Inc.
++ Contributed by Thomas Frieden (ThomasF@hyperion-entertainment.com)
++
++ This file is part of GCC.
++
++ GCC 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.
++
++ GCC 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 GCC; see the file COPYING. If not, write to the
++ Free Software Foundation, 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA. */
++
++
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "diagnostic-core.h"
++#include "tm.h"
++#include "hash-set.h"
++#include "inchash.h"
++#include "rtl.h"
++#include "regs.h"
++#include "hard-reg-set.h"
++#include "real.h"
++#include "insn-config.h"
++#include "conditions.h"
++#include "insn-flags.h"
++#include "insn-attr.h"
++#include "flags.h"
++#include "recog.h"
++#include "obstack.h"
++#include "symtab.h"
++#include "tree.h"
++#include "expr.h"
++#include "optabs.h"
++#include "except.h"
++#include "function.h"
++#include "output.h"
++#include "tm_p.h"
++#include "fold-const.h"
++#include "langhooks.h"
++#include "explow.h"
++
++#undef DEBUG
++#ifdef DEBUG
++#define dprintf(...) \
++printf("%s: ", __PRETTY_FUNCTION__); \
++printf(__VA_ARGS__)
++#else
++#define dprintf(...) /* __VA_ARGS__ */
++#endif
++
++#undef TARGET_EXPAND_BUILTIN_SAVEREGS
++#define TARGET_EXPAND_BUILTIN_SAVEREGS() \
++ amigaos_expand_builtin_saveregs ()
++
++#ifdef __amigaos4__
++static const char * __attribute__((used)) amigaos_stack_cookie = "$STACK:768000";
++#endif /* __amigaos4__ */
++
++#if 0
++const char *amigaos_crt_string;
++#endif
++
++/* Initialize a variable CUM of type CUMULATIVE_ARGS
++ for a call to a function whose data type is FNTYPE.
++ For a library call, FNTYPE is 0.
++
++ Most of the work is delegated to init_cumulative_args() in rs6000.c,
++ here we just check for special attributes and update call_cookie
++ accordingly. */
++#if 0
++void
++amigaos_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
++ rtx libname ATTRIBUTE_UNUSED, int incoming,
++ int n_named_args)
++{
++ dprintf ("enter(cum=%p,fntype=%p)\n",cum,fntype);
++ init_cumulative_args (cum, fntype, libname, incoming, FALSE, n_named_args);
++
++ /* Check if either libcall or linear varargs, set appropriate cookie */
++ if (fntype && (lookup_attribute ("libcall", TYPE_ATTRIBUTES (fntype))))
++ cum->call_cookie |= CALL_LINEARVARARGS;
++
++ if (fntype && (lookup_attribute ("linearvarargs", TYPE_ATTRIBUTES (fntype))))
++ cum->call_cookie |= CALL_LINEARVARARGS;
++
++ dprintf ("exit\n");
++}
++
++/* Update the data in CUM to advance over an argument
++ of mode MODE and data type TYPE.
++ (TYPE is null for libcalls where that information may not be available.)
++
++ If the function has the linearvarargs attribute and this argument
++ to advance over is the last non-vararg argument, then advance over
++ all registers, so that the overflow area is hit immediately.
++ Otherwise, just let function_arg_advance () from rs6000.c do its
++ thing. */
++
++void
++amigaos_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
++ tree type, int named)
++{
++ dprintf ("enter\n");
++ function_arg_advance (cum, mode, type, named, 0);
++
++ if (cum->call_cookie & CALL_LINEARVARARGS && cum->nargs_prototype <= 0)
++ {
++ cum->sysv_gregno = GP_ARG_MAX_REG + 1;
++ cum->fregno = FP_ARG_V4_MAX_REG + 1;
++ }
++ dprintf ("exit\n");
++}
++
++
++/* Determine where to put an argument to a function.
++
++ Linearvarargs should always go to the stack, apart from that
++ any decision made by function_arg () in rs6000.c will be OK. */
++
++struct rtx_def *
++amigaos_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
++ tree type, int named)
++{
++ struct rtx_def *res = 0;
++
++ dprintf ("enter\n");
++ if (mode == VOIDmode && cum->call_cookie & CALL_LINEARVARARGS)
++ res = GEN_INT (cum->call_cookie);
++ else
++ res = function_arg (cum, mode, type, named);
++
++ dprintf ("exit\n");
++
++ return res;
++}
++#endif
++
++/* Implement va_start.
++
++ For linearvarargs functions, immediately increase the fpr
++ and gpr count to the maximum value, so that va_arg will look
++ only at the stack. */
++#if 0
++void
++amigaos_expand_builtin_va_start (tree valist, rtx nextarg)
++{
++printf("amigaos_expand_builtin_va_start()\n");
++ rs6000_va_start (valist, nextarg);
++
++ if (crtl->args.info.call_cookie & CALL_LINEARVARARGS)
++ {
++ tree f_gpr, f_fpr;
++ tree gpr, fpr, t;
++
++ f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
++ f_fpr = TREE_CHAIN (f_gpr);
++
++ valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
++ gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
++ fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
++
++ /* Set gpr use count to 8, forcing the overflow area to be used */
++ t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_cst (NULL_TREE, 8));
++ TREE_SIDE_EFFECTS (t) = 1;
++ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
++
++ /* Likewise for floating point arguments */
++ t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_cst (NULL_TREE, 8));
++ TREE_SIDE_EFFECTS (t) = 1;
++ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
++ }
++}
++#endif
++
++/* Implement __builtin_saveregs for linearvarargs functions. */
++#if 0
++struct rtx_def *
++amigaos_expand_builtin_saveregs (void)
++{
++ rtx block, mem_gpr_fpr, mem_overflow, tmp;
++ tree fntype;
++ int stdarg_p;
++ HOST_WIDE_INT words, gpr;
++ struct rtx_def *res;
++
++ dprintf ("enter\n");
++
++ if (crtl->args.info.call_cookie & CALL_LINEARVARARGS)
++ {
++ HOST_WIDE_INT bits;
++
++ fntype = TREE_TYPE (current_function_decl);
++ stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
++ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
++ != void_type_node));
++
++ /* Allocate the va_list constructor. */
++ block = assign_stack_local (BLKmode, 3 * UNITS_PER_WORD, BITS_PER_WORD);
++ MEM_READONLY_P (block) = 1;
++ MEM_READONLY_P (XEXP (block, 0)) = 1;
++
++ mem_gpr_fpr = change_address (block, word_mode, XEXP (block, 0));
++ mem_overflow = change_address (block, ptr_mode,
++ plus_constant (XEXP (block, 0),
++ UNITS_PER_WORD));
++ /*mem_reg_save_area = change_address (block, ptr_mode,
++ plus_constant (XEXP (block, 0),
++ 2 * UNITS_PER_WORD));*/
++
++ /* Construct the two characters of `gpr' and `fpr' as a unit. */
++ words = crtl->args.info.words;
++ gpr = crtl->args.info.sysv_gregno - GP_ARG_MIN_REG;
++
++ /* Varargs has the va_dcl argument, but we don't count it. */
++ if (!stdarg_p)
++ {
++ if (gpr > GP_ARG_NUM_REG)
++ words -= 1;
++ }
++
++ bits = (GP_ARG_MAX_REG - GP_ARG_MIN_REG + 1) << 8
++ | (FP_ARG_MAX_REG - FP_ARG_MIN_REG + 1);
++ if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD)
++ tmp = GEN_INT (bits << (BITS_PER_WORD - 16));
++ else
++ {
++ bits <<= BITS_PER_WORD - HOST_BITS_PER_WIDE_INT - 16;
++ tmp = immed_double_const (0, bits, word_mode);
++ }
++
++ emit_move_insn (mem_gpr_fpr, tmp);
++
++ /* Find the overflow area. */
++ tmp = expand_binop (Pmode, add_optab, virtual_incoming_args_rtx,
++ GEN_INT (words * UNITS_PER_WORD),
++ mem_overflow, 0, OPTAB_WIDEN);
++ if (tmp != mem_overflow)
++ emit_move_insn (mem_overflow, tmp);
++
++ /*tmp = expand_binop (Pmode, add_optab, virtual_stack_vars_rtx,
++ GEN_INT (-RS6000_VARARGS_SIZE),
++ mem_reg_save_area, 0, OPTAB_WIDEN);
++ if (tmp != mem_reg_save_area)
++ emit_move_insn (mem_reg_save_area, tmp);*/
++
++ /* Return the address of the va_list constructor. */
++ res = XEXP (block, 0);
++ }
++ else
++ {
++ res = expand_builtin_saveregs ();
++ }
++
++ dprintf ("exit\n");
++ return res;
++}
++#endif
++
++/* Define subtarget builtins */
++
++void
++amigaos_init_builtins (void)
++{
++ tree ftype;
++ ftype = build_function_type (ptr_type_node,
++ tree_cons (NULL_TREE,
++ build_pointer_type (TREE_TYPE (va_list_type_node)),
++ void_list_node));
++
++ add_builtin_function ("__builtin_getlinearva",
++ ftype,
++ AMIGAOS_BUILTIN_GETLINEARVA,
++ BUILT_IN_MD, NULL, NULL_TREE);
++}
++
++
++/* Expand builtins */
++rtx
++amigaos_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
++ enum machine_mode mode ATTRIBUTE_UNUSED,
++ int ignore ATTRIBUTE_UNUSED, bool *success)
++{
++ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
++ tree f_gpr, f_fpr, f_res, f_ovf;
++ tree arg0, valist, ovf;
++
++ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
++
++// debug_tree(exp);
++// debug_tree(fndecl);
++ if (fcode != AMIGAOS_BUILTIN_GETLINEARVA)
++ {
++ *success = 0;
++ return NULL_RTX;
++ }
++
++ if (! (crtl->args.info.call_cookie & CALL_LINEARVARARGS))
++ {
++ /* TODO: This probably should be a fatal, but then the generated executable can't be linked. */
++ error ("__builtin_getlinearva can only be used in a linearvarargs function");
++ *success = 1;
++ return 0;
++ }
++
++ arg0 = CALL_EXPR_ARG (exp, 0);
++ if (arg0 == error_mark_node)
++ return const0_rtx;
++
++ f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
++ f_fpr = TREE_CHAIN (f_gpr);
++ f_res = TREE_CHAIN (f_fpr);
++ f_ovf = TREE_CHAIN (f_res);
++ target = const0_rtx;
++ valist = build_simple_mem_ref(arg0);//build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (arg0)), arg0);
++ ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
++ target = copy_to_reg (expand_expr (ovf, NULL_RTX, Pmode, EXPAND_NORMAL));
++ *success = 1;
++ return target;
++}
++
++/* Handle a "linearvarargs" attribute. */
++tree
++amigaos_handle_linearvarargs_attribute (tree *node, tree name,
++ tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED,
++ bool *no_add_attrs)
++{
++ if (TREE_CODE (*node) != FUNCTION_TYPE
++ && TREE_CODE (*node) != METHOD_TYPE
++ && TREE_CODE (*node) != FIELD_DECL
++ && TREE_CODE (*node) != TYPE_DECL)
++ {
++ warning (0, "%s attribute only applies to functions",
++ IDENTIFIER_POINTER (name));
++ *no_add_attrs = true;
++ }
++
++ return NULL_TREE;
++}
++
++
++/* Generate code for base relative access */
++
++rtx
++amigaos_legitimize_baserel_address (rtx addr)
++{
++ rtx dest = gen_reg_rtx (Pmode);
++
++ emit_insn (gen_elf_base_high (dest, gen_rtx_REG (Pmode, 2), addr));
++ emit_insn (gen_elf_base_low (dest, dest, addr));
++
++ return dest;
++}
++
++int
++amigaos_not_baserel_tree_p(tree decl)
++{
++ return(TREE_READONLY(decl)
++ || TREE_CONSTANT(decl)
++ || (DECL_ATTRIBUTES(decl)
++ && lookup_attribute("force_no_baserel", DECL_ATTRIBUTES(decl))));
++}
++
++int
++amigaos_baserel_operand(rtx x)
++{
++ tree decl;
++ int ret = 0;
++
++ if (GET_CODE(x) == SYMBOL_REF)
++ {
++ decl = SYMBOL_REF_DECL(x);
++
++ if (decl)
++ {
++ if (SYMBOL_REF_FUNCTION_P(x) || amigaos_not_baserel_tree_p(decl))
++ ret = 0;
++ else
++ ret = 1;
++ }
++ }
++ else if (GET_CODE(x) == CONST
++ && GET_CODE(XEXP(x, 0)) == PLUS
++ && GET_CODE(XEXP(XEXP(x, 0), 0)) == SYMBOL_REF
++ && GET_CODE(XEXP(XEXP(x, 0), 1)) == CONST_INT)
++ ret = amigaos_baserel_operand(XEXP(XEXP(x, 0), 0));
++ else if (GET_CODE(x) == LO_SUM)
++ ret = amigaos_baserel_operand(XEXP(x, 1));
++
++ return ret;
++}
++
++void amigaos_function_end_prologue(FILE *file);
++void amigaos_function_end_prologue(FILE *file)
++{
++ if (TARGET_BASEREL
++ && current_function_decl
++ && lookup_attribute ("baserel_restore", TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
++ {
++ fprintf( file, "\tbl __baserel_get_addr\n");
++ }
++}
++
++
++tree
++amigaos_handle_baserel_restore_attribute (tree *node, tree name,
++ tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED,
++ bool *no_add_attrs)
++{
++ if (TREE_CODE (*node) != FUNCTION_TYPE
++ && TREE_CODE (*node) != METHOD_TYPE
++ && TREE_CODE (*node) != FIELD_DECL
++ && TREE_CODE (*node) != TYPE_DECL)
++ {
++ warning (0, "%s attribute only applies to functions",
++ IDENTIFIER_POINTER (name));
++ *no_add_attrs = true;
++ }
++
++ return NULL_TREE;
++}
++
++tree
++amigaos_handle_force_no_baserel_attribute (tree *node, tree name,
++ tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED,
++ bool *no_add_attrs)
++{
++ if (TREE_CODE (*node) != VAR_DECL)
++ {
++ warning (0, "%s attribute only applies to variables",
++ IDENTIFIER_POINTER (name));
++ *no_add_attrs = true;
++ }
++
++ return NULL_TREE;
++}
++
++/* Handle a "check68kfuncptr" attribute. */
++
++tree
++amigaos_handle_check68kfuncptr_attribute (tree *node, tree name,
++ tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED,
++ bool *no_add_attrs)
++{
++ if (TREE_CODE (*node) != FUNCTION_TYPE
++ && TREE_CODE (*node) != METHOD_TYPE
++ && TREE_CODE (*node) != FIELD_DECL
++ && TREE_CODE (*node) != TYPE_DECL)
++ {
++ warning (0, "%s attribute only applies to functions",
++ IDENTIFIER_POINTER (name));
++ *no_add_attrs = true;
++ }
++
++ return NULL_TREE;
++}
+diff --git a/gcc/config/rs6000/amigaos.h b/gcc/config/rs6000/amigaos.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..4556163c22a8fadc51c9ed7401c7e6c414e58c0e
+--- /dev/null
++++ gcc/config/rs6000/amigaos.h
+@@ -0,0 +1,431 @@
++/* Definitions of target machine for GNU compiler, for AmigaOS.
++ Copyright (C) 1997, 2003, 2005 Free Software Foundation, Inc.
++
++ This file is part of GCC.
++
++ GCC 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.
++
++ GCC 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 GCC; see the file COPYING. If not, write to the
++ Free Software Foundation, 59 Temple Place - Suite 330, Boston,
++ MA 02111-1307, USA. */
++
++
++/* Don't assume anything about the header files. */
++#define NO_IMPLICIT_EXTERN_C
++
++#undef MD_EXEC_PREFIX
++#undef MD_STARTFILE_PREFIX
++
++/* Make CPU default to 604e. FIXME: Make this 750 later */
++#undef PROCESSOR_DEFAULT
++#define PROCESSOR_DEFAULT PROCESSOR_PPC604e
++
++#undef DEFAULT_ABI
++#define DEFAULT_ABI ABI_V4
++
++#undef ASM_CPU_SPEC
++#define ASM_CPU_SPEC \
++"%{!mcpu*: \
++ %{mpower: %{!mpower2: -mpwr}} \
++ %{mpower2: -mpwrx} \
++ %{mpowerpc64*: -mppc64} \
++ %{!mpowerpc64*: %{mpowerpc*: -mppc}} \
++ %{mno-power: %{!mpowerpc*: -mcom}} \
++ %{!mno-power: %{!mpower*: %(asm_default)}}} \
++%{mcpu=common: -mcom} \
++%{mcpu=power: -mpwr} \
++%{mcpu=power2: -mpwrx} \
++%{mcpu=power3: -mppc64} \
++%{mcpu=power4: -mpower4} \
++%{mcpu=power5: -mpower4} \
++%{mcpu=powerpc: -mppc} \
++%{mcpu=rios: -mpwr} \
++%{mcpu=rios1: -mpwr} \
++%{mcpu=rios2: -mpwrx} \
++%{mcpu=rsc: -mpwr} \
++%{mcpu=rsc1: -mpwr} \
++%{mcpu=rs64a: -mppc64} \
++%{mcpu=401: -mppc} \
++%{mcpu=403: -m403} \
++%{mcpu=405: -m405} \
++%{mcpu=405fp: -m405} \
++%{mcpu=440: -m440} \
++%{mcpu=440fp: -m440} \
++%{mcpu=505: -mppc} \
++%{mcpu=601: -m601} \
++%{mcpu=602: -mppc} \
++%{mcpu=603: -mppc} \
++%{mcpu=603e: -mppc} \
++%{mcpu=ec603e: -mppc} \
++%{mcpu=604: -mppc} \
++%{mcpu=604e: -mppc} \
++%{mcpu=620: -mppc64} \
++%{mcpu=630: -mppc64} \
++%{mcpu=740: -mppc} \
++%{mcpu=750: -mppc} \
++%{mcpu=G3: -mppc} \
++%{mcpu=7400: -mppc -maltivec} \
++%{mcpu=7450: -mppc -maltivec} \
++%{mcpu=G4: -mppc -maltivec} \
++%{mcpu=801: -mppc} \
++%{mcpu=821: -mppc} \
++%{mcpu=823: -mppc} \
++%{mcpu=860: -mppc} \
++%{mcpu=970: -mpower4 -maltivec} \
++%{mcpu=G5: -mpower4 -maltivec} \
++%{mcpu=8540: -me500} \
++%{maltivec: -maltivec}"
++
++#define IS_MCRT(MCRTNAME) \
++ (strcmp(amigaos_crt, MCRTNAME) == 0)
++
++/* Make most of the definitions from other compilers available */
++#undef TARGET_OS_CPP_BUILTINS
++#define TARGET_OS_CPP_BUILTINS() \
++ do \
++ { \
++ builtin_define_std ("PPC"); \
++ builtin_define_std ("powerpc"); \
++ builtin_assert ("cpu=powerpc"); \
++ builtin_assert ("machine=powerpc"); \
++ builtin_define_std ("AMIGA"); \
++ builtin_define_std ("AMIGAOS"); \
++ builtin_define_std ("AMIGAOS4"); \
++ builtin_define_std ("amiga"); \
++ builtin_define_std ("amigaos"); \
++ builtin_define_std ("amigaos4"); \
++ builtin_assert ("system=amigaos"); \
++ if (!amigaos_crt) \
++ { \
++ error ("no CRT specified"); \
++ } \
++ else if (IS_MCRT("clib2") || IS_MCRT("clib2-ts")) \
++ { \
++ builtin_define_std ("CLIB2"); \
++ if (IS_MCRT("clib2-ts")) \
++ builtin_define ("__THREAD_SAFE"); \
++ } \
++ else if (IS_MCRT("ixemul")) \
++ { \
++ builtin_define_std ("ixemul"); \
++ builtin_define_std ("IXEMUL"); \
++ } \
++ else if (IS_MCRT("libnix")) \
++ { \
++ builtin_define_std ("libnix"); \
++ builtin_define_std ("LIBNIX"); \
++ } \
++ else if (IS_MCRT("newlib")) \
++ { \
++ builtin_define_std ("NEWLIB"); \
++ } \
++ TARGET_OS_SYSV_CPP_BUILTINS (); \
++ } \
++ while (0)
++
++#undef CPP_SPEC
++#define CPP_SPEC "%{posix: -D_POSIX_SOURCE} %(cpp_os_default)"
++
++/*#define STANDARD_INCLUDE_DIR "/GCC/include"*/
++/*#undef SYSTEM_INCLUDE_DIR *//* So that the include path order is the same in native and cross compilers */
++#undef LOCAL_INCLUDE_DIR
++
++#ifndef CROSS_DIRECTORY_STRUCTURE
++#define BASE_GCC_SPEC "/GCC/"
++#define BASE_SDK_SPEC "/SDK/"
++#else
++#define BASE_GCC_SPEC EXEC_PREFIX
++#define BASE_SDK_SPEC EXEC_PREFIX "ppc-amigaos/SDK/"
++#endif
++
++#define LIB_SUBDIR_TYPE_SPEC "\
++%{mbaserel:/baserel; msdata|msdata=default|msdata=sysv:/small-data}\
++%{msoft-float:/soft-float}"
++
++/* default linker specs */
++#undef REAL_LIBGCC_SPEC
++#define REAL_LIBGCC_SPEC "\
++%{static|static-libgcc: %{!use-dynld: -lgcc -lgcc_eh} %{use-dynld: -lgcc} }%{!static:%{!static-libgcc:%{!shared:%{!shared-libgcc: %{!use-dynld: -lgcc -lgcc_eh} %{use-dynld: -lgcc}}%{shared-libgcc:-lgcc}}%{shared:%{shared-libgcc:-lgcc}%{!shared-libgcc:-lgcc}}}}"
++
++
++/* make newlib the default */
++#if 1
++#define CPP_AMIGA_DEFAULT_SPEC "%{mcrt=default|!mcrt=*:%<mcrt=default -mcrt=newlib} %(cpp_newlib)"
++#define LINK_AMIGA_DEFAULT_SPEC "%(link_newlib)"
++#define STARTFILE_AMIGA_DEFAULT_SPEC "%(startfile_newlib)"
++#define ENDFILE_AMIGA_DEFAULT_SPEC "%(endfile_newlib)"
++#undef MULTILIB_DEFAULTS
++#define MULTILIB_DEFAULTS {"mcrt=newlib"}
++#else
++/* make clib2 the default */
++#define CPP_AMIGA_DEFAULT_SPEC "%{mcrt=default|!mcrt=*:%<mcrt=default -mcrt=clib2} %(cpp_clib2)"
++#define LINK_AMIGA_DEFAULT_SPEC "%(link_clib2)"
++#define STARTFILE_AMIGA_DEFAULT_SPEC "%(startfile_clib2)"
++#define ENDFILE_AMIGA_DEFAULT_SPEC "%(endfile_clib2)"
++#undef MULTILIB_DEFAULTS
++#define MULTILIB_DEFAULTS {"mcrt=clib2"}
++#endif
++
++/* clib2 */
++
++#define CPP_CLIB2_SPEC "\
++-isystem %(base_sdk)clib2/include -isystem %(base_sdk)local/clib2/include"
++
++#define LIB_SUBDIR_CLIB2_SPEC "%{mcrt=clib2-ts:lib.threadsafe; :lib}%(lib_subdir_type)"
++
++#define LINK_CLIB2_SPEC "\
++-L%(base_sdk)clib2/%(lib_subdir_clib2) \
++-L%(base_gcc)lib/gcc/ppc-amigaos/%(version)/%{mcrt=clib2-ts:clib2-ts; :clib2}/lib%(lib_subdir_type) \
++-L%(base_sdk)local/clib2/%(lib_subdir_clib2)"
++
++#define STARTFILE_CLIB2_SPEC "\
++%(base_sdk)clib2/%{mcrt=clib2-ts:lib.threadsafe; :lib}" \
++ "%{!msoft-float:%(lib_subdir_type)}/crtbegin.o \
++%(base_sdk)clib2/%{mcrt=clib2-ts:lib.threadsafe; :lib}" \
++ "%{!msoft-float:%(lib_subdir_type)}/crt0.o"
++
++#define ENDFILE_CLIB2_SPEC "\
++%(base_sdk)clib2/%{mcrt=clib2-ts:lib.threadsafe; :lib}" \
++ "%{!msoft-float:%(lib_subdir_type)}/crtend.o"
++
++/* ixemul */
++
++#define CPP_IXEMUL_SPEC "\
++-isystem %(base_sdk)ixemul/include -isystem %(base_sdk)local/ixemul/include"
++
++#define LIB_SUBDIR_IXEMUL_SPEC "lib%(lib_subdir_type)"
++
++#define LINK_IXEMUL_SPEC "\
++-L%(base_sdk)ixemul/%(lib_subdir_ixemul) \
++-L%(base_gcc)lib/gcc/ppc-amigaos/%(version)/ixemul/%(lib_subdir_ixemul) \
++-L%(base_sdk)local/ixemul/%(lib_subdir_ixemul)"
++
++/* ixemul startfile should work for all library flavours */
++#define STARTFILE_IXEMUL_SPEC "%(base_sdk)ixemul/%(lib_subdir_ixemul)/crtbegin.o"
++#define ENDFILE_IXEMUL_SPEC "%(base_sdk)ixemul/%(lib_subdir_ixemul)/crtend.o"
++
++/* libnix */
++
++#define CPP_LIBNIX_SPEC "\
++-isystem %(base_sdk)libnix/include -isystem %(base_sdk)local/libnix/include"
++
++#define LIB_SUBDIR_LIBNIX_SPEC "lib%(lib_subdir_type)"
++
++#define LINK_LIBNIX_SPEC "\
++-L%(base_sdk)libnix/%(lib_subdir_libnix) \
++-L%(base_gcc)lib/gcc/ppc-amigaos/%(version)/libnix/%(lib_subdir_libnix) \
++-L%(base_sdk)local/libnix/%(lib_subdir_libnix)"
++
++#define STARTFILE_LIBNIX_SPEC "%(base_sdk)libnix/%(lib_subdir_libnix)/crtbegin.o"
++#define ENDFILE_LIBNIX_SPEC "%(base_sdk)libnix/%(lib_subdir_libnix)/crtend.o"
++
++/* newlib */
++
++#define CPP_NEWLIB_SPEC "\
++-isystem %(base_sdk)newlib/include -isystem %(base_sdk)local/newlib/include"
++
++#define LIB_SUBDIR_NEWLIB_SPEC "lib%(lib_subdir_type)"
++
++#define LINK_NEWLIB_SPEC "\
++-L%(base_sdk)newlib/%(lib_subdir_newlib) \
++-L%(base_gcc)lib/gcc/ppc-amigaos/%(version)/newlib/%(lib_subdir_newlib) \
++-L%(base_sdk)local/newlib/%(lib_subdir_newlib)"
++
++/* newlib startfile should work for all library flavours */
++#define STARTFILE_NEWLIB_SPEC "\
++%{shared: %(base_sdk)newlib/%(lib_subdir_newlib)/shcrtbegin.o} %{!shared: %(base_sdk)newlib/%(lib_subdir_newlib)/crtbegin.o}"
++
++#define ENDFILE_NEWLIB_SPEC "\
++%{shared: %(base_sdk)newlib/%(lib_subdir_newlib)/shcrtend.o} %{!shared: %(base_sdk)newlib/%(lib_subdir_newlib)/crtend.o}"
++
++/* End clib specific */
++
++#undef CPP_OS_DEFAULT_SPEC
++#define CPP_OS_DEFAULT_SPEC "\
++%{mcrt=clib2|mcrt=clib2-ts: %(cpp_clib2); \
++mcrt=ixemul: %(cpp_ixemul); \
++mcrt=libnix: %(cpp_libnix); \
++mcrt=newlib: %(cpp_newlib); \
++mcrt=default|!mcrt=*: %{mcrt=default|!nostdinc: %(cpp_amiga_default)}; \
++: %eInvalid C runtime library} \
++-isystem %(base_sdk)include/include_h \
++-isystem %(base_sdk)include/netinclude \
++-isystem %(base_sdk)local/common/include \
++%{mbaserel: %{msdata|msdata=default|msdata=sysv: %e-mbaserel and -msdata options are incompatible}} \
++%{newlib: %e-newlib is obsolete, use -mcrt=newlib instead}"
++
++#undef LINK_SPEC
++#define LINK_SPEC "\
++--defsym __amigaos4__=1 \
++%{!shared: %{!use-dynld: -Bstatic}} \
++-q -d %{h*} %{v:-V} %{G*} \
++%{Wl,*:%*} %{YP,*} %{R*} \
++%{Qy:} %{!Qn:-Qy} \
++%(link_shlib) %(link_text) \
++%{mbaserel: %{msdata|msdata=default|msdata=sysv: %e-mbaserel and -msdata options are incompatible}} \
++%{mcrt=clib2|mcrt=clib2-ts: %(link_clib2); \
++mcrt=ixemul: %(link_ixemul); \
++mcrt=libnix: %(link_libnix); \
++mcrt=newlib: %(link_newlib); \
++mcrt=default|!mcrt=*: %(link_amiga_default); \
++: %eInvalid C runtime library} \
++-L%(base_sdk)local/common/lib%(lib_subdir_type) \
++%{newlib: %e-newlib is obsolete, use -mcrt=newlib instead}"
++
++/* FIXME: LINK_TEXT has been made empty now. Could we get rid of it? */
++#if 0
++#define LINK_TEXT "\
++%{use-dynld: -Ttext=0x100000} %{!use-dynld: %{shared: -Ttext=0x100000} %{!shared: %{!Wl,-T*: %{!T*:-Ttext=0}}}}"
++#else
++#define LINK_TEXT ""
++#endif
++
++#define LINK_SHLIB "\
++%{shared:-shared -dy --defsym __dynld_version__=1} %{!shared: %{static:-static}} %{use-dynld: -dy}"
++
++#undef STARTFILE_SPEC
++#define STARTFILE_SPEC "\
++%{mcrt=clib2|mcrt=clib2-ts: %(startfile_clib2); \
++mcrt=ixemul: %(startfile_ixemul); \
++mcrt=libnix: %(startfile_libnix); \
++mcrt=newlib: %(startfile_newlib); \
++mcrt=default|!mcrt=*: %(startfile_amiga_default); \
++: %eInvalid C runtime library}"
++
++#undef ENDFILE_SPEC
++#define ENDFILE_SPEC "\
++%{mcrt=clib2|mcrt=clib2-ts: %(endfile_clib2); \
++mcrt=ixemul: %(endfile_ixemul); \
++mcrt=libnix: %(endfile_libnix); \
++mcrt=newlib: %(endfile_newlib); \
++mcrt=default|!mcrt=*: %(endfile_amiga_default); \
++: %eInvalid C runtime library}"
++
++#undef LIB_SPEC
++#define LIB_SPEC "\
++--start-group -lc --end-group"
++
++#undef TARGET_DEFAULT
++#define TARGET_DEFAULT 0
++
++#undef SUBTARGET_EXTRA_SPECS
++#define SUBTARGET_EXTRA_SPECS \
++ {"base_gcc", BASE_GCC_SPEC}, \
++ {"base_sdk", BASE_SDK_SPEC}, \
++ {"cpp_os_default", CPP_OS_DEFAULT_SPEC}, \
++ {"lib_subdir_type", LIB_SUBDIR_TYPE_SPEC}, \
++ /* default C runtime */ \
++ {"cpp_amiga_default", CPP_AMIGA_DEFAULT_SPEC}, \
++ {"link_amiga_default", LINK_AMIGA_DEFAULT_SPEC}, \
++ {"startfile_amiga_default", STARTFILE_AMIGA_DEFAULT_SPEC}, \
++ {"endfile_amiga_default", ENDFILE_AMIGA_DEFAULT_SPEC}, \
++ /* clib2 */ \
++ {"cpp_clib2", CPP_CLIB2_SPEC}, \
++ {"lib_subdir_clib2", LIB_SUBDIR_CLIB2_SPEC}, \
++ {"link_clib2", LINK_CLIB2_SPEC}, \
++ {"startfile_clib2", STARTFILE_CLIB2_SPEC}, \
++ {"endfile_clib2", ENDFILE_CLIB2_SPEC}, \
++ /* ixemul */ \
++ {"cpp_ixemul", CPP_IXEMUL_SPEC}, \
++ {"lib_subdir_ixemul", LIB_SUBDIR_IXEMUL_SPEC}, \
++ {"link_ixemul", LINK_IXEMUL_SPEC}, \
++ {"startfile_ixemul", STARTFILE_IXEMUL_SPEC}, \
++ {"endfile_ixemul", ENDFILE_IXEMUL_SPEC}, \
++ /* libnix */ \
++ {"cpp_libnix", CPP_LIBNIX_SPEC}, \
++ {"lib_subdir_libnix", LIB_SUBDIR_LIBNIX_SPEC}, \
++ {"link_libnix", LINK_LIBNIX_SPEC}, \
++ {"startfile_libnix", STARTFILE_LIBNIX_SPEC}, \
++ {"endfile_libnix", ENDFILE_LIBNIX_SPEC}, \
++ /* newlib */ \
++ {"cpp_newlib", CPP_NEWLIB_SPEC}, \
++ {"lib_subdir_newlib", LIB_SUBDIR_NEWLIB_SPEC}, \
++ {"link_newlib", LINK_NEWLIB_SPEC}, \
++ {"startfile_newlib", STARTFILE_NEWLIB_SPEC}, \
++ {"endfile_newlib", ENDFILE_NEWLIB_SPEC}, \
++ /* used in link spec */ \
++ {"link_text", LINK_TEXT}, \
++ {"link_shlib", LINK_SHLIB},
++
++#undef DEFAULT_VTABLE_THUNKS
++#ifndef USE_GNULIBC_1
++#define DEFAULT_VTABLE_THUNKS 1
++#endif
++
++#undef JUMP_TABLES_IN_TEXT_SECTION
++#define JUMP_TABLES_IN_TEXT_SECTION 0
++
++/* Used as cookie for linear vararg passing */
++#define CALL_LINEARVARARGS 0x10000000
++
++/* AmigaOS specific options */
++
++/* Strings provided for own options management in rs6000.c */
++/*extern const char *amigaos_crt_string;*/
++
++#define SUB3TARGET_OVERRIDE_OPTIONS \
++do \
++{ \
++ if (TARGET_ALTIVEC) \
++ { \
++ rs6000_altivec_abi = 1; \
++ TARGET_ALTIVEC_VRSAVE = 1; \
++ } \
++} while(0)
++
++#undef SUBTARGET_EXPAND_BUILTIN
++#define SUBTARGET_EXPAND_BUILTIN(EXP, TARGET, SUBTARGET, MODE, IGNORE, SUCCESS) \
++ amigaos_expand_builtin (EXP, TARGET, SUBTARGET, MODE, IGNORE, SUCCESS)
++
++#undef SUBTARGET_INIT_BUILTINS
++#define SUBTARGET_INIT_BUILTINS \
++ amigaos_init_builtins ()
++
++/* AmigaOS specific attribute */
++#define SUBTARGET_ATTRIBUTE_TABLE \
++ { "linearvarargs", 0, 0, false, true, true, amigaos_handle_linearvarargs_attribute, false}, \
++ { "lineartags", 0, 0, false, true, true, amigaos_handle_lineartags_attribute, false}, \
++ { "baserel_restore", 0, 0, false, true, true, amigaos_handle_baserel_restore_attribute, false }, \
++ { "force_no_baserel", 0, 0, true, false, false, amigaos_handle_force_no_baserel_attribute, false }, \
++ { "check68kfuncptr", 0, 0, false, true, true, amigaos_handle_check68kfuncptr_attribute, false }
++
++/* Overrides */
++/*
++#undef INIT_CUMULATIVE_ARGS
++#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
++ amigaos_init_cumulative_args (&CUM, FNTYPE, LIBNAME, FALSE, N_NAMED_ARGS)
++
++#undef INIT_CUMULATIVE_INCOMING_ARGS
++#define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \
++ amigaos_init_cumulative_args (&CUM, FNTYPE, LIBNAME, TRUE, 1000)
++
++#undef FUNCTION_ARG_ADVANCE
++#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
++ amigaos_function_arg_advance (&CUM, MODE, TYPE, NAMED)
++
++#undef FUNCTION_ARG
++#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
++ amigaos_function_arg (&CUM, MODE, TYPE, NAMED)
++*/
++#undef EXPAND_BUILTIN_VA_START
++#define EXPAND_BUILTIN_VA_START(VALIST, NEXTARG) \
++ amigaos_expand_builtin_va_start (VALIST, NEXTARG)
++
++#undef SLOW_UNALIGNED_ACCESS
++#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) \
++ (STRICT_ALIGNMENT \
++ || (((MODE) == SFmode) && (ALIGN) < 32) \
++ || (((MODE) == DFmode || (MODE) == TFmode || (MODE) == DImode) \
++ && (ALIGN) < 64))
++
++/* This target uses the amigaos.opt file. */
++#define TARGET_USES_AMIGAOS_OPT 1
+diff --git a/gcc/config/rs6000/amigaos.opt b/gcc/config/rs6000/amigaos.opt
+new file mode 100644
+index 0000000000000000000000000000000000000000..93d74f10bea8c1b23c82a9650bb0c3c153464ba7
+--- /dev/null
++++ gcc/config/rs6000/amigaos.opt
+@@ -0,0 +1,37 @@
++; Options for the PowerPC AmigaOS port
++;
++; Copyright (C) 2005 Free Software Foundation, Inc.
++; Contributed by Jens Langner <Jens.Langner@light-speed.de>
++;
++; This file is part of GCC.
++;
++; GCC 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.
++;
++; GCC 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 GCC; see the file COPYING. If not, write to the Free
++; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
++; 02110-1301, USA.
++
++mcrt=
++Target RejectNegative Joined Var(amigaos_crt) Init("newlib")
++Select C runtime library
++
++mbaserel
++Target Report Mask(BASEREL)
++Generate base relative data access
++
++mcheck68kfuncptr
++Target Report Var(CHECK68KFUNCPTR)
++Generate target checking for function pointers
++
++use-dynld
++Target Driver
++Generated binary employs the dynamic linker for shared objects.
+diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def
+index 7b79efcedb31000524ac8ac485a054bef70ff9c3..07ecb46ca445f2503529b61f1acecfd722b673ce 100644
+--- gcc/config/rs6000/rs6000-builtin.def
++++ gcc/config/rs6000/rs6000-builtin.def
+@@ -1985,6 +1985,13 @@ RS6000_BUILTIN_X (RS6000_BUILTIN_MTFSF, "__builtin_mtfsf",
+ RS6000_BTC_MISC | RS6000_BTC_UNARY | RS6000_BTC_VOID,
+ CODE_FOR_rs6000_mtfsf)
+
+ /* Darwin CfString builtin. */
+ BU_SPECIAL_X (RS6000_BUILTIN_CFSTRING, "__builtin_cfstring", RS6000_BTM_ALWAYS,
+ RS6000_BTC_MISC)
++
++/* AmigaOS specific builtin. */
++RS6000_BUILTIN_2 (AMIGAOS_BUILTIN_GETLINEARVA, /* ENUM */ \
++ "__builtin_getlinearva", /* NAME */ \
++ RS6000_BTM_ALWAYS, /* MASK */ \
++ RS6000_BTC_MISC, /* ATTR */ \
++ CODE_FOR_nothing) /* ICODE */
+diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
+index f5c2d422a8076e6fa5da3b864ade636c54cd9af8..ee0ea2ffabb6b9c6fdcba687d88be1e1164374ee 100644
+--- gcc/config/rs6000/rs6000.c
++++ gcc/config/rs6000/rs6000.c
+@@ -161,12 +161,18 @@ typedef struct rs6000_stack {
+ not in save_size */
+ int spe_gp_size; /* size of 64-bit GPR save size for SPE */
+ int spe_padding_size;
+ HOST_WIDE_INT total_size; /* total bytes allocated for stack */
+ int spe_64bit_regs_used;
+ int savres_strategy;
++#ifdef TARGET_BASEREL
++ int baserel_save_p; /* true if the baserel register needs to be
++ saved */
++ int baserel_save_offset; /* offset to save baserel register */
++ int baserel_size; /* size of saved baserel register */
++#endif
+ } rs6000_stack_t;
+
+ /* A C structure for machine-specific, per-function data.
+ This is added to the cfun structure. */
+ typedef struct GTY(()) machine_function
+ {
+@@ -1426,12 +1432,18 @@ static const struct attribute_spec rs6000_attribute_table[] =
+
+ #undef TARGET_ASM_FUNCTION_PROLOGUE
+ #define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
+ #undef TARGET_ASM_FUNCTION_EPILOGUE
+ #define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue
+
++#ifdef TARGET_BASEREL
++extern void amigaos_function_end_prologue(FILE *);
++#undef TARGET_ASM_FUNCTION_END_PROLOGUE
++#define TARGET_ASM_FUNCTION_END_PROLOGUE amigaos_function_end_prologue
++#endif
++
+ #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+ #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA rs6000_output_addr_const_extra
+
+ #undef TARGET_LEGITIMIZE_ADDRESS
+ #define TARGET_LEGITIMIZE_ADDRESS rs6000_legitimize_address
+
+@@ -6957,12 +6969,20 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+ {
+ enum tls_model model = SYMBOL_REF_TLS_MODEL (x);
+ if (model != 0)
+ return rs6000_legitimize_tls_address (x, model);
+ }
+
++#ifdef TARGET_BASEREL
++ if (TARGET_BASEREL
++ && amigaos_baserel_operand(x))
++ {
++ return amigaos_legitimize_baserel_address(x);
++ }
++#endif
++
+ extra = 0;
+ switch (mode)
+ {
+ case TFmode:
+ case TDmode:
+ case TImode:
+@@ -8549,12 +8569,21 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode mode)
+ tmp = gen_rtx_PLUS (mode, tmp, addend);
+ tmp = force_operand (tmp, operands[0]);
+ }
+ operands[1] = tmp;
+ }
+
++#ifdef TARGET_BASEREL
++ if (/*GET_CODE (operands[1]) == SYMBOL_REF
++ && */TARGET_BASEREL
++ && amigaos_baserel_operand (operands[1]))
++ {
++ operands[1] = amigaos_legitimize_baserel_address (operands[1]);
++ }
++#endif
++
+ /* Handle the case where reload calls us with an invalid address. */
+ if (reload_in_progress && mode == Pmode
+ && (! general_operand (operands[1], mode)
+ || ! nonimmediate_operand (operands[0], mode)))
+ goto emit_set;
+
+@@ -8852,12 +8881,20 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode mode)
+ #endif
+ emit_insn (gen_macho_high (target, operands[1]));
+ emit_insn (gen_macho_low (operands[0], target, operands[1]));
+ return;
+ }
+
++#ifdef TARGET_BASEREL
++ if (TARGET_BASEREL && amigaos_baserel_operand(operands[1]))
++ {
++ emit_insn (gen_elf_base_high (target, gen_rtx_REG (Pmode, 2), operands[1]));
++ emit_insn (gen_elf_base_low (operands[0], target, operands[1]));
++ return;
++ }
++#endif
+ emit_insn (gen_elf_high (target, operands[1]));
+ emit_insn (gen_elf_low (operands[0], target, operands[1]));
+ return;
+ }
+
+ /* If this is a SYMBOL_REF that refers to a constant pool entry,
+@@ -9372,12 +9409,18 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
+ if ((!fntype && rs6000_default_long_calls)
+ || (fntype
+ && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
+ && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
+ cum->call_cookie |= CALL_LONG;
+
++ /* AmigaOS4: Check if either libcall or linear varargs, set appropriate cookie */
++ if (fntype && (lookup_attribute ("libcall", TYPE_ATTRIBUTES (fntype))))
++ cum->call_cookie |= CALL_LINEARVARARGS;
++ if (fntype && (lookup_attribute ("linearvarargs", TYPE_ATTRIBUTES (fntype))))
++ cum->call_cookie |= CALL_LINEARVARARGS;
++
+ if (TARGET_DEBUG_ARG)
+ {
+ fprintf (stderr, "\ninit_cumulative_args:");
+ if (fntype)
+ {
+ tree ret_type = TREE_TYPE (fntype);
+@@ -10023,12 +10066,21 @@ rs6000_function_arg_advance_1 (CUMULATIVE_ARGS *cum, machine_mode mode,
+ fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
+ cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
+ fprintf (stderr, "named = %d, align = %d, depth = %d\n",
+ named, align_words - start_words, depth);
+ }
+ }
++
++ /* If the function has the linearvarargs attribute and this argument
++ to advance over is the last non-vararg argument, then advance over
++ all registers, so that the overflow area is hit immediately. */
++ if (cum->call_cookie & CALL_LINEARVARARGS && cum->nargs_prototype <= 0)
++ {
++ cum->sysv_gregno = GP_ARG_MAX_REG + 1;
++ cum->fregno = FP_ARG_V4_MAX_REG + 1;
++ }
+ }
+
+ static void
+ rs6000_function_arg_advance (cumulative_args_t cum, machine_mode mode,
+ const_tree type, bool named)
+ {
+@@ -11189,12 +11241,18 @@ setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
+ save_area = virtual_incoming_args_rtx;
+
+ if (targetm.calls.must_pass_in_stack (mode, type))
+ first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
+ }
+
++#ifdef CALL_LINEARVARARGS
++ /* For AmigaOS: No need to save registers for linearvarargs functions */
++ if (next_cum.call_cookie & CALL_LINEARVARARGS)
++ return;
++#endif
++
+ set = get_varargs_alias_set ();
+ if (! no_rtl && first_reg_offset < GP_ARG_NUM_REG
+ && cfun->va_list_gpr_size)
+ {
+ int n_gpr, nregs = GP_ARG_NUM_REG - first_reg_offset;
+
+@@ -11316,13 +11374,13 @@ rs6000_build_builtin_va_list (void)
+ return build_array_type (record, build_index_type (size_zero_node));
+ }
+
+ /* Implement va_start. */
+
+ static void
+-rs6000_va_start (tree valist, rtx nextarg)
++rs6000_va_start2 (tree valist, rtx nextarg)
+ {
+ HOST_WIDE_INT words, n_gpr, n_fpr;
+ tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
+ tree gpr, fpr, ovf, sav, t;
+
+ /* Only SVR4 needs something special. */
+@@ -11351,12 +11409,21 @@ rs6000_va_start (tree valist, rtx nextarg)
+ words = crtl->args.info.words;
+ n_gpr = MIN (crtl->args.info.sysv_gregno - GP_ARG_MIN_REG,
+ GP_ARG_NUM_REG);
+ n_fpr = MIN (crtl->args.info.fregno - FP_ARG_MIN_REG,
+ FP_ARG_NUM_REG);
+
++ /* For linearvarargs functions, immediately increase the fpr
++ and gpr count to the maximum value, so that va_arg will look
++ only at the stack. */
++ if (crtl->args.info.call_cookie & CALL_LINEARVARARGS)
++ {
++ n_gpr = GP_ARG_NUM_REG;
++ n_fpr = FP_ARG_NUM_REG;
++ }
++
+ if (TARGET_DEBUG_ARG)
+ fprintf (stderr, "va_start: words = "HOST_WIDE_INT_PRINT_DEC", n_gpr = "
+ HOST_WIDE_INT_PRINT_DEC", n_fpr = "HOST_WIDE_INT_PRINT_DEC"\n",
+ words, n_gpr, n_fpr);
+
+ if (cfun->va_list_gpr_size)
+@@ -11402,12 +11469,18 @@ rs6000_va_start (tree valist, rtx nextarg)
+ t = fold_build_pointer_plus_hwi (t, cfun->machine->varargs_save_offset);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+
++void
++rs6000_va_start (tree valist, rtx nextarg)
++{
++ rs6000_va_start2(valist, nextarg);
++}
++
+ /* Implement va_arg. */
+
+ static tree
+ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
+ gimple_seq *post_p)
+ {
+@@ -14155,12 +14228,20 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
+ size_t i;
+ rtx ret;
+ bool success;
+ HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+ bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
+
++ /* Try subtarget first */
++#ifdef SUBTARGET_EXPAND_BUILTIN
++ ret = SUBTARGET_EXPAND_BUILTIN (exp, target, subtarget, mode, ignore, &success);
++ if (success)
++ return ret;
++#endif
++
++
+ if (TARGET_DEBUG_BUILTIN)
+ {
+ enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+ const char *name1 = rs6000_builtin_info[uns_fcode].name;
+ const char *name2 = ((icode != CODE_FOR_nothing)
+ ? get_insn_name ((int)icode)
+@@ -19214,13 +19295,22 @@ print_operand_address (FILE *file, rtx x)
+ #endif
+ #if TARGET_ELF
+ else if (GET_CODE (x) == LO_SUM && REG_P (XEXP (x, 0))
+ && CONSTANT_P (XEXP (x, 1)))
+ {
+ output_addr_const (file, XEXP (x, 1));
++#ifdef TARGET_BASEREL
++ if (TARGET_BASEREL && amigaos_baserel_operand(x))
++ {
++ fprintf (file, "@brel@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
++ }
++ else
++ fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
++#else
+ fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
++#endif
+ }
+ #endif
+ else if (toc_relative_expr_p (x, false))
+ {
+ /* This hack along with a corresponding hack in
+ rs6000_output_addr_const_extra arranges to output addends
+@@ -21827,12 +21917,25 @@ rs6000_stack_info (void)
+ - info_ptr->first_altivec_reg_save);
+
+ /* Does this function call anything? */
+ info_ptr->calls_p = (! crtl->is_leaf
+ || cfun->machine->ra_needs_full_frame);
+
++#ifdef TARGET_BASEREL
++ /* Check if the function wants to setup the baserel register (r2) */
++ if (TARGET_BASEREL
++ && current_function_decl
++ && lookup_attribute ("baserel_restore", TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
++ {
++ info_ptr->baserel_save_p = 1;
++ info_ptr->baserel_size = reg_size;
++ df_set_regs_ever_live(2,true);
++ info_ptr->calls_p = 1;
++ }
++#endif /* TARGET_BASEREL */
++
+ /* Determine if we need to save the condition code registers. */
+ if (df_regs_ever_live_p (CR2_REGNO)
+ || df_regs_ever_live_p (CR3_REGNO)
+ || df_regs_ever_live_p (CR4_REGNO))
+ {
+ info_ptr->cr_save_p = 1;
+@@ -21944,13 +22047,19 @@ rs6000_stack_info (void)
+ info_ptr->lr_save_offset = 2*reg_size;
+ break;
+
+ case ABI_V4:
+ info_ptr->fp_save_offset = - info_ptr->fp_size;
+ info_ptr->gp_save_offset = info_ptr->fp_save_offset - info_ptr->gp_size;
++#ifdef TARGET_BASEREL
++ info_ptr->baserel_save_offset = info_ptr->gp_save_offset
++ - info_ptr->baserel_size;
++ info_ptr->cr_save_offset = info_ptr->baserel_save_offset - info_ptr->cr_size;
++#else
+ info_ptr->cr_save_offset = info_ptr->gp_save_offset - info_ptr->cr_size;
++#endif
+
+ if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
+ {
+ /* Align stack so SPE GPR save area is aligned on a
+ double-word boundary. */
+ if (info_ptr->spe_gp_size != 0 && info_ptr->cr_save_offset != 0)
+@@ -22004,12 +22113,16 @@ rs6000_stack_info (void)
+ + ehrd_size
+ + ehcr_size
+ + info_ptr->cr_size
+ + info_ptr->vrsave_size,
+ save_align);
+
++#ifdef TARGET_BASEREL
++ info_ptr->save_size += RS6000_ALIGN (info_ptr->baserel_size, save_align);
++#endif
++
+ non_fixed_size = (info_ptr->vars_size
+ + info_ptr->parm_size
+ + info_ptr->save_size);
+
+ info_ptr->total_size = RS6000_ALIGN (non_fixed_size + info_ptr->fixed_size,
+ ABI_STACK_BOUNDARY / BITS_PER_UNIT);
+@@ -22188,12 +22301,17 @@ debug_stack_info (rs6000_stack_t *info)
+ if (info->lr_save_p)
+ fprintf (stderr, "\tlr_save_p = %5d\n", info->lr_save_p);
+
+ if (info->cr_save_p)
+ fprintf (stderr, "\tcr_save_p = %5d\n", info->cr_save_p);
+
++#ifdef TARGET_BASEREL
++ if (info->baserel_save_p)
++ fprintf (stderr, "\tbaserel_save_p = %5d\n", info->baserel_save_p);
++#endif
++
+ if (info->vrsave_mask)
+ fprintf (stderr, "\tvrsave_mask = 0x%x\n", info->vrsave_mask);
+
+ if (info->push_p)
+ fprintf (stderr, "\tpush_p = %5d\n", info->push_p);
+
+@@ -22224,12 +22342,17 @@ debug_stack_info (rs6000_stack_t *info)
+ if (info->cr_save_offset)
+ fprintf (stderr, "\tcr_save_offset = %5d\n", info->cr_save_offset);
+
+ if (info->varargs_save_offset)
+ fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset);
+
++#ifdef TARGET_BASEREL
++ if (info->baserel_save_offset && TARGET_BASEREL)
++ fprintf (stderr, "\tbaserel_save_offset = %5d\n", info->baserel_save_offset);
++#endif
++
+ if (info->total_size)
+ fprintf (stderr, "\ttotal_size = "HOST_WIDE_INT_PRINT_DEC"\n",
+ info->total_size);
+
+ if (info->vars_size)
+ fprintf (stderr, "\tvars_size = "HOST_WIDE_INT_PRINT_DEC"\n",
+@@ -22253,12 +22376,17 @@ debug_stack_info (rs6000_stack_t *info)
+ if (info->altivec_size)
+ fprintf (stderr, "\taltivec_size = %5d\n", info->altivec_size);
+
+ if (info->vrsave_size)
+ fprintf (stderr, "\tvrsave_size = %5d\n", info->vrsave_size);
+
++#ifdef TARGET_BASEREL
++ if (info->baserel_size && TARGET_BASEREL)
++ fprintf (stderr, "\tbaserel_size = %5d\n", info->baserel_size);
++#endif
++
+ if (info->altivec_padding_size)
+ fprintf (stderr, "\taltivec_padding_size= %5d\n",
+ info->altivec_padding_size);
+
+ if (info->spe_padding_size)
+ fprintf (stderr, "\tspe_padding_size = %5d\n",
+@@ -23989,12 +24117,28 @@ rs6000_emit_prologue (void)
+ emit_frame_save (frame_reg_rtx, reg_mode,
+ info->first_gp_reg_save + i,
+ info->gp_save_offset + frame_off + reg_size * i,
+ sp_off - frame_off);
+ }
+
++#ifdef TARGET_BASEREL
++ if (info->baserel_save_p && TARGET_BASEREL)
++ {
++ /* Store r2 */
++ rtx addr, reg, mem;
++
++ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
++ GEN_INT (info->baserel_save_offset + frame_off)); /* or sp_off? */
++ mem = gen_frame_mem (reg_mode, addr);
++
++ reg = gen_rtx_REG (reg_mode, 2);
++ insn = emit_move_insn (mem, reg);
++ rs6000_frame_related (insn, gen_rtx_REG (Pmode, 12), info->total_size, /* verify info->total_size */
++ NULL_RTX, NULL_RTX);
++ }
++#endif
+ if (crtl->calls_eh_return)
+ {
+ unsigned int i;
+ rtvec p;
+
+ for (i = 0; ; ++i)
+@@ -24446,12 +24590,19 @@ rs6000_emit_prologue (void)
+
+ if (!info->lr_save_p)
+ emit_move_insn (lr, gen_rtx_REG (Pmode, 0));
+ }
+ #endif
+
++#ifdef TARGET_BASEREL
++ /* Emit a blockage to prevent r2-dependant instructions from moving into
++ * the prologue. r2 is set up later in amigaos_function_end_prologue. */
++ if (info->baserel_save_p && TARGET_BASEREL)
++ emit_insn (gen_blockage ());
++#endif
++
+ /* If we need to, save the TOC register after doing the stack setup.
+ Do not emit eh frame info for this save. The unwinder wants info,
+ conceptually attached to instructions in this function, about
+ register values in the caller of this function. This R2 may have
+ already been changed from the value in the caller.
+ We don't attempt to write accurate DWARF EH frame info for R2
+@@ -24502,12 +24653,17 @@ rs6000_output_savres_externs (FILE *file)
+ & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
+ int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0);
+ name = rs6000_savres_routine_name (info, regno, sel);
+ fprintf (file, "\t.extern %s\n", name);
+ }
+ }
++
++#ifdef TARGET_BASEREL
++ if (info->baserel_save_p && TARGET_BASEREL)
++ fprintf (file, "\t.extern __baserel_get_addr\n");
++#endif
+ }
+
+ /* Write function prologue. */
+
+ static void
+ rs6000_output_function_prologue (FILE *file,
+@@ -25319,12 +25475,30 @@ rs6000_emit_epilogue (int sibcall)
+ + reg_size * (int) i);
+
+ emit_move_insn (gen_rtx_REG (reg_mode, regno), mem);
+ }
+ }
+
++#ifdef TARGET_BASEREL
++ if (info->baserel_save_p && TARGET_BASEREL)
++ {
++ rtx addr, mem, reg;
++
++ /* Restore r2 */
++ addr = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 12),
++ GEN_INT (info->baserel_save_offset + frame_off)); /* or sp_off? */
++ mem = gen_frame_mem (reg_mode, addr);
++
++ reg = gen_rtx_REG (reg_mode, 2);
++ emit_move_insn (reg, mem);
++
++ /* Mark register as used. */
++ emit_insn (gen_rtx_USE (VOIDmode, reg));
++ }
++#endif
++
+ /* Restore GPRs. This is done as a PARALLEL if we are using
+ the load-multiple instructions. */
+ if (TARGET_SPE_ABI
+ && info->spe_64bit_regs_used
+ && info->first_gp_reg_save != 32)
+ {
+diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
+index 653c2c94e11a6f22d20fe3e33532e4d354c2be5e..99ad439bc53ba7194804bb9bcb47e5756e7175e2 100644
+--- gcc/config/rs6000/rs6000.h
++++ gcc/config/rs6000/rs6000.h
+@@ -2771,6 +2771,9 @@ enum rs6000_builtin_type_index
+ #define void_type_internal_node (rs6000_builtin_types[RS6000_BTI_void])
+
+ extern GTY(()) tree rs6000_builtin_types[RS6000_BTI_MAX];
+ extern GTY(()) tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT];
+
+ #define TARGET_SUPPORTS_WIDE_INT 1
++
++/* Used by amigaos port */
++void rs6000_va_start (tree valist, rtx nextarg);
+diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
+index 0e5883c7fc895a454d3677f0818c4f13b625c9ce..c8304a75b801c6c5fbe7617e0b42eb46ad15d050 100644
+--- gcc/config/rs6000/rs6000.md
++++ gcc/config/rs6000/rs6000.md
+@@ -10950,12 +10950,37 @@
+ "TARGET_TOC"
+ "la %0,%a1"
+ "&& TARGET_CMODEL != CMODEL_SMALL && reload_completed"
+ [(set (match_dup 0) (high:P (match_dup 1)))
+ (set (match_dup 0) (lo_sum:P (match_dup 0) (match_dup 1)))])
+
++;; This needs to be above elf_high/elf_low since elf_base_low and elf_low
++;; have the same instruction signature, so in some cases elf_low would be
++;; generated instead of elf_base_low. Since the requirements for elf_base_low
++;; are more restrictive than those for elf_low, there should be no problems
++;; when determining which instruction to use. Additionally, the elf_low function
++;; has now been guared against used accidently.
++(define_insn "elf_base_high"
++ [(set (match_operand:SI 0 "gpc_reg_operand" "=b")
++ (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b")
++ (high:SI (match_operand 2 "" ""))))]
++ "TARGET_ELF && ! TARGET_64BIT && TARGET_BASEREL"
++ "{cau|addis} %0,%1,%2@brel@ha"
++ [(set_attr "length" "4")])
++
++;; Nearly same as elf_low, but used base relative relocs.
++;; The second alternative has also been removed (as %K always
++;; uses normal relocs, see rs6000.c/print_operand()).
++(define_insn "elf_base_low"
++ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
++ (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b")
++ (match_operand 2 "" "")))]
++ "TARGET_ELF && ! TARGET_64BIT && TARGET_BASEREL && amigaos_baserel_operand(operands[2])"
++ "{cal|la} %0,%2@brel@l(%1)"
++ [(set_attr "length" "4")])
++
+ ;; Elf specific ways of loading addresses for non-PIC code.
+ ;; The output of this could be r0, but we make a very strong
+ ;; preference for a base register because it will usually
+ ;; be needed there.
+ (define_insn "elf_high"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=b*r")
+@@ -10964,13 +10989,13 @@
+ "lis %0,%1@ha")
+
+ (define_insn "elf_low"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b")
+ (match_operand 2 "" "")))]
+- "TARGET_ELF && ! TARGET_64BIT"
++ "TARGET_ELF && ! TARGET_64BIT && !(TARGET_BASEREL && amigaos_baserel_operand(operands[2]))"
+ "la %0,%2@l(%1)")
+
+ ;; Call and call_value insns
+ (define_expand "call"
+ [(parallel [(call (mem:SI (match_operand 0 "address_operand" ""))
+ (match_operand 1 "" ""))
+diff --git a/gcc/config/rs6000/t-amigaos b/gcc/config/rs6000/t-amigaos
+new file mode 100644
+index 0000000000000000000000000000000000000000..15d9d3fd5a5f0c8109cd158242745fa52b19257e
+--- /dev/null
++++ gcc/config/rs6000/t-amigaos
+@@ -0,0 +1,20 @@
++# Makefile fragment for AmigaOS/PPC target.
++
++# Extra object file linked to the cc1* executables.
++amigaos.o: $(srcdir)/config/rs6000/amigaos.c $(CONFIG_H)
++ $(CXX) -c $(ALL_CXXFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
++
++# We always have limits.h.
++LIMITS_H_TEST = true
++
++# Override defaults.
++# FIXME: This is only correct when building a native version natively.
++NATIVE_SYSTEM_HEADER_DIR=/gcc/include
++#OTHER_FIXINCLUDES_DIRS=${gcc_tooldir}/include
++
++# Build the libraries for both newlib and clib2
++# We do not build soft float flavours as none of the
++# libs support soft floats
++MULTILIB_OPTIONS = mcrt=newlib/mcrt=clib2
++MULTILIB_DIRNAMES = newlib clib2
++#MULTILIB_REUSE = =mcrt=newlib
+diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
+index 22792556c2431d1875e36cee2304c91d709102ea..cd6a6f14e32a9ee078dd048f5d20965960ac4f44 100644
+--- gcc/cp/typeck.c
++++ gcc/cp/typeck.c
+@@ -3525,12 +3525,28 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
+
+ return error_mark_node;
+ }
+
+ /* fntype now gets the type of function pointed to. */
+ fntype = TREE_TYPE (fntype);
++
++ if (lookup_attribute ("libcall", TYPE_ATTRIBUTES (fntype)) ||
++ lookup_attribute ("libcall2", TYPE_ATTRIBUTES (fntype)))
++ {
++ if (TREE_CODE (function) == COMPONENT_REF && lvalue_p (function))
++ {
++ /* Type of 0 operand of a component ref is always a dereferenced object but
++ * we need to pass the address of this object */
++
++ /* FIXME: param_types? */
++ vec_safe_insert(*params,0,
++ build1(ADDR_EXPR, build_pointer_type (TREE_TYPE (TREE_OPERAND (function, 0))),
++ TREE_OPERAND (function, 0)));
++ }
++ }
++
+ parm_types = TYPE_ARG_TYPES (fntype);
+
+ if (params == NULL)
+ {
+ allocated = make_tree_vector ();
+ params = &allocated;
+diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
+index 70a09032d433c2834f6d1458dcaee92763616570..f63512c1029aa2168a89824ce284844387121082 100644
+--- gcc/doc/extend.texi
++++ gcc/doc/extend.texi
+@@ -4508,12 +4508,163 @@ The @code{weak} attribute causes the declaration to be emitted as a weak
+ symbol rather than a global. This is primarily useful in defining
+ library functions that can be overridden in user code, though it can
+ also be used with non-function declarations. Weak symbols are supported
+ for ELF targets, and also for a.out targets when using the GNU assembler
+ and linker.
+
++@item libcall
++@cindex AmigaOS specific function attributes
++On AmigaOS, the @code{libcall} attribute is used to declare function
++pointers in an AmigaOS @emph{Interface}. When such a function pointer
++is invoked, a pointer to the Interface itself is passed as a hidden
++first argument, similar to @code{this} in C++.
++
++ISO/IEC 9899:1999 Edits for Libcall functions
++
++The following are a set of changes to ISO/IEC 9899:1999 (aka C99)
++that document the exact semantics of the language extension.
++
++@itemize @bullet
++@item
++@cite{6.5.2.2 Function calls}
++
++Change paragraph 3 to
++
++@quotation
++[...] denotes the called function. The arguments to the function
++are specified by the implicit argument, if any, followed by the list
++of expressions.
++@end quotation
++
++Add new paragraph before paragraph 4
++
++@quotation
++If the expression that denotes the called function is a structure or union
++member expression as defined in (6.5.2.3) (or such an expression enclosed
++in any number of parentheses expressions), is an lvalue, and has a type
++that includes the attribute @code{libcall}, then the function call has an
++implicit argument. In other cases there is no implicit argument. If there
++is an implicit argument, then this will be the first argument to the function,
++and the list of expressions will follow it. The type of the implicit
++argument is that of a pointer to the structure or union object of which the
++function expression designates a member. The value of the implicit argument
++is the address of this structure or union object.
++@end quotation
++@end itemize
++
++@item linearvarargs
++@cindex AmigaOS specific function attributes
++On AmigaOS, the @code{linearvarargs} attribute causes all unprototyped
++arguments to a varargs function to be passed on the stack, and not in
++registers as the SVR4 ABI defines. Please note that @code{libcall} also
++implies @code{linearvarargs}.
++
++@item baserel_restore
++@cindex AmigaOS specific function attributes
++On AmigaOS, when compiling with @option{-mbaserel} causes the compiler
++to create a call to @code{baserel_get_addr} function in the function prologue
++to set up register @code{r2}. The previous contents of register @code{r2}
++are restored in the function epilogue. See @option{-mbaserel} option for
++more details.
++
++@item check68kfuncptr
++@cindex AmigaOS specific function attributes
++On AmigaOS, when calling a function using a function pointer causes
++the compiler to emit additional code to allow for function pointers
++to m68k functions. This is currently available only in the C front end.
++
++The generated code will call @code{__amigaos4_check68k_check} function
++which expects one function pointer argument and returns an integer
++value. If the return value is non-zero, the function pointer will be
++used to perform the function call in the usual way, otherwise
++@code{__amigaos4_check68k_trampoline} function will be called to perform
++the call. The @code{__amigaos4_check68k_check} function should be provided
++by the user and will usually just return the result of
++@code{exec.library} @code{IsNative} call on its argument.
++
++The @code{__amigaos4_check68k_trampoline} function is a @code{linearvarargs}
++function and should also be provided by the user. It will receive at
++least two arguments: the number of arguments to the function pointer and
++the function pointer itself. Additionally, the arguments to the function
++pointer will follow on the stack, each having one zero longword in front
++of it with one final zero longword after all the arguments. This makes it
++possible to create tag pairs and a terminating @code{TAG_DONE} for a
++call to @code{EmulateTags} in @code{exec.library}. The return code of
++@code{__amigaos4_check68k_trampoline} function will be used as a return
++code of the function pointer call.
++
++The following example can be used for functions that have no more than
++13 arguments:
++
++@smallexample
++static const UWORD trampoline_code[][6] =
++@{
++ /* @r{JMP (A5)} */
++ @{0X4ED5, 0, 0, 0, 0, 0@},
++ /* @r{MOVEM.L D0, -(A7); JSR (A5); ADDQ.L #4,A7; RTS} */
++ @{0X48E7, 0X8000, 0X4E95, 0X588F, 0X4E75, 0@},
++ /* @r{MOVEM.L D0-D1, -(A7); JSR (A5); ADDQ.L #8, A7; RTS} */
++ @{0X48E7, 0XC000, 0X4E95, 0X508F, 0X4E75, 0@},
++ /* @r{MOVEM.L D0-D2, -(A7); JSR (A5); ADDA.W #0X000C, A7; RTS} */
++ @{0X48E7, 0XE000, 0X4E95, 0XDEFC, 0X000C, 0X4E75@},
++ /* @r{MOVEM.L D0-D3, -(A7); JSR (A5); ADDA.W #0X0010, A7; RTS} */
++ @{0X48E7, 0XF000, 0X4E95, 0XDEFC, 0X0010, 0X4E75@},
++ /* @r{MOVEM.L D0-D4, -(A7); JSR (A5); ADDA.W #0X0014, A7; RTS} */
++ @{0X48E7, 0XF800, 0X4E95, 0XDEFC, 0X0014, 0X4E75@},
++ /* @r{MOVEM.L D0-D5, -(A7); JSR (A5); ADDA.W #0X0018, A7; RTS} */
++ @{0X48E7, 0XFC00, 0X4E95, 0XDEFC, 0X0018, 0X4E75@},
++ /* @r{MOVEM.L D0-D6, -(A7); JSR (A5); ADDA.W #0X001C, A7; RTS} */
++ @{0X48E7, 0XFE00, 0X4E95, 0XDEFC, 0X001C, 0X4E75@},
++ /* @r{MOVEM.L D0-D7, -(A7); JSR (A5); ADDA.W #0X0020, A7; RTS} */
++ @{0X48E7, 0XFF00, 0X4E95, 0XDEFC, 0X0020, 0X4E75@},
++ /* @r{MOVEM.L D0-D7/A0, -(A7); JSR (A5); ADDA.W #0X0024, A7; RTS} */
++ @{0X48E7, 0XFF80, 0X4E95, 0XDEFC, 0X0024, 0X4E75@},
++ /* @r{MOVEM.L D0-D7/A0-A1, -(A7); JSR (A5); ADDA.W #0X0028, A7; RTS} */
++ @{0X48E7, 0XFFC0, 0X4E95, 0XDEFC, 0X0028, 0X4E75@},
++ /* @r{MOVEM.L D0-D7/A0-A2, -(A7); JSR (A5); ADDA.W #0X002C, A7; RTS} */
++ @{0X48E7, 0XFFE0, 0X4E95, 0XDEFC, 0X002C, 0X4E75@},
++ /* @r{MOVEM.L D0-D7/A0-A3, -(A7); JSR (A5); ADDA.W #0X0030, A7; RTS} */
++ @{0X48E7, 0XFFF0, 0X4E95, 0XDEFC, 0X0030, 0X4E75@},
++ /* @r{MOVEM.L D0-D7/A0-A3, -(A7); JSR (A5); ADDA.W #0X0034, A7; RTS} */
++ @{0X48E7, 0XFFF8, 0X4E95, 0XDEFC, 0X0034, 0X4E75@}
++@};
++
++int VARARGS68K __amigaos4_check68k_trampoline(int num_args,
++ int func,
++ ...)
++@{
++ int result, i;
++ va_list args;
++ long *stack;
++
++ va_startlinear(args, func);
++ stack = va_getlinearva(args, long *);
++
++ /* @r{Replace 0's with tag id's} */
++ for(i = 0; i < 8 && i < num_args; i++)
++ stack[i * 2] = ET_RegisterD0 + i;
++
++ while(i < num_args)
++ @{
++ stack[i * 2] = ET_RegisterA0 + i - 8;
++ i++;
++ @}
++
++ if (num_args < sizeof(trampoline_code)
++ / sizeof(trampoline_code[0]))
++ result = IExec->EmulateTags(trampoline_code[num_args],
++ ET_SaveRegs, TRUE,
++ ET_RegisterA5, func,
++ TAG_MORE, stack);
++
++ va_end(args);
++
++ return(result);
++@}
++@end smallexample
++
+ @item weakref
+ @itemx weakref ("@var{target}")
+ @cindex @code{weakref} function attribute
+ The @code{weakref} attribute marks a declaration as a weak reference.
+ Without arguments, it should be accompanied by an @code{alias} attribute
+ naming the target symbol. Optionally, the @var{target} may be given as
+@@ -5698,12 +5849,28 @@ struct
+
+ @noindent
+ Here, @code{t5} takes up 2 bytes.
+ @end enumerate
+ @end table
+
++@subsection AmigaOS PPC Variable Attributes
++
++One attribute is currently defined for AmigaOS PPC.
++
++@table @code
++@item force_no_baserel
++@cindex forcing a variable not to be addressed base relative
++
++This attribute forces access to a variable in code compiled with
++@option{-mbaserel} option not to be base relative. If necessary, the
++access should be protected with some sort of arbitration. See
++documentation on @option{-mbaserel} option for more details about this
++attribute.
++
++@end table
++
+ @subsection Xstormy16 Variable Attributes
+
+ One attribute is currently defined for xstormy16 configurations:
+ @code{below100}.
+
+ @table @code
+diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
+index d3be5899c57fa2147893f27c7c7bddac98bd4ff4..68ecbffa0f2f92f5ecc7331e8e855240134dbcdf 100644
+--- gcc/doc/invoke.texi
++++ gcc/doc/invoke.texi
+@@ -1109,12 +1109,16 @@ See RS/6000 and PowerPC Options.
+ -mtarget-align -mno-target-align @gol
+ -mlongcalls -mno-longcalls}
+
+ @emph{zSeries Options}
+ See S/390 and zSeries Options.
+
++@emph{AmigaOS PPC options}
++@gccoptlist{-mcrt=@var{crt} -mbaserel -mno-baserel @gol
++-mcheck68kfuncptr}
++
+ @item Code Generation Options
+ @xref{Code Gen Options,,Options for Code Generation Conventions}.
+ @gccoptlist{-fcall-saved-@var{reg} -fcall-used-@var{reg} @gol
+ -ffixed-@var{reg} -fexceptions @gol
+ -fnon-call-exceptions -fdelete-dead-exceptions -funwind-tables @gol
+ -fasynchronous-unwind-tables @gol
+@@ -12227,12 +12231,13 @@ platform.
+ * VMS Options::
+ * VxWorks Options::
+ * x86 Options::
+ * x86 Windows Options::
+ * Xstormy16 Options::
+ * Xtensa Options::
++* AmigaOS PPC options::
+ * zSeries Options::
+ @end menu
+
+ @node AArch64 Options
+ @subsection AArch64 Options
+ @cindex AArch64 Options
+@@ -23178,12 +23183,143 @@ These options are defined for Xstormy16:
+ @table @gcctabopt
+ @item -msim
+ @opindex msim
+ Choose startup files and linker script suitable for the simulator.
+ @end table
+
++@node AmigaOS PPC options
++@subsection AmigaOS PPC options
++@cindex AmigaOS PPC options
++
++@table @gcctabopt
++
++@item -mcrt=@var{crt}
++@opindex mcrt
++
++Select the C runtime library to use. The same option must be used for
++both compiling and linking. Some of the possible values are @samp{default},
++@samp{clib2}, @samp{clib2-ts} (thread-safe variant of clib2) and @samp{newlib}.
++Each option makes available an appropriate define, for example
++@code{__CLIB2__}, @code{__NEWLIB__} etc. Additionally, @samp{clib2-ts} option
++provides the @code{__THREAD_SAFE} define.
++
++@item -mbaserel
++@opindex mbaserel
++
++Generate code to access all non-constant data relative to register @code{r2}.
++The executable should also be linked with @option{-mbaserel} option.
++
++This option is useful for creating shared libraries for which all
++openers have a separate copy of non-constant data but share the constant
++data. A better way to do this is by using interface cloning, but
++sometimes this is not possible, for example when some package is being
++ported in form of shared library.
++
++This option can also be used to create residentable programs with
++special startup code.
++
++The startup code or the appropriate interface setup method should use
++@code{CopyDataSegment} function from @samp{elf.library} v51.8 or later to
++copy and relocate the data segment that each instance should have a copy of
++and then set up @code{r2} (and/or @code{EnvironmentVector} interface field
++for libraries) appropriately:
++
++@smallexample
++Elf32_Handle handle = NULL;
++BPTR seg = IDOS->GetProcSegList(NULL);
++
++if (seg)
++@{
++ IDOS->GetSegListInfoTags(seg, GSLI_ElfHandle, &handle, TAG_DONE);
++
++ if (handle
++ && (handle = IElf->OpenElfTags(OET_ElfHandle, handle, TAG_DONE)))
++ @{
++ uint32 offset;
++ uint8 *data = IElf->CopyDataSegment(handle, &offset);
++
++ if (data)
++ @{
++ /* @r{Store @code{data} somewhere since it will be required}
++ * @r{in the cleanup stage}
++ */
++
++ CurrentInterface->Data.EnvironmentVector = data + offset;
++
++ /* @r{Optionally, set r2 to the same value as @code{EnvironmentVector}} if the
++ * @r{current method will call functions access instance local data. This is}
++ * @r{not necessary if the current method will only call interface methods}
++ * @r{which have @code{baserel_restore} attribute (see below).}
++ */
++
++ IElf->CloseElfTags(handle, CET_ReClose, TRUE, TAG_DONE);
++ @}
++ else
++ /* Data was not allocated */;
++ @}
++ else
++ /* ELF handle couldn't be obtained */;
++@}
++else
++ /* Process segment list was not retrieved */;
++
++@end smallexample
++
++The copied data segment should be freed in the cleanup stage using the
++same procedure to obtain the ELF handle and then @code{FreeDataSegmentCopy}
++should be called with the value @code{CopyDataSegment} returned (@emph{not}
++with the value that @code{EnvironmentVector} contains).
++
++Interface methods should include @code{baserel_restore} attribute in their
++definition. When this attribute is present, the compiler will call
++@code{__baserel_get_addr} function in the function prologue. This function
++should set up @code{r2} register and must not modify any other registers
++except @code{r2}. Since it will be called in function prologue, register
++@code{r3} will contain the the first argument of the function. For
++interfaces, this is the interface pointer through which
++@code{EnvironmentVector} field can be accessed. Previous contents
++of register @code{r2} will be restored in the function epilogue.
++
++One possible implementation of @code{__baserel_get_addr} function:
++
++@smallexample
++asm("\n\
++ text\n\
++ globl __baserel_get_addr\n\
++
++__baserel_get_addr:\n\
++ lwz 2, 48(3) /* @r{Fetch EnvironmentVector from struct Interface *} */\n\
++ blr\n\
++");
++@end smallexample
++
++If some non-constant variable needs to be shared by all instances, it
++can be declared with @code{force_no_baserel} attribute. The variable will
++still be present in instance local data area that was created on
++startup, but the compiler will generate code to access it in the
++original data section for all instances. Because of that, the
++declaration of the variable with this attribute must be available to the
++compiler whenever the variable is accessed, otherwise it will generate
++code to access instance local copy of that variable which is probably
++not the desired behaviour. Additionally, some sort of access arbitration
++is probably required.
++
++@item -mno-baserel
++@opindex mno-baserel
++
++Generate absolute data access. This is the default.
++
++@item -mcheck68kfuncptr
++@opindex mcheck68kfuncptr
++
++Causes each function call through a function pointer to be performed as
++if the function pointer was declared with the @samp{check68kfuncptr}
++function attribute. @xref{Function Attributes}.
++
++@end table
++
+ @node Xtensa Options
+ @subsection Xtensa Options
+ @cindex Xtensa Options
+
+ These options are supported for Xtensa targets:
+
+diff --git a/gcc/expr.c b/gcc/expr.c
+index 5c095507f4a303b1c4ab3519d165735be5a37d07..fb57de6652c4bd9dd39300eaaf6c3b2b8aad5fb8 100644
+--- gcc/expr.c
++++ gcc/expr.c
+@@ -8134,13 +8134,12 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
+ tree treeop0, treeop1, treeop2;
+ #define REDUCE_BIT_FIELD(expr) (reduce_bit_field \
+ ? reduce_to_bit_field_precision ((expr), \
+ target, \
+ type) \
+ : (expr))
+-
+ type = ops->type;
+ mode = TYPE_MODE (type);
+ unsignedp = TYPE_UNSIGNED (type);
+
+ treeop0 = ops->op0;
+ treeop1 = ops->op1;
+diff --git a/gcc/gcc.c b/gcc/gcc.c
+index d956c36b151eea45681aa650c39c522f85be359f..d4d061080ba1166fb14069094556246b32265da4 100644
+--- gcc/gcc.c
++++ gcc/gcc.c
+@@ -2730,13 +2730,13 @@ execute (void)
+ commands[0].argv[0] = (string) ? string : commands[0].argv[0];
+ }
+
+ for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++)
+ if (arg && strcmp (arg, "|") == 0)
+ { /* each command. */
+-#if defined (__MSDOS__) || defined (OS2) || defined (VMS)
++#if defined (__MSDOS__) || defined (OS2) || defined (VMS) || defined(AMIGA)
+ fatal_error (input_location, "-pipe not supported");
+ #endif
+ argbuf[i] = 0; /* Termination of
+ command args. */
+ commands[n_commands].prog = argbuf[i + 1];
+ commands[n_commands].argv
+@@ -4261,13 +4261,12 @@ process_command (unsigned int decoded_options_count,
+ add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS",
+ PREFIX_PRIORITY_LAST, 2, 0);
+ #endif
+ add_prefix (&startfile_prefixes, standard_exec_prefix, "BINUTILS",
+ PREFIX_PRIORITY_LAST, 1, 0);
+ }
+-
+ gcc_assert (!IS_ABSOLUTE_PATH (tooldir_base_prefix));
+ tooldir_prefix2 = concat (tooldir_base_prefix, spec_host_machine,
+ dir_separator_str, NULL);
+
+ /* Look for tools relative to the location from which the driver is
+ running, or, if that is not available, the configured prefix. */
+@@ -6312,12 +6311,17 @@ give_switch (int switchnum, int omit_first_word)
+ if (dot)
+ (CONST_CAST (char *, arg))[length] = '.';
+ do_spec_1 (suffix_subst, 1, NULL);
+ }
+ else
+ do_spec_1 (arg, 1, NULL);
++
++#ifdef __amigaos__
++ /* Don't lose args which happen to be the empty string */
++ arg_going = 1;
++#endif /* __amigaos__ */
+ }
+ }
+
+ do_spec_1 (" ", 0, NULL);
+ switches[switchnum].validated = true;
+ }
+@@ -6702,13 +6706,15 @@ is_directory (const char *path1, bool linker)
+ len1 = strlen (path1);
+ path = (char *) alloca (3 + len1);
+ memcpy (path, path1, len1);
+ cp = path + len1;
+ if (!IS_DIR_SEPARATOR (cp[-1]))
+ *cp++ = DIR_SEPARATOR;
++#ifndef __amigaos__
+ *cp++ = '.';
++#endif
+ *cp = '\0';
+
+ /* Exclude directories that the linker is known to search. */
+ if (linker
+ && IS_DIR_SEPARATOR (path[0])
+ && ((cp - path == 6
+@@ -7223,22 +7229,24 @@ driver::set_up_specs () const
+ ? gcc_exec_prefix : standard_exec_prefix,
+ machine_suffix,
+ standard_startfile_prefix, NULL),
+ NULL, PREFIX_PRIORITY_LAST, 0, 1);
+ }
+
++#ifndef __amigaos__
+ /* Sysrooted prefixes are relocated because target_system_root is
+ also relocated by gcc_exec_prefix. */
+ if (*standard_startfile_prefix_1)
+ add_sysrooted_prefix (&startfile_prefixes,
+ standard_startfile_prefix_1, "BINUTILS",
+ PREFIX_PRIORITY_LAST, 0, 1);
+ if (*standard_startfile_prefix_2)
+ add_sysrooted_prefix (&startfile_prefixes,
+ standard_startfile_prefix_2, "BINUTILS",
+ PREFIX_PRIORITY_LAST, 0, 1);
++#endif
+ }
+
+ /* Process any user specified specs in the order given on the command
+ line. */
+ for (struct user_specs *uptr = user_specs_head; uptr; uptr = uptr->next)
+ {
+diff --git a/gcc/prefix.c b/gcc/prefix.c
+index 3d7532380d5ea5b6a56fd89688cbd76a5d01df57..4ce2ce2e576ca3ad7e9ffee2a2ddc0d25620b3b9 100644
+--- gcc/prefix.c
++++ gcc/prefix.c
+@@ -326,13 +326,13 @@ update_path (const char *path, const char *key)
+
+ #ifdef UPDATE_PATH_HOST_CANONICALIZE
+ /* Perform host dependent canonicalization when needed. */
+ UPDATE_PATH_HOST_CANONICALIZE (result);
+ #endif
+
+-#ifdef DIR_SEPARATOR_2
++#if defined (DIR_SEPARATOR_2) && !defined (__amigaos__)
+ /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR. */
+ if (DIR_SEPARATOR_2 != DIR_SEPARATOR)
+ tr (result, DIR_SEPARATOR_2, DIR_SEPARATOR);
+ #endif
+
+ #if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2)
+diff --git a/intl/dcigettext.c b/intl/dcigettext.c
+index a8d4a14d273b153b117b507ec76356635ccd876e..a9cc1066050e10b539149027a5c159f21accfaca 100644
+--- intl/dcigettext.c
++++ intl/dcigettext.c
+@@ -145,13 +145,15 @@ extern int errno;
+ # define tfind __tfind
+ #else
+ # if !defined HAVE_GETCWD
+ char *getwd ();
+ # define getcwd(buf, max) getwd (buf)
+ # else
++# if !defined getcwd
+ char *getcwd ();
++# endif
+ # endif
+ # ifndef HAVE_STPCPY
+ static char *stpcpy PARAMS ((char *dest, const char *src));
+ # endif
+ # ifndef HAVE_MEMPCPY
+ static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
+diff --git a/libcpp/line-map.c b/libcpp/line-map.c
+index f9260d00008988a5b5f6b23e03f8f9abd61edd16..b48616406c55ca77e0ebfaa795f83bc661445f3e 100644
+--- libcpp/line-map.c
++++ libcpp/line-map.c
+@@ -717,12 +717,15 @@ linemap_ordinary_map_lookup (struct line_maps *set, source_location line)
+
+ mn = LINEMAPS_ORDINARY_CACHE (set);
+ mx = LINEMAPS_ORDINARY_USED (set);
+
+ cached = LINEMAPS_ORDINARY_MAP_AT (set, mn);
+ /* We should get a segfault if no line_maps have been added yet. */
++#ifdef __amigaos4__
++ linemap_assert(cached != 0);
++#endif
+ if (line >= MAP_START_LOCATION (cached))
+ {
+ if (mn + 1 == mx || line < MAP_START_LOCATION (&cached[1]))
+ return cached;
+ }
+ else
+diff --git a/libgcc/config.host b/libgcc/config.host
+index 4329891fb986fee1c1e01ee367df18c927a7a4b8..9b5c8e2c189ad14dbadbd8e982b6e25113a41fa5 100644
+--- libgcc/config.host
++++ libgcc/config.host
+@@ -956,12 +956,15 @@ nios2-*-*)
+ tmake_file="$tmake_file nios2/t-nios2 t-softfp-sfdf t-softfp-excl t-softfp"
+ extra_parts="$extra_parts crti.o crtn.o"
+ ;;
+ pdp11-*-*)
+ tmake_file="pdp11/t-pdp11 t-fdpbit"
+ ;;
++powerpc-*-amigaos*)
++ tmake_file="${tmake_file} rs6000/t-savresfgpr rs6000/t-amigaos"
++ ;;
+ powerpc-*-darwin*)
+ case ${host} in
+ *-*-darwin9* | *-*-darwin[12][0-9]*)
+ # libSystem contains unwind information for signal frames since
+ # Darwin 9.
+ ;;
+diff --git a/libgcc/config/rs6000/t-amigaos b/libgcc/config/rs6000/t-amigaos
+new file mode 100644
+index 0000000000000000000000000000000000000000..da1e303eed7e60df883971a610e8904db0df3e23
+--- /dev/null
++++ libgcc/config/rs6000/t-amigaos
+@@ -0,0 +1,45 @@
++# We need to enable the altivec in the assembler as
++# crtsavevr.S needs it. Not sure how this is handled
++# on other platforms or if this is a limitiation
++# of our binutils.
++HOST_LIBGCC2_CFLAGS += -Wa,-maltivec
++
++# The shared library needs to be compiled with -fPIC
++
++gcc_s_compile += -fPIC
++
++
++# We want fine grained libraries, so use the new code to build the
++# floating point emulation libraries.
++FPBIT = fp-bit.c
++DPBIT = dp-bit.c
++
++dp-bit.c: $(srcdir)/config/fp-bit.c
++ cat $(srcdir)/config/fp-bit.c > dp-bit.c
++
++fp-bit.c: $(srcdir)/config/fp-bit.c
++ echo '#define FLOAT' > fp-bit.c
++ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
++
++# Build a shared libgcc library.
++# Note that this also builds clib2 shared lib which is not useable at
++# this writing
++#
++# We don't set LIBGCC2_CFLAGS += -fPIC here as this will also
++# produce a position independend static library. The -fPIC is
++# ensured in the special libgcc t-amigaos file.
++#
++SHLIB_DIR = @multilib_dir@
++SHLIB_SLIBDIR_QUAL = @shlib_slibdir_qual@
++SHLIB_OBJS = @shlib_objs@
++SHLIB_EXT = .so
++SHLIB_SONAME = @shlib_base_name@$(SHLIB_EXT)
++SHLIB_LINK = $(GCC_FOR_TARGET) -shared $(SHLIB_OBJS) -nodefaultlibs $(LIBGCC2_CFLAGS) \
++ -Wl,--soname=libgcc$(SHLIB_EXT) \
++ -o $(SHLIB_DIR)/$(SHLIB_SONAME) @multilib_flags@ $(SHLIB_LC)
++
++# Install the shared libgcc library, but ensure that the name is libgcc.so
++SHLIB_INSTALL = \
++ $(mkinstalldirs) $(DESTDIR)$(inst_libdir); \
++ $(INSTALL_DATA) $(SHLIB_DIR)/$(SHLIB_SONAME) \
++ $(DESTDIR)$(inst_libdir)/libgcc$(SHLIB_EXT);
+diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in
+index f06cc69a973bcf39235febce84a2d7fad7130eed..a3d556b812465e04f339b04bfee766aaaa8eb65b 100644
+--- libiberty/Makefile.in
++++ libiberty/Makefile.in
+@@ -140,12 +140,13 @@ CFILES = alloca.c argv.c asprintf.c atexit.c \
+ make-temp-file.c md5.c memchr.c memcmp.c memcpy.c memmem.c \
+ memmove.c mempcpy.c memset.c mkstemps.c \
+ objalloc.c obstack.c \
+ partition.c pexecute.c \
+ pex-common.c pex-djgpp.c pex-msdos.c pex-one.c \
+ pex-unix.c pex-win32.c \
++ pex-amigaos.c \
+ physmem.c putenv.c \
+ random.c regex.c rename.c rindex.c \
+ safe-ctype.c setenv.c setproctitle.c sha1.c sigsetmask.c \
+ simple-object.c simple-object-coff.c simple-object-elf.c \
+ simple-object-mach-o.c simple-object-xcoff.c \
+ snprintf.c sort.c \
+@@ -207,12 +208,13 @@ CONFIGURED_OFILES = ./asprintf.$(objext) ./atexit.$(objext) \
+ ./getcwd.$(objext) ./getpagesize.$(objext) \
+ ./gettimeofday.$(objext) \
+ ./index.$(objext) ./insque.$(objext) \
+ ./memchr.$(objext) ./memcmp.$(objext) ./memcpy.$(objext) \
+ ./memmem.$(objext) ./memmove.$(objext) \
+ ./mempcpy.$(objext) ./memset.$(objext) ./mkstemps.$(objext) \
++ ./pex-amigaos.$(objext) \
+ ./pex-djgpp.$(objext) ./pex-msdos.$(objext) \
+ ./pex-unix.$(objext) ./pex-win32.$(objext) \
+ ./putenv.$(objext) \
+ ./random.$(objext) ./rename.$(objext) ./rindex.$(objext) \
+ ./setenv.$(objext) \
+ ./setproctitle.$(objext) \
+@@ -1120,12 +1122,19 @@ $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir
+ else true; fi
+ if [ x"$(NOASANFLAG)" != x ]; then \
+ $(COMPILE.c) $(PICFLAG) $(NOASANFLAG) $(srcdir)/pex-win32.c -o noasan/$@; \
+ else true; fi
+ $(COMPILE.c) $(srcdir)/pex-win32.c $(OUTPUT_OPTION)
+
++./pex-amigaos.$(objext): $(srcdir)/pex-amigaos.c config.h $(INCDIR)/ansidecl.h \
++ $(INCDIR)/libiberty.h $(srcdir)/pex-common.h
++ if [ x"$(PICFLAG)" != x ]; then \
++ $(COMPILE.c) $(PICFLAG) $(srcdir)/pex-amigaos.c -o pic/$@; \
++ else true; fi
++ $(COMPILE.c) $(srcdir)/pex-amigaos.c $(OUTPUT_OPTION)
++
+ ./pexecute.$(objext): $(srcdir)/pexecute.c config.h $(INCDIR)/ansidecl.h \
+ $(INCDIR)/libiberty.h
+ if [ x"$(PICFLAG)" != x ]; then \
+ $(COMPILE.c) $(PICFLAG) $(srcdir)/pexecute.c -o pic/$@; \
+ else true; fi
+ if [ x"$(NOASANFLAG)" != x ]; then \
+diff --git a/libiberty/basename.c b/libiberty/basename.c
+index 0f2c069f0ccf5a7d91e4913548e068c247e12efb..6ba5c4aa4f814fbc28f03127d22e91253c980c1b 100644
+--- libiberty/basename.c
++++ libiberty/basename.c
+@@ -15,32 +15,13 @@ Behavior is undefined if the pathname ends in a directory separator.
+ #ifdef HAVE_CONFIG_H
+ #include "config.h"
+ #endif
+ #include "ansidecl.h"
+ #include "libiberty.h"
+ #include "safe-ctype.h"
+-
+-#ifndef DIR_SEPARATOR
+-#define DIR_SEPARATOR '/'
+-#endif
+-
+-#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+- defined (__OS2__)
+-#define HAVE_DOS_BASED_FILE_SYSTEM
+-#ifndef DIR_SEPARATOR_2
+-#define DIR_SEPARATOR_2 '\\'
+-#endif
+-#endif
+-
+-/* Define IS_DIR_SEPARATOR. */
+-#ifndef DIR_SEPARATOR_2
+-# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+-#else /* DIR_SEPARATOR_2 */
+-# define IS_DIR_SEPARATOR(ch) \
+- (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+-#endif /* DIR_SEPARATOR_2 */
++#include "filenames.h"
+
+ char *
+ basename (const char *name)
+ {
+ const char *base;
+
+diff --git a/libiberty/configure b/libiberty/configure
+index b06cab24efa57a9bc6aff387d47833188b796e53..645595a1fdbe34c8387fd19ad78dc1132b4760e3 100755
+--- libiberty/configure
++++ libiberty/configure
+@@ -6809,12 +6809,13 @@ fi
+
+ # Figure out which version of pexecute to use.
+ case "${host}" in
+ *-*-mingw* | *-*-winnt*) pexecute=pex-win32 ;;
+ *-*-msdosdjgpp*) pexecute=pex-djgpp ;;
+ *-*-msdos*) pexecute=pex-msdos ;;
++ *-*-amigaos*) pexecute=pex-amigaos;;
+ *) pexecute=pex-unix ;;
+ esac
+
+
+ if test x$gcc_no_link = xyes; then
+ if test "x${ac_cv_func_mmap_fixed_mapped+set}" != xset; then
+diff --git a/libiberty/configure.ac b/libiberty/configure.ac
+index 922aa86e9b03719135b2b12ee5aad1c0cbd74342..1c5704ff8cf09fc7446aea2d17e163c9589af542 100644
+--- libiberty/configure.ac
++++ libiberty/configure.ac
+@@ -685,12 +685,13 @@ fi
+
+ # Figure out which version of pexecute to use.
+ case "${host}" in
+ *-*-mingw* | *-*-winnt*) pexecute=pex-win32 ;;
+ *-*-msdosdjgpp*) pexecute=pex-djgpp ;;
+ *-*-msdos*) pexecute=pex-msdos ;;
++ *-*-amigaos*) pexecute=pex-amigaos ;;
+ *) pexecute=pex-unix ;;
+ esac
+ AC_SUBST(pexecute)
+
+ libiberty_AC_FUNC_STRNCMP
+
+diff --git a/libiberty/lrealpath.c b/libiberty/lrealpath.c
+index b27c8de990e974c7294dfc4024ef44fbd3844a52..1491511553f865caaf8effc67a3ea42319edd3cf 100644
+--- libiberty/lrealpath.c
++++ libiberty/lrealpath.c
+@@ -46,12 +46,13 @@ components will be simplified. The returned value will be allocated using
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+ #ifdef HAVE_STRING_H
+ #include <string.h>
+ #endif
++#include <stdio.h> /* for MAXPATHLEN */
+
+ /* On GNU libc systems the declaration is only visible with _GNU_SOURCE. */
+ #if defined(HAVE_CANONICALIZE_FILE_NAME) \
+ && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME)
+ extern char *canonicalize_file_name (const char *);
+ #endif
+@@ -106,13 +107,13 @@ lrealpath (const char *filename)
+ compile time buffer size and no alternative function. Query the
+ OS, using pathconf(), for the buffer limit. Care is needed
+ though, some systems do not limit PATH_MAX (return -1 for
+ pathconf()) making it impossible to pass a correctly sized buffer
+ to realpath() (it could always overflow). On those systems, we
+ skip this. */
+-#if defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H)
++#if !defined (REALPATH_LIMIT) && defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H)
+ {
+ /* Find out the max path size. */
+ long path_max = pathconf ("/", _PC_PATH_MAX);
+ if (path_max > 0)
+ {
+ /* PATH_MAX is bounded. */
+diff --git a/libiberty/make-relative-prefix.c b/libiberty/make-relative-prefix.c
+index fe639d18bd2815a5ec33aef28720386725ab1bd5..0b5691adc3f6ed9013472568d9d001495205673b 100644
+--- libiberty/make-relative-prefix.c
++++ libiberty/make-relative-prefix.c
+@@ -63,44 +63,43 @@ relative prefix can be found, return @code{NULL}.
+ #endif
+
+ #include <string.h>
+
+ #include "ansidecl.h"
+ #include "libiberty.h"
++#include "filenames.h"
+
+ #ifndef R_OK
+ #define R_OK 4
+ #define W_OK 2
+ #define X_OK 1
+ #endif
+
+-#ifndef DIR_SEPARATOR
+-# define DIR_SEPARATOR '/'
+-#endif
+-
+ #if defined (_WIN32) || defined (__MSDOS__) \
+ || defined (__DJGPP__) || defined (__OS2__)
+-# define HAVE_DOS_BASED_FILE_SYSTEM
+-# define HAVE_HOST_EXECUTABLE_SUFFIX
+-# define HOST_EXECUTABLE_SUFFIX ".exe"
+-# ifndef DIR_SEPARATOR_2
+-# define DIR_SEPARATOR_2 '\\'
+-# endif
+-# define PATH_SEPARATOR ';'
+-#else
+-# define PATH_SEPARATOR ':'
++# define HAVE_HOST_EXECUTABLE_SUFFIX
++# define HOST_EXECUTABLE_SUFFIX ".exe"
++# define PATH_SEPARATOR ';'
++#endif
++
++#ifdef __amigaos__
++# define PATH_SEPARATOR ':'
++# define DIR_UP ".."
+ #endif
+
+-#ifndef DIR_SEPARATOR_2
+-# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+-#else
+-# define IS_DIR_SEPARATOR(ch) \
+- (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
++#ifndef PATH_SEPARATOR
++# define PATH_SEPARATOR ':'
+ #endif
+
+-#define DIR_UP ".."
++#ifndef DIR_UP
++# define DIR_UP ".."
++#endif
++
++#ifndef DIR_SEPARATOR
++# define DIR_SEPARATOR '/'
++#endif
+
+ static char *save_string (const char *, int);
+ static char **split_directories (const char *, int *);
+ static void free_split_directories (char **);
+
+ static char *
+diff --git a/libiberty/make-temp-file.c b/libiberty/make-temp-file.c
+index 244cc23c5090e1c0d227820dc703adbc8022f8d5..5edcd153410bcd459a0546fd9d3cef6ee91a29af 100644
+--- libiberty/make-temp-file.c
++++ libiberty/make-temp-file.c
+@@ -38,25 +38,26 @@ Boston, MA 02110-1301, USA. */
+ #include <sys/file.h> /* May get R_OK, etc. on some systems. */
+ #endif
+ #if defined(_WIN32) && !defined(__CYGWIN__)
+ #include <windows.h>
+ #endif
+
++#ifndef DIR_SEPARATOR
++#define DIR_SEPARATOR '/'
++#endif
++
+ #ifndef R_OK
+ #define R_OK 4
+ #define W_OK 2
+ #define X_OK 1
+ #endif
+
+ #include "libiberty.h"
+-extern int mkstemps (char *, int);
++#include "filenames.h"
+
+-/* '/' works just fine on MS-DOS based systems. */
+-#ifndef DIR_SEPARATOR
+-#define DIR_SEPARATOR '/'
+-#endif
++extern int mkstemps (char *, int);
+
+ /* Name of temporary file.
+ mktemp requires 6 trailing X's. */
+ #define TEMP_FILE "ccXXXXXX"
+ #define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1)
+
+@@ -78,17 +79,19 @@ try_dir (const char *dir, const char *base)
+ if (dir != 0
+ && access (dir, R_OK | W_OK | X_OK) == 0)
+ return dir;
+ return 0;
+ }
+
++#ifndef __amigaos__
+ static const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 };
+ static const char usrtmp[] =
+ { DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
+ static const char vartmp[] =
+ { DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
++#endif /* __amigaos__ */
+
+ #endif
+
+ static char *memoized_tmpdir;
+
+ /*
+@@ -127,27 +130,37 @@ choose_tmpdir (void)
+ if (strcmp (P_tmpdir, "\\") == 0)
+ base = try_dir ("\\.", base);
+ else
+ base = try_dir (P_tmpdir, base);
+ #endif
+
++#ifndef __amigaos__
+ /* Try /var/tmp, /usr/tmp, then /tmp. */
+ base = try_dir (vartmp, base);
+ base = try_dir (usrtmp, base);
+ base = try_dir (tmp, base);
++#else
++ base = try_dir ("T:", base);
++#endif
+
+ /* If all else fails, use the current directory! */
+ if (base == 0)
+ base = ".";
+ /* Append DIR_SEPARATOR to the directory we've chosen
+ and return it. */
+ len = strlen (base);
+ tmpdir = XNEWVEC (char, len + 2);
+ strcpy (tmpdir, base);
+- tmpdir[len] = DIR_SEPARATOR;
+- tmpdir[len+1] = '\0';
++
++ /* Don't add DIR_SEPARATOR if base already ends with a dir separator,
++ it's unneeded and can cause ill effects on e.g. AmigaOS. */
++ if (!IS_DIR_SEPARATOR(base[len-1]))
++ {
++ tmpdir[len] = DIR_SEPARATOR;
++ tmpdir[len+1] = '\0';
++ }
+ memoized_tmpdir = tmpdir;
+ #else /* defined(_WIN32) && !defined(__CYGWIN__) */
+ DWORD len;
+
+ /* Figure out how much space we need. */
+ len = GetTempPath(0, NULL);
+diff --git a/libiberty/pex-amigaos.c b/libiberty/pex-amigaos.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..0c61a108764c8501f8a2e9552c7c07499f402b1a
+--- /dev/null
++++ libiberty/pex-amigaos.c
+@@ -0,0 +1,325 @@
++/* Utilities to execute a program in a subprocess (possibly linked by pipes
++ with other subprocesses), and wait for it. Generic AMIGAOS specialization.
++ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
++ Free Software Foundation, Inc.
++
++This file is part of the libiberty library.
++Libiberty is free software; you can redistribute it and/or
++modify it under the terms of the GNU Library General Public
++License as published by the Free Software Foundation; either
++version 2 of the License, or (at your option) any later version.
++
++Libiberty 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
++Library General Public License for more details.
++
++You should have received a copy of the GNU Library General Public
++License along with libiberty; see the file COPYING.LIB. If not,
++write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
++Boston, MA 02110-1301, USA. */
++
++#include "pex-common.h"
++
++#include <stdio.h>
++#include <errno.h>
++#ifdef NEED_DECLARATION_ERRNO
++extern int errno;
++#endif
++#ifdef HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++#include <string.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <sys/stat.h>
++#include <ctype.h>
++
++/* Use ECHILD if available, otherwise use EINVAL. */
++#ifdef ECHILD
++#define PWAIT_ERROR ECHILD
++#else
++#define PWAIT_ERROR EINVAL
++#endif
++
++#if !defined(FD_CLOEXEC)
++#define FD_CLOEXEC 1
++#endif
++
++static int pex_amiga_open_read (struct pex_obj *, const char *, int);
++static int pex_amiga_open_write (struct pex_obj *, const char *, int);
++static pid_t pex_amiga_exec_child (struct pex_obj *, int, const char *,
++ char * const *, char * const *,
++ int, int, int, int,
++ const char **, int *);
++static int pex_amiga_close (struct pex_obj *, int);
++static int pex_amiga_wait (struct pex_obj *, long, int *, struct pex_time *,
++ int, const char **, int *);
++static FILE *pex_amiga_fdopenr (struct pex_obj *, int, int);
++static FILE *pex_amiga_fdopenw (struct pex_obj *, int, int);
++
++/* The list of functions we pass to the common routines. */
++
++const struct pex_funcs funcs =
++{
++ pex_amiga_open_read,
++ pex_amiga_open_write,
++ pex_amiga_exec_child,
++ pex_amiga_close,
++ pex_amiga_wait,
++ NULL, /* pipe */
++ pex_amiga_fdopenr,
++ pex_amiga_fdopenw,
++ NULL, /* cleanup */
++};
++
++/* Return a newly initialized pex_obj structure. */
++
++struct pex_obj *
++pex_init (int flags, const char *pname, const char *tempbase)
++{
++ /* AMIGAOS does not support pipes. */
++ flags &= ~ PEX_USE_PIPES;
++ return pex_init_common (flags, pname, tempbase, &funcs);
++}
++
++/* Open a file for reading. */
++
++static int
++pex_amiga_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
++ int binary ATTRIBUTE_UNUSED)
++{
++ return open (name, O_RDONLY);
++}
++
++/* Open a file for writing. */
++
++static int
++pex_amiga_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
++ int binary ATTRIBUTE_UNUSED)
++{
++ /* Note that we can't use O_EXCL here because gcc may have already
++ created the temporary file via make_temp_file. */
++ return open (name, O_WRONLY | O_CREAT | O_TRUNC);
++}
++
++/* Close a file. */
++
++static int
++pex_amiga_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
++{
++ return close (fd);
++}
++
++/* Execute a child. */
++
++const unsigned char __shell_escape_character = '\\';
++
++static pid_t
++pex_amiga_exec_child (struct pex_obj *obj, int flags ATTRIBUTE_UNUSED, const char *executable ATTRIBUTE_UNUSED,
++ char * const * argv, char * const * env ATTRIBUTE_UNUSED,
++ int in ATTRIBUTE_UNUSED, int out ATTRIBUTE_UNUSED, int errdes ATTRIBUTE_UNUSED,
++ int toclose ATTRIBUTE_UNUSED, const char **errmsg, int *err)
++{
++ int rc;
++ char *scmd,*s;
++ int i,j,c,len,arglen;
++ int need_quote;
++ int already_have_quote;
++ int escaped;
++ int *statuses;
++
++ len = 0;
++
++ for(i = 0 ; argv[i] != NULL ; i++)
++ {
++ arglen = strlen(argv[i]);
++
++ len += 1 + arglen;
++
++ need_quote = already_have_quote = 0;
++
++ /* Check if this parameter is already surrounded by double quotes.
++ What counts is that the first character is a double quote. We
++ hope that the last character is an unescaped double quote, but
++ don't check for it. */
++ if(argv[i][0] == '\"')
++ {
++ already_have_quote = 1;
++ }
++ else
++ {
++ /* Check if there's a blank space in the argument. If so, we will
++ need to add double quote characters. */
++ for (j = 0 ; j < arglen ; j++)
++ {
++ c = argv[i][j];
++
++ if (isspace(c))
++ {
++ need_quote = 1;
++ break;
++ }
++ }
++
++ /* Make room for the double quote characters that we will have to add. */
++ if(need_quote)
++ len += 2;
++ }
++
++ /* Check if there are " or * characters in the quoted string which
++ may have to be escaped. */
++ if (need_quote || already_have_quote)
++ {
++ for (j = 0 ; j < arglen ; j++)
++ {
++ c = argv[i][j];
++
++ /* We just might have to add an escape character in front of these two. */
++ if (c == '\"' || c == '*')
++ len++;
++ }
++ }
++ }
++
++ s = scmd = (char *) xmalloc (len+1);
++
++ for(i = 0 ; argv[i] != NULL ; i++)
++ {
++ arglen = strlen(argv[i]);
++
++ need_quote = already_have_quote = 0;
++
++ if (argv[i][0] == '\"')
++ {
++ already_have_quote = 1;
++ }
++ else
++ {
++ for (j = 0 ; j < arglen ; j++)
++ {
++ c = argv[i][j];
++
++ if (isspace(c))
++ {
++ need_quote = 1;
++ break;
++ }
++ }
++ }
++
++ if(s != scmd)
++ (*s++) = ' ';
++
++ if(need_quote)
++ (*s++) = '\"';
++
++ escaped = 0;
++
++ for(j = 0 ; j < arglen ; j++)
++ {
++ c = argv[i][j];
++
++ /* If this is a " or * and the parameter is quoted, try to
++ add an escape character in front of it. */
++ if((c == '\"' || c == '*') && (need_quote || already_have_quote))
++ {
++ /* Careful, don't escape the first double
++ quote character by mistake. */
++ if(!already_have_quote || j > 0)
++ {
++ /* Don't add an escape character here if the previous character
++ already was an escape character. */
++ if(!escaped)
++ (*s++) = '*';
++ }
++ }
++
++ (*s++) = c;
++
++ /* Remember if the last character read was an escape character. */
++ if (escaped)
++ escaped = 0;
++ else
++ escaped = (c == __shell_escape_character && c != '*');
++ }
++
++ if(need_quote)
++ (*s++) = '\"';
++ }
++
++ (*s) = '\0';
++
++ rc = system (scmd);
++
++ free (scmd);
++
++ if (rc == -1)
++ {
++ *err = errno;
++ *errmsg = install_error_msg;
++ return -1;
++ }
++
++ /* Save the exit status for later. When we are called, obj->count
++ is the number of children which have executed before this
++ one. */
++ statuses = (int *) obj->sysdep;
++ statuses = XRESIZEVEC (int, statuses, obj->count + 1);
++ statuses[obj->count] = (rc << 8); /* Tuck the status away for pwait */
++ obj->sysdep = (void *) statuses;
++
++ return obj->count;
++}
++
++/* Create a pipe. */
++/*
++static int
++pex_amiga_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
++ int binary ATTRIBUTE_UNUSED)
++{
++ return pipe (p);
++}
++*/
++
++/* Get a FILE pointer to read from a file descriptor. */
++
++static FILE *
++pex_amiga_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
++ int binary ATTRIBUTE_UNUSED)
++{
++ return fdopen (fd, "r");
++}
++
++/* Get a FILE pointer to write to a file descriptor. */
++
++static FILE *
++pex_amiga_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
++ int binary ATTRIBUTE_UNUSED)
++{
++ if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
++ return NULL;
++ return fdopen (fd, "w");
++}
++
++
++/* Wait for a child process to complete. Actually the child process
++ has already completed, and we just need to return the exit
++ status. */
++
++static int
++pex_amiga_wait (struct pex_obj *obj, long pid, int *status,
++ struct pex_time *time, int done ATTRIBUTE_UNUSED,
++ const char **errmsg ATTRIBUTE_UNUSED,
++ int *err ATTRIBUTE_UNUSED)
++{
++ int *statuses;
++
++ if (time != NULL)
++ memset (time, 0, sizeof (struct pex_time));
++
++ statuses = (int *) obj->sysdep;
++ *status = statuses[pid];
++
++ return 0;
++}
+diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
+index 8cd4c76e70d82a9913c45f26b99e386ad659a3a0..b14ada402280cf8afa221731680d82b794a83352 100755
+--- libstdc++-v3/configure
++++ libstdc++-v3/configure
+@@ -77229,12 +77229,171 @@ done
+
+ $as_echo "#define HAVE_TANF 1" >>confdefs.h
+
+ $as_echo "#define HAVE_TANHF 1" >>confdefs.h
+
+ ;;
++ *-amigaos*)
++ for ac_header in nan.h ieeefp.h endian.h sys/isa_defs.h \
++ machine/endian.h machine/param.h sys/machine.h sys/types.h \
++ fp.h locale.h float.h inttypes.h
++do :
++ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
++ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
++eval as_val=\$$as_ac_Header
++ if test "x$as_val" = x""yes; then :
++ cat >>confdefs.h <<_ACEOF
++#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
++_ACEOF
++
++fi
++
++done
++
++ SECTION_FLAGS='-ffunction-sections -fdata-sections'
++
++
++ # If we're not using GNU ld, then there's no point in even trying these
++ # tests. Check for that first. We should have already tested for gld
++ # by now (in libtool), but require it now just to be safe...
++ test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS=''
++ test -z "$OPT_LDFLAGS" && OPT_LDFLAGS=''
++
++
++
++ # The name set by libtool depends on the version of libtool. Shame on us
++ # for depending on an impl detail, but c'est la vie. Older versions used
++ # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on
++ # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually
++ # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't
++ # set (hence we're using an older libtool), then set it.
++ if test x${with_gnu_ld+set} != xset; then
++ if test x${ac_cv_prog_gnu_ld+set} != xset; then
++ # We got through "ac_require(ac_prog_ld)" and still not set? Huh?
++ with_gnu_ld=no
++ else
++ with_gnu_ld=$ac_cv_prog_gnu_ld
++ fi
++ fi
++
++ # Start by getting the version number. I think the libtool test already
++ # does some of this, but throws away the result.
++ glibcxx_ld_is_gold=no
++ if test x"$with_gnu_ld" = x"yes"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5
++$as_echo_n "checking for ld version... " >&6; }
++
++ if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then
++ glibcxx_ld_is_gold=yes
++ fi
++ ldver=`$LD --version 2>/dev/null |
++ sed -e 's/GNU gold /GNU ld /;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'`
++
++ glibcxx_gnu_ld_version=`echo $ldver | \
++ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'`
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5
++$as_echo "$glibcxx_gnu_ld_version" >&6; }
++ fi
++
++ # Set --gc-sections.
++ glibcxx_have_gc_sections=no
++ if test "$glibcxx_ld_is_gold" = "yes"; then
++ if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then
++ glibcxx_have_gc_sections=yes
++ fi
++ else
++ glibcxx_gcsections_min_ld=21602
++ if test x"$with_gnu_ld" = x"yes" &&
++ test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then
++ glibcxx_have_gc_sections=yes
++ fi
++ fi
++ if test "$glibcxx_have_gc_sections" = "yes"; then
++ # Sufficiently young GNU ld it is! Joy and bunny rabbits!
++ # NB: This flag only works reliably after 2.16.1. Configure tests
++ # for this are difficult, so hard wire a value that should work.
++
++ ac_test_CFLAGS="${CFLAGS+set}"
++ ac_save_CFLAGS="$CFLAGS"
++ CFLAGS='-Wl,--gc-sections'
++
++ # Check for -Wl,--gc-sections
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5
++$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; }
++ if test x$gcc_no_link = xyes; then
++ as_fn_error "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5
++fi
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++ int one(void) { return 1; }
++ int two(void) { return 2; }
++
++int
++main ()
++{
++ two();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_gcsections=yes
++else
++ ac_gcsections=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++ if test "$ac_gcsections" = "yes"; then
++ rm -f conftest.c
++ touch conftest.c
++ if $CC -c conftest.c; then
++ if $LD --gc-sections -o conftest conftest.o 2>&1 | \
++ grep "Warning: gc-sections option ignored" > /dev/null; then
++ ac_gcsections=no
++ fi
++ fi
++ rm -f conftest.c conftest.o conftest
++ fi
++ if test "$ac_gcsections" = "yes"; then
++ SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS"
++ fi
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5
++$as_echo "$ac_gcsections" >&6; }
++
++ if test "$ac_test_CFLAGS" = set; then
++ CFLAGS="$ac_save_CFLAGS"
++ else
++ # this is the suspicious part
++ CFLAGS=''
++ fi
++ fi
++
++ # Set -z,relro.
++ # Note this is only for shared objects.
++ ac_ld_relro=no
++ if test x"$with_gnu_ld" = x"yes"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5
++$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; }
++ cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"`
++ if test -n "$cxx_z_relo"; then
++ OPT_LDFLAGS="-Wl,-z,relro"
++ ac_ld_relro=yes
++ fi
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5
++$as_echo "$ac_ld_relro" >&6; }
++ fi
++
++ # Set linker optimization flags.
++ if test x"$with_gnu_ld" = x"yes"; then
++ OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS"
++ fi
++
++
++
++
++ ;;
+ *)
+ as_fn_error "No support for this host/target combination." "$LINENO" 5
+ ;;
+ esac
+
+ fi
+@@ -80295,43 +80454,1687 @@ $as_echo "$gxx_include_dir" >&6; }
+
+
+ WARN_FLAGS='-Wall -Wextra -Wwrite-strings -Wcast-qual -Wabi'
+
+
+
+-ac_config_files="$ac_config_files Makefile"
+-
+-ac_config_files="$ac_config_files scripts/testsuite_flags"
+-
+-ac_config_files="$ac_config_files scripts/extract_symvers"
++# create libtool - libtool > 2.0:
++: ${CONFIG_LT=./config.lt}
++{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_LT" >&5
++$as_echo "$as_me: creating $CONFIG_LT" >&6;}
++as_write_fail=0
++cat >"$CONFIG_LT" <<_ASEOF || as_write_fail=1
++#! $SHELL
++# Generated by $as_me.
++# Run this file to recreate a libtool stub with the current configuration.
++SHELL=\${CONFIG_SHELL-$SHELL}
++export SHELL
++_ASEOF
++cat >>"$CONFIG_LT" <<\_ASEOF || as_write_fail=1
++## -------------------- ##
++## M4sh Initialization. ##
++## -------------------- ##
+
+-ac_config_files="$ac_config_files doc/xsl/customization.xsl"
++# Be more Bourne compatible
++DUALCASE=1; export DUALCASE # for MKS sh
++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
++ emulate sh
++ NULLCMD=:
++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
++ # is contrary to our usage. Disable this feature.
++ alias -g '${1+"$@"}'='"$@"'
++ setopt NO_GLOB_SUBST
++else
++ case `(set -o) 2>/dev/null` in #(
++ *posix*) :
++ set -o posix ;; #(
++ *) :
++ ;;
++esac
++fi
+
+
+-# Multilibs need MULTISUBDIR defined correctly in certain makefiles so
+-# that multilib installs will end up installed in the correct place.
+-# The testsuite needs it for multilib-aware ABI baseline files.
+-# To work around this not being passed down from config-ml.in ->
+-# srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually
+-# append it here. Only modify Makefiles that have just been created.
+-#
+-# Also, get rid of this simulated-VPATH thing that automake does.
+-ac_config_files="$ac_config_files include/Makefile libsupc++/Makefile src/Makefile src/c++98/Makefile src/c++11/Makefile src/filesystem/Makefile doc/Makefile po/Makefile testsuite/Makefile python/Makefile"
++as_nl='
++'
++export as_nl
++# Printing a long string crashes Solaris 7 /usr/bin/printf.
++as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
++# Prefer a ksh shell builtin over an external printf program on Solaris,
++# but without wasting forks for bash or zsh.
++if test -z "$BASH_VERSION$ZSH_VERSION" \
++ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
++ as_echo='print -r --'
++ as_echo_n='print -rn --'
++elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
++ as_echo='printf %s\n'
++ as_echo_n='printf %s'
++else
++ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
++ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
++ as_echo_n='/usr/ucb/echo -n'
++ else
++ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
++ as_echo_n_body='eval
++ arg=$1;
++ case $arg in #(
++ *"$as_nl"*)
++ expr "X$arg" : "X\\(.*\\)$as_nl";
++ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
++ esac;
++ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
++ '
++ export as_echo_n_body
++ as_echo_n='sh -c $as_echo_n_body as_echo'
++ fi
++ export as_echo_body
++ as_echo='sh -c $as_echo_body as_echo'
++fi
+
++# The user is always right.
++if test "${PATH_SEPARATOR+set}" != set; then
++ PATH_SEPARATOR=:
++ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
++ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
++ PATH_SEPARATOR=';'
++ }
++fi
+
+-ac_config_commands="$ac_config_commands generate-headers"
+
++# IFS
++# We need space, tab and new line, in precisely that order. Quoting is
++# there to prevent editors from complaining about space-tab.
++# (If _AS_PATH_WALK were called with IFS unset, it would disable word
++# splitting by setting IFS to empty value.)
++IFS=" "" $as_nl"
+
+-cat >confcache <<\_ACEOF
+-# This file is a shell script that caches the results of configure
+-# tests run on this system so they can be shared between configure
+-# scripts and configure runs, see configure's option --config-cache.
+-# It is not useful on other systems. If it contains results you don't
+-# want to keep, you may remove or edit it.
+-#
+-# config.status only pays attention to the cache file if you give it
++# Find who we are. Look in the path if we contain no directory separator.
++case $0 in #((
++ *[\\/]* ) as_myself=$0 ;;
++ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
++ done
++IFS=$as_save_IFS
++
++ ;;
++esac
++# We did not find ourselves, most probably we were run as `sh COMMAND'
++# in which case we are not to be found in the path.
++if test "x$as_myself" = x; then
++ as_myself=$0
++fi
++if test ! -f "$as_myself"; then
++ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
++ exit 1
++fi
++
++# Unset variables that we do not need and which cause bugs (e.g. in
++# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
++# suppresses any "Segmentation fault" message there. '((' could
++# trigger a bug in pdksh 5.2.14.
++for as_var in BASH_ENV ENV MAIL MAILPATH
++do eval test x\${$as_var+set} = xset \
++ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
++done
++PS1='$ '
++PS2='> '
++PS4='+ '
++
++# NLS nuisances.
++LC_ALL=C
++export LC_ALL
++LANGUAGE=C
++export LANGUAGE
++
++# CDPATH.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
++
++
++# as_fn_error ERROR [LINENO LOG_FD]
++# ---------------------------------
++# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
++# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
++# script with status $?, using 1 if that was 0.
++as_fn_error ()
++{
++ as_status=$?; test $as_status -eq 0 && as_status=1
++ if test "$3"; then
++ as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
++ fi
++ $as_echo "$as_me: error: $1" >&2
++ as_fn_exit $as_status
++} # as_fn_error
++
++
++# as_fn_set_status STATUS
++# -----------------------
++# Set $? to STATUS, without forking.
++as_fn_set_status ()
++{
++ return $1
++} # as_fn_set_status
++
++# as_fn_exit STATUS
++# -----------------
++# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
++as_fn_exit ()
++{
++ set +e
++ as_fn_set_status $1
++ exit $1
++} # as_fn_exit
++
++# as_fn_unset VAR
++# ---------------
++# Portably unset VAR.
++as_fn_unset ()
++{
++ { eval $1=; unset $1;}
++}
++as_unset=as_fn_unset
++# as_fn_append VAR VALUE
++# ----------------------
++# Append the text in VALUE to the end of the definition contained in VAR. Take
++# advantage of any shell optimizations that allow amortized linear growth over
++# repeated appends, instead of the typical quadratic growth present in naive
++# implementations.
++if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
++ eval 'as_fn_append ()
++ {
++ eval $1+=\$2
++ }'
++else
++ as_fn_append ()
++ {
++ eval $1=\$$1\$2
++ }
++fi # as_fn_append
++
++# as_fn_arith ARG...
++# ------------------
++# Perform arithmetic evaluation on the ARGs, and store the result in the
++# global $as_val. Take advantage of shells that can avoid forks. The arguments
++# must be portable across $(()) and expr.
++if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
++ eval 'as_fn_arith ()
++ {
++ as_val=$(( $* ))
++ }'
++else
++ as_fn_arith ()
++ {
++ as_val=`expr "$@" || test $? -eq 1`
++ }
++fi # as_fn_arith
++
++
++if expr a : '\(a\)' >/dev/null 2>&1 &&
++ test "X`expr 00001 : '.*\(...\)'`" = X001; then
++ as_expr=expr
++else
++ as_expr=false
++fi
++
++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
++ as_basename=basename
++else
++ as_basename=false
++fi
++
++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
++ as_dirname=dirname
++else
++ as_dirname=false
++fi
++
++as_me=`$as_basename -- "$0" ||
++$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
++ X"$0" : 'X\(//\)$' \| \
++ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X/"$0" |
++ sed '/^.*\/\([^/][^/]*\)\/*$/{
++ s//\1/
++ q
++ }
++ /^X\/\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\/\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++
++# Avoid depending upon Character Ranges.
++as_cr_letters='abcdefghijklmnopqrstuvwxyz'
++as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
++as_cr_Letters=$as_cr_letters$as_cr_LETTERS
++as_cr_digits='0123456789'
++as_cr_alnum=$as_cr_Letters$as_cr_digits
++
++ECHO_C= ECHO_N= ECHO_T=
++case `echo -n x` in #(((((
++-n*)
++ case `echo 'xy\c'` in
++ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
++ xy) ECHO_C='\c';;
++ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
++ ECHO_T=' ';;
++ esac;;
++*)
++ ECHO_N='-n';;
++esac
++
++rm -f conf$$ conf$$.exe conf$$.file
++if test -d conf$$.dir; then
++ rm -f conf$$.dir/conf$$.file
++else
++ rm -f conf$$.dir
++ mkdir conf$$.dir 2>/dev/null
++fi
++if (echo >conf$$.file) 2>/dev/null; then
++ if ln -s conf$$.file conf$$ 2>/dev/null; then
++ as_ln_s='ln -s'
++ # ... but there are two gotchas:
++ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
++ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
++ # In both cases, we have to default to `cp -p'.
++ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
++ as_ln_s='cp -p'
++ elif ln conf$$.file conf$$ 2>/dev/null; then
++ as_ln_s=ln
++ else
++ as_ln_s='cp -p'
++ fi
++else
++ as_ln_s='cp -p'
++fi
++rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
++rmdir conf$$.dir 2>/dev/null
++
++
++# as_fn_mkdir_p
++# -------------
++# Create "$as_dir" as a directory, including parents if necessary.
++as_fn_mkdir_p ()
++{
++
++ case $as_dir in #(
++ -*) as_dir=./$as_dir;;
++ esac
++ test -d "$as_dir" || eval $as_mkdir_p || {
++ as_dirs=
++ while :; do
++ case $as_dir in #(
++ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
++ *) as_qdir=$as_dir;;
++ esac
++ as_dirs="'$as_qdir' $as_dirs"
++ as_dir=`$as_dirname -- "$as_dir" ||
++$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$as_dir" : 'X\(//\)[^/]' \| \
++ X"$as_dir" : 'X\(//\)$' \| \
++ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$as_dir" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++ test -d "$as_dir" && break
++ done
++ test -z "$as_dirs" || eval "mkdir $as_dirs"
++ } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
++
++
++} # as_fn_mkdir_p
++if mkdir -p . 2>/dev/null; then
++ as_mkdir_p='mkdir -p "$as_dir"'
++else
++ test -d ./-p && rmdir ./-p
++ as_mkdir_p=false
++fi
++
++if test -x / >/dev/null 2>&1; then
++ as_test_x='test -x'
++else
++ if ls -dL / >/dev/null 2>&1; then
++ as_ls_L_option=L
++ else
++ as_ls_L_option=
++ fi
++ as_test_x='
++ eval sh -c '\''
++ if test -d "$1"; then
++ test -d "$1/.";
++ else
++ case $1 in #(
++ -*)set "./$1";;
++ esac;
++ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
++ ???[sx]*):;;*)false;;esac;fi
++ '\'' sh
++ '
++fi
++as_executable_p=$as_test_x
++
++# Sed expression to map a string onto a valid CPP name.
++as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
++
++# Sed expression to map a string onto a valid variable name.
++as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
++
++
++exec 6>&1
++## --------------------------------- ##
++## Main body of "$CONFIG_LT" script. ##
++## --------------------------------- ##
++_ASEOF
++test $as_write_fail = 0 && chmod +x "$CONFIG_LT"
++
++cat >>"$CONFIG_LT" <<\_LTEOF
++lt_cl_silent=false
++exec 5>>config.log
++{
++ echo
++ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
++## Running $as_me. ##
++_ASBOX
++} >&5
++
++lt_cl_help="\
++\`$as_me' creates a local libtool stub from the current configuration,
++for use in further configure time tests before the real libtool is
++generated.
++
++Usage: $0 [OPTIONS]
++
++ -h, --help print this help, then exit
++ -V, --version print version number, then exit
++ -q, --quiet do not print progress messages
++ -d, --debug don't remove temporary files
++
++Report bugs to <bug-libtool@gnu.org>."
++
++lt_cl_version="\
++package-unused config.lt version-unused
++configured by $0, generated by GNU Autoconf 2.64.
++
++Copyright (C) 2009 Free Software Foundation, Inc.
++This config.lt script is free software; the Free Software Foundation
++gives unlimited permision to copy, distribute and modify it."
++
++while test $# != 0
++do
++ case $1 in
++ --version | --v* | -V )
++ echo "$lt_cl_version"; exit 0 ;;
++ --help | --h* | -h )
++ echo "$lt_cl_help"; exit 0 ;;
++ --debug | --d* | -d )
++ debug=: ;;
++ --quiet | --q* | --silent | --s* | -q )
++ lt_cl_silent=: ;;
++
++ -*) as_fn_error "unrecognized option: $1
++Try \`$0 --help' for more information." "$LINENO" 5 ;;
++
++ *) as_fn_error "unrecognized argument: $1
++Try \`$0 --help' for more information." "$LINENO" 5 ;;
++ esac
++ shift
++done
++
++if $lt_cl_silent; then
++ exec 6>/dev/null
++fi
++_LTEOF
++
++cat >>"$CONFIG_LT" <<_LTEOF
++
++
++# The HP-UX ksh and POSIX shell print the target directory to stdout
++# if CDPATH is set.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
++
++sed_quote_subst='$sed_quote_subst'
++double_quote_subst='$double_quote_subst'
++delay_variable_subst='$delay_variable_subst'
++macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
++macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
++enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
++enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
++pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
++enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
++SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
++ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
++host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
++host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
++host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
++build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
++build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
++build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
++SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
++Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
++GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
++EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
++FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
++LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
++NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
++LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
++max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
++ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
++exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
++lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
++lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
++lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
++reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
++reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
++OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
++deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
++file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
++AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
++AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
++STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
++RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
++old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
++old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
++old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
++lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
++CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
++CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
++compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
++GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
++lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
++lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
++lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
++objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
++MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
++lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
++need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
++DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
++NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
++LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
++OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
++OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
++libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
++shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
++extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
++archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
++enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
++export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
++whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
++compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
++old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
++old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
++archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
++archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
++module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
++module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
++with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
++allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
++no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
++hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
++hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`'
++hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
++hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
++hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
++hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
++hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
++hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
++inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
++link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
++fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`'
++always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
++export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
++exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
++include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
++prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
++file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
++variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
++need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
++need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
++version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
++runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
++shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
++shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
++libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
++library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
++soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
++install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
++postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
++postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
++finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
++finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
++hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
++sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
++sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
++hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
++enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
++enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
++enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
++old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
++striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
++compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`'
++predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`'
++postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`'
++predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`'
++postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`'
++compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`'
++LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`'
++reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`'
++reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`'
++old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
++compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`'
++GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`'
++lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`'
++archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`'
++enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`'
++export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
++whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
++compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`'
++old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`'
++old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`'
++archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
++archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
++module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`'
++module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
++with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`'
++allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
++no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
++hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
++hardcode_libdir_flag_spec_ld_CXX='`$ECHO "$hardcode_libdir_flag_spec_ld_CXX" | $SED "$delay_single_quote_subst"`'
++hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`'
++hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`'
++hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`'
++hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`'
++hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`'
++hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`'
++inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`'
++link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`'
++fix_srcfile_path_CXX='`$ECHO "$fix_srcfile_path_CXX" | $SED "$delay_single_quote_subst"`'
++always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`'
++export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`'
++exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
++include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
++prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
++file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`'
++hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`'
++compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`'
++predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`'
++postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`'
++predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`'
++postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`'
++compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`'
++
++LTCC='$LTCC'
++LTCFLAGS='$LTCFLAGS'
++compiler='$compiler_DEFAULT'
++
++# A function that is used when there is no print builtin or printf.
++func_fallback_echo ()
++{
++ eval 'cat <<_LTECHO_EOF
++\$1
++_LTECHO_EOF'
++}
++
++# Quote evaled strings.
++for var in SHELL \
++ECHO \
++SED \
++GREP \
++EGREP \
++FGREP \
++LD \
++NM \
++LN_S \
++lt_SP2NL \
++lt_NL2SP \
++reload_flag \
++OBJDUMP \
++deplibs_check_method \
++file_magic_cmd \
++AR \
++AR_FLAGS \
++STRIP \
++RANLIB \
++CC \
++CFLAGS \
++compiler \
++lt_cv_sys_global_symbol_pipe \
++lt_cv_sys_global_symbol_to_cdecl \
++lt_cv_sys_global_symbol_to_c_name_address \
++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
++lt_prog_compiler_no_builtin_flag \
++lt_prog_compiler_wl \
++lt_prog_compiler_pic \
++lt_prog_compiler_static \
++lt_cv_prog_compiler_c_o \
++need_locks \
++DSYMUTIL \
++NMEDIT \
++LIPO \
++OTOOL \
++OTOOL64 \
++shrext_cmds \
++export_dynamic_flag_spec \
++whole_archive_flag_spec \
++compiler_needs_object \
++with_gnu_ld \
++allow_undefined_flag \
++no_undefined_flag \
++hardcode_libdir_flag_spec \
++hardcode_libdir_flag_spec_ld \
++hardcode_libdir_separator \
++fix_srcfile_path \
++exclude_expsyms \
++include_expsyms \
++file_list_spec \
++variables_saved_for_relink \
++libname_spec \
++library_names_spec \
++soname_spec \
++install_override_mode \
++finish_eval \
++old_striplib \
++striplib \
++compiler_lib_search_dirs \
++predep_objects \
++postdep_objects \
++predeps \
++postdeps \
++compiler_lib_search_path \
++LD_CXX \
++reload_flag_CXX \
++compiler_CXX \
++lt_prog_compiler_no_builtin_flag_CXX \
++lt_prog_compiler_wl_CXX \
++lt_prog_compiler_pic_CXX \
++lt_prog_compiler_static_CXX \
++lt_cv_prog_compiler_c_o_CXX \
++export_dynamic_flag_spec_CXX \
++whole_archive_flag_spec_CXX \
++compiler_needs_object_CXX \
++with_gnu_ld_CXX \
++allow_undefined_flag_CXX \
++no_undefined_flag_CXX \
++hardcode_libdir_flag_spec_CXX \
++hardcode_libdir_flag_spec_ld_CXX \
++hardcode_libdir_separator_CXX \
++fix_srcfile_path_CXX \
++exclude_expsyms_CXX \
++include_expsyms_CXX \
++file_list_spec_CXX \
++compiler_lib_search_dirs_CXX \
++predep_objects_CXX \
++postdep_objects_CXX \
++predeps_CXX \
++postdeps_CXX \
++compiler_lib_search_path_CXX; do
++ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
++ *[\\\\\\\`\\"\\\$]*)
++ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
++ ;;
++ *)
++ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
++ ;;
++ esac
++done
++
++# Double-quote double-evaled strings.
++for var in reload_cmds \
++old_postinstall_cmds \
++old_postuninstall_cmds \
++old_archive_cmds \
++extract_expsyms_cmds \
++old_archive_from_new_cmds \
++old_archive_from_expsyms_cmds \
++archive_cmds \
++archive_expsym_cmds \
++module_cmds \
++module_expsym_cmds \
++export_symbols_cmds \
++prelink_cmds \
++postinstall_cmds \
++postuninstall_cmds \
++finish_cmds \
++sys_lib_search_path_spec \
++sys_lib_dlsearch_path_spec \
++reload_cmds_CXX \
++old_archive_cmds_CXX \
++old_archive_from_new_cmds_CXX \
++old_archive_from_expsyms_cmds_CXX \
++archive_cmds_CXX \
++archive_expsym_cmds_CXX \
++module_cmds_CXX \
++module_expsym_cmds_CXX \
++export_symbols_cmds_CXX \
++prelink_cmds_CXX; do
++ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
++ *[\\\\\\\`\\"\\\$]*)
++ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
++ ;;
++ *)
++ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
++ ;;
++ esac
++done
++
++ac_aux_dir='$ac_aux_dir'
++xsi_shell='$xsi_shell'
++lt_shell_append='$lt_shell_append'
++
++# See if we are running on zsh, and set the options which allow our
++# commands through without removal of \ escapes INIT.
++if test -n "\${ZSH_VERSION+set}" ; then
++ setopt NO_GLOB_SUBST
++fi
++
++
++ PACKAGE='$PACKAGE'
++ VERSION='$VERSION'
++ TIMESTAMP='$TIMESTAMP'
++ RM='$RM'
++ ofile='$ofile'
++
++
++
++
++
++_LTEOF
++
++cat >>"$CONFIG_LT" <<\_LTEOF
++{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $ofile" >&5
++$as_echo "$as_me: creating $ofile" >&6;}
++
++
++ # See if we are running on zsh, and set the options which allow our
++ # commands through without removal of \ escapes.
++ if test -n "${ZSH_VERSION+set}" ; then
++ setopt NO_GLOB_SUBST
++ fi
++
++ cfgfile="${ofile}T"
++ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
++ $RM "$cfgfile"
++
++ cat <<_LT_EOF >> "$cfgfile"
++#! $SHELL
++
++# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
++# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
++# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
++# NOTE: Changes made to this file will be lost: look at ltmain.sh.
++#
++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
++# 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
++# Written by Gordon Matzigkeit, 1996
++#
++# This file is part of GNU Libtool.
++#
++# GNU Libtool 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.
++#
++# As a special exception to the GNU General Public License,
++# if you distribute this file as part of a program or library that
++# is built using GNU Libtool, you may include this file under the
++# same distribution terms that you use for the rest of that program.
++#
++# GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy
++# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
++# obtained by writing to the Free Software Foundation, Inc.,
++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++
++
++# The names of the tagged configurations supported by this script.
++available_tags="CXX "
++
++# ### BEGIN LIBTOOL CONFIG
++
++# Which release of libtool.m4 was used?
++macro_version=$macro_version
++macro_revision=$macro_revision
++
++# Whether or not to build shared libraries.
++build_libtool_libs=$enable_shared
++
++# Whether or not to build static libraries.
++build_old_libs=$enable_static
++
++# What type of objects to build.
++pic_mode=$pic_mode
++
++# Whether or not to optimize for fast installation.
++fast_install=$enable_fast_install
++
++# Shell to use when invoking shell scripts.
++SHELL=$lt_SHELL
++
++# An echo program that protects backslashes.
++ECHO=$lt_ECHO
++
++# The host system.
++host_alias=$host_alias
++host=$host
++host_os=$host_os
++
++# The build system.
++build_alias=$build_alias
++build=$build
++build_os=$build_os
++
++# A sed program that does not truncate output.
++SED=$lt_SED
++
++# Sed that helps us avoid accidentally triggering echo(1) options like -n.
++Xsed="\$SED -e 1s/^X//"
++
++# A grep program that handles long lines.
++GREP=$lt_GREP
++
++# An ERE matcher.
++EGREP=$lt_EGREP
++
++# A literal string matcher.
++FGREP=$lt_FGREP
++
++# A BSD- or MS-compatible name lister.
++NM=$lt_NM
++
++# Whether we need soft or hard links.
++LN_S=$lt_LN_S
++
++# What is the maximum length of a command?
++max_cmd_len=$max_cmd_len
++
++# Object file suffix (normally "o").
++objext=$ac_objext
++
++# Executable file suffix (normally "").
++exeext=$exeext
++
++# whether the shell understands "unset".
++lt_unset=$lt_unset
++
++# turn spaces into newlines.
++SP2NL=$lt_lt_SP2NL
++
++# turn newlines into spaces.
++NL2SP=$lt_lt_NL2SP
++
++# An object symbol dumper.
++OBJDUMP=$lt_OBJDUMP
++
++# Method to check whether dependent libraries are shared objects.
++deplibs_check_method=$lt_deplibs_check_method
++
++# Command to use when deplibs_check_method == "file_magic".
++file_magic_cmd=$lt_file_magic_cmd
++
++# The archiver.
++AR=$lt_AR
++AR_FLAGS=$lt_AR_FLAGS
++
++# A symbol stripping program.
++STRIP=$lt_STRIP
++
++# Commands used to install an old-style archive.
++RANLIB=$lt_RANLIB
++old_postinstall_cmds=$lt_old_postinstall_cmds
++old_postuninstall_cmds=$lt_old_postuninstall_cmds
++
++# Whether to use a lock for old archive extraction.
++lock_old_archive_extraction=$lock_old_archive_extraction
++
++# A C compiler.
++LTCC=$lt_CC
++
++# LTCC compiler flags.
++LTCFLAGS=$lt_CFLAGS
++
++# Take the output of nm and produce a listing of raw symbols and C names.
++global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
++
++# Transform the output of nm in a proper C declaration.
++global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
++
++# Transform the output of nm in a C name address pair.
++global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
++
++# Transform the output of nm in a C name address pair when lib prefix is needed.
++global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
++
++# The name of the directory that contains temporary libtool files.
++objdir=$objdir
++
++# Used to examine libraries when file_magic_cmd begins with "file".
++MAGIC_CMD=$MAGIC_CMD
++
++# Must we lock files when doing compilation?
++need_locks=$lt_need_locks
++
++# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
++DSYMUTIL=$lt_DSYMUTIL
++
++# Tool to change global to local symbols on Mac OS X.
++NMEDIT=$lt_NMEDIT
++
++# Tool to manipulate fat objects and archives on Mac OS X.
++LIPO=$lt_LIPO
++
++# ldd/readelf like tool for Mach-O binaries on Mac OS X.
++OTOOL=$lt_OTOOL
++
++# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
++OTOOL64=$lt_OTOOL64
++
++# Old archive suffix (normally "a").
++libext=$libext
++
++# Shared library suffix (normally ".so").
++shrext_cmds=$lt_shrext_cmds
++
++# The commands to extract the exported symbol list from a shared archive.
++extract_expsyms_cmds=$lt_extract_expsyms_cmds
++
++# Variables whose values should be saved in libtool wrapper scripts and
++# restored at link time.
++variables_saved_for_relink=$lt_variables_saved_for_relink
++
++# Do we need the "lib" prefix for modules?
++need_lib_prefix=$need_lib_prefix
++
++# Do we need a version for libraries?
++need_version=$need_version
++
++# Library versioning type.
++version_type=$version_type
++
++# Shared library runtime path variable.
++runpath_var=$runpath_var
++
++# Shared library path variable.
++shlibpath_var=$shlibpath_var
++
++# Is shlibpath searched before the hard-coded library search path?
++shlibpath_overrides_runpath=$shlibpath_overrides_runpath
++
++# Format of library name prefix.
++libname_spec=$lt_libname_spec
++
++# List of archive names. First name is the real one, the rest are links.
++# The last name is the one that the linker finds with -lNAME
++library_names_spec=$lt_library_names_spec
++
++# The coded name of the library, if different from the real name.
++soname_spec=$lt_soname_spec
++
++# Permission mode override for installation of shared libraries.
++install_override_mode=$lt_install_override_mode
++
++# Command to use after installation of a shared archive.
++postinstall_cmds=$lt_postinstall_cmds
++
++# Command to use after uninstallation of a shared archive.
++postuninstall_cmds=$lt_postuninstall_cmds
++
++# Commands used to finish a libtool library installation in a directory.
++finish_cmds=$lt_finish_cmds
++
++# As "finish_cmds", except a single script fragment to be evaled but
++# not shown.
++finish_eval=$lt_finish_eval
++
++# Whether we should hardcode library paths into libraries.
++hardcode_into_libs=$hardcode_into_libs
++
++# Compile-time system search path for libraries.
++sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
++
++# Run-time system search path for libraries.
++sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
++
++# Whether dlopen is supported.
++dlopen_support=$enable_dlopen
++
++# Whether dlopen of programs is supported.
++dlopen_self=$enable_dlopen_self
++
++# Whether dlopen of statically linked programs is supported.
++dlopen_self_static=$enable_dlopen_self_static
++
++# Commands to strip libraries.
++old_striplib=$lt_old_striplib
++striplib=$lt_striplib
++
++
++# The linker used to build libraries.
++LD=$lt_LD
++
++# How to create reloadable object files.
++reload_flag=$lt_reload_flag
++reload_cmds=$lt_reload_cmds
++
++# Commands used to build an old-style archive.
++old_archive_cmds=$lt_old_archive_cmds
++
++# A language specific compiler.
++CC=$lt_compiler
++
++# Is the compiler the GNU compiler?
++with_gcc=$GCC
++
++# Compiler flag to turn off builtin functions.
++no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
++
++# How to pass a linker flag through the compiler.
++wl=$lt_lt_prog_compiler_wl
++
++# Additional compiler flags for building library objects.
++pic_flag=$lt_lt_prog_compiler_pic
++
++# Compiler flag to prevent dynamic linking.
++link_static_flag=$lt_lt_prog_compiler_static
++
++# Does compiler simultaneously support -c and -o options?
++compiler_c_o=$lt_lt_cv_prog_compiler_c_o
++
++# Whether or not to add -lc for building shared libraries.
++build_libtool_need_lc=$archive_cmds_need_lc
++
++# Whether or not to disallow shared libs when runtime libs are static.
++allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
++
++# Compiler flag to allow reflexive dlopens.
++export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
++
++# Compiler flag to generate shared objects directly from archives.
++whole_archive_flag_spec=$lt_whole_archive_flag_spec
++
++# Whether the compiler copes with passing no objects directly.
++compiler_needs_object=$lt_compiler_needs_object
++
++# Create an old-style archive from a shared archive.
++old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
++
++# Create a temporary old-style archive to link instead of a shared archive.
++old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
++
++# Commands used to build a shared archive.
++archive_cmds=$lt_archive_cmds
++archive_expsym_cmds=$lt_archive_expsym_cmds
++
++# Commands used to build a loadable module if different from building
++# a shared archive.
++module_cmds=$lt_module_cmds
++module_expsym_cmds=$lt_module_expsym_cmds
++
++# Whether we are building with GNU ld or not.
++with_gnu_ld=$lt_with_gnu_ld
++
++# Flag that allows shared libraries with undefined symbols to be built.
++allow_undefined_flag=$lt_allow_undefined_flag
++
++# Flag that enforces no undefined symbols.
++no_undefined_flag=$lt_no_undefined_flag
++
++# Flag to hardcode \$libdir into a binary during linking.
++# This must work even if \$libdir does not exist
++hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
++
++# If ld is used when linking, flag to hardcode \$libdir into a binary
++# during linking. This must work even if \$libdir does not exist.
++hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
++
++# Whether we need a single "-rpath" flag with a separated argument.
++hardcode_libdir_separator=$lt_hardcode_libdir_separator
++
++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
++# DIR into the resulting binary.
++hardcode_direct=$hardcode_direct
++
++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
++# DIR into the resulting binary and the resulting library dependency is
++# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
++# library is relocated.
++hardcode_direct_absolute=$hardcode_direct_absolute
++
++# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
++# into the resulting binary.
++hardcode_minus_L=$hardcode_minus_L
++
++# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
++# into the resulting binary.
++hardcode_shlibpath_var=$hardcode_shlibpath_var
++
++# Set to "yes" if building a shared library automatically hardcodes DIR
++# into the library and all subsequent libraries and executables linked
++# against it.
++hardcode_automatic=$hardcode_automatic
++
++# Set to yes if linker adds runtime paths of dependent libraries
++# to runtime path list.
++inherit_rpath=$inherit_rpath
++
++# Whether libtool must link a program against all its dependency libraries.
++link_all_deplibs=$link_all_deplibs
++
++# Fix the shell variable \$srcfile for the compiler.
++fix_srcfile_path=$lt_fix_srcfile_path
++
++# Set to "yes" if exported symbols are required.
++always_export_symbols=$always_export_symbols
++
++# The commands to list exported symbols.
++export_symbols_cmds=$lt_export_symbols_cmds
++
++# Symbols that should not be listed in the preloaded symbols.
++exclude_expsyms=$lt_exclude_expsyms
++
++# Symbols that must always be exported.
++include_expsyms=$lt_include_expsyms
++
++# Commands necessary for linking programs (against libraries) with templates.
++prelink_cmds=$lt_prelink_cmds
++
++# Specify filename containing input files.
++file_list_spec=$lt_file_list_spec
++
++# How to hardcode a shared library path into an executable.
++hardcode_action=$hardcode_action
++
++# The directories searched by this compiler when creating a shared library.
++compiler_lib_search_dirs=$lt_compiler_lib_search_dirs
++
++# Dependencies to place before and after the objects being linked to
++# create a shared library.
++predep_objects=$lt_predep_objects
++postdep_objects=$lt_postdep_objects
++predeps=$lt_predeps
++postdeps=$lt_postdeps
++
++# The library search path used internally by the compiler when linking
++# a shared library.
++compiler_lib_search_path=$lt_compiler_lib_search_path
++
++# ### END LIBTOOL CONFIG
++
++_LT_EOF
++
++ case $host_os in
++ aix3*)
++ cat <<\_LT_EOF >> "$cfgfile"
++# AIX sometimes has problems with the GCC collect2 program. For some
++# reason, if we set the COLLECT_NAMES environment variable, the problems
++# vanish in a puff of smoke.
++if test "X${COLLECT_NAMES+set}" != Xset; then
++ COLLECT_NAMES=
++ export COLLECT_NAMES
++fi
++_LT_EOF
++ ;;
++ esac
++
++
++ltmain="$ac_aux_dir/ltmain.sh"
++
++
++ # We use sed instead of cat because bash on DJGPP gets confused if
++ # if finds mixed CR/LF and LF-only lines. Since sed operates in
++ # text mode, it properly converts lines to CR/LF. This bash problem
++ # is reportedly fixed, but why not run on old versions too?
++ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
++ || (rm -f "$cfgfile"; exit 1)
++
++ case $xsi_shell in
++ yes)
++ cat << \_LT_EOF >> "$cfgfile"
++
++# func_dirname file append nondir_replacement
++# Compute the dirname of FILE. If nonempty, add APPEND to the result,
++# otherwise set result to NONDIR_REPLACEMENT.
++func_dirname ()
++{
++ case ${1} in
++ */*) func_dirname_result="${1%/*}${2}" ;;
++ * ) func_dirname_result="${3}" ;;
++ esac
++}
++
++# func_basename file
++func_basename ()
++{
++ func_basename_result="${1##*/}"
++}
++
++# func_dirname_and_basename file append nondir_replacement
++# perform func_basename and func_dirname in a single function
++# call:
++# dirname: Compute the dirname of FILE. If nonempty,
++# add APPEND to the result, otherwise set result
++# to NONDIR_REPLACEMENT.
++# value returned in "$func_dirname_result"
++# basename: Compute filename of FILE.
++# value retuned in "$func_basename_result"
++# Implementation must be kept synchronized with func_dirname
++# and func_basename. For efficiency, we do not delegate to
++# those functions but instead duplicate the functionality here.
++func_dirname_and_basename ()
++{
++ case ${1} in
++ */*) func_dirname_result="${1%/*}${2}" ;;
++ * ) func_dirname_result="${3}" ;;
++ esac
++ func_basename_result="${1##*/}"
++}
++
++# func_stripname prefix suffix name
++# strip PREFIX and SUFFIX off of NAME.
++# PREFIX and SUFFIX must not contain globbing or regex special
++# characters, hashes, percent signs, but SUFFIX may contain a leading
++# dot (in which case that matches only a dot).
++func_stripname ()
++{
++ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
++ # positional parameters, so assign one to ordinary parameter first.
++ func_stripname_result=${3}
++ func_stripname_result=${func_stripname_result#"${1}"}
++ func_stripname_result=${func_stripname_result%"${2}"}
++}
++
++# func_opt_split
++func_opt_split ()
++{
++ func_opt_split_opt=${1%%=*}
++ func_opt_split_arg=${1#*=}
++}
++
++# func_lo2o object
++func_lo2o ()
++{
++ case ${1} in
++ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
++ *) func_lo2o_result=${1} ;;
++ esac
++}
++
++# func_xform libobj-or-source
++func_xform ()
++{
++ func_xform_result=${1%.*}.lo
++}
++
++# func_arith arithmetic-term...
++func_arith ()
++{
++ func_arith_result=$(( $* ))
++}
++
++# func_len string
++# STRING may not start with a hyphen.
++func_len ()
++{
++ func_len_result=${#1}
++}
++
++_LT_EOF
++ ;;
++ *) # Bourne compatible functions.
++ cat << \_LT_EOF >> "$cfgfile"
++
++# func_dirname file append nondir_replacement
++# Compute the dirname of FILE. If nonempty, add APPEND to the result,
++# otherwise set result to NONDIR_REPLACEMENT.
++func_dirname ()
++{
++ # Extract subdirectory from the argument.
++ func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
++ if test "X$func_dirname_result" = "X${1}"; then
++ func_dirname_result="${3}"
++ else
++ func_dirname_result="$func_dirname_result${2}"
++ fi
++}
++
++# func_basename file
++func_basename ()
++{
++ func_basename_result=`$ECHO "${1}" | $SED "$basename"`
++}
++
++
++# func_stripname prefix suffix name
++# strip PREFIX and SUFFIX off of NAME.
++# PREFIX and SUFFIX must not contain globbing or regex special
++# characters, hashes, percent signs, but SUFFIX may contain a leading
++# dot (in which case that matches only a dot).
++# func_strip_suffix prefix name
++func_stripname ()
++{
++ case ${2} in
++ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
++ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
++ esac
++}
++
++# sed scripts:
++my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q'
++my_sed_long_arg='1s/^-[^=]*=//'
++
++# func_opt_split
++func_opt_split ()
++{
++ func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"`
++ func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
++}
++
++# func_lo2o object
++func_lo2o ()
++{
++ func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
++}
++
++# func_xform libobj-or-source
++func_xform ()
++{
++ func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
++}
++
++# func_arith arithmetic-term...
++func_arith ()
++{
++ func_arith_result=`expr "$@"`
++}
++
++# func_len string
++# STRING may not start with a hyphen.
++func_len ()
++{
++ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
++}
++
++_LT_EOF
++esac
++
++case $lt_shell_append in
++ yes)
++ cat << \_LT_EOF >> "$cfgfile"
++
++# func_append var value
++# Append VALUE to the end of shell variable VAR.
++func_append ()
++{
++ eval "$1+=\$2"
++}
++_LT_EOF
++ ;;
++ *)
++ cat << \_LT_EOF >> "$cfgfile"
++
++# func_append var value
++# Append VALUE to the end of shell variable VAR.
++func_append ()
++{
++ eval "$1=\$$1\$2"
++}
++
++_LT_EOF
++ ;;
++ esac
++
++
++ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
++ || (rm -f "$cfgfile"; exit 1)
++
++ mv -f "$cfgfile" "$ofile" ||
++ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
++ chmod +x "$ofile"
++
++
++ cat <<_LT_EOF >> "$ofile"
++
++# ### BEGIN LIBTOOL TAG CONFIG: CXX
++
++# The linker used to build libraries.
++LD=$lt_LD_CXX
++
++# How to create reloadable object files.
++reload_flag=$lt_reload_flag_CXX
++reload_cmds=$lt_reload_cmds_CXX
++
++# Commands used to build an old-style archive.
++old_archive_cmds=$lt_old_archive_cmds_CXX
++
++# A language specific compiler.
++CC=$lt_compiler_CXX
++
++# Is the compiler the GNU compiler?
++with_gcc=$GCC_CXX
++
++# Compiler flag to turn off builtin functions.
++no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
++
++# How to pass a linker flag through the compiler.
++wl=$lt_lt_prog_compiler_wl_CXX
++
++# Additional compiler flags for building library objects.
++pic_flag=$lt_lt_prog_compiler_pic_CXX
++
++# Compiler flag to prevent dynamic linking.
++link_static_flag=$lt_lt_prog_compiler_static_CXX
++
++# Does compiler simultaneously support -c and -o options?
++compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
++
++# Whether or not to add -lc for building shared libraries.
++build_libtool_need_lc=$archive_cmds_need_lc_CXX
++
++# Whether or not to disallow shared libs when runtime libs are static.
++allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
++
++# Compiler flag to allow reflexive dlopens.
++export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
++
++# Compiler flag to generate shared objects directly from archives.
++whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
++
++# Whether the compiler copes with passing no objects directly.
++compiler_needs_object=$lt_compiler_needs_object_CXX
++
++# Create an old-style archive from a shared archive.
++old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
++
++# Create a temporary old-style archive to link instead of a shared archive.
++old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
++
++# Commands used to build a shared archive.
++archive_cmds=$lt_archive_cmds_CXX
++archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
++
++# Commands used to build a loadable module if different from building
++# a shared archive.
++module_cmds=$lt_module_cmds_CXX
++module_expsym_cmds=$lt_module_expsym_cmds_CXX
++
++# Whether we are building with GNU ld or not.
++with_gnu_ld=$lt_with_gnu_ld_CXX
++
++# Flag that allows shared libraries with undefined symbols to be built.
++allow_undefined_flag=$lt_allow_undefined_flag_CXX
++
++# Flag that enforces no undefined symbols.
++no_undefined_flag=$lt_no_undefined_flag_CXX
++
++# Flag to hardcode \$libdir into a binary during linking.
++# This must work even if \$libdir does not exist
++hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
++
++# If ld is used when linking, flag to hardcode \$libdir into a binary
++# during linking. This must work even if \$libdir does not exist.
++hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX
++
++# Whether we need a single "-rpath" flag with a separated argument.
++hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
++
++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
++# DIR into the resulting binary.
++hardcode_direct=$hardcode_direct_CXX
++
++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
++# DIR into the resulting binary and the resulting library dependency is
++# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
++# library is relocated.
++hardcode_direct_absolute=$hardcode_direct_absolute_CXX
++
++# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
++# into the resulting binary.
++hardcode_minus_L=$hardcode_minus_L_CXX
++
++# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
++# into the resulting binary.
++hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
++
++# Set to "yes" if building a shared library automatically hardcodes DIR
++# into the library and all subsequent libraries and executables linked
++# against it.
++hardcode_automatic=$hardcode_automatic_CXX
++
++# Set to yes if linker adds runtime paths of dependent libraries
++# to runtime path list.
++inherit_rpath=$inherit_rpath_CXX
++
++# Whether libtool must link a program against all its dependency libraries.
++link_all_deplibs=$link_all_deplibs_CXX
++
++# Fix the shell variable \$srcfile for the compiler.
++fix_srcfile_path=$lt_fix_srcfile_path_CXX
++
++# Set to "yes" if exported symbols are required.
++always_export_symbols=$always_export_symbols_CXX
++
++# The commands to list exported symbols.
++export_symbols_cmds=$lt_export_symbols_cmds_CXX
++
++# Symbols that should not be listed in the preloaded symbols.
++exclude_expsyms=$lt_exclude_expsyms_CXX
++
++# Symbols that must always be exported.
++include_expsyms=$lt_include_expsyms_CXX
++
++# Commands necessary for linking programs (against libraries) with templates.
++prelink_cmds=$lt_prelink_cmds_CXX
++
++# Specify filename containing input files.
++file_list_spec=$lt_file_list_spec_CXX
++
++# How to hardcode a shared library path into an executable.
++hardcode_action=$hardcode_action_CXX
++
++# The directories searched by this compiler when creating a shared library.
++compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX
++
++# Dependencies to place before and after the objects being linked to
++# create a shared library.
++predep_objects=$lt_predep_objects_CXX
++postdep_objects=$lt_postdep_objects_CXX
++predeps=$lt_predeps_CXX
++postdeps=$lt_postdeps_CXX
++
++# The library search path used internally by the compiler when linking
++# a shared library.
++compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
++
++# ### END LIBTOOL TAG CONFIG: CXX
++_LT_EOF
++
++
++as_fn_exit 0
++_LTEOF
++chmod +x "$CONFIG_LT"
++
++# configure is writing to config.log, but config.lt does its own redirection,
++# appending to config.log, which fails on DOS, as config.log is still kept
++# open by configure. Here we exec the FD to /dev/null, effectively closing
++# config.log, so it can be properly (re)opened and appended to by config.lt.
++lt_cl_success=:
++test "$silent" = yes &&
++ lt_config_lt_args="$lt_config_lt_args --quiet"
++exec 5>/dev/null
++$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
++exec 5>>config.log
++$lt_cl_success || as_fn_exit 1
++
++
++ac_config_files="$ac_config_files Makefile"
++
++ac_config_files="$ac_config_files scripts/testsuite_flags"
++
++ac_config_files="$ac_config_files scripts/extract_symvers"
++
++ac_config_files="$ac_config_files doc/xsl/customization.xsl"
++
++
++# Multilibs need MULTISUBDIR defined correctly in certain makefiles so
++# that multilib installs will end up installed in the correct place.
++# The testsuite needs it for multilib-aware ABI baseline files.
++# To work around this not being passed down from config-ml.in ->
++# srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually
++# append it here. Only modify Makefiles that have just been created.
++#
++# Also, get rid of this simulated-VPATH thing that automake does.
++ac_config_files="$ac_config_files include/Makefile libsupc++/Makefile src/Makefile src/c++98/Makefile src/c++11/Makefile src/filesystem/Makefile doc/Makefile po/Makefile testsuite/Makefile python/Makefile"
++
++
++ac_config_commands="$ac_config_commands generate-headers"
++
++
++cat >confcache <<\_ACEOF
++# This file is a shell script that caches the results of configure
++# tests run on this system so they can be shared between configure
++# scripts and configure runs, see configure's option --config-cache.
++# It is not useful on other systems. If it contains results you don't
++# want to keep, you may remove or edit it.
++#
++# config.status only pays attention to the cache file if you give it
+ # the --recheck option to rerun configure.
+ #
+ # `ac_cv_env_foo' variables (set or unset) will be overridden when
+ # loading this file, other *unset* `ac_cv_foo' will be assigned the
+ # following values.
+
+@@ -81494,12 +83297,13 @@ fi
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
++ac_aux_dir='$ac_aux_dir'
+
+
+
+ GCC="$GCC"
+ CC="$CC"
+ acx_cv_header_stdint="$acx_cv_header_stdint"
+diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
+index 580fb8b2eb8ab25bed4872f1d071ba925cf3dcff..76ddbdae13f46336f68672e217e5dfa2fdffee97 100644
+--- libstdc++-v3/configure.ac
++++ libstdc++-v3/configure.ac
+@@ -492,12 +492,15 @@ fi
+ GLIBCXX_EXPORT_INSTALL_INFO
+
+ # Export all the include and flag information to Makefiles.
+ GLIBCXX_EXPORT_INCLUDES
+ GLIBCXX_EXPORT_FLAGS
+
++# create libtool - libtool > 2.0:
++LT_OUTPUT
++
+ dnl In autoconf 2.5x, AC_OUTPUT is replaced by four AC_CONFIG_* macros,
+ dnl which can all be called multiple times as needed, plus one (different)
+ dnl AC_OUTPUT macro. This one lists the files to be created:
+ AC_CONFIG_FILES(Makefile)
+ AC_CONFIG_FILES([scripts/testsuite_flags],[chmod +x scripts/testsuite_flags])
+ AC_CONFIG_FILES([scripts/extract_symvers],[chmod +x scripts/extract_symvers])
+diff --git a/libstdc++-v3/crossconfig.m4 b/libstdc++-v3/crossconfig.m4
+index 10247f940b55ee77df940044c3889b08b51cfb4c..c7d1034f4870e92dfd502d25bc7cc858f6a19370 100644
+--- libstdc++-v3/crossconfig.m4
++++ libstdc++-v3/crossconfig.m4
+@@ -266,11 +266,19 @@ case "${host}" in
+ AC_DEFINE(HAVE_SINF)
+ AC_DEFINE(HAVE_SINHF)
+ AC_DEFINE(HAVE_SQRTF)
+ AC_DEFINE(HAVE_TANF)
+ AC_DEFINE(HAVE_TANHF)
+ ;;
++ *-amigaos*)
++ AC_CHECK_HEADERS([nan.h ieeefp.h endian.h sys/isa_defs.h \
++ machine/endian.h machine/param.h sys/machine.h sys/types.h \
++ fp.h locale.h float.h inttypes.h])
++ SECTION_FLAGS='-ffunction-sections -fdata-sections'
++ AC_SUBST(SECTION_FLAGS)
++ GLIBCXX_CHECK_LINKER_FEATURES
++ ;;
+ *)
+ AC_MSG_ERROR([No support for this host/target combination.])
+ ;;
+ esac
+ ])
+diff --git a/libstdc++-v3/include/c_global/cstddef b/libstdc++-v3/include/c_global/cstddef
+index 33f4f8f76bd497d345ec7440b9397427e26671eb..7c39a30d2bc41b4eb82b13c3d390cfce52854457 100644
+--- libstdc++-v3/include/c_global/cstddef
++++ libstdc++-v3/include/c_global/cstddef
+@@ -44,12 +44,15 @@
+ #include <bits/c++config.h>
+ #include <stddef.h>
+
+ #if __cplusplus >= 201103L
+ namespace std
+ {
++/* Needed as clib2 on AmigaOS has no C11 support yet */
++#if __STDC_VERSION__ >= 201112L
+ // We handle size_t, ptrdiff_t, and nullptr_t in c++config.h.
+ using ::max_align_t;
++#endif
+ }
+ #endif
+
+ #endif // _GLIBCXX_CSTDDEF
+diff --git a/libstdc++-v3/include/c_std/cstddef b/libstdc++-v3/include/c_std/cstddef
+index d46a4ea16388d674917a74620c3f50d43de84bb6..9189ed063448a45439a265bf4a51cc36e0c731ed 100644
+--- libstdc++-v3/include/c_std/cstddef
++++ libstdc++-v3/include/c_std/cstddef
+@@ -44,12 +44,15 @@
+ #include <bits/c++config.h>
+ #include <stddef.h>
+
+ #if __cplusplus >= 201103L
+ namespace std
+ {
++/* Needed as clib2 on AmigaOS has no C11 support yet */
++#if __STDC_VERSION__ >= 201112L
+ // We handle size_t, ptrdiff_t, and nullptr_t in c++config.h.
+ using ::max_align_t;
++#endif
+ }
+ #endif
+
+ #endif // _GLIBCXX_CSTDDEF
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/gcc/0002-Added-new-function-attribute-lineartags-and-pragma-a.p b/ppc-amigaos/recipes/patches/gcc/0002-Added-new-function-attribute-lineartags-and-pragma-a.p
new file mode 100644
index 0000000..1eec43a
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/gcc/0002-Added-new-function-attribute-lineartags-and-pragma-a.p
@@ -0,0 +1,376 @@
+From c8d51b6ed56c643f9744d7a18fee3b13a76b98d3 Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Fri, 14 Nov 2014 20:03:56 +0100
+Subject: [PATCH 2/6] Added new function attribute "lineartags" and pragma
+ "amigaos tagtype".
+
+Functions that have the lineartags attribute are assumed to be functions
+with tags, in which case type checking is now enabled. That is, the value
+that follow a specific tag is assumed to be a certain type. If this is
+not the case, the compiler will warn.
+
+The compiler can be taught about that types via the new pragma
+#pragma amigaos tagtype(TYPE)
+which is written before an "enum" or a "static const int" that defines
+the number of the tag.
+
+For instance:
+
+#pragma amigaos tagtype(struct Screen *)
+static const int WA_CustomScreen = WA_Dummy + 0x0D;
+
+ or
+
+#pragma amigaos tagtype(struct Screen *)
+enum {WA_CustomScreen = WA_Dummy + 0x0D};
+
+is possible now.
+
+It is not very robust yet wrt to catching misuses of the new feature.
+For instance, no check is done that the attribute is applied to varargs
+functions.
+---
+ gcc/c-family/c-pragma.c | 10 +++
+ gcc/c/c-parser.c | 129 +++++++++++++++++++++++++++++++++++++
+ gcc/c/c-typeck.c | 24 +++++++
+ gcc/config/rs6000/amigaos-protos.h | 1 +
+ gcc/config/rs6000/amigaos.c | 7 ++
+ 5 files changed, 171 insertions(+)
+
+diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
+index 6894f0e7c3d1ea932ff05f370680be3d18dfcf94..24278250901bfa75c9aae9be63a62351f33e390e 100644
+--- gcc/c-family/c-pragma.c
++++ gcc/c-family/c-pragma.c
+@@ -1066,12 +1066,21 @@ handle_pragma_message (cpp_reader *ARG_UNUSED(dummy))
+ warning (OPT_Wpragmas, "junk at end of %<#pragma message%>");
+
+ if (TREE_STRING_LENGTH (message) > 1)
+ inform (input_location, "#pragma message: %s", TREE_STRING_POINTER (message));
+ }
+
++/* This is queried by the invoker of the handler */
++int was_tagtypepragma;
++/* Tagtype pragma */
++static void
++handle_pragma_tagtype (cpp_reader *reader)
++{
++ was_tagtypepragma = 1;
++}
++
+ /* Mark whether the current location is valid for a STDC pragma. */
+
+ static bool valid_location_for_stdc_pragma;
+
+ void
+ mark_valid_location_for_stdc_pragma (bool flag)
+@@ -1483,12 +1492,13 @@ init_pragma (void)
+
+ c_register_pragma_with_expansion (0, "redefine_extname",
+ handle_pragma_redefine_extname);
+
+ c_register_pragma_with_expansion (0, "message", handle_pragma_message);
+
++ c_register_pragma_with_expansion ("amigaos", "tagtype", handle_pragma_tagtype);
+ #ifdef REGISTER_TARGET_PRAGMAS
+ REGISTER_TARGET_PRAGMAS ();
+ #endif
+
+ /* Allow plugins to register their own pragmas. */
+ invoke_plugin_callbacks (PLUGIN_PRAGMAS, NULL);
+diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
+index 86cbc404a4c10edac0ce2341ae0099f624ee36ea..cc77530b090576db35610468052d84763c3965fd 100644
+--- gcc/c/c-parser.c
++++ gcc/c/c-parser.c
+@@ -80,12 +80,74 @@ along with GCC; see the file COPYING3. If not see
+ #include "cgraph.h"
+ #include "plugin.h"
+ #include "omp-low.h"
+ #include "builtins.h"
+ #include "gomp-constants.h"
+
++static htab_t amigaos_tagdecl_to_type;
++
++struct amigaos_hash_type
++{
++ tree decl;
++ tree type;
++};
++
++static hashval_t
++amigaos_hash_descriptor (const void *p)
++{
++ return htab_hash_pointer (((const amigaos_hash_type *)p)->decl);
++}
++
++static int
++amigaos_eq_descriptor (const void *p1, const void *p2)
++{
++ return ((const amigaos_hash_type *)p1)->decl == ((const amigaos_hash_type *)p2)->decl;
++}
++
++/**
++ * Returns the tag type that is associated with the given type.
++ *
++ * @param type
++ * @return
++ */
++tree amigaos_get_type_associated_tagtype(tree decl)
++{
++ amigaos_hash_type aht = {decl, 0};
++ amigaos_hash_type *faht;
++
++ if (!amigaos_tagdecl_to_type)
++ return NULL;
++
++ faht = (amigaos_hash_type *)htab_find(amigaos_tagdecl_to_type, &aht);
++ if (!faht)
++ return NULL;
++ return faht->type;
++}
++
++static void amigaos_put_type_associated_tagtype(tree decl, tree type)
++{
++ gcc_assert(decl);
++
++ if (!amigaos_tagdecl_to_type)
++ amigaos_tagdecl_to_type = htab_create (10, amigaos_hash_descriptor, amigaos_eq_descriptor, NULL);
++
++ amigaos_hash_type *aht = (amigaos_hash_type *)xmalloc(sizeof(*aht));
++ aht->decl = decl;
++ aht->type = type;
++
++ void **pentry = htab_find_slot (amigaos_tagdecl_to_type, aht, INSERT);
++ gcc_assert(pentry);
++ gcc_assert(*pentry == NULL);
++ *pentry = aht;
++}
++
++/**
++ * Contains the tagtype that is currently processed or NULL_TREE
++ * if no tagtype is processed.
++ */
++static tree amigaos_current_tagtype;
+
+ /* Initialization routine for this file. */
+
+ void
+ c_parse_init (void)
+ {
+@@ -2390,12 +2452,15 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
+ goto out;
+ attrs_ok = true;
+ seen_type = true;
+ t = c_parser_enum_specifier (parser);
+ invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec);
+ declspecs_add_type (loc, specs, t);
++ /* Handle special tagtype enhanced enums */
++ if (amigaos_current_tagtype != NULL_TREE && t.spec != NULL_TREE)
++ amigaos_put_type_associated_tagtype(t.spec, amigaos_current_tagtype);
+ break;
+ case RID_STRUCT:
+ case RID_UNION:
+ if (!typespec_ok)
+ goto out;
+ attrs_ok = true;
+@@ -9590,12 +9655,32 @@ c_parser_objc_at_dynamic_declaration (c_parser *parser)
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ objc_add_dynamic_declaration (loc, list);
+ }
+
+
++/**
++ * This function is called whenever a declaration was finished that was preceded
++ * by a tagtype pragma.
++ *
++ * @param gcc_data will be the finished declaration
++ * @param user_data will be the parsed c type of the declaration (c_type_name *)
++ * that was specified ahead of the declaration via the pragma.
++ */
++static void amigaos_tagtype_finish_decl_callback (void *gcc_data, void *user_data)
++{
++ tree decl = (tree)gcc_data;
++ c_type_name *ctype = (c_type_name*)user_data;
++ tree type = groktypename (ctype, NULL, NULL);
++
++ /* TODO: All sorts of checks */
++
++ /* Now put the association in our own hash table */
++ amigaos_put_type_associated_tagtype(decl, type);
++}
++
+ /* Handle pragmas. Some OpenMP pragmas are associated with, and therefore
+ should be considered, statements. ALLOW_STMT is true if we're within
+ the context of a function and such pragmas are to be allowed. Returns
+ true if we actually parsed such a pragma. */
+
+ static bool
+@@ -9777,12 +9862,56 @@ c_parser_pragma (c_parser *parser, enum pragma_context context)
+ break;
+ }
+
+ c_parser_consume_pragma (parser);
+ c_invoke_pragma_handler (id);
+
++ /* If was_tagtypepragma is set, the pragma was a tagtype one,
++ * which, at the moment, cannot easily handled outside of this
++ * file.
++ */
++ extern int was_tagtypepragma;
++ if (was_tagtypepragma)
++ {
++ c_token *tok = c_parser_peek_token (the_parser);
++ enum cpp_ttype ret = tok->type;
++ c_parser_consume_token(parser);
++
++ c_type_name *ctype = c_parser_type_name(parser);
++ tree ctypetree = groktypename (ctype, NULL, NULL);
++
++ /* Make the parsed type available to all functions called from here on */
++ amigaos_current_tagtype = ctypetree;
++
++ tok = c_parser_peek_token (the_parser);
++ ret = tok->type;
++ c_parser_consume_token(parser);
++ c_parser_skip_to_pragma_eol(parser);
++
++ tok = c_parser_peek_token (the_parser);
++ ret = tok->type;
++
++ /* Parse the line that follows. We will register for a PLUGIN_FINISH_DECL event
++ * to minimize contermination
++ */
++ bool old_flag_plugin_added = flag_plugin_added;
++ register_callback ("amigaos-tagtype", PLUGIN_FINISH_DECL,
++ amigaos_tagtype_finish_decl_callback,
++ ctype);
++ flag_plugin_added = 1;
++ c_parser_declaration_or_fndef(parser, false, false, true, false, true, NULL, vNULL);
++ unregister_callback ("amigaos-tagtype", PLUGIN_FINISH_DECL);
++ flag_plugin_added = old_flag_plugin_added;
++ /* Reset the variable that is set in the pragma handler */
++ was_tagtypepragma = 0;
++ /* The tagtype has been processed */
++ amigaos_current_tagtype = NULL_TREE;
++ return false;
++ }
++
++
+ /* Skip to EOL, but suppress any error message. Those will have been
+ generated by the handler routine through calling error, as opposed
+ to calling c_parser_error. */
+ parser->error = true;
+ c_parser_skip_to_pragma_eol (parser);
+
+diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
+index a98622b16f546b88eb7fdce9ca7631c3ca37470a..2c03a10f1127c2bec5d9280ecc2f786fd5d13153 100644
+--- gcc/c/c-typeck.c
++++ gcc/c/c-typeck.c
+@@ -3100,12 +3100,14 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
+ unsigned int parmnum;
+ bool error_args = false;
+ const bool type_generic = fundecl
+ && lookup_attribute ("type generic", TYPE_ATTRIBUTES (TREE_TYPE (fundecl)));
+ bool type_generic_remove_excess_precision = false;
+ tree selector;
++ const bool lineartags = fundecl
++ && lookup_attribute ("lineartags", TYPE_ATTRIBUTES (TREE_TYPE (fundecl)));
+
+ /* Change pointer to function to the function itself for
+ diagnostics. */
+ if (TREE_CODE (function) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
+ function = TREE_OPERAND (function, 0);
+@@ -3139,12 +3141,14 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
+ if (flag_cilkplus && fundecl && is_cilkplus_reduce_builtin (fundecl))
+ return vec_safe_length (values);
+
+ /* Scan the given expressions and types, producing individual
+ converted arguments. */
+
++ tree prev_tagtype = NULL_TREE;
++
+ for (typetail = typelist, parmnum = 0;
+ values && values->iterate (parmnum, &val);
+ ++parmnum)
+ {
+ tree type = typetail ? TREE_VALUE (typetail) : 0;
+ tree valtype = TREE_TYPE (val);
+@@ -3193,12 +3197,32 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
+ }
+ val = c_fully_fold (val, false, NULL);
+ STRIP_TYPE_NOPS (val);
+
+ val = require_complete_type (val);
+
++ /* If this is a function call with linear tags try to improve the expected
++ * type on base of recorded tag <-> type mapping.
++ */
++ if (lineartags && type == 0)
++ {
++ extern tree amigaos_get_type_associated_tagtype(tree type);
++
++ if (prev_tagtype)
++ {
++ type = prev_tagtype;
++ prev_tagtype = NULL_TREE;
++ }
++ else
++ {
++ prev_tagtype = amigaos_get_type_associated_tagtype(val);
++ if (!prev_tagtype)
++ prev_tagtype = amigaos_get_type_associated_tagtype((*origtypes)[parmnum]);
++ }
++ }
++
+ if (type != 0)
+ {
+ /* Formal parm type is specified by a function prototype. */
+
+ if (type == error_mark_node || !COMPLETE_TYPE_P (type))
+ {
+diff --git a/gcc/config/rs6000/amigaos-protos.h b/gcc/config/rs6000/amigaos-protos.h
+index eb5f8fc5f3d546b8d8e1cdd8118a3085079df50e..3b8c994cdbd192eaf7112c780f0106a4d96cbb90 100644
+--- gcc/config/rs6000/amigaos-protos.h
++++ gcc/config/rs6000/amigaos-protos.h
+@@ -27,12 +27,13 @@ extern void amigaos_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
+ extern struct rtx_def *amigaos_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
+ extern void amigaos_expand_builtin_va_start (tree valist, rtx nextarg);
+ extern struct rtx_def *amigaos_expand_builtin_saveregs (void);
+ extern void amigaos_init_builtins (void);
+ extern rtx amigaos_expand_builtin (tree, rtx, rtx, enum machine_mode, int, bool*);
+ extern tree amigaos_handle_linearvarargs_attribute (tree *, tree, tree, int, bool*);
++extern tree amigaos_handle_lineartags_attribute (tree *, tree, tree, int, bool*);
+ extern tree amigaos_handle_baserel_restore_attribute (tree *, tree, tree, int, bool*);
+ extern tree amigaos_handle_force_no_baserel_attribute (tree *, tree, tree, int, bool*);
+ extern tree amigaos_handle_check68kfuncptr_attribute (tree *, tree, tree, int, bool*);
+ extern rtx amigaos_legitimize_baserel_address (rtx addr);
+ extern int amigaos_baserel_operand(rtx x);
+ extern int amigaos_not_baserel_tree_p(tree decl);
+diff --git a/gcc/config/rs6000/amigaos.c b/gcc/config/rs6000/amigaos.c
+index 0f575a38e4dc4aac0b454c56bf62f625c0f7eb9c..ccf4f912cb66cd424a2398c6535e05fa493f39f1 100644
+--- gcc/config/rs6000/amigaos.c
++++ gcc/config/rs6000/amigaos.c
+@@ -345,12 +345,19 @@ amigaos_handle_linearvarargs_attribute (tree *node, tree name,
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+ }
+
++tree
++amigaos_handle_lineartags_attribute (tree *node, tree name, tree args, int flags, bool *no_add_attrs)
++{
++ /* TODO: This function should applied only to functions or methods */
++ return NULL_TREE;
++}
++
+
+ /* Generate code for base relative access */
+
+ rtx
+ amigaos_legitimize_baserel_address (rtx addr)
+ {
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/gcc/0003-Disable-.machine-directive-generation.p b/ppc-amigaos/recipes/patches/gcc/0003-Disable-.machine-directive-generation.p
new file mode 100644
index 0000000..edadf9d
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/gcc/0003-Disable-.machine-directive-generation.p
@@ -0,0 +1,49 @@
+From 43dda55bb84a70181e84f496fd8417ed3c22db54 Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Thu, 9 Jul 2015 06:54:37 +0200
+Subject: [PATCH 3/6] Disable .machine directive generation.
+
+It breaks manual args to the assembler with different flavor,
+e.g., -Wa,-m440. This is probably not the right fix.
+
+This reverts parts of a commit from 2015-03-03.
+---
+ gcc/config/rs6000/rs6000.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
+index ee0ea2ffabb6b9c6fdcba687d88be1e1164374ee..19544afa364f7f7ab1a5c5a61ad7891218398f99 100644
+--- gcc/config/rs6000/rs6000.c
++++ gcc/config/rs6000/rs6000.c
+@@ -5191,12 +5191,14 @@ rs6000_file_start (void)
+ }
+
+ #ifdef USING_ELFOS_H
+ if (rs6000_default_cpu == 0 || rs6000_default_cpu[0] == '\0'
+ || !global_options_set.x_rs6000_cpu_index)
+ {
++ /* Temporarily disabled as it overrides e.g., -mcpu=440 */
++#if 0
+ fputs ("\t.machine ", asm_out_file);
+ if ((rs6000_isa_flags & OPTION_MASK_DIRECT_MOVE) != 0)
+ fputs ("power8\n", asm_out_file);
+ else if ((rs6000_isa_flags & OPTION_MASK_POPCNTD) != 0)
+ fputs ("power7\n", asm_out_file);
+ else if ((rs6000_isa_flags & OPTION_MASK_CMPB) != 0)
+@@ -5206,12 +5208,13 @@ rs6000_file_start (void)
+ else if ((rs6000_isa_flags & OPTION_MASK_MFCRF) != 0)
+ fputs ("power4\n", asm_out_file);
+ else if ((rs6000_isa_flags & OPTION_MASK_POWERPC64) != 0)
+ fputs ("ppc64\n", asm_out_file);
+ else
+ fputs ("ppc\n", asm_out_file);
++#endif
+ }
+ #endif
+
+ if (DEFAULT_ABI == ABI_ELFv2)
+ fprintf (file, "\t.abiversion 2\n");
+
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/gcc/0004-The-default-link-mode-is-static-for-AmigaOS.p b/ppc-amigaos/recipes/patches/gcc/0004-The-default-link-mode-is-static-for-AmigaOS.p
new file mode 100644
index 0000000..5eeb4e5
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/gcc/0004-The-default-link-mode-is-static-for-AmigaOS.p
@@ -0,0 +1,51 @@
+From 8eb1aa062283f82007d639e862278a750f314da5 Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Wed, 2 Dec 2015 20:56:33 +0100
+Subject: [PATCH 4/6] The default link mode is static for AmigaOS.
+
+Changed the g++ driver to reflect this.
+---
+ gcc/cp/g++spec.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/gcc/cp/g++spec.c b/gcc/cp/g++spec.c
+index 6536d7e776f861b4bd40277e96c80a635cbcc85e..ff1d77eaefc20039f7e5df48ffb849ee533b9797 100644
+--- gcc/cp/g++spec.c
++++ gcc/cp/g++spec.c
+@@ -102,14 +102,14 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
+ /* By default, we throw on the math library if we have one. */
+ int need_math = (MATH_LIBRARY[0] != '\0');
+
+ /* By default, we throw on the time library if we have one. */
+ int need_time = (TIME_LIBRARY[0] != '\0');
+
+- /* True if we saw -static. */
+- int static_link = 0;
++ /* False if we saw -shared. */
++ int static_link = 1;
+
+ /* True if we should add -shared-libgcc to the command-line. */
+ int shared_libgcc = 1;
+
+ /* The total number of arguments with the new stuff. */
+ unsigned int argc;
+@@ -196,12 +196,16 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
+ break;
+
+ case OPT_static:
+ static_link = 1;
+ break;
+
++ case OPT_shared:
++ static_link = 0;
++ break;
++
+ case OPT_static_libgcc:
+ shared_libgcc = 0;
+ break;
+
+ case OPT_static_libstdc__:
+ library = library >= 0 ? 2 : library;
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/gcc/0005-Disable-the-usage-of-dev-urandom-when-compiling-for-.p b/ppc-amigaos/recipes/patches/gcc/0005-Disable-the-usage-of-dev-urandom-when-compiling-for-.p
new file mode 100644
index 0000000..99621d8
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/gcc/0005-Disable-the-usage-of-dev-urandom-when-compiling-for-.p
@@ -0,0 +1,73 @@
+From c9b38a7315faed955e2f01e37f84d06ba32aa9b5 Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Wed, 2 Dec 2015 21:39:42 +0100
+Subject: [PATCH 5/6] Disable the usage of /dev/urandom when compiling for
+ AmigaOS.
+
+---
+ gcc/gcc.c | 3 +++
+ gcc/toplev.c | 4 ++--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/gcc/gcc.c b/gcc/gcc.c
+index d4d061080ba1166fb14069094556246b32265da4..8239a6b2152ac192498cd8a50b0d4b9c7db45c62 100644
+--- gcc/gcc.c
++++ gcc/gcc.c
+@@ -9124,22 +9124,25 @@ print_asm_header_spec_function (int arg ATTRIBUTE_UNUSED,
+ /* Get a random number for -frandom-seed */
+
+ static unsigned HOST_WIDE_INT
+ get_random_number (void)
+ {
+ unsigned HOST_WIDE_INT ret = 0;
++
++#ifndef __amigaos4__
+ int fd;
+
+ fd = open ("/dev/urandom", O_RDONLY);
+ if (fd >= 0)
+ {
+ read (fd, &ret, sizeof (HOST_WIDE_INT));
+ close (fd);
+ if (ret)
+ return ret;
+ }
++#endif
+
+ /* Get some more or less random data. */
+ #ifdef HAVE_GETTIMEOFDAY
+ {
+ struct timeval tv;
+
+diff --git a/gcc/toplev.c b/gcc/toplev.c
+index cb6c51739ffc40d19f83efafb02d7670e4da2915..3ba2210c953d2dde2ab919808b86ed3e7a4f4d1e 100644
+--- gcc/toplev.c
++++ gcc/toplev.c
+@@ -288,22 +288,22 @@ static void
+ init_local_tick (void)
+ {
+ if (!flag_random_seed)
+ {
+ /* Try urandom first. Time of day is too likely to collide.
+ In case of any error we just use the local tick. */
+-
++#ifndef __amigaos4__
+ int fd = open ("/dev/urandom", O_RDONLY);
+ if (fd >= 0)
+ {
+ if (read (fd, &random_seed, sizeof (random_seed))
+ != sizeof (random_seed))
+ random_seed = 0;
+ close (fd);
+ }
+-
++#endif
+ /* Now get the tick anyways */
+ #ifdef HAVE_GETTIMEOFDAY
+ {
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/gcc/0006-Expand-arg-zero-on-AmigaOS-using-the-PROGDIR-assign.p b/ppc-amigaos/recipes/patches/gcc/0006-Expand-arg-zero-on-AmigaOS-using-the-PROGDIR-assign.p
new file mode 100644
index 0000000..6f15af2
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/gcc/0006-Expand-arg-zero-on-AmigaOS-using-the-PROGDIR-assign.p
@@ -0,0 +1,41 @@
+From 85c5321c36040abb1c3b70cb1e0f9bf217178957 Mon Sep 17 00:00:00 2001
+From: Sebastian Bauer <mail@sebastianbauer.info>
+Date: Sat, 5 Dec 2015 13:17:26 +0100
+Subject: [PATCH 6/6] Expand arg zero on AmigaOS using the PROGDIR: assign.
+
+This should make sure that the proper relative paths are computed during
+process_command().
+---
+ gcc/gcc.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/gcc/gcc.c b/gcc/gcc.c
+index 8239a6b2152ac192498cd8a50b0d4b9c7db45c62..f6f1ba3195a4ffc8e335d7abe797d4b006fc96d5 100644
+--- gcc/gcc.c
++++ gcc/gcc.c
+@@ -6898,12 +6898,22 @@ compare_files (char *cmpfile[])
+ int
+ driver::main (int argc, char **argv)
+ {
+ bool early_exit;
+
+ set_progname (argv[0]);
++#ifdef __amigaos4__
++ /* Expand the command name on AmigaOS */
++ char *expanded_progdir = lrealpath("/progdir/");
++ if (expanded_progdir)
++ {
++ char *expanded_argv0 = concat(expanded_progdir,"/",progname,NULL);
++ argv[0] = expanded_argv0; /* FIXME: Leak */
++ free(expanded_progdir);
++ }
++#endif
+ expand_at_files (&argc, &argv);
+ decode_argv (argc, const_cast <const char **> (argv));
+ global_initializations ();
+ build_multilib_strings ();
+ set_up_specs ();
+ putenv_COLLECT_GCC (argv[0]);
+--
+2.1.4
+
diff --git a/ppc-amigaos/recipes/patches/gcc/gmp-configure.p b/ppc-amigaos/recipes/patches/gcc/gmp-configure.p
deleted file mode 100644
index a8ac807..0000000
--- a/ppc-amigaos/recipes/patches/gcc/gmp-configure.p
+++ /dev/null
@@ -1,11 +0,0 @@
---- gmp/configure.orig 2012-08-17 18:03:57.000000000 +0100
-+++ gmp/configure 2012-08-17 18:04:17.000000000 +0100
-@@ -30006,8 +30006,6 @@
- echo "define(<M4WRAP_SPURIOUS>,<$gmp_cv_m4_m4wrap_spurious>)" >> $gmp_tmpconfigm4
-
-
--else
-- M4=m4-not-needed
- fi
-
- # Only do the GMP_ASM checks if there's a .S or .asm wanting them.