summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Young <chris@unsatisfactorysoftware.co.uk>2016-02-28 15:57:25 +0000
committerChris Young <chris@unsatisfactorysoftware.co.uk>2016-02-28 15:57:25 +0000
commit84675cfd17dc1dd6c01f248cb9c94d9995b42f53 (patch)
tree16af7f02f61b0ca864d2020248a35764c045d0f2
parentf704c927b5b8e365ff2fbd053c185306051e0123 (diff)
downloadtoolchains-84675cfd17dc1dd6c01f248cb9c94d9995b42f53.tar.gz
toolchains-84675cfd17dc1dd6c01f248cb9c94d9995b42f53.tar.bz2
Import binutils patches from https://github.com/sba1/adtools/tree/master/binutils/2.23.2/patches
-rw-r--r--ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p27432
-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/remove_unused.p406
8 files changed, 28206 insertions, 406 deletions
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..9ac09fe
--- /dev/null
+++ b/ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p
@@ -0,0 +1,27432 @@
+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
+--- a/bfd/ChangeLog-9697
++++ b/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
+--- a/bfd/ChangeLog-9899
++++ b/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
+--- a/bfd/Makefile.am
++++ b/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
+--- a/bfd/Makefile.in
++++ b/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
++++ b/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
++++ b/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
++++ b/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
+--- a/bfd/aoutx.h
++++ b/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
+--- a/bfd/bfd-in2.h
++++ b/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
+--- a/bfd/bfd.c
++++ b/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
+--- a/bfd/bfdio.c
++++ b/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
+--- a/bfd/config.bfd
++++ b/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
+--- a/bfd/configure
++++ b/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
+--- a/bfd/configure.host
++++ b/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
+--- a/bfd/configure.in
++++ b/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
+--- a/bfd/doc/Makefile.am
++++ b/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
+--- a/bfd/doc/Makefile.in
++++ b/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
+--- a/bfd/doc/bfd.texinfo
++++ b/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
++++ b/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-ppc.c b/bfd/elf32-amigaos.c
+similarity index 97%
+copy from bfd/elf32-ppc.c
+copy to bfd/elf32-amigaos.c
+index 6454a8350da35adf6ed1e2209d9e4774ab7c50e3..9bf9535888f2345d60a8f802680ae03f41f67a5f 100644
+--- a/bfd/elf32-ppc.c
++++ b/bfd/elf32-amigaos.c
+@@ -31,32 +31,50 @@
+ #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
+@@ -1381,12 +1399,74 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
+ /* 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) */
+@@ -1935,12 +2015,16 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ 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];
+ };
+@@ -2268,13 +2352,13 @@ ppc_elf_lookup_section_flags (char *flag_name)
+ return 0;
+ }
+
+ /* Add the VLE flag if required. */
+
+ bfd_boolean
+-ppc_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr)
++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;
+@@ -2285,12 +2369,15 @@ ppc_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr)
+
+ 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. */
+@@ -2337,13 +2424,14 @@ ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
+
+ static int
+ ppc_elf_additional_program_headers (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
+ {
+ asection *s;
+- int ret = 0;
++// 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");
+@@ -2353,13 +2441,13 @@ ppc_elf_additional_program_headers (bfd *abfd,
+ return ret;
+ }
+
+ /* Modify the segment map for VLE executables. */
+
+ bfd_boolean
+-ppc_elf_modify_segment_map (bfd *abfd,
++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;
+@@ -2546,13 +2634,13 @@ apuinfo_list_finish (void)
+ #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_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
++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;
+@@ -2646,24 +2734,24 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
+ }
+
+ /* 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_write_section (bfd *abfd ATTRIBUTE_UNUSED,
++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_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
++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;
+@@ -3232,13 +3320,13 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info)
+ abort ();
+ }
+ else
+ {
+ /* The powerpc .got has a blrl instruction in it. Mark it
+ executable. */
+- flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS
++ 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");
+@@ -3340,13 +3428,13 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
+
+ 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;
++ 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);
+ }
+
+@@ -3410,13 +3498,13 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info,
+ 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
++ 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;
+
+@@ -4186,12 +4274,19 @@ ppc_elf_check_relocs (bfd *abfd,
+ 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;
+@@ -4679,13 +4774,13 @@ ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents,
+ }
+
+
+ /* 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_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
++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;
+@@ -4976,13 +5071,13 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
+ }
+
+ /* Set plt output section type, htab->tls_get_addr, and call the
+ generic ELF tls_setup function. */
+
+ asection *
+-ppc_elf_tls_setup (bfd *obfd,
++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);
+@@ -5075,13 +5170,13 @@ branch_reloc_hash_match (const bfd *ibfd,
+ }
+
+ /* Run through all the TLS relocs looking for optimization
+ opportunities. */
+
+ bfd_boolean
+-ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
++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;
+@@ -6008,12 +6103,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ 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");
+@@ -6037,12 +6136,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ 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;
+@@ -6400,12 +6503,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ 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)
+ {
+@@ -7172,13 +7279,13 @@ is_static_defined (struct elf_link_hash_entry *h)
+
+ /* 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_ppc_at_tls_transform (unsigned int insn, unsigned int reg)
++_bfd_elf_amigaos_ppc_at_tls_transform (unsigned int insn, unsigned int reg)
+ {
+ unsigned int rtra;
+
+ if ((insn & (0x3f << 26)) != 31 << 26)
+ return 0;
+
+@@ -7212,13 +7319,13 @@ _bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg)
+
+ /* 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_ppc_at_tprel_transform (unsigned int insn, unsigned int reg)
++_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 */
+@@ -8076,13 +8183,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
+ /* 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_ppc_at_tprel_transform (insn, 2);
++ 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
+@@ -8502,13 +8609,47 @@ ppc_elf_relocate_section (bfd *output_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;
+
+@@ -8899,12 +9040,15 @@ ppc_elf_relocate_section (bfd *output_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;
+@@ -9124,18 +9268,24 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
+ || 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);
+@@ -9166,24 +9316,34 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
+ * 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)
+- sym->st_value = 0;
++ {
++ /* 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;
+@@ -9275,12 +9435,15 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
+ 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;
+ }
+
+@@ -9735,16 +9898,14 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
+ return FALSE;
+ }
+
+ return ret;
+ }
+
+-#define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec
+-#define TARGET_LITTLE_NAME "elf32-powerpcle"
+-#define TARGET_BIG_SYM bfd_elf32_powerpc_vec
+-#define TARGET_BIG_NAME "elf32-powerpc"
++#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
+@@ -9789,153 +9950,23 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
+ #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_modify_segment_map
++#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_begin_write_processing
+-#define elf_backend_final_write_processing ppc_elf_final_write_processing
+-#define elf_backend_write_section ppc_elf_write_section
++#define elf_backend_begin_write_processing ppc_elf_amigaos_begin_write_processing
++#define elf_backend_final_write_processing ppc_elf_amigaos_final_write_processing
++#define elf_backend_write_section ppc_elf_amigaos_write_section
+ #define elf_backend_get_sec_type_attr ppc_elf_get_sec_type_attr
+ #define elf_backend_plt_sym_val ppc_elf_plt_sym_val
+ #define elf_backend_action_discarded ppc_elf_action_discarded
+ #define elf_backend_init_index_section _bfd_elf_init_1_index_section
+ #define elf_backend_post_process_headers _bfd_elf_set_osabi
+ #define elf_backend_lookup_section_flags_hook ppc_elf_lookup_section_flags
+-#define elf_backend_section_processing ppc_elf_section_processing
+-
+-#include "elf32-target.h"
+-
+-/* FreeBSD Target */
+-
+-#undef TARGET_LITTLE_SYM
+-#undef TARGET_LITTLE_NAME
+-
+-#undef TARGET_BIG_SYM
+-#define TARGET_BIG_SYM bfd_elf32_powerpc_freebsd_vec
+-#undef TARGET_BIG_NAME
+-#define TARGET_BIG_NAME "elf32-powerpc-freebsd"
+-
+-#undef ELF_OSABI
+-#define ELF_OSABI ELFOSABI_FREEBSD
+-
+-#undef elf32_bed
+-#define elf32_bed elf32_powerpc_fbsd_bed
+-
+-#include "elf32-target.h"
+-
+-/* VxWorks Target */
+-
+-#undef TARGET_LITTLE_SYM
+-#undef TARGET_LITTLE_NAME
+-
+-#undef TARGET_BIG_SYM
+-#define TARGET_BIG_SYM bfd_elf32_powerpc_vxworks_vec
+-#undef TARGET_BIG_NAME
+-#define TARGET_BIG_NAME "elf32-powerpc-vxworks"
+-
+-#undef ELF_OSABI
+-
+-/* VxWorks uses the elf default section flags for .plt. */
+-static const struct bfd_elf_special_section *
+-ppc_elf_vxworks_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+-{
+- if (sec->name == NULL)
+- return NULL;
+-
+- if (strcmp (sec->name, ".plt") == 0)
+- return _bfd_elf_get_sec_type_attr (abfd, sec);
+-
+- return ppc_elf_get_sec_type_attr (abfd, sec);
+-}
+-
+-/* Like ppc_elf_link_hash_table_create, but overrides
+- appropriately for VxWorks. */
+-static struct bfd_link_hash_table *
+-ppc_elf_vxworks_link_hash_table_create (bfd *abfd)
+-{
+- struct bfd_link_hash_table *ret;
+-
+- ret = ppc_elf_link_hash_table_create (abfd);
+- if (ret)
+- {
+- struct ppc_elf_link_hash_table *htab
+- = (struct ppc_elf_link_hash_table *)ret;
+- htab->is_vxworks = 1;
+- htab->plt_type = PLT_VXWORKS;
+- htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE;
+- htab->plt_slot_size = VXWORKS_PLT_ENTRY_SIZE;
+- htab->plt_initial_entry_size = VXWORKS_PLT_INITIAL_ENTRY_SIZE;
+- }
+- return ret;
+-}
+-
+-/* Tweak magic VxWorks symbols as they are loaded. */
+-static bfd_boolean
+-ppc_elf_vxworks_add_symbol_hook (bfd *abfd,
+- struct bfd_link_info *info,
+- Elf_Internal_Sym *sym,
+- const char **namep ATTRIBUTE_UNUSED,
+- flagword *flagsp ATTRIBUTE_UNUSED,
+- asection **secp,
+- bfd_vma *valp)
+-{
+- if (!elf_vxworks_add_symbol_hook(abfd, info, sym,namep, flagsp, secp,
+- valp))
+- return FALSE;
+-
+- return ppc_elf_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, valp);
+-}
+-
+-static void
+-ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
+-{
+- ppc_elf_final_write_processing(abfd, linker);
+- elf_vxworks_final_write_processing(abfd, linker);
+-}
+-
+-/* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so
+- define it. */
+-#undef elf_backend_want_plt_sym
+-#define elf_backend_want_plt_sym 1
+-#undef elf_backend_want_got_plt
+-#define elf_backend_want_got_plt 1
+-#undef elf_backend_got_symbol_offset
+-#define elf_backend_got_symbol_offset 0
+-#undef elf_backend_plt_not_loaded
+-#define elf_backend_plt_not_loaded 0
+-#undef elf_backend_plt_readonly
+-#define elf_backend_plt_readonly 1
+-#undef elf_backend_got_header_size
+-#define elf_backend_got_header_size 12
+-
+-#undef bfd_elf32_get_synthetic_symtab
+-
+-#undef bfd_elf32_bfd_link_hash_table_create
+-#define bfd_elf32_bfd_link_hash_table_create \
+- ppc_elf_vxworks_link_hash_table_create
+-#undef elf_backend_add_symbol_hook
+-#define elf_backend_add_symbol_hook \
+- ppc_elf_vxworks_add_symbol_hook
+-#undef elf_backend_link_output_symbol_hook
+-#define elf_backend_link_output_symbol_hook \
+- elf_vxworks_link_output_symbol_hook
+-#undef elf_backend_final_write_processing
+-#define elf_backend_final_write_processing \
+- ppc_elf_vxworks_final_write_processing
+-#undef elf_backend_get_sec_type_attr
+-#define elf_backend_get_sec_type_attr \
+- ppc_elf_vxworks_get_sec_type_attr
+-#undef elf_backend_emit_relocs
+-#define elf_backend_emit_relocs \
+- elf_vxworks_emit_relocs
+-
+-#undef elf32_bed
+-#define elf32_bed ppc_elf_vxworks_bed
+-#undef elf_backend_post_process_headers
++#define elf_backend_section_processing ppc_elf_amigaos_section_processing
+
+ #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
++++ b/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
+--- a/bfd/elf32-i386.c
++++ b/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
++++ b/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
+--- a/bfd/elf32-ppc.c
++++ b/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
++++ b/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
++++ b/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
++++ b/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
+--- a/bfd/libbfd.h
++++ b/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
+--- a/bfd/linker.c
++++ b/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
+--- a/bfd/reloc.c
++++ b/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
+--- a/bfd/targets.c
++++ b/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
+--- a/binutils/objcopy.c
++++ b/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
+--- a/binutils/readelf.c
++++ b/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)
+ {