diff options
17 files changed, 45760 insertions, 434 deletions
diff --git a/ppc-amigaos/Makefile b/ppc-amigaos/Makefile index a53fe9c..51d0c87 100644 --- a/ppc-amigaos/Makefile +++ b/ppc-amigaos/Makefile @@ -1,21 +1,20 @@ -UPSTREAM_GCC_VERSION := 467 -UPSTREAM_GCC_TARBALL := gcc-$(UPSTREAM_GCC_VERSION) -UPSTREAM_GCC_URI := http://svn.code.sf.net/p/adtools/code/branches/gcc/4.5.x@$(UPSTREAM_GCC_VERSION) +UPSTREAM_GCC_VERSION := 5.3.0 +UPSTREAM_GCC_TARBALL := gcc-$(UPSTREAM_GCC_VERSION).tar.bz2 +UPSTREAM_GCC_URI := http://ftp.gnu.org/gnu/gcc/gcc-$(UPSTREAM_GCC_VERSION)/$(UPSTREAM_GCC_TARBALL) -UPSTREAM_BINUTILS_VERSION := 467 -UPSTREAM_BINUTILS_TARBALL := binutils-$(UPSTREAM_BINUTILS_VERSION) -UPSTREAM_BINUTILS_URI := http://svn.code.sf.net/p/adtools/code/trunk/binutils@$(UPSTREAM_BINUTILS_VERSION) +UPSTREAM_BINUTILS_VERSION := 2.23.2 +UPSTREAM_BINUTILS_TARBALL := binutils-$(UPSTREAM_BINUTILS_VERSION).tar.bz2 +UPSTREAM_BINUTILS_URI := ftp://ftp.gnu.org/gnu/binutils/$(UPSTREAM_BINUTILS_TARBALL) -UPSTREAM_GMP_VERSION := 4.3.2 +UPSTREAM_GMP_VERSION := 5.0.5 UPSTREAM_GMP_TARBALL := gmp-$(UPSTREAM_GMP_VERSION).tar.bz2 UPSTREAM_GMP_URI := http://ftp.gnu.org/gnu/gmp/$(UPSTREAM_GMP_TARBALL) -# Would use 3.0.0, but that dislikes in-tree gmp sources -UPSTREAM_MPFR_VERSION := 2.4.2 +UPSTREAM_MPFR_VERSION := 3.1.2 UPSTREAM_MPFR_TARBALL := mpfr-$(UPSTREAM_MPFR_VERSION).tar.bz2 UPSTREAM_MPFR_URI := http://www.mpfr.org/mpfr-$(UPSTREAM_MPFR_VERSION)/$(UPSTREAM_MPFR_TARBALL) -UPSTREAM_MPC_VERSION := 0.8.2 +UPSTREAM_MPC_VERSION := 0.9 UPSTREAM_MPC_TARBALL := mpc-$(UPSTREAM_MPC_VERSION).tar.gz UPSTREAM_MPC_URI := http://www.multiprecision.org/mpc/download/$(UPSTREAM_MPC_TARBALL) @@ -118,7 +117,8 @@ $(BUILDSTEPS)/srcdir-step2.d: $(BUILDSTEPS)/srcdir-step1.d $(SOURCESDIR)/$(UPSTR touch $@ $(BUILDSTEPS)/srcdir-step1.d: $(BUILDSTEPS)/$(UPSTREAM_GCC_TARBALL).d - cp -r $(SOURCESDIR)/$(UPSTREAM_GCC_TARBALL) $(GCC_SRCDIR) + tar xjf $(SOURCESDIR)/$(UPSTREAM_GCC_TARBALL) + mv gcc-$(UPSTREAM_GCC_VERSION) $(GCC_SRCDIR) touch $@ $(BUILDSTEPS)/$(UPSTREAM_GCC_TARBALL).d: $(BUILDSTEPS)/buildsteps.d $(SOURCESDIR)/$(UPSTREAM_GCC_TARBALL) @@ -128,17 +128,16 @@ $(BUILDSTEPS)/$(UPSTREAM_GCC_TARBALL).d: $(BUILDSTEPS)/buildsteps.d $(SOURCESDIR # Rules to build and install binutils ### -# Ugh. Upstream binutils is not remotely 64-bit safe. -# Build a 32bit binary until this gets fixed $(BUILDSTEPS)/binutils.d: $(BUILDSTEPS)/binutils-srcdir.d mkdir -p $(BUILDDIR)/binutils - cd $(BUILDDIR)/binutils && CFLAGS="-m32" LDFLAGS="-m32" $(BINUTILS_SRCDIR)/configure --prefix=$(PREFIX) --target=$(TARGET_NAME) --disable-nls + cd $(BUILDDIR)/binutils && $(BINUTILS_SRCDIR)/configure --prefix=$(PREFIX) --target=$(TARGET_NAME) --disable-nls --enable-plugins cd $(BUILDDIR)/binutils && make cd $(BUILDDIR)/binutils && make install touch $@ $(BUILDSTEPS)/binutils-srcdir.d: $(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL) - cp -r $(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL) $(BINUTILS_SRCDIR) + tar xjf $(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL) + mv binutils-$(UPSTREAM_BINUTILS_VERSION) $(BINUTILS_SRCDIR) for p in `ls $(RECIPES)/patches/binutils/*.p` ; do patch -d $(BINUTILS_SRCDIR) -p0 <$$p ; done touch $@ @@ -147,7 +146,7 @@ $(BUILDSTEPS)/binutils-srcdir.d: $(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL) ### $(SOURCESDIR)/$(UPSTREAM_GCC_TARBALL): - svn co $(UPSTREAM_GCC_URI) $@ + wget -q -O $@ $(UPSTREAM_GCC_URI) $(SOURCESDIR)/$(UPSTREAM_GMP_TARBALL): wget -q -O $@ $(UPSTREAM_GMP_URI) @@ -159,7 +158,7 @@ $(SOURCESDIR)/$(UPSTREAM_MPC_TARBALL): wget -q -O $@ $(UPSTREAM_MPC_URI) $(SOURCESDIR)/$(UPSTREAM_BINUTILS_TARBALL): - svn co $(UPSTREAM_BINUTILS_URI) $@ + wget -q -O $@ $(UPSTREAM_BINUTILS_URI) $(SOURCESDIR)/$(UPSTREAM_NDK_TARBALL): wget -q -O $@ $(UPSTREAM_NDK_URI) diff --git a/ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p b/ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p new file mode 100644 index 0000000..ccc8a07 --- /dev/null +++ b/ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p @@ -0,0 +1,26193 @@ +From 1678a95339b8893195b307a953a0053ceeca0133 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Sat, 14 Feb 2015 14:54:44 +0100 +Subject: [PATCH 1/7] Changes for various Amiga targets. + +--- + bfd/ChangeLog-9697 | 64 + + bfd/ChangeLog-9899 | 5 + + bfd/Makefile.am | 18 +- + bfd/Makefile.in | 24 +- + bfd/amigaos.c | 3189 +++++++++ + bfd/amigaoslink.c | 1032 +++ + bfd/aout-amiga.c | 152 + + bfd/aoutx.h | 26 +- + bfd/bfd-in2.h | 12 + + bfd/bfd.c | 1 + + bfd/bfdio.c | 25 + + bfd/config.bfd | 28 +- + bfd/configure | 5 + + bfd/configure.host | 1 + + bfd/configure.in | 5 + + bfd/doc/Makefile.am | 15 +- + bfd/doc/Makefile.in | 15 +- + bfd/doc/bfd.texinfo | 9 +- + bfd/elf32-amiga.c | 3844 +++++++++++ + bfd/{elf32-ppc.c => elf32-amigaos.c} | 341 +- + bfd/elf32-i386-amithlon.c | 198 + + bfd/elf32-i386.c | 17 +- + bfd/elf32-morphos.c | 7137 +++++++++++++++++++++ + bfd/elf32-ppc.c | 4 + + bfd/hosts/amigaos.h | 5 + + bfd/hosts/morphos.h | 5 + + bfd/libamiga.h | 187 + + bfd/libbfd.h | 8 + + bfd/linker.c | 26 +- + bfd/reloc.c | 19 + + bfd/targets.c | 11 + + binutils/objcopy.c | 50 +- + binutils/readelf.c | 5 + + binutils/rename.c | 4 +- + config.sub | 11 +- + config/mh-amigaos | 13 + + config/mh-morphos | 13 + + configure | 6 + + configure.ac | 6 + + gas/ChangeLog-9697 | 12 + + gas/ChangeLog-9899 | 4 + + gas/Makefile.am | 5 +- + gas/Makefile.in | 20 +- + gas/as.c | 14 + + gas/config/m68k-parse.h | 3 + + gas/config/m68k-parse.y | 10 +- + gas/config/obj-amigahunk.c | 212 + + gas/config/obj-amigahunk.h | 54 + + gas/config/obj-elf.c | 4 +- + gas/config/tc-i386.h | 15 +- + gas/config/tc-m68k.c | 312 +- + gas/config/tc-m68k.h | 15 + + gas/config/tc-ppc.c | 36 +- + gas/config/tc-sh.c | 28 +- + gas/config/te-amiga.h | 24 + + gas/config/te-amigaos.h | 14 + + gas/config/{te-nbsd.h => te-amithlon.h} | 16 +- + gas/config/te-morphos.h | 14 + + gas/configure | 20 + + gas/configure.in | 18 + + gas/configure.tgt | 8 +- + gas/read.c | 21 +- + gas/read.h | 4 + + gas/write.c | 31 +- + gas/write.h | 4 +- + gprof/Makefile.am | 2 +- + gprof/Makefile.in | 2 +- + gprof/configure | 13 + + gprof/configure.in | 11 + + gprof/gconfig.in | 4 - + include/elf/amigaos.h | 27 + + include/elf/ppc.h | 12 + + include/libiberty.h | 2 +- + ld/ChangeLog-9197 | 15 + + ld/ChangeLog-9899 | 5 + + ld/Makefile.am | 38 + + ld/Makefile.in | 46 + + ld/configure.host | 4 + + ld/configure.tgt | 9 + + ld/emulparams/amiga.sh | 6 + + ld/emulparams/amiga_bss.sh | 6 + + ld/emulparams/amigaos.sh | 26 + + ld/emulparams/amithlon.sh | 11 + + ld/emulparams/morphos.sh | 6 + + ld/emulparams/morphos_baserel.sh | 6 + + ld/emulparams/ppcamiga.sh | 8 + + ld/emulparams/ppcamiga_bss.sh | 8 + + ld/emultempl/amiga.em | 288 + + ld/emultempl/{elf32.em => amigaos.em} | 0 + ld/emultempl/amithlon.em | 1698 +++++ + ld/emultempl/morphos.em | 1104 ++++ + ld/emultempl/ppc32elf.em | 12 + + ld/ldctor.c | 18 +- + ld/ldfile.c | 54 +- + ld/ldfile.h | 5 + + ld/ldlang.c | 7 + + ld/ldlang.h | 2 + + ld/ldlex.c | 127 +- + ld/ldmain.c | 7 + + ld/scripttempl/amiga.sc | 49 + + ld/scripttempl/amiga_bss.sc | 41 + + ld/scripttempl/{elf64hppa.sc => amigaos.sc} | 132 +- + ld/scripttempl/{mep.sc => amithlon.sc} | 145 +- + ld/scripttempl/{elfi370.sc => morphos.sc} | 57 +- + ld/scripttempl/{elfi370.sc => morphos_baserel.sc} | 108 +- + libiberty/config/mh-amigaos | 12 + + libiberty/config/mh-morphos | 12 + + libiberty/lrealpath.c | 6 + + opcodes/m68k-dis.c | 2 +- + 109 files changed, 20966 insertions(+), 641 deletions(-) + create mode 100644 bfd/amigaos.c + create mode 100644 bfd/amigaoslink.c + create mode 100644 bfd/aout-amiga.c + create mode 100644 bfd/elf32-amiga.c + copy bfd/{elf32-ppc.c => elf32-amigaos.c} (97%) + create mode 100644 bfd/elf32-i386-amithlon.c + create mode 100644 bfd/elf32-morphos.c + create mode 100644 bfd/hosts/amigaos.h + create mode 100644 bfd/hosts/morphos.h + create mode 100644 bfd/libamiga.h + create mode 100644 config/mh-amigaos + create mode 100644 config/mh-morphos + create mode 100644 gas/config/obj-amigahunk.c + create mode 100644 gas/config/obj-amigahunk.h + create mode 100644 gas/config/te-amiga.h + create mode 100644 gas/config/te-amigaos.h + copy gas/config/{te-nbsd.h => te-amithlon.h} (65%) + create mode 100644 gas/config/te-morphos.h + create mode 100644 include/elf/amigaos.h + create mode 100644 ld/emulparams/amiga.sh + create mode 100644 ld/emulparams/amiga_bss.sh + create mode 100644 ld/emulparams/amigaos.sh + create mode 100644 ld/emulparams/amithlon.sh + create mode 100644 ld/emulparams/morphos.sh + create mode 100644 ld/emulparams/morphos_baserel.sh + create mode 100644 ld/emulparams/ppcamiga.sh + create mode 100644 ld/emulparams/ppcamiga_bss.sh + create mode 100644 ld/emultempl/amiga.em + copy ld/emultempl/{elf32.em => amigaos.em} (100%) + create mode 100644 ld/emultempl/amithlon.em + create mode 100644 ld/emultempl/morphos.em + create mode 100644 ld/scripttempl/amiga.sc + create mode 100644 ld/scripttempl/amiga_bss.sc + copy ld/scripttempl/{elf64hppa.sc => amigaos.sc} (88%) + copy ld/scripttempl/{mep.sc => amithlon.sc} (76%) + copy ld/scripttempl/{elfi370.sc => morphos.sc} (88%) + copy ld/scripttempl/{elfi370.sc => morphos_baserel.sc} (69%) + create mode 100644 libiberty/config/mh-amigaos + create mode 100644 libiberty/config/mh-morphos + +diff --git a/bfd/ChangeLog-9697 b/bfd/ChangeLog-9697 +index e9a5c1d60a313aaf09d1a8add619022cfdf575fa..1c2bb3f3c91d32e8b95f8b0cf16b98c58cde454b 100644 +--- bfd/ChangeLog-9697 ++++ bfd/ChangeLog-9697 +@@ -46,12 +46,19 @@ Mon Dec 22 13:20:57 1997 Ian Lance Taylor <ian@cygnus.com> + + Mon Dec 22 13:04:33 1997 Joel Sherrill <joel@oarcorp.com> + + * config.bfd (i[3456]86*-go32-rtems*): Fix to be the same as + i[3456]86-go32. + ++Fri Dec 19 14:25:58 1997 Daniel Verite <daniel@brainstorm.fr> ++ ++ * amigaos.c (amiga_bfd_copy_private_section_data): Add return ++ value. ++ * amigaoslink.c (amiga_final_link): Update linker_mark fields for ++ input sections involved in the output. ++ + Thu Dec 18 16:01:25 1997 Doug Evans <devans@canuck.cygnus.com> + + * configure: Regenerate to get @SHELL@ substituted. + + Wed Dec 17 09:45:09 1997 Nick Clifton <nickc@cygnus.com> + +@@ -594,12 +601,22 @@ Tue Sep 23 19:03:13 1997 Ian Lance Taylor <ian@cygnus.com> + + * elf.c (map_sections_to_segments): Even if we are not demand + paged, don't put a loadable section after a nonloadable section. + (assign_file_positions_for_segments): Increment the file offset + for a section with contents, even if it is not loadable. + ++Tue Sep 23 09:46:10 1997 Fred Fish <fnf@ninemoons.com> ++ ++ * amigaos.c (alloca): Only declare if not defined as macro. ++ ++Mon Sep 22 10:15:30 1997 Fred Fish <fnf@ninemoons.com> ++ ++ * amigaos.c (sysdep.h): Relocate include to provided needed ++ <sys/types.h> file. ++ * amigaoslink.c (sysdep.h): Ditto, and remove <sys/types.h>. ++ + Sun Sep 21 11:03:24 1997 Nick Clifton <nickc@cygnus.com> + + * elf32-v850.c (v850_elf_final_link_relocate): Add return code + indicating that __ctbp could not be found. + + Thu Sep 18 15:04:57 1997 Nick Clifton <nickc@cygnus.com> +@@ -764,12 +781,18 @@ Tue Aug 26 17:26:51 1997 Ian Lance Taylor <ian@cygnus.com> + * doc/Makefile.am (MKDOC): Use EXEEXT_FOR_BUILD, not EXEEXT. + * aclocal.m4: Rebuild. + * configure: Rebuild. + * Makefile.in: Rebuild. + * doc/Makefile.in: Rebuild. + ++Mon Aug 25 16:32:00 1997 Steffen Opel <opel@rumms.uni-mannheim.de> ++ ++ * Makefile.in (guide, install-guide, clean-guide, bfd.guide): ++ New targets for AmigaGuide documentation. ++ (install): Add install-info and install-guide. ++ + Mon Aug 25 16:14:34 1997 Christopher Provenzano <proven@cygnus.com> + + * configure: Rebuild with latest devo autoconf for NT support + + Mon Aug 25 16:11:04 1997 Nick Clifton <nickc@cygnus.com> + +@@ -3764,12 +3787,18 @@ Fri Aug 30 11:49:19 1996 Ian Lance Taylor <ian@cygnus.com> + page before checking D_PAGED. + + * ihex.c (ihex_scan): Removed unnecessary extbase variable. + (ihex_write_object_contents): Remove extbase; always use segbase + instead. + ++Thu Aug 29 17:53:51 1996 Daniel Verite <daniel@brainstorm.eu.org> ++ ++ * amigaos.c (amiga_get_section_contents): Handle sections that ++ are larger than their disksize. ++ (amiga_make_unique_section): Remove infinite loop. ++ + Thu Aug 29 16:52:17 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * configure.in (i[345]86-*-*): Recognize i686 for pentium pro. + * configure.host (i[345]86-*-*): Ditto. + * config.bfd (i[345]86-*-*): Ditto. + * configure: Regenerate. +@@ -3989,12 +4018,19 @@ Mon Aug 5 13:42:41 1996 Ian Lance Taylor <ian@cygnus.com> + * elf.c (map_sections_to_segments): Rewrite tests for starting a + new segment to make them more comprehensible. If the relationship + between the LMA and the VMA changed, start a new segment. Don't + check dynsec when deciding whether to start a new segment for a + writeable section; -N will now handle this. + ++Sun Aug 4 22:15:56 1996 Fred Fish <fnf@ninemoons.com> ++ ++ * amigaoslink.c (sys/types.h): Include before genlink.h to get ++ definition for size_t which is used in genlink.h. This was not ++ getting defined during a cross compilation on alpha-dec-osf2.0 for ++ some reason. ++ + Thu Aug 1 22:43:08 1996 Jeffrey A Law (law@cygnus.com) + + * libhppa.h: Remove "esel" changes. Not the right approach. + * som.c: Corresponding changes. + (som_bfd_derive_misc_symbol_info): Use ST_DATA for symbols + which don't have a SOM symbol type associated with them. +@@ -4085,12 +4121,17 @@ Mon Jul 22 15:30:30 1996 Ian Lance Taylor <ian@cygnus.com> + + Fri Jul 19 18:15:51 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Fix test for whether a compiler has a 64 bit + type. From Jim Wilson <wilson@cygnus.com>. + ++Thu Jul 18 16:58:11 1996 Daniel Verite <daniel@brainstorm.eu.org> ++ ++ * amigaoslink.c (aout_perform_reloc): Fix baserel 16 bits relocs. ++ (my_add_to): Fix sign bug in extraction of 16 bits values. ++ + Thu Jul 18 15:39:10 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.host (mips-sgi-irix6*): New host. + + * configure.in: Set and substitute VERSION, BFD_HOST_64BIT_LONG + (replacing HOST_64BITLONG), BFD_HOST_64_BIT_DEFINED, +@@ -4214,12 +4255,17 @@ Mon Jul 8 16:18:03 1996 Ian Lance Taylor <ian@cygnus.com> + (mips_relhi_addr, mips_relhi_addend): Remove. + (mips_relhi_reloc): Maintain a list of unmatched RELHI relocs. + (mips_rello_reloc): Process mips_relhi_list. + (mips_relocate_section): Permit an arbitrary number of REFHI or + RELHI relocs before the associated REFLO or RELLO reloc. + ++Sun Jul 7 12:15:39 1996 Kamil Iskra <iskra@student.uci.agh.edu.pl> ++ ++ * amigaos.c (amiga_write_symbols): Fix Daniel's workaround for ++ outputting long symbol names. ++ + Fri Jul 5 19:27:49 1996 Ian Lance Taylor <ian@cygnus.com> + + * aout-target.h (MY(callback)): Set reloc_count fields. + + Thu Jul 4 12:00:37 1996 Ian Lance Taylor <ian@cygnus.com> + +@@ -4293,12 +4339,17 @@ Fri Jun 28 11:17:00 1996 Richard Henderson <rth@tamu.edu> + (elf64_alpha_link_hash_newfunc): Initialize flags field. + (elf64_alpha_check_relocs): Record types of LITUSE entries that + are found for LITERAL relocs. + (elf64_alpha_adjust_dynamic_symbol): If a symbol has its address + taken, we cannot generate a .plt entry for the symbol. + ++Thu Jun 27 17:35:32 1996 Daniel Verite <daniel@brainstorm.eu.org> ++ ++ * amigaos.c (amiga_write_object_contents): Don't output symbols ++ which are not attached to any section, such as indirect symbols. ++ + Thu Jun 27 11:24:29 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Add AC_ISC_POSIX, and check for setitimer and + sysconf functions (for gprof). + * configure, config.in: Rebuild. + +@@ -4522,12 +4573,25 @@ Wed Jun 12 11:16:37 1996 Ian Lance Taylor <ian@cygnus.com> + Tue Jun 11 15:24:48 1996 Ian Lance Taylor <ian@cygnus.com> + + * xcofflink.c (xcoff_build_ldsyms): Set XCOFF_DEF_REGULAR for a + common symbol defined by the linker. Don't export function code + even if export_defineds is set. + ++Tue Jun 11 12:52:10 1996 Daniel Verite <daniel@brainstorm.eu.org> ++ ++ * amigaoslink.c (mygeta4): Function removed. ++ (amiga_final_link): Search for ___a4_init symbol in the global hash ++ table and cache its value in the backend data. ++ ++ * amigaos.c (write_longs): Return a boolean instead of the ++ number of longs written. ++ (write_section_contents): Split reloc hunks at 0xffff entries. ++ (amiga_write_symbols): Cut the names in hunk symbols at 124 characters ++ (workaround for an amigaos bug). ++ (amiga_handle_rest): Added a sanity check in reloc hunks parsing. ++ + Mon Jun 10 11:57:27 1996 Jeffrey A Law (law@cygnus.com) + + * coff-h8300.c (howto_table): Add new entries for R_BCC_INV + and R_JMP_DEL. + (rtype2howto): Handle R_BCC_INV and R_JMP_DEL. + (h8300_symbol_address_p): New function. +diff --git a/bfd/ChangeLog-9899 b/bfd/ChangeLog-9899 +index 6d7f5cd616db22097b8238d8686f60484c9e6ee6..6e25901995a73646a13037d32c14563df20f74b3 100644 +--- bfd/ChangeLog-9899 ++++ bfd/ChangeLog-9899 +@@ -5570,12 +5570,17 @@ Wed Jan 21 21:16:06 1998 Manfred Hollstein <manfred@s-direktnet.de> + (GET_SCNDHR_NLNNO): Likewise. + + Mon Jan 19 12:49:52 1998 Ian Lance Taylor <ian@cygnus.com> + + * cpu-sh.c (arch_info_struct): Correct next field of sh3e. + ++Sun Jan 18 10:39:52 1998 Daniel Verite <daniel@brainstorm.fr> ++ ++ * amigaos.c (CAN_WRITE_OUTSYM): New macro. ++ (amiga_write_object_contents): Use CAN_WRITE_OUTSYM ++ + Wed Jan 14 17:23:27 1998 Nick Clifton <nickc@cygnus.com> + + * elf32-m32r.c: Add macros to handle NOP insertion. + + Wed Jan 14 16:15:22 1998 Richard Henderson <rth@cygnus.com> + +diff --git a/bfd/Makefile.am b/bfd/Makefile.am +index 9ab2aa947a0a96ba5a469652c579a4d181793646..c224a3cecc392df96a6bc20c8dc73eb81c677269 100644 +--- bfd/Makefile.am ++++ bfd/Makefile.am +@@ -232,13 +232,16 @@ ALL_MACHINES_CFILES = \ + cpu-z80.c \ + cpu-z8k.c + + # The .o files needed by all of the 32 bit vectors that are configured into + # target_vector in targets.c if configured with --enable-targets=all. + BFD32_BACKENDS = \ ++ amigaos.lo \ ++ amigaoslink.lo \ + aout-adobe.lo \ ++ aout-amiga.lo \ + aout-arm.lo \ + aout-cris.lo \ + aout-ns32k.lo \ + aout-sparcle.lo \ + aout-tic30.lo \ + aout0.lo \ +@@ -287,12 +290,13 @@ BFD32_BACKENDS = \ + elf-strtab.lo \ + elf-vxworks.lo \ + elf.lo \ + elf32-am33lin.lo \ + elf32-arc.lo \ + elf32-arm.lo \ ++ elf32-amigaos.lo \ + elf32-avr.lo \ + elf32-bfin.lo \ + elf32-cr16.lo \ + elf32-cr16c.lo \ + elf32-cris.lo \ + elf32-crx.lo \ +@@ -320,12 +324,13 @@ BFD32_BACKENDS = \ + elf32-m68k.lo \ + elf32-m88k.lo \ + elf32-mcore.lo \ + elf32-mep.lo \ + elf32-microblaze.lo \ + elf32-mips.lo \ ++ elf32-morphos.lo \ + elf32-moxie.lo \ + elf32-msp430.lo \ + elf32-mt.lo \ + elf32-openrisc.lo \ + elf32-or32.lo \ + elf32-pj.lo \ +@@ -420,13 +425,16 @@ BFD32_BACKENDS = \ + xcofflink.lo \ + xsym.lo \ + xtensa-isa.lo \ + xtensa-modules.lo + + BFD32_BACKENDS_CFILES = \ ++ amigaos.c \ ++ amigaoslink.c \ + aout-adobe.c \ ++ aout-amiga.c \ + aout-arm.c \ + aout-cris.c \ + aout-ns32k.c \ + aout-sparcle.c \ + aout-tic30.c \ + aout0.c \ +@@ -475,12 +483,13 @@ BFD32_BACKENDS_CFILES = \ + elf-strtab.c \ + elf-vxworks.c \ + elf.c \ + elf32-am33lin.c \ + elf32-arc.c \ + elf32-arm.c \ ++ elf32-amigaos.c \ + elf32-avr.c \ + elf32-bfin.c \ + elf32-cr16.c \ + elf32-cr16c.c \ + elf32-cris.c \ + elf32-crx.c \ +@@ -508,12 +517,13 @@ BFD32_BACKENDS_CFILES = \ + elf32-m68k.c \ + elf32-m88k.c \ + elf32-mcore.c \ + elf32-mep.c \ + elf32-microblaze.c \ + elf32-mips.c \ ++ elf32-morphos.c \ + elf32-moxie.c \ + elf32-msp430.c \ + elf32-mt.c \ + elf32-openrisc.c \ + elf32-or32.c \ + elf32-pj.c \ +@@ -745,13 +755,13 @@ CFILES = $(SOURCE_CFILES) $(BUILD_CFILES) + + ## This is a list of all .h files which are in the source tree. + SOURCE_HFILES = \ + aout-target.h aoutf1.h aoutx.h coffcode.h coffswap.h ecoffswap.h \ + elf-bfd.h elf-hppa.h elf32-hppa.h \ + elf64-hppa.h elfcode.h elfcore.h \ +- freebsd.h genlink.h go32stub.h \ ++ freebsd.h genlink.h go32stub.h libamiga.h \ + libaout.h libbfd.h libcoff.h libecoff.h libhppa.h libieee.h \ + libnlm.h liboasys.h libpei.h libxcoff.h mach-o.h \ + netbsd.h nlm-target.h nlmcode.h nlmswap.h ns32k.h \ + pef.h pef-traceback.h peicode.h som.h version.h \ + vms.h xsym.h + +@@ -1013,12 +1023,6 @@ coff-tic4x.lo: coff-tic4x.c + @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR) + @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo + @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< $(NO_WERROR) + +-coff-tic54x.lo: coff-tic54x.c +-@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR) +-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +-@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< $(NO_WERROR) +diff --git a/bfd/Makefile.in b/bfd/Makefile.in +index 99902757111d8011447cde1dda030e5a9c817ff2..bcdf435a15eb144bca66d8bfe04122a45e647446 100644 +--- bfd/Makefile.in ++++ bfd/Makefile.in +@@ -532,13 +532,16 @@ ALL_MACHINES_CFILES = \ + cpu-z8k.c + + + # The .o files needed by all of the 32 bit vectors that are configured into + # target_vector in targets.c if configured with --enable-targets=all. + BFD32_BACKENDS = \ ++ amigaos.lo \ ++ amigaoslink.lo \ + aout-adobe.lo \ ++ aout-amiga.lo \ + aout-arm.lo \ + aout-cris.lo \ + aout-ns32k.lo \ + aout-sparcle.lo \ + aout-tic30.lo \ + aout0.lo \ +@@ -587,12 +590,13 @@ BFD32_BACKENDS = \ + elf-strtab.lo \ + elf-vxworks.lo \ + elf.lo \ + elf32-am33lin.lo \ + elf32-arc.lo \ + elf32-arm.lo \ ++ elf32-amigaos.lo \ + elf32-avr.lo \ + elf32-bfin.lo \ + elf32-cr16.lo \ + elf32-cr16c.lo \ + elf32-cris.lo \ + elf32-crx.lo \ +@@ -620,12 +624,13 @@ BFD32_BACKENDS = \ + elf32-m68k.lo \ + elf32-m88k.lo \ + elf32-mcore.lo \ + elf32-mep.lo \ + elf32-microblaze.lo \ + elf32-mips.lo \ ++ elf32-morphos.lo \ + elf32-moxie.lo \ + elf32-msp430.lo \ + elf32-mt.lo \ + elf32-openrisc.lo \ + elf32-or32.lo \ + elf32-pj.lo \ +@@ -720,13 +725,16 @@ BFD32_BACKENDS = \ + xcofflink.lo \ + xsym.lo \ + xtensa-isa.lo \ + xtensa-modules.lo + + BFD32_BACKENDS_CFILES = \ ++ amigaos.c \ ++ amigaoslink.c \ + aout-adobe.c \ ++ aout-amiga.c \ + aout-arm.c \ + aout-cris.c \ + aout-ns32k.c \ + aout-sparcle.c \ + aout-tic30.c \ + aout0.c \ +@@ -775,12 +783,13 @@ BFD32_BACKENDS_CFILES = \ + elf-strtab.c \ + elf-vxworks.c \ + elf.c \ + elf32-am33lin.c \ + elf32-arc.c \ + elf32-arm.c \ ++ elf32-amigaos.c \ + elf32-avr.c \ + elf32-bfin.c \ + elf32-cr16.c \ + elf32-cr16c.c \ + elf32-cris.c \ + elf32-crx.c \ +@@ -808,12 +817,13 @@ BFD32_BACKENDS_CFILES = \ + elf32-m68k.c \ + elf32-m88k.c \ + elf32-mcore.c \ + elf32-mep.c \ + elf32-microblaze.c \ + elf32-mips.c \ ++ elf32-morphos.c \ + elf32-moxie.c \ + elf32-msp430.c \ + elf32-mt.c \ + elf32-openrisc.c \ + elf32-or32.c \ + elf32-pj.c \ +@@ -1046,13 +1056,13 @@ BUILD_CFILES = \ + + CFILES = $(SOURCE_CFILES) $(BUILD_CFILES) + SOURCE_HFILES = \ + aout-target.h aoutf1.h aoutx.h coffcode.h coffswap.h ecoffswap.h \ + elf-bfd.h elf-hppa.h elf32-hppa.h \ + elf64-hppa.h elfcode.h elfcore.h \ +- freebsd.h genlink.h go32stub.h \ ++ freebsd.h genlink.h go32stub.h libamiga.h \ + libaout.h libbfd.h libcoff.h libecoff.h libhppa.h libieee.h \ + libnlm.h liboasys.h libpei.h libxcoff.h mach-o.h \ + netbsd.h nlm-target.h nlmcode.h nlmswap.h ns32k.h \ + pef.h pef-traceback.h peicode.h som.h version.h \ + vms.h xsym.h + +@@ -1215,13 +1225,16 @@ mostlyclean-compile: + + distclean-compile: + -rm -f *.tab.c + + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix386-core.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix5ppc-core.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amigaos.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amigaoslink.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-adobe.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-amiga.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-arm.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-cris.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-ns32k.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-sparcle.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-tic30.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout0.Plo@am__quote@ +@@ -1365,12 +1378,13 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-m10300.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-nacl.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-strtab.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-vxworks.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-am33lin.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-amigaos.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-arc.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-arm.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-avr.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-bfin.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-cr16.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-cr16c.Plo@am__quote@ +@@ -1401,12 +1415,13 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68k.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m88k.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mcore.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mep.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-microblaze.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mips.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-morphos.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-moxie.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-msp430.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mt.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-openrisc.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-or32.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-pj.Plo@am__quote@ +@@ -2065,16 +2080,9 @@ coff-tic4x.lo: coff-tic4x.c + @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR) + @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo + @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< $(NO_WERROR) + +-coff-tic54x.lo: coff-tic54x.c +-@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR) +-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +-@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< $(NO_WERROR) +- + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: +diff --git a/bfd/amigaos.c b/bfd/amigaos.c +new file mode 100644 +index 0000000000000000000000000000000000000000..9d715d64d458e6599c19ed65fbb61c253d2ab208 +--- /dev/null ++++ bfd/amigaos.c +@@ -0,0 +1,3189 @@ ++/* BFD back-end for Commodore-Amiga AmigaOS binaries. ++ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 ++ Free Software Foundation, Inc. ++ Contributed by Leonard Norrgard. Partially based on the bout ++ and ieee BFD backends and Markus Wild's tool hunk2gcc. ++ Revised and updated by Stephan Thesing. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++ ++/* ++SECTION ++ amiga back end ++ ++This section describes the overall structure of the Amiga BFD back end. ++The linker stuff can be found in @xref{amigalink}. ++@menu ++@* implementation:: ++@* amigalink:: ++@end menu ++ ++INODE ++implementation, amigalink, amiga, amiga ++ ++SECTION ++ implementation ++ ++The need for a port of the bfd library for Amiga style object (hunk) files ++arose by the desire to port the GNU debugger gdb to the Amiga. ++Also, the linker ld should be updated to the current version (2.5.2). ++@@* ++This port bases on the work done by Leonard Norrgard, who started porting ++gdb. Raphael Luebbert, who supports the ixemul.library, has also worked on ++implementing the needed @code{ptrace()} system call and gas2.5. ++ ++@menu ++@* not supported:: ++@* Does it work?:: ++@* TODO:: ++@end menu ++ ++INODE ++not supported, Does it work?, implementation, implementation ++ ++SUBSECTION ++ not supported ++ ++Currently, the implementation does not support Amiga link library files, like ++e.g. amiga.lib. This may be added in a later version, if anyone starts work ++on it, or I find some time for it. ++ ++The handling of the symbols in hunk files is a little bit broken: ++ o The symbols in a load file are totally ignored at the moment, so gdb and gprof ++ do not work. ++ o The symbols of a object module (Hunk file, starting with HUNK_UNIT) are read in ++ correctly, but HUNK_SYMBOL hunks are also ignored. ++ ++The reason for this is the following: ++Amiga symbol hunks do not allow for much information. Only a name and a value are allowed. ++On the other hand, a.out format carries along much more information (see, e.g. the ++entry on set symbols in the ld manual). The old linker copied this information into ++a HUNK_DEBUG hunk. Now there is the choice: ++ o ignoring the debug hunk, read in only HUNK_SYMBOL definitions => extra info is lost. ++ o read in the debug hunk and use the information therein => How can clashs between the ++ information in the debug hunk and HUNK_SYMBOL or HUNK_EXT hunks be avoided? ++I haven't decided yet, what to do about this. ++ ++Although bfd allows to link together object modules of different flavours, ++producing a.out style executables does not work on Amiga :-) ++It should, however, be possible to create a.out files with the -r option of ld ++(incremental link). ++ ++INODE ++Does it work?, TODO, not supported, implementation ++ ++SUBSECTION ++ Does it work? ++ ++Currently, the following utilities work: ++ o objdump ++ o objcopy ++ o strip ++ o nm ++ o ar ++ o gas ++ ++INODE ++TODO, , Does it work?, implementation ++ ++SUBSECTION ++ TODO ++ ++ o fix FIXME:s ++ ++@* ++BFD: ++ o add flag to say if the format allows multiple sections with the ++ same name. Fix bfd_get_section_by_name() and bfd_make_section() ++ accordingly. ++ ++ o dumpobj.c: the disassembler: use relocation record data to find symbolic ++ names of addresses, when available. Needs new routine where one can ++ specify the source section of the symbol to be printed as well as some ++ rewrite of the disassemble functions. ++*/ ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "libbfd.h" ++#include "libamiga.h" ++ ++#define BYTES_IN_WORD 4 ++#include "aout/aout64.h" /* struct external_nlist */ ++ ++#ifndef alloca ++extern PTR alloca PARAMS ((size_t)); ++#endif ++ ++#define bfd_is_bfd_section(sec) \ ++ (bfd_is_abs_section(sec)||bfd_is_com_section(sec)||bfd_is_und_section(sec)||bfd_is_ind_section(sec)) ++ ++struct arch_syms { ++ unsigned long offset; /* disk offset in the archive */ ++ unsigned long size; /* size of the block of symbols */ ++ unsigned long unit_offset; /* start of unit on disk */ ++ struct arch_syms *next; /* linked list */ ++}; ++ ++typedef struct amiga_ardata_struct { ++ /* generic stuff */ ++ struct artdata generic; ++ /* amiga-specific stuff */ ++ unsigned long filesize; ++ struct arch_syms *defsyms; ++ unsigned long defsym_count; ++ unsigned long outnum; ++} amiga_ardata_type; ++ ++#define amiga_ardata(bfd) (*(amiga_ardata_type **)(void *)&(bfd)->tdata.aout_ar_data) ++ ++#define bfd_msg (*_bfd_error_handler) ++ ++#define GL(x) bfd_get_32 (abfd, (bfd_byte *) (x)) ++#define GW(x) bfd_get_16 (abfd, (bfd_byte *) (x)) ++#define LONGSIZE(l) (((l)+3) >> 2) ++ ++/* AmigaOS doesn't like HUNK_SYMBOL with symbol names longer than 124 characters */ ++#define MAX_NAME_SIZE 124 ++ ++static bfd_boolean get_long PARAMS ((bfd *, unsigned long *)); ++static const struct bfd_target *amiga_object_p PARAMS ((bfd *)); ++static sec_ptr amiga_get_section_by_hunk_number PARAMS ((bfd *, long)); ++static bfd_boolean amiga_add_reloc PARAMS ((bfd *, sec_ptr, bfd_size_type, ++ amiga_symbol_type *, reloc_howto_type *, long)); ++static sec_ptr amiga_make_unique_section PARAMS ((bfd *, const char *)); ++static bfd_boolean parse_archive_units PARAMS ((bfd *, int *, unsigned long, ++ bfd_boolean, struct arch_syms **, symindex *)); ++static bfd_boolean amiga_digest_file PARAMS ((bfd *)); ++static bfd_boolean amiga_read_unit PARAMS ((bfd *, unsigned long)); ++static bfd_boolean amiga_read_load PARAMS ((bfd *)); ++static bfd_boolean amiga_handle_cdb_hunk PARAMS ((bfd *, unsigned long, ++ unsigned long, unsigned long, unsigned long)); ++static bfd_boolean amiga_handle_rest PARAMS ((bfd *, sec_ptr, bfd_boolean)); ++static bfd_boolean amiga_mkobject PARAMS ((bfd *)); ++static bfd_boolean amiga_mkarchive PARAMS ((bfd *)); ++static bfd_boolean write_longs PARAMS ((const unsigned long *, unsigned long, ++ bfd *)); ++static long determine_datadata_relocs PARAMS ((bfd *, sec_ptr)); ++static void remove_section_index PARAMS ((sec_ptr, int *)); ++static bfd_boolean amiga_write_object_contents PARAMS ((bfd *)); ++static bfd_boolean write_name PARAMS ((bfd *, const char *, unsigned long)); ++static bfd_boolean amiga_write_archive_contents PARAMS ((bfd *)); ++static bfd_boolean amiga_write_armap PARAMS ((bfd *, unsigned int, ++ struct orl *, unsigned int, int)); ++static int determine_type PARAMS ((arelent *)); ++static bfd_boolean amiga_write_section_contents PARAMS ((bfd *, sec_ptr, ++ sec_ptr, unsigned long, int *, int)); ++static bfd_boolean amiga_write_symbols PARAMS ((bfd *, sec_ptr)); ++static bfd_boolean amiga_get_section_contents PARAMS ((bfd *, sec_ptr, PTR, ++ file_ptr, bfd_size_type)); ++static bfd_boolean amiga_new_section_hook PARAMS ((bfd *, sec_ptr)); ++static bfd_boolean amiga_slurp_symbol_table PARAMS ((bfd *)); ++static long amiga_get_symtab_upper_bound PARAMS ((bfd *)); ++static long amiga_get_symtab PARAMS ((bfd *, asymbol **)); ++static asymbol *amiga_make_empty_symbol PARAMS ((bfd *)); ++static void amiga_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *)); ++static void amiga_print_symbol PARAMS ((bfd *, PTR, asymbol *, ++ bfd_print_symbol_type)); ++static long amiga_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); ++static bfd_boolean read_raw_relocs PARAMS ((bfd *, sec_ptr, unsigned long, ++ unsigned long)); ++static bfd_boolean amiga_slurp_relocs PARAMS ((bfd *, sec_ptr, asymbol **)); ++static long amiga_canonicalize_reloc PARAMS ((bfd *, sec_ptr, arelent **, ++ asymbol **)); ++static bfd_boolean amiga_set_section_contents PARAMS ((bfd *, sec_ptr, PTR, ++ file_ptr, bfd_size_type)); ++static bfd_boolean amiga_set_arch_mach PARAMS ((bfd *, enum bfd_architecture, ++ unsigned long)); ++static int amiga_sizeof_headers PARAMS ((bfd *, bfd_boolean)); ++static bfd_boolean amiga_find_nearest_line PARAMS ((bfd *, sec_ptr, ++ asymbol **, bfd_vma, const char **, const char **, unsigned int *)); ++static reloc_howto_type *amiga_bfd_reloc_type_lookup PARAMS ((bfd *, ++ bfd_reloc_code_real_type)); ++static bfd_boolean amiga_bfd_copy_private_bfd_data PARAMS ((bfd *, bfd *)); ++static bfd_boolean amiga_bfd_copy_private_section_data PARAMS ((bfd *, ++ sec_ptr, bfd *, sec_ptr)); ++static bfd_boolean amiga_slurp_armap PARAMS ((bfd *)); ++static void amiga_truncate_arname PARAMS ((bfd *, const char *, char *)); ++static const struct bfd_target *amiga_archive_p PARAMS ((bfd *)); ++static bfd *amiga_openr_next_archived_file PARAMS ((bfd *, bfd *)); ++static PTR amiga_read_ar_hdr PARAMS ((bfd *)); ++static int amiga_generic_stat_arch_elt PARAMS ((bfd *, struct stat *)); ++ ++/*#define DEBUG_AMIGA 1*/ ++#if DEBUG_AMIGA ++#include <stdarg.h> ++static void ++error_print (const char *fmt, ...) ++{ ++ va_list args; ++ va_start (args, fmt); ++ vfprintf (stderr, fmt, args); ++ va_end (args); ++} ++#define DPRINT(L,x) if (L>=DEBUG_AMIGA) error_print x ++#else ++#define DPRINT(L,x) ++#endif ++ ++enum {R_ABS32=0,R_PC16,R_PC8,R_SD32,R_SD16,R_SD8,R_ABS32SHORT,R_PC26,R_PC32,R__MAX}; ++static reloc_howto_type howto_table[R__MAX] = ++{ ++ {H_ABS32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield,/* complain_on_overflow */ ++ 0, /* special_function */ ++ "RELOC32", /* textual name */ ++ FALSE, /* partial_inplace */ ++ 0xffffffff, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE}, /* pcrel_offset */ ++ {H_PC16, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0, "RELRELOC16", FALSE, 0x0000ffff, 0x0000ffff, TRUE}, ++ {H_PC8, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0, "RELRELOC8", FALSE, 0x000000ff, 0x000000ff, TRUE}, ++ {H_SD32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "DREL32", FALSE, 0xffffffff, 0xffffffff, FALSE}, ++ {H_SD16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "DREL16", FALSE, 0x0000ffff, 0x0000ffff, FALSE}, ++ {H_SD8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "DREL8", FALSE, 0x000000ff, 0x000000ff, FALSE}, ++ {H_ABS32SHORT, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "RELOC32SHORT", FALSE, 0x0000ffff, 0x0000ffff, FALSE}, ++ {H_PC26, 0, 2, 26, TRUE, 0, complain_overflow_signed, 0, "RELRELOC26", FALSE, 0x03fffffc, 0x03fffffc, TRUE}, ++ {H_PC32, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0, "RELRELOC32", FALSE, 0xffffffff, 0xffffffff, TRUE} ++}; ++ ++/* The following are gross hacks that need to be fixed. The problem is ++ that the linker unconditionally references these values without ++ going through any of bfd's standard interface. Thus they need to ++ be defined in a bfd module that is included in *all* configurations, ++ and are currently in bfd.c, otherwise linking the linker will fail ++ on non-Amiga target configurations. */ ++ ++/* This one is used by the linker and tells us, if a debug hunk should ++ be written out. */ ++extern int write_debug_hunk; ++ ++/* This is also used by the linker to set the attribute of sections. */ ++extern int amiga_attribute; ++ ++/* used with base-relative linking */ ++extern int amiga_base_relative; ++ ++/* used with -resident linking */ ++extern int amiga_resident; ++ ++static bfd_boolean ++get_long (abfd, n) ++ bfd *abfd; ++ unsigned long *n; ++{ ++ if (bfd_bread ((PTR)n, 4, abfd) != 4) ++ return FALSE; ++ *n = GL (n); ++ return TRUE; ++} ++ ++static const struct bfd_target * ++amiga_object_p (abfd) ++ bfd *abfd; ++{ ++ unsigned long x; ++ char buf[8]; ++ ++ /* An Amiga object file must be at least 8 bytes long. */ ++ if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf)) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return NULL; ++ } ++ ++ bfd_seek (abfd, 0, SEEK_SET); ++ ++ /* Does it look like an Amiga object file? */ ++ x = GL (&buf[0]); ++ if ((x != HUNK_UNIT) && (x != HUNK_HEADER)) ++ { ++ /* Not an Amiga file. */ ++ bfd_set_error (bfd_error_wrong_format); ++ return NULL; ++ } ++ ++ /* Can't fail and return (but must be declared bfd_boolean to suit ++ other bfd requirements). */ ++ (void) amiga_mkobject (abfd); ++ ++ AMIGA_DATA(abfd)->IsLoadFile = (x == HUNK_HEADER); ++ ++ if (!amiga_digest_file (abfd)) ++ { ++ /* Something went wrong. */ ++ DPRINT(20,("bfd parser stopped at offset 0x%lx\n",bfd_tell(abfd))); ++ return NULL; ++ } ++ ++ /* Set default architecture to m68k:68000. */ ++ /* So we can link on 68000 AMIGAs... */ ++ abfd->arch_info = bfd_scan_arch ("m68k:68000"); ++ ++ return abfd->xvec; ++} ++ ++static sec_ptr ++amiga_get_section_by_hunk_number (abfd, hunk_number) ++ bfd *abfd; ++ long hunk_number; ++{ ++ /* A cache, so we don't have to search the entire list every time. */ ++ static sec_ptr last_reference; ++ static bfd *last_bfd; ++ sec_ptr p; ++ ++ if (last_reference) ++ if (last_bfd == abfd && last_reference->target_index == hunk_number) ++ return last_reference; ++ for (p = abfd->sections; p != NULL; p = p->next) ++ if (p->target_index == hunk_number) ++ { ++ last_reference = p; ++ last_bfd = abfd; ++ return p; ++ } ++ BFD_FAIL (); ++ return NULL; ++} ++ ++static bfd_boolean ++amiga_add_reloc (abfd, section, offset, symbol, howto, target_hunk) ++ bfd *abfd; ++ sec_ptr section; ++ bfd_size_type offset; ++ amiga_symbol_type *symbol; ++ reloc_howto_type *howto; ++ long target_hunk; ++{ ++ amiga_reloc_type *reloc; ++ sec_ptr target_sec; ++ ++ reloc = (amiga_reloc_type *) bfd_alloc (abfd, sizeof (amiga_reloc_type)); ++ if (reloc == NULL) ++ return FALSE; ++ ++ abfd->flags |= HAS_RELOC; ++ section->flags |= SEC_RELOC; ++ ++ if (amiga_per_section(section)->reloc_tail) ++ amiga_per_section(section)->reloc_tail->next = reloc; ++ else ++ section->relocation = &reloc->relent; ++ amiga_per_section(section)->reloc_tail = reloc; ++ ++ reloc->relent.sym_ptr_ptr = &reloc->symbol; ++ reloc->relent.address = offset; ++ reloc->relent.addend = 0; ++ reloc->relent.howto = howto; ++ ++ reloc->next = NULL; ++ if (symbol==NULL) { /* relative to section */ ++ target_sec = amiga_get_section_by_hunk_number (abfd, target_hunk); ++ if (target_sec) ++ reloc->symbol = target_sec->symbol; ++ else ++ return FALSE; ++ } ++ else ++ reloc->symbol = &symbol->symbol; ++ ++ return TRUE; ++} ++ ++/* BFD doesn't currently allow multiple sections with the same ++ name, so we try a little harder to get a unique name. */ ++static sec_ptr ++amiga_make_unique_section (abfd, name) ++ bfd *abfd; ++ const char *name; ++{ ++ sec_ptr section; ++ ++ bfd_set_error (bfd_error_no_error); ++ section = bfd_make_section (abfd, name); ++ if ((section == NULL) && (bfd_get_error() == bfd_error_no_error)) ++ { ++#if 0 ++ char *new_name = bfd_alloc (abfd, strlen(name) + 4); ++ int i = 1; ++ ++ /* We try to come up with an original name (since BFD currently ++ requires all sections to have different names). */ ++ while (!section && (i<=99)) ++ { ++ sprintf (new_name, "%s_%u", name, i++); ++ section = bfd_make_section (abfd, new_name); ++ } ++#else ++ section = bfd_make_section_anyway (abfd, name); ++#endif ++ } ++ return section; ++} ++ ++#if DEBUG_AMIGA ++#define DPRINTHUNK(x) fprintf(stderr,"Processing %s hunk (0x%x)...",\ ++ (x) == HUNK_UNIT ? "HUNK_UNIT" :\ ++ (x) == HUNK_NAME ? "HUNK_NAME" :\ ++ (x) == HUNK_CODE ? "HUNK_CODE" :\ ++ (x) == HUNK_DATA ? "HUNK_DATA" :\ ++ (x) == HUNK_BSS ? "HUNK_BSS" :\ ++ (x) == HUNK_ABSRELOC32 ? "HUNK_RELOC32" :\ ++ (x) == HUNK_RELRELOC16 ? "HUNK_RELRELOC16" :\ ++ (x) == HUNK_RELRELOC8 ? "HUNK_RELRELOC8" :\ ++ (x) == HUNK_EXT ? "HUNK_EXT" :\ ++ (x) == HUNK_SYMBOL ? "HUNK_SYMBOL" :\ ++ (x) == HUNK_DEBUG ? "HUNK_DEBUG" :\ ++ (x) == HUNK_END ? "HUNK_END" :\ ++ (x) == HUNK_HEADER ? "HUNK_HEADER" :\ ++ (x) == HUNK_OVERLAY ? "HUNK_OVERLAY" :\ ++ (x) == HUNK_BREAK ? "HUNK_BREAK" :\ ++ (x) == HUNK_DREL32 ? "HUNK_DREL32" :\ ++ (x) == HUNK_DREL16 ? "HUNK_DREL16" :\ ++ (x) == HUNK_DREL8 ? "HUNK_DREL8" :\ ++ (x) == HUNK_LIB ? "HUNK_LIB" :\ ++ (x) == HUNK_INDEX ? "HUNK_INDEX" :\ ++ (x) == HUNK_RELOC32SHORT ? "HUNK_RELOC32SHORT" :\ ++ (x) == HUNK_RELRELOC32 ? "HUNK_RELRELOC32" :\ ++ (x) == HUNK_PPC_CODE ? "HUNK_PPC_CODE" :\ ++ (x) == HUNK_RELRELOC26 ? "HUNK_RELRELOC26" :\ ++ "*unknown*",(x)) ++#define DPRINTHUNKEND fprintf(stderr,"done\n") ++#else ++#define DPRINTHUNK(x) ++#define DPRINTHUNKEND ++#endif ++ ++static bfd_boolean ++parse_archive_units (abfd, n_units, filesize, one, syms, symcount) ++ bfd *abfd; ++ int *n_units; ++ unsigned long filesize; ++ bfd_boolean one; /* parse only the first unit? */ ++ struct arch_syms **syms; ++ symindex *symcount; ++{ ++ struct arch_syms *nsyms,*syms_tail=NULL; ++ unsigned long unit_offset,defsym_pos=0; ++ unsigned long hunk_type,type,len,no,n; ++ symindex defsymcount=0; ++ ++ *n_units = 0; ++ while (get_long (abfd, &hunk_type)) { ++ switch (hunk_type) { ++ case HUNK_END: ++ break; ++ case HUNK_UNIT: ++ unit_offset = bfd_tell (abfd) - 4; ++ (*n_units)++; ++ if (one && *n_units>1) { ++ bfd_seek (abfd, -4, SEEK_CUR); ++ return TRUE; ++ } ++ /* Fall through */ ++ case HUNK_NAME: ++ case HUNK_CODE: ++ case HUNK_DATA: ++ case HUNK_DEBUG: ++ case HUNK_PPC_CODE: ++ if (!get_long (abfd, &len) ++ || bfd_seek (abfd, HUNK_VALUE (len) << 2, SEEK_CUR)) ++ return FALSE; ++ break; ++ case HUNK_BSS: ++ if (!get_long (abfd, &len)) ++ return FALSE; ++ break; ++ case HUNK_ABSRELOC32: ++ case HUNK_RELRELOC16: ++ case HUNK_RELRELOC8: ++ case HUNK_SYMBOL: ++ case HUNK_DREL32: ++ case HUNK_DREL16: ++ case HUNK_DREL8: ++ for (;;) { ++ /* read offsets count */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (!no) ++ break; ++ /* skip hunk+offsets */ ++ if (bfd_seek (abfd, (no+1)<<2, SEEK_CUR)) ++ return FALSE; ++ } ++ break; ++ case HUNK_EXT: ++ defsym_pos = 0; ++ if (!get_long (abfd, &n)) ++ return FALSE; ++ while (n) { ++ len = n & 0xffffff; ++ type = (n>>24) & 0xff; ++ switch (type) { ++ case EXT_SYMB: ++ case EXT_DEF: ++ case EXT_ABS: ++ /* retain the positions of defined symbols for each object ++ in the archive. They'll be used later to build a ++ pseudo-armap, which _bfd_generic_link_add_archive_symbols ++ needs */ ++ if (defsym_pos==0) ++ defsym_pos = bfd_tell (abfd) - 4; ++ /* skip name & value */ ++ if (bfd_seek (abfd, (len+1)<<2, SEEK_CUR)) ++ return FALSE; ++ defsymcount++; ++ break; ++ ++ case EXT_ABSREF32: ++ case EXT_RELREF16: ++ case EXT_RELREF8: ++ case EXT_DEXT32: ++ case EXT_DEXT16: ++ case EXT_DEXT8: ++ case EXT_RELREF32: ++ case EXT_RELREF26: ++ /* skip name */ ++ if (bfd_seek (abfd, len<<2, SEEK_CUR)) ++ return FALSE; ++ /* skip references */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (no && bfd_seek (abfd, no<<2, SEEK_CUR)) ++ return FALSE; ++ break; ++ ++ case EXT_ABSCOMMON: ++ case EXT_DEXT32COMMON: ++ case EXT_DEXT16COMMON: ++ case EXT_DEXT8COMMON: ++ /* skip name & value */ ++ if (bfd_seek (abfd, (len+1)<<2, SEEK_CUR)) ++ return FALSE; ++ /* skip references */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (no && bfd_seek (abfd, no<<2, SEEK_CUR)) ++ return FALSE; ++ break; ++ ++ default: /* error */ ++ bfd_msg ("unexpected type %ld(0x%lx) in hunk_ext1 at offset 0x%lx", ++ type, type, bfd_tell (abfd)); ++ return FALSE; ++ } ++ ++ if (!get_long (abfd, &n)) ++ return FALSE; ++ } ++ if (defsym_pos != 0 && syms) { ++ /* there are some defined symbols, keep enough information on ++ them to simulate an armap later on */ ++ nsyms = (struct arch_syms *) bfd_alloc (abfd, sizeof (struct arch_syms)); ++ nsyms->next = NULL; ++ if (syms_tail) ++ syms_tail->next = nsyms; ++ else ++ *syms = nsyms; ++ syms_tail = nsyms; ++ nsyms->offset = defsym_pos; ++ nsyms->size = bfd_tell (abfd) - defsym_pos; ++ nsyms->unit_offset = unit_offset; ++ } ++ break; /* of HUNK_EXT */ ++ ++ default: ++#if 0 ++ bfd_msg ("unexpected hunk 0x%lx at offset 0x%lx", ++ hunk_type, bfd_tell (abfd)); ++#endif ++ return FALSE; ++ } ++ } ++ if (syms && symcount) ++ *symcount = defsymcount; ++ return (bfd_tell (abfd) == filesize); ++} ++ ++static bfd_boolean ++amiga_digest_file (abfd) ++ bfd *abfd; ++{ ++ struct stat stat_buffer; ++ unsigned long tmp; ++ ++ if (!get_long (abfd, &tmp)) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ ++ switch (HUNK_VALUE (tmp)) ++ { ++ case HUNK_UNIT: ++ /* Read the unit(s) */ ++ if (bfd_stat (abfd, &stat_buffer) < 0) ++ return FALSE; ++/* ++ while ((pos=bfd_tell (abfd)) < stat_buffer.st_size) ++ {*/ ++ if (!amiga_read_unit (abfd, stat_buffer.st_size - abfd->origin)) ++ return FALSE; ++ if (abfd->arelt_data) ++ arelt_size (abfd) = bfd_tell (abfd); ++/* }*/ ++ break; ++ ++ case HUNK_HEADER: ++ /* This is a load file */ ++ if (!amiga_read_load (abfd)) ++ return FALSE; ++ break; ++ } ++ ++ return TRUE; ++}/* of amiga_digest_file */ ++ ++ ++/* Read in Unit file */ ++/* file pointer is located after the HUNK_UNIT LW */ ++static bfd_boolean ++amiga_read_unit (abfd, size) ++ bfd *abfd; ++ unsigned long size; ++{ ++ unsigned long hunk_number=0,hunk_type,tmp; ++ ++ /* read LW length of unit's name */ ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ ++ /* and skip it (FIXME maybe) */ ++ if (bfd_seek (abfd, tmp<<2, SEEK_CUR)) ++ return FALSE; ++ ++ while (bfd_tell (abfd) < size) ++ { ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ ++ /* Now there may be CODE, DATA, BSS, SYMBOL, DEBUG, RELOC Hunks */ ++ hunk_type = HUNK_VALUE (tmp); ++ switch (hunk_type) ++ { ++ case HUNK_UNIT: ++ /* next unit, seek back and return */ ++ return (bfd_seek (abfd, -4, SEEK_CUR) == 0); ++ ++ case HUNK_DEBUG: ++ /* we don't parse hunk_debug at the moment */ ++ if (!get_long (abfd, &tmp) || bfd_seek (abfd, tmp<<2, SEEK_CUR)) ++ return FALSE; ++ break; ++ ++ case HUNK_NAME: ++ case HUNK_CODE: ++ case HUNK_DATA: ++ case HUNK_BSS: ++ case HUNK_PPC_CODE: ++ /* Handle this hunk, including relocs, etc. ++ The finishing HUNK_END is consumed by the routine */ ++ if (!amiga_handle_cdb_hunk (abfd, hunk_type, hunk_number++, 0, -1)) ++ return FALSE; ++ break; ++ ++ default: ++ /* Something very nasty happened: invalid hunk occured... */ ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ break; ++ }/* Of switch hunk_type */ ++ ++ /* Next hunk */ ++ } ++ return TRUE; ++} ++ ++ ++/* Read a load file */ ++static bfd_boolean ++amiga_read_load (abfd) ++ bfd *abfd; ++{ ++ unsigned long max_hunk_number,hunk_type,tmp,i; ++ unsigned long *hunk_attributes,*hunk_sizes; ++ char buf[16]; ++ ++ /* Read hunk lengths (and memory attributes...) */ ++ /* Read in each hunk */ ++ ++ if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf)) ++ return FALSE; ++ ++ /* If there are resident libs: abort (obsolete feature) */ ++ if (GL (&buf[0]) != 0) ++ return FALSE; ++ ++ max_hunk_number = GL (&buf[4]); ++ ++ /* Sanity */ ++ if (max_hunk_number<1) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ ++ AMIGA_DATA(abfd)->nb_hunks = max_hunk_number; ++ ++ /* Num of root hunk must be 0 */ ++ if (GL (&buf[8]) != 0) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ ++ /* Num of last hunk must be mhn-1 */ ++ if (GL (&buf[12]) != max_hunk_number-1) ++ { ++ bfd_msg ("Overlay loadfiles are not supported"); ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ ++ hunk_sizes = alloca (max_hunk_number * sizeof (unsigned long)); ++ hunk_attributes = alloca (max_hunk_number * sizeof (unsigned long)); ++ if (hunk_sizes == NULL || hunk_attributes == NULL) ++ { ++ bfd_set_error (bfd_error_no_memory); ++ return FALSE; ++ } ++ ++ /* Now, read in sizes and memory attributes */ ++ for (i=0; i<max_hunk_number; i++) ++ { ++ if (!get_long (abfd, &hunk_sizes[i])) ++ return FALSE; ++ switch (HUNK_ATTRIBUTE (hunk_sizes[i])) ++ { ++ case HUNK_ATTR_CHIP: ++ hunk_attributes[i] = MEMF_CHIP; ++ break; ++ case HUNK_ATTR_FAST: ++ hunk_attributes[i] = MEMF_FAST; ++ break; ++ case HUNK_ATTR_FOLLOWS: ++ if (!get_long (abfd, &hunk_attributes[i])) ++ return FALSE; ++ break; ++ default: ++ hunk_attributes[i] = 0; ++ break; ++ } ++ hunk_sizes[i] = HUNK_VALUE (hunk_sizes[i]) << 2; ++ } ++ ++ for (i=0; i<max_hunk_number; i++) ++ { ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ ++ /* This may be HUNK_NAME, CODE, DATA, BSS, DEBUG */ ++ hunk_type = HUNK_VALUE (tmp); ++ switch (hunk_type) ++ { ++ case HUNK_NAME: ++ case HUNK_CODE: ++ case HUNK_DATA: ++ case HUNK_BSS: ++ case HUNK_PPC_CODE: ++ if (!amiga_handle_cdb_hunk (abfd, hunk_type, i, ++ hunk_attributes[i], hunk_sizes[i])) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ break; ++ ++ case HUNK_DEBUG: ++ if (--i,!amiga_handle_cdb_hunk (abfd, hunk_type, -1, 0, 0)) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ break; ++ ++ default: ++ /* invalid hunk */ ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ break; ++ }/* Of switch */ ++ } ++ ++ return TRUE; ++}/* Of amiga_read_load */ ++ ++ ++/* Handle NAME, CODE, DATA, BSS, DEBUG Hunks */ ++static bfd_boolean ++amiga_handle_cdb_hunk (abfd, hunk_type, hunk_number, hunk_attribute, ++ hunk_size) ++ bfd *abfd; ++ unsigned long hunk_type; ++ unsigned long hunk_number; ++ unsigned long hunk_attribute; ++ unsigned long hunk_size; ++/* If hunk_size==-1, then we are digesting a HUNK_UNIT */ ++{ ++ sec_ptr current_section; ++ char *sec_name,*current_name=NULL; ++ unsigned long len,tmp; ++ int secflags,is_load=(hunk_size!=(unsigned long)-1); ++ ++ if (hunk_type==HUNK_NAME) /* get name */ ++ { ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ ++ len = HUNK_VALUE (tmp) << 2; ++ if (len != 0) ++ { ++ current_name = bfd_alloc (abfd, len+1); ++ if (!current_name) ++ return FALSE; ++ ++ if (bfd_bread (current_name, len, abfd) != len) ++ return FALSE; ++ ++ current_name[len] = '\0'; ++ if (current_name[0] == '\0') ++ { ++ bfd_release (abfd, current_name); ++ current_name = NULL; ++ } ++ } ++ ++ if (!get_long (abfd, &hunk_type)) ++ return FALSE; ++ } ++ ++ /* file_pointer is now after hunk_type */ ++ secflags = 0; ++ switch (hunk_type) ++ { ++ case HUNK_CODE: ++ case HUNK_PPC_CODE: ++ secflags = SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS; ++ sec_name = ".text"; ++ goto do_section; ++ ++ case HUNK_DATA: ++ secflags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS; ++ sec_name = ".data"; ++ goto do_section; ++ ++ case HUNK_BSS: ++ secflags = SEC_ALLOC; ++ sec_name = ".bss"; ++ ++ do_section: ++ if (!current_name) ++ current_name = sec_name; ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ len = HUNK_VALUE (tmp) << 2; /* Length of section */ ++ if (!is_load) ++ { ++ hunk_attribute=HUNK_ATTRIBUTE (len); ++ hunk_attribute=(hunk_attribute==HUNK_ATTR_CHIP)?MEMF_CHIP: ++ (hunk_attribute==HUNK_ATTR_FAST)?MEMF_FAST:0; ++ } ++ ++ /* Make new section */ ++ current_section = amiga_make_unique_section (abfd, current_name); ++ if (!current_section) ++ return FALSE; ++ ++ current_section->filepos = bfd_tell (abfd); ++ /* For a loadfile, the section size in memory comes from the ++ hunk header. The size on disk may be smaller. */ ++ current_section->_cooked_size = current_section->_raw_size = ++ ((hunk_size==(unsigned long)-1) ? len : hunk_size); ++ current_section->target_index = hunk_number; ++ bfd_set_section_flags (abfd, current_section, secflags); ++ ++ amiga_per_section(current_section)->disk_size = len; /* size on disk */ ++ amiga_per_section(current_section)->attribute = hunk_attribute; ++ ++ /* skip the contents */ ++ if ((secflags & SEC_HAS_CONTENTS) && bfd_seek (abfd, len, SEEK_CUR)) ++ return FALSE; ++ ++ if (!amiga_handle_rest (abfd, current_section, is_load)) ++ return FALSE; ++ break; ++ ++ /* Currently, there is one debug hunk per executable, instead of one ++ per unit as it would with a "standard" AmigaOS implementation. So ++ the debug hunk is at the same level as code/data/bss. ++ This will change in the future */ ++ case HUNK_DEBUG: ++ /* format of gnu debug hunk is: ++ HUNK_DEBUG ++ N ++ ZMAGIC ++ symtabsize ++ strtabsize ++ symtabdata [length=symtabsize] ++ strtabdata [length=strtabsize] ++ [pad bytes] ++ */ ++ ++ /* read LW length */ ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ len = tmp << 2; ++ if (len > 12) ++ { ++ char buf[12]; ++ if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf)) ++ return FALSE; ++ if (GL (&buf[0]) == ZMAGIC) /* GNU DEBUG HUNK */ ++ { ++ amiga_data_type *amiga_data=AMIGA_DATA(abfd); ++ /* FIXME: we should add the symbols in the debug hunk to symtab... */ ++ amiga_data->symtab_size = GL (&buf[4]); ++ amiga_data->stringtab_size = GL (&buf[8]); ++ adata(abfd).sym_filepos = bfd_tell (abfd); ++ adata(abfd).str_filepos = adata(abfd).sym_filepos + ++ amiga_data->symtab_size; ++ } ++ len -= sizeof(buf); ++ } ++ if (bfd_seek (abfd, len, SEEK_CUR)) ++ return FALSE; ++ break; ++ ++ default: ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ break; ++ }/* switch (hunk_type) */ ++ ++ return TRUE; ++}/* Of amiga_handle_cdb_hunk */ ++ ++ ++/* Handle rest of a hunk ++ I.e.: Relocs, EXT, SYMBOLS... */ ++static bfd_boolean ++amiga_handle_rest (abfd, current_section, isload) ++ bfd *abfd; ++ sec_ptr current_section; ++ bfd_boolean isload; ++{ ++ amiga_per_section_type *asect=amiga_per_section(current_section); ++ unsigned long hunk_type,relno,type,len,no; ++ raw_reloc_type *relp; ++ ++ for (relno=0;;) ++ { ++ if (!get_long (abfd, &hunk_type)) ++ return FALSE; ++ switch (hunk_type) ++ { ++ case HUNK_END: ++ if (relno) ++ { ++ abfd->flags |= HAS_RELOC; ++ current_section->flags |= SEC_RELOC; ++ current_section->reloc_count = relno; ++ } ++ return TRUE; ++ break; ++ ++ case HUNK_DREL32: ++ if (isload) ++ hunk_type = HUNK_RELOC32SHORT; ++ case HUNK_ABSRELOC32: ++ case HUNK_RELRELOC16: ++ case HUNK_RELRELOC8: ++ case HUNK_DREL16: ++ case HUNK_DREL8: ++ case HUNK_RELOC32SHORT: ++ /* count and skip relocs */ ++ relp = (raw_reloc_type *) bfd_alloc (abfd, sizeof (*relp)); ++ relp->next = asect->relocs; ++ asect->relocs = relp; ++ relp->pos = bfd_tell (abfd) - 4; ++ relp->num = 0; ++ if (hunk_type != HUNK_RELOC32SHORT) { ++ for (;;) { ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (!no) ++ break; ++ relp->num += no; ++ if (bfd_seek (abfd, (no+1)<<2, SEEK_CUR)) ++ return FALSE; ++ } ++ } ++ else { ++ for (;;) { ++ char buf[2]; ++ if (bfd_bread (buf, 2, abfd) != 2) ++ return FALSE; ++ if (no=GW(buf),!no) ++ break; ++ relp->num += no; ++ if (bfd_seek (abfd, (no+1)<<1, SEEK_CUR)) ++ return FALSE; ++ } ++ if ((bfd_tell (abfd) & 2) && bfd_seek (abfd, 2, SEEK_CUR)) ++ return FALSE; ++ } ++ relno += relp->num; ++ break; ++ ++ case HUNK_SYMBOL: ++ /* In a unit, we ignore these, since all symbol information ++ comes with HUNK_EXT, in a load file, these are added */ ++ if (!isload) ++ { ++ asect->hunk_symbol_pos = bfd_tell (abfd); ++ for (;;) { ++ /* size of symbol */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (!no) ++ break; ++ /* skip the name */ ++ if (bfd_seek (abfd, (no+1)<<2, SEEK_CUR)) ++ return FALSE; ++ } ++ break; ++ } ++ /* We add these, by falling through... */ ++ ++ case HUNK_EXT: ++ /* We leave these alone, until they are requested by the user */ ++ asect->hunk_ext_pos = bfd_tell (abfd); ++ for (;;) ++ { ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (!no) ++ break; ++ ++ /* symbol type and length */ ++ type = (no>>24) & 0xff; ++ len = no & 0xffffff; ++ ++ /* skip symbol name */ ++ if (bfd_seek (abfd, len<<2, SEEK_CUR)) ++ return FALSE; ++ ++ /* We have symbols */ ++ abfd->flags |= HAS_SYMS; ++ abfd->symcount++; ++ ++ switch (type) ++ { ++ case EXT_SYMB: /* Symbol hunks are relative to hunk start... */ ++ case EXT_DEF: /* def relative to hunk */ ++ case EXT_ABS: /* def absolute */ ++ /* skip the value */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ break; ++ ++ case EXT_ABSCOMMON: /* Common ref/def */ ++ case EXT_DEXT32COMMON: ++ case EXT_DEXT16COMMON: ++ case EXT_DEXT8COMMON: ++ /* FIXME: skip the size of common block */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ ++ /* Fall through */ ++ ++ case EXT_ABSREF32: /* 32 bit ref */ ++ case EXT_RELREF16: /* 16 bit ref */ ++ case EXT_RELREF8: /* 8 bit ref */ ++ case EXT_DEXT32: /* 32 bit baserel */ ++ case EXT_DEXT16: /* 16 bit baserel */ ++ case EXT_DEXT8: /* 8 bit baserel */ ++ case EXT_RELREF32: ++ case EXT_RELREF26: ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (no) ++ { ++ relno += no; ++ /* skip references */ ++ if (bfd_seek (abfd, no<<2, SEEK_CUR)) ++ return FALSE; ++ } ++ break; ++ ++ default: /* error */ ++ bfd_msg ("unexpected type %ld(0x%lx) in hunk_ext2 at offset 0x%lx", ++ type, type, bfd_tell (abfd)); ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ break; ++ }/* of switch type */ ++ } ++ break; ++ ++ case HUNK_DEBUG: ++ /* If a debug hunk is found at this position, the file has ++ been generated by a third party tool and the debug info ++ here are useless to us. Just skip the hunk, then. */ ++ if (!get_long (abfd, &no) || bfd_seek (abfd, no<<2, SEEK_CUR)) ++ return FALSE; ++ break; ++ ++ default: /* error */ ++ bfd_seek (abfd, -4, SEEK_CUR); ++ bfd_msg ("missing HUNK_END: unexpected hunktype %ld(0x%lx) at offset 0x%lx", ++ hunk_type, hunk_type, bfd_tell (abfd)); ++ hunk_type = HUNK_VALUE(hunk_type); ++ if (hunk_type == HUNK_CODE || hunk_type == HUNK_DATA || hunk_type == HUNK_BSS) ++ return TRUE; ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ break; ++ }/* Of switch */ ++ }/* Of for */ ++ return TRUE; ++}/* of amiga_handle_rest */ ++ ++static bfd_boolean ++amiga_mkobject (abfd) ++ bfd *abfd; ++{ ++ amiga_data_type *rawptr; ++ rawptr = (amiga_data_type *) bfd_zalloc (abfd, sizeof (*rawptr)); ++ abfd->tdata.amiga_data = rawptr; ++ return (rawptr!=NULL); ++} ++ ++static bfd_boolean ++amiga_mkarchive (abfd) ++ bfd *abfd; ++{ ++ amiga_ardata_type *ar; ++ ar = (amiga_ardata_type *) bfd_zalloc (abfd, sizeof (*ar)); ++ amiga_ardata (abfd) = ar; ++ return (ar!=NULL); ++} ++ ++/* write nb long words (possibly swapped out) to the output file */ ++static bfd_boolean ++write_longs (in, nb, abfd) ++ const unsigned long *in; ++ unsigned long nb; ++ bfd *abfd; ++{ ++ unsigned char out[10*4]; ++ unsigned long i; ++ ++ while (nb) ++ { ++ for (i=0; i<nb && i<10; in++,i++) ++ bfd_putb32 (in[0], &out[i*4]); ++ if (bfd_bwrite ((PTR)out, 4*i, abfd) != 4*i) ++ return FALSE; ++ nb -= i; ++ } ++ return TRUE; ++} ++ ++static long ++determine_datadata_relocs (abfd, section) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ sec_ptr section; ++{ ++ sec_ptr insection; ++ asymbol *sym_p; ++ unsigned int i; ++ long relocs=1; ++ ++ for (i=0;i<section->reloc_count;i++) ++ { ++ arelent *r=section->orelocation[i]; ++ if (r == NULL) ++ continue; ++ sym_p=*(r->sym_ptr_ptr); /* The symbol for this relocation */ ++ insection=sym_p->section; ++ ++ /* Is reloc relative to a special section? */ ++ if (bfd_is_bfd_section(insection)) ++ continue; /* Nothing to do, since this translates to HUNK_EXT */ ++ if (insection->output_section == section) ++ relocs++; ++ } ++ return relocs; ++} ++ ++/* Adjust the indices map when we decide not to output the section <sec> */ ++static void ++remove_section_index (sec, index_map) ++ sec_ptr sec; ++ int *index_map; ++{ ++ int i=sec->index; ++ for (sec=sec->next,index_map[i++]=-1; sec; sec=sec->next) ++ (index_map[i++])--; ++} ++ ++/* Write out the contents of a bfd */ ++static bfd_boolean ++amiga_write_object_contents (abfd) ++ bfd *abfd; ++{ ++ long datadata_relocs=0,bss_size=0,idx; ++ int *index_map,max_hunk=-1; ++ sec_ptr data_sec,p; ++ unsigned long i,n[5]; ++ ++ /* Distinguish UNITS, LOAD Files ++ Write out hunks+relocs+HUNK_EXT+HUNK_DEBUG (GNU format) */ ++ DPRINT(5,("Entering write_object_conts\n")); ++ ++ abfd->output_has_begun=TRUE; /* Output has begun */ ++ ++ index_map = bfd_alloc (abfd, abfd->section_count * sizeof (int)); ++ if (!index_map) ++ return FALSE; ++ ++ for (idx=0, p=abfd->sections; p!=NULL; p=p->next) ++ index_map[idx++] = p->index; ++ ++ /* Distinguish Load files and Unit files */ ++ if (AMIGA_DATA(abfd)->IsLoadFile) ++ { ++ DPRINT(5,("Writing load file\n")); ++ ++ if (amiga_base_relative) ++ BFD_ASSERT (abfd->section_count==3); ++ ++ /* Write out load file header */ ++ n[0] = HUNK_HEADER; ++ n[1] = n[2] = 0; ++ for (p=abfd->sections; p!=NULL; p=p->next) { ++ /* For baserel linking, don't remove empty sections, since they ++ may get some contents later on */ ++ if ((amiga_base_relative || p->_raw_size!=0 || p->_cooked_size!=0) && ++ !(amiga_base_relative && !strcmp (p->name, ".bss"))) ++ n[2]++; ++ else ++ remove_section_index (p, index_map); ++ } ++ n[3] = 0; ++ n[4] = n[2]-1; ++ if (!write_longs (n, 5, abfd)) ++ return FALSE; ++ ++ /* Write out sizes and memory specifiers... */ ++ /* We have to traverse the section list again, bad but no other way... */ ++ if (amiga_base_relative) { ++ for (p=abfd->sections; p!=NULL; p=p->next) ++ { ++ if (amiga_resident && !strcmp(p->name,".data")) ++ { ++ datadata_relocs = determine_datadata_relocs (abfd, p); ++ data_sec = p; ++ } ++ else if (!strcmp(p->name,".bss")) ++ { ++ /* Get size for header */ ++ bss_size = p->_raw_size; ++ } ++ } ++ } ++ ++ for (p=abfd->sections; p!=NULL; p=p->next) ++ { ++ long extra = 0, i; ++ ++ if (index_map[p->index] < 0) ++ continue; ++ ++ if (datadata_relocs && !strcmp(p->name,".text")) ++ extra = datadata_relocs * 4; ++ else if (bss_size && !strcmp (p->name, ".data")) ++ extra = bss_size; ++ /* convert to a size in long words */ ++ n[0] = LONGSIZE (p->_raw_size + extra); ++ ++ i = amiga_per_section(p)->attribute; ++ switch (i) ++ { ++ case MEMF_CHIP: ++ n[0]|=HUNKF_CHIP; ++ i=1; ++ break; ++ case MEMF_FAST: ++ n[0]|=HUNKF_FAST; ++ i=1; ++ break; ++ case 0: /* nothing */ ++ i=1; ++ break; ++ default: /* special one */ ++ n[0]|=0xc0000000; ++ n[1]=i; ++ i=2; ++ break; ++ }/* Of switch */ ++ ++ if (!write_longs (n, i, abfd)) ++ return FALSE; ++ }/* Of for */ ++ } ++ else ++ { /* Unit, no base-relative linking here.. */ ++ DPRINT(5,("Writing unit\n")); ++ ++ /* Write out unit header */ ++ n[0]=HUNK_UNIT; ++ if (!write_longs (n, 1, abfd) || !write_name (abfd, abfd->filename, 0)) ++ return FALSE; ++ ++ for (i=0;i<bfd_get_symcount (abfd);i++) { ++ asymbol *sym_p=abfd->outsymbols[i]; ++ sec_ptr osection=sym_p->section; ++ if (!osection || !bfd_is_com_section(osection->output_section)) ++ continue; ++ for (p=abfd->sections; p!=NULL; p=p->next) { ++ if (!strcmp(p->name, ".bss")) { ++ if (!p->_raw_size && !p->_cooked_size) ++ p->_cooked_size = sym_p->value; ++ break; ++ } ++ } ++ break; ++ } ++ ++ for (p=abfd->sections; p!=NULL; p=p->next) { ++ if (p->_raw_size==0 && p->_cooked_size==0) ++ remove_section_index (p, index_map); ++ } ++ } ++ ++ /* Compute the maximum hunk number of the ouput file */ ++ for (p=abfd->sections; p!=NULL; p=p->next) ++ max_hunk++; ++ ++ /* Write out every section */ ++ for (p=abfd->sections; p!=NULL; p=p->next) ++ { ++ if (index_map[p->index] < 0) ++ continue; ++ ++#define ddrels (datadata_relocs&&!strcmp(p->name,".text")?datadata_relocs:0) ++ if (!amiga_write_section_contents (abfd,p,data_sec,ddrels,index_map, ++ max_hunk)) ++ return FALSE; ++ ++ if (!amiga_write_symbols (abfd,p)) /* Write out symbols + HUNK_END */ ++ return FALSE; ++ }/* of for sections */ ++ ++ /* Write out debug hunk, if requested */ ++ if (AMIGA_DATA(abfd)->IsLoadFile && write_debug_hunk) ++ { ++ extern bfd_boolean ++ translate_to_native_sym_flags (bfd*, asymbol*, struct external_nlist*); ++ ++ unsigned int offset = 4, symbols = 0, i; ++ unsigned long str_size = 4; /* the first 4 bytes will be replaced with the length */ ++ asymbol *sym; ++ sec_ptr s; ++ ++ /* We have to convert all the symbols in abfd to a.out style... */ ++ if (bfd_get_symcount (abfd)) ++ { ++#define CAN_WRITE_OUTSYM(sym) (sym!=NULL && sym->section && \ ++ ((sym->section->owner && \ ++ bfd_get_flavour (sym->section->owner) == \ ++ bfd_target_aout_flavour) || \ ++ bfd_asymbol_flavour (sym) == \ ++ bfd_target_aout_flavour)) ++ ++ for (i = 0; i < bfd_get_symcount (abfd); i++) ++ { ++ sym = abfd->outsymbols[i]; ++ /* NULL entries have been written already... */ ++ if (CAN_WRITE_OUTSYM (sym)) ++ { ++ str_size += strlen(sym->name) + 1; ++ symbols++; ++ } ++ } ++ ++ if (!symbols) ++ return TRUE; ++ ++ /* Now, set the .text, .data and .bss fields in the tdata struct ++ because translate_to_native_sym_flags needs them... */ ++ for (i=0,s=abfd->sections;s!=NULL;s=s->next) ++ if (!strcmp(s->name,".text")) ++ { ++ i|=1; ++ adata(abfd).textsec=s; ++ } ++ else if (!strcmp(s->name,".data")) ++ { ++ i|=2; ++ adata(abfd).datasec=s; ++ } ++ else if (!strcmp(s->name,".bss")) ++ { ++ i|=4; ++ adata(abfd).bsssec=s; ++ } ++ ++ if (i!=7) /* section(s) missing... */ ++ { ++ bfd_msg ("Missing section, debughunk not written"); ++ return TRUE; ++ } ++ ++ /* Write out HUNK_DEBUG, size, ZMAGIC, ... */ ++ n[0] = HUNK_DEBUG; ++ n[1] = 3 + ((symbols * sizeof(struct internal_nlist) + str_size + 3) >> 2); ++ n[2] = ZMAGIC; /* Magic number */ ++ n[3] = symbols * sizeof(struct internal_nlist); ++ n[4] = str_size; ++ if (!write_longs (n, 5, abfd)) ++ return FALSE; ++ ++ /* Write out symbols */ ++ for (i = 0; i < bfd_get_symcount (abfd); i++) /* Translate every symbol */ ++ { ++ sym = abfd->outsymbols[i]; ++ if (CAN_WRITE_OUTSYM (sym)) ++ { ++ amiga_symbol_type *t = (amiga_symbol_type *) sym; ++ struct external_nlist data; ++ ++ bfd_h_put_16(abfd, t->desc, data.e_desc); ++ bfd_h_put_8(abfd, t->other, data.e_other); ++ bfd_h_put_8(abfd, t->type, data.e_type); ++ if (!translate_to_native_sym_flags(abfd,sym,&data)) ++ { ++ bfd_msg ("Cannot translate flags for %s", sym->name); ++ } ++ bfd_h_put_32(abfd, offset, &data.e_strx[0]); /* Store index */ ++ offset += strlen(sym->name) + 1; ++ if (bfd_bwrite ((PTR)&data, sizeof(data), abfd) ++ != sizeof(data)) ++ return FALSE; ++ } ++ } ++ ++ /* Write out strings */ ++ if (!write_longs (&str_size, 1, abfd)) ++ return FALSE; ++ ++ for (i = 0; i < bfd_get_symcount (abfd); i++) ++ { ++ sym = abfd->outsymbols[i]; ++ if (CAN_WRITE_OUTSYM (sym)) ++ { ++ size_t len = strlen(sym->name) + 1; ++ ++ /* Write string tab */ ++ if (bfd_bwrite (sym->name, len, abfd) != len) ++ return FALSE; ++ } ++ } ++ ++ /* Write padding */ ++ n[0] = 0; ++ i = (4 - (str_size & 3)) & 3; ++ if (i && bfd_bwrite ((PTR)n, i, abfd) != i) ++ return FALSE; ++ ++ /* write a HUNK_END here to finish the loadfile, or AmigaOS ++ will refuse to load it */ ++ n[0] = HUNK_END; ++ if (!write_longs (n, 1, abfd)) ++ return FALSE; ++ }/* Of if bfd_get_symcount (abfd) */ ++ }/* Of write out debug hunk */ ++ ++ bfd_release (abfd, index_map); ++ return TRUE; ++} ++ ++/* Write a string padded to 4 bytes and preceded by it's length in ++ long words ORed with <value> */ ++static bfd_boolean ++write_name (abfd, name, value) ++ bfd *abfd; ++ const char *name; ++ unsigned long value; ++{ ++ unsigned long n[1]; ++ size_t l; ++ ++ l = strlen (name); ++ if (AMIGA_DATA(abfd)->IsLoadFile && l > MAX_NAME_SIZE) ++ l = MAX_NAME_SIZE; ++ n[0] = (LONGSIZE (l) | value); ++ if (!write_longs (n, 1, abfd)) ++ return FALSE; ++ if (bfd_bwrite (name, l, abfd) != l) ++ return FALSE; ++ n[0] = 0; ++ l = (4 - (l & 3)) & 3; ++ return (l && bfd_bwrite ((PTR)n, l, abfd) != l ? FALSE : TRUE); ++} ++ ++static bfd_boolean ++amiga_write_archive_contents (arch) ++ bfd *arch; ++{ ++ struct stat status; ++ bfd *object; ++ ++ for (object = arch->archive_head; object; object = object->next) ++ { ++ unsigned long remaining; ++ ++ if (bfd_write_p (object)) ++ { ++ bfd_set_error (bfd_error_invalid_operation); ++ return FALSE; ++ } ++ ++ if (object->arelt_data != NULL) ++ { ++ remaining = arelt_size (object); ++ } ++ else ++ { ++ if (stat (object->filename, &status) != 0) ++ { ++ bfd_set_error (bfd_error_system_call); ++ return FALSE; ++ } ++ remaining = status.st_size; ++ } ++ ++ if (bfd_seek (object, 0, SEEK_SET)) ++ return FALSE; ++ ++ while (remaining) ++ { ++ char buf[DEFAULT_BUFFERSIZE]; ++ unsigned long amt = sizeof(buf); ++ if (amt > remaining) ++ amt = remaining; ++ errno = 0; ++ if (bfd_bread (buf, amt, object) != amt) ++ { ++ if (bfd_get_error () != bfd_error_system_call) ++ bfd_set_error (bfd_error_malformed_archive); ++ return FALSE; ++ } ++ if (bfd_bwrite (buf, amt, arch) != amt) ++ return FALSE; ++ remaining -= amt; ++ } ++ } ++ return TRUE; ++} ++ ++static bfd_boolean ++amiga_write_armap (arch, elength, map, orl_count, stridx) ++ bfd *arch ATTRIBUTE_UNUSED; ++ unsigned int elength ATTRIBUTE_UNUSED; ++ struct orl *map ATTRIBUTE_UNUSED; ++ unsigned int orl_count ATTRIBUTE_UNUSED; ++ int stridx ATTRIBUTE_UNUSED; ++{ ++ return TRUE; ++} ++ ++static int ++determine_type (r) ++ arelent *r; ++{ ++ switch (r->howto->type) ++ { ++ case H_ABS8: /* 8 bit absolute */ ++ case H_PC8: /* 8 bit pcrel */ ++ return 2; ++ ++ case H_ABS16: /* 16 bit absolute */ ++ case H_PC16: /* 16 bit pcrel */ ++ return 1; ++ ++ case H_ABS32: /* 32 bit absolute */ ++ /*case H_PC32:*//* 32 bit pcrel */ ++ return 0; ++ ++ case H_SD8: /* 8 bit base rel */ ++ return 5; ++ ++ case H_SD16: /* 16 bit base rel */ ++ return 4; ++ ++ case H_SD32: /* 32 bit baserel */ ++ return 3; ++ ++ default: /* Error, can't represent this */ ++ bfd_set_error (bfd_error_nonrepresentable_section); ++ return -1; ++ }/* Of switch */ ++} ++ ++#define NB_RELOC_TYPES 6 ++static const unsigned long reloc_types[NB_RELOC_TYPES] = { ++ HUNK_ABSRELOC32, HUNK_RELRELOC16, HUNK_RELRELOC8, ++ HUNK_DREL32, HUNK_DREL16, HUNK_DREL8 ++}; ++ ++/* Write out section contents, including relocs */ ++static bfd_boolean ++amiga_write_section_contents (abfd, section, data_sec, datadata_relocs, ++ index_map, max_hunk) ++ bfd *abfd; ++ sec_ptr section; ++ sec_ptr data_sec; ++ unsigned long datadata_relocs; ++ int *index_map; ++ int max_hunk; ++{ ++ sec_ptr insection; ++ asymbol *sym_p; ++ arelent *r; ++ unsigned long zero=0,disksize,pad,n[2],k,l,s; ++ long *reloc_counts,reloc_count=0; ++ unsigned char *values; ++ int i,j,x,type; ++ ++ DPRINT(5,("Entering write_section_contents\n")); ++ ++ /* If we are base-relative linking and the section is .bss and abfd ++ is a load file, then return */ ++ if (AMIGA_DATA(abfd)->IsLoadFile) ++ { ++ if (amiga_base_relative && !strcmp(section->name, ".bss")) ++ return TRUE; /* Nothing to do */ ++ } ++ else ++ { ++ /* WRITE out HUNK_NAME + section name */ ++ n[0] = HUNK_NAME; ++ if (!write_longs (n, 1, abfd) || !write_name (abfd, section->name, 0)) ++ return FALSE; ++ } ++ ++ /* Depending on the type of the section, write out HUNK_{CODE|DATA|BSS} */ ++ if (section->flags & SEC_CODE) /* Code section */ ++ n[0] = HUNK_CODE; ++ else if (section->flags & (SEC_DATA | SEC_LOAD)) /* data section */ ++ n[0] = HUNK_DATA; ++ else if (section->flags & SEC_ALLOC) /* BSS */ ++ n[0] = HUNK_BSS; ++ else if (section->flags & SEC_DEBUGGING) /* debug section */ ++ n[0] = HUNK_DEBUG; ++ else /* Error */ ++ { ++#if 0 ++ bfd_set_error (bfd_error_nonrepresentable_section); ++ return FALSE; ++#else ++ /* FIXME: Just dump everything we don't currently recognize into ++ a DEBUG hunk. */ ++ n[0] = HUNK_DEBUG; ++#endif ++ } ++ ++ DPRINT(10,("Section type is %lx\n",n[0])); ++ ++ /* Get real size in n[1], this may be shorter than the size in the header */ ++ if (amiga_per_section(section)->disk_size == 0) ++ amiga_per_section(section)->disk_size = section->_raw_size; ++ disksize = LONGSIZE (amiga_per_section(section)->disk_size) + datadata_relocs; ++ n[1] = disksize; ++ ++ /* in a load file, we put section attributes only in the header */ ++ if (!AMIGA_DATA(abfd)->IsLoadFile) ++ { ++ /* Get attribute for section */ ++ switch (amiga_per_section(section)->attribute) ++ { ++ case MEMF_CHIP: ++ n[1] |= HUNKF_CHIP; ++ break; ++ case MEMF_FAST: ++ n[1] |= HUNKF_FAST; ++ break; ++ case 0: ++ break; ++ default: /* error, can't represent this */ ++ bfd_set_error (bfd_error_nonrepresentable_section); ++ return FALSE; ++ break; ++ } ++ }/* Of switch */ ++ ++ if (!write_longs (n, 2, abfd)) ++ return FALSE; ++ ++ DPRINT(5,("Wrote code and size=%lx\n",n[1])); ++ ++ /* If a BSS hunk, we're done, else write out section contents */ ++ if (HUNK_VALUE (n[0]) == HUNK_BSS) ++ return TRUE; ++ ++ DPRINT(5,("Non bss hunk...\n")); ++ ++ /* Traverse through the relocs, sample them in reloc_data, adjust section ++ data to get 0 addend ++ Then compactify reloc_data ++ Set the entry in the section for the reloc to NULL */ ++ ++ if (disksize != 0) ++ BFD_ASSERT ((section->flags & SEC_IN_MEMORY) != 0); ++ ++ reloc_counts = (long *) bfd_zalloc (abfd, NB_RELOC_TYPES * (max_hunk+1) ++ * sizeof (long)); ++ if (!reloc_counts) ++ return FALSE; ++ ++ DPRINT(5,("Section has %d relocs\n",section->reloc_count)); ++ ++ for (l = 0; l < section->reloc_count; l++) ++ { ++ r = section->orelocation[l]; ++ if (r == NULL) ++ continue; ++ ++ sym_p = *(r->sym_ptr_ptr); /* The symbol for this relocation */ ++ insection = sym_p->section; ++ DPRINT(5,("Sec for reloc is %lx(%s)\n",insection,insection->name)); ++ DPRINT(5,("Symbol for this reloc is %lx(%s)\n",sym_p,sym_p->name)); ++ /* Is reloc relative to a special section? */ ++ if (bfd_is_bfd_section(insection)) ++ continue; /* Nothing to do, since this translates to HUNK_EXT */ ++ ++ r->addend += sym_p->value; /* Add offset of symbol from section start */ ++ ++ /* Address of reloc has been unchanged since original reloc, or has ++ been adjusted by get_relocated_section_contents. */ ++ /* For relocs, the vma of the target section is in the data, the ++ addend is -vma of that section =>No need to add vma */ ++ /* Add in offset */ ++ r->addend += insection->output_offset; ++ ++ /* Determine which hunk to write, and index of target */ ++ x = index_map[insection->output_section->index]; ++ if (x<0 || x>max_hunk) { ++ bfd_msg ("erroneous relocation to hunk %d/%s from %s", ++ x, insection->output_section->name, insection->name); ++ bfd_set_error (bfd_error_nonrepresentable_section); ++ return FALSE; ++ } ++ ++ type = determine_type(r); ++ if (type == -1) ++ return FALSE; ++ if (type >= NB_RELOC_TYPES) { ++ bfd_set_error (bfd_error_nonrepresentable_section); ++ return FALSE; ++ } ++ reloc_counts[type+(x*NB_RELOC_TYPES)]++; ++ reloc_count++; ++ ++ /* There is no error checking with these... */ ++ DPRINT(5,("reloc address=%lx,addend=%lx\n",r->address,r->addend)); ++ values = §ion->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(§ion->contents[offset],location,count); ++ ++ return TRUE; ++}/* Of set_section_contents */ ++ ++ ++/* FIXME: Is this everything? */ ++static bfd_boolean ++amiga_set_arch_mach (abfd, arch, machine) ++ bfd *abfd; ++ enum bfd_architecture arch; ++ unsigned long machine; ++{ ++ bfd_default_set_arch_mach(abfd, arch, machine); ++ if (arch == bfd_arch_m68k) ++ { ++ switch (machine) ++ { ++ case bfd_mach_m68000: ++ case bfd_mach_m68008: ++ case bfd_mach_m68010: ++ case bfd_mach_m68020: ++ case bfd_mach_m68030: ++ case bfd_mach_m68040: ++ case bfd_mach_m68060: ++ case 0: ++ return TRUE; ++ default: ++ break; ++ } ++ } ++ return FALSE; ++} ++ ++static int ++amiga_sizeof_headers (ignore_abfd, ignore) ++ bfd *ignore_abfd ATTRIBUTE_UNUSED; ++ bfd_boolean ignore ATTRIBUTE_UNUSED; ++{ ++ /* The amiga hunk format doesn't have headers. */ ++ return 0; ++} ++ ++/* Provided a BFD, a section and an offset into the section, calculate ++ and return the name of the source file and the line nearest to the ++ wanted location. */ ++bfd_boolean ++amiga_find_nearest_line (abfd, section, symbols, offset, filename_ptr, ++ functionname_ptr, line_ptr) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ sec_ptr section ATTRIBUTE_UNUSED; ++ asymbol **symbols ATTRIBUTE_UNUSED; ++ bfd_vma offset ATTRIBUTE_UNUSED; ++ const char **filename_ptr ATTRIBUTE_UNUSED; ++ const char **functionname_ptr ATTRIBUTE_UNUSED; ++ unsigned int *line_ptr ATTRIBUTE_UNUSED; ++{ ++ /* FIXME (see aoutx.h, for example) */ ++ return FALSE; ++} ++ ++static reloc_howto_type * ++amiga_bfd_reloc_type_lookup (abfd, code) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ bfd_reloc_code_real_type code; ++{ ++ DPRINT(5,("reloc: %s (%d)\n",bfd_get_reloc_code_name(code),code)); ++ switch (code) ++ { ++ case BFD_RELOC_8_PCREL: return &howto_table[R_PC8]; ++ case BFD_RELOC_16_PCREL: return &howto_table[R_PC16]; ++ case BFD_RELOC_32_PCREL: return &howto_table[R_PC32]; ++ case BFD_RELOC_8: return &howto_table[R_PC8]; ++ case BFD_RELOC_16: return &howto_table[R_PC16]; ++ case BFD_RELOC_32: return &howto_table[R_ABS32]; ++ case BFD_RELOC_8_BASEREL: return &howto_table[R_SD8]; ++ case BFD_RELOC_16_BASEREL: return &howto_table[R_SD16]; ++ case BFD_RELOC_32_BASEREL: return &howto_table[R_SD32]; ++ case BFD_RELOC_CTOR: return &howto_table[R_ABS32]; ++ /* FIXME: everything handled? */ ++ default: return NULL; ++ } ++} ++ ++static bfd_boolean ++amiga_bfd_copy_private_bfd_data (ibfd, obfd) ++ bfd *ibfd; ++ bfd *obfd; ++{ ++ if (bfd_get_flavour (ibfd) == bfd_target_amiga_flavour ++ && bfd_get_flavour (obfd) == bfd_target_amiga_flavour) { ++ AMIGA_DATA(obfd)->IsLoadFile = AMIGA_DATA(ibfd)->IsLoadFile; ++ } ++ return TRUE; ++} ++ ++static bfd_boolean ++amiga_bfd_copy_private_section_data (ibfd, isec, obfd, osec) ++ bfd *ibfd ATTRIBUTE_UNUSED; ++ sec_ptr isec; ++ bfd *obfd ATTRIBUTE_UNUSED; ++ sec_ptr osec; ++{ ++ if (bfd_get_flavour (osec->owner) == bfd_target_amiga_flavour ++ && bfd_get_flavour (isec->owner) == bfd_target_amiga_flavour) { ++ amiga_per_section(osec)->disk_size = amiga_per_section(isec)->disk_size; ++ amiga_per_section(osec)->attribute = amiga_per_section(isec)->attribute; ++ } ++ return TRUE; ++} ++ ++/* There is no armap in the amiga libraries, so we fill carsym entries ++ one by one after having parsed the whole archive. */ ++static bfd_boolean ++amiga_slurp_armap (abfd) ++ bfd *abfd; ++{ ++ struct arch_syms *syms; ++ carsym *defsyms,*csym; ++ unsigned long symcount; ++ ++ /* allocate the carsyms */ ++ syms = amiga_ardata(abfd)->defsyms; ++ symcount = amiga_ardata(abfd)->defsym_count; ++ ++ defsyms = (carsym *) bfd_alloc (abfd, sizeof (carsym) * symcount); ++ if (!defsyms) ++ return FALSE; ++ ++ bfd_ardata(abfd)->symdefs = defsyms; ++ bfd_ardata(abfd)->symdef_count = symcount; ++ ++ for (csym = defsyms; syms; syms = syms->next) { ++ unsigned long type, len, n; ++ char *symblock; ++ if (bfd_seek (abfd, syms->offset, SEEK_SET)) ++ return FALSE; ++ symblock = (char *) bfd_alloc (abfd, syms->size); ++ if (!symblock) ++ return FALSE; ++ if (bfd_bread (symblock, syms->size, abfd) != syms->size) ++ return FALSE; ++ while (n=GL(symblock),n) ++ { ++ symblock += 4; ++ len = n & 0xffffff; ++ type = (n>>24) & 0xff; ++ switch (type) { ++ case EXT_SYMB: ++ case EXT_DEF: ++ case EXT_ABS: ++ len <<= 2; ++ csym->name = symblock; ++ csym->name[len] = '\0'; ++ csym->file_offset = syms->unit_offset; ++ csym++; ++ symblock += len+4; /* name+value */ ++ break; ++ case EXT_ABSREF32: ++ case EXT_RELREF16: ++ case EXT_RELREF8: ++ case EXT_DEXT32: ++ case EXT_DEXT16: ++ case EXT_DEXT8: ++ case EXT_RELREF32: ++ case EXT_RELREF26: ++ symblock += len<<2; ++ symblock += (1+GL (symblock))<<2; ++ break; ++ case EXT_ABSCOMMON: ++ case EXT_DEXT32COMMON: ++ case EXT_DEXT16COMMON: ++ case EXT_DEXT8COMMON: ++ symblock += (len<<2)+4; ++ symblock += (1+GL (symblock))<<2; ++ break; ++ default: /* error */ ++ bfd_msg ("unexpected type %ld(0x%lx) in hunk_ext3 at offset 0x%lx", ++ type, type, bfd_tell (abfd)); ++ return FALSE; ++ } ++ } ++ } ++ bfd_has_map (abfd) = TRUE; ++ return TRUE; ++} ++ ++static void ++amiga_truncate_arname (abfd, pathname, arhdr) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ const char *pathname ATTRIBUTE_UNUSED; ++ char *arhdr ATTRIBUTE_UNUSED; ++{ ++} ++ ++static const struct bfd_target * ++amiga_archive_p (abfd) ++ bfd *abfd; ++{ ++ struct arch_syms *symbols=NULL; ++ struct stat stat_buffer; ++ symindex symcount=0; ++ int units; ++ ++ if (bfd_stat (abfd, &stat_buffer) < 0) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return NULL; ++ } ++ ++ if (stat_buffer.st_size != 0) ++ { ++ /* scan the units */ ++ if (!parse_archive_units (abfd, &units, stat_buffer.st_size, FALSE, ++ &symbols, &symcount)) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return NULL; ++ } ++ ++ /* if there is only one unit, file suffix is not .a and .lib, we ++ consider it an object, not an archive. Obviously it's not ++ always true but taking objects for archives makes ld fail, ++ so we don't have much of a choice */ ++ if (units == 1) ++ { ++ char *p = strrchr (abfd->filename, '.'); ++ if (p == NULL || (strcmp (p, ".a") && strcmp (p, ".lib"))) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return NULL; ++ } ++ } ++ } ++ ++ if (abfd->arelt_data) ++ arelt_size (abfd) = bfd_tell (abfd); ++ ++ bfd_seek (abfd, 0, SEEK_SET); ++ abfd->arch_info = bfd_scan_arch ("m68k:68000"); ++ ++ if (amiga_mkarchive (abfd)) ++ { ++ bfd_ardata(abfd)->first_file_filepos = 0; ++ amiga_ardata(abfd)->filesize = stat_buffer.st_size; ++ amiga_ardata(abfd)->defsyms = symbols; ++ amiga_ardata(abfd)->defsym_count = symcount; ++ if (amiga_slurp_armap (abfd)) ++ return abfd->xvec; ++ } ++ ++ return NULL; ++} ++ ++static bfd * ++amiga_openr_next_archived_file (archive, last_file) ++ bfd *archive; ++ bfd *last_file; ++{ ++ file_ptr filestart; ++ ++ if (!last_file) ++ filestart = bfd_ardata (archive)->first_file_filepos; ++ else ++ { ++ unsigned int size = arelt_size (last_file); ++ /* Pad to an even boundary... */ ++ filestart = last_file->origin + size; ++ filestart += filestart % 2; ++ } ++ ++ return _bfd_get_elt_at_filepos (archive, filestart); ++} ++ ++static PTR ++amiga_read_ar_hdr (abfd) ++ bfd *abfd; ++{ ++ struct areltdata *ared; ++ unsigned long start_pos,len; ++ char buf[8],*base,*name; ++ ++ start_pos = bfd_tell (abfd); ++ if (start_pos >= amiga_ardata(abfd)->filesize) { ++ bfd_set_error (bfd_error_no_more_archived_files); ++ return NULL; ++ } ++ ++ /* get unit type and name length in long words */ ++ if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf)) ++ return NULL; ++ ++ if (GL (&buf[0]) != HUNK_UNIT) { ++ bfd_set_error (bfd_error_malformed_archive); ++ return NULL; ++ } ++ ++ ared = bfd_zalloc (abfd, sizeof (struct areltdata)); ++ if (ared == NULL) ++ return NULL; ++ ++ len = GL (&buf[4]) << 2; ++ ++ ared->filename = bfd_alloc (abfd, len+1 > 16 ? len+1 : 16); ++ if (ared->filename == NULL) ++ return NULL; ++ ++ switch (len) { ++ default: ++ if (bfd_bread (ared->filename, len, abfd) != len) ++ return NULL; ++ ared->filename[len] = '\0'; ++ /* strip path part */ ++ base = strchr (name = ared->filename, ':'); ++ if (base != NULL) ++ name = base + 1; ++ for (base = name; *name; ++name) ++ if (*name == '/') ++ base = name + 1; ++ if (*base != '\0') { ++ ared->filename = base; ++ break; ++ } ++ /* Fall through */ ++ case 0: /* fake a name */ ++ sprintf (ared->filename, "obj-%08lu.o", ++amiga_ardata(abfd)->outnum); ++ break; ++ } ++ ++ if (bfd_seek (abfd, start_pos+4, SEEK_SET)) ++ return NULL; ++ ++ if (!amiga_read_unit (abfd, amiga_ardata(abfd)->filesize)) ++ return NULL; ++ ++ ared->parsed_size = bfd_tell (abfd) - start_pos; ++ if (bfd_seek (abfd, start_pos, SEEK_SET)) ++ return NULL; ++ ++ return (PTR) ared; ++} ++ ++static int ++amiga_generic_stat_arch_elt (abfd, buf) ++ bfd *abfd; ++ struct stat *buf; ++{ ++ if (abfd->arelt_data == NULL) ++ { ++ bfd_set_error (bfd_error_invalid_operation); ++ return -1; ++ } ++ ++ /* No header in amiga archives. Let's set reasonable default values */ ++ buf->st_mode = 0644; ++ buf->st_uid = 0; ++ buf->st_gid = 0; ++ buf->st_mtime = 2922*24*60*60; ++ buf->st_size = arelt_size (abfd); ++ ++ return 0; ++} ++ ++/* Entry points through BFD_JUMP_TABLE_GENERIC */ ++#define amiga_close_and_cleanup _bfd_generic_close_and_cleanup ++#define amiga_bfd_free_cached_info _bfd_generic_bfd_free_cached_info ++/* amiga_new_section_hook defined above */ ++/* amiga_get_section_contents defined above */ ++#define amiga_get_section_contents_in_window _bfd_generic_get_section_contents_in_window ++ ++/* Entry points through BFD_JUMP_TABLE_COPY */ ++#define amiga_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data ++/*#define amiga_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data*/ ++#define amiga_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data ++#define amiga_bfd_set_private_flags _bfd_generic_bfd_set_private_flags ++#define amiga_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data ++ ++/* Entry points through BFD_JUMP_TABLE_ARCHIVE */ ++/*#define amiga_slurp_armap bfd_slurp_armap*/ ++#define amiga_slurp_extended_name_table _bfd_slurp_extended_name_table ++#define amiga_construct_extended_name_table _bfd_archive_bsd_construct_extended_name_table ++/*#define amiga_truncate_arname bfd_gnu_truncate_arname*/ ++/*#define amiga_write_armap bsd_write_armap*/ ++/*#define amiga_read_ar_hdr _bfd_generic_read_ar_hdr*/ ++/*#define amiga_openr_next_archived_file bfd_generic_openr_next_archived_file*/ ++#define amiga_get_elt_at_index _bfd_generic_get_elt_at_index ++/*#define amiga_generic_stat_arch_elt bfd_generic_stat_arch_elt*/ ++#define amiga_update_armap_timestamp _bfd_archive_bsd_update_armap_timestamp ++ ++/* Entry points through BFD_JUMP_TABLE_SYMBOLS */ ++/* amiga_get_symtab_upper_bound defined above */ ++/* amiga_get_symtab defined above */ ++/* amiga_make_empty_symbol defined above */ ++/* amiga_print_symbol defined above */ ++/* amiga_get_symbol_info defined above */ ++#define amiga_bfd_is_local_label_name bfd_generic_is_local_label_name ++#define amiga_get_lineno (alent * (*)(bfd *, asymbol *)) bfd_nullvoidptr ++/* amiga_find_nearest_line defined above */ ++#define amiga_bfd_make_debug_symbol (asymbol * (*)(bfd *, PTR, unsigned long)) bfd_nullvoidptr ++#define amiga_read_minisymbols _bfd_generic_read_minisymbols ++#define amiga_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol ++ ++/* Entry points through BFD_JUMP_TABLE_LINK ++ NOTE: We use a special get_relocated_section_contents both in amiga AND in a.out files. ++ In addition, we use an own final_link routine, which is nearly identical to _bfd_generic_final_link */ ++bfd_byte * ++get_relocated_section_contents PARAMS ((bfd *, struct bfd_link_info *, ++ struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **)); ++#define amiga_bfd_get_relocated_section_contents get_relocated_section_contents ++#define amiga_bfd_relax_section bfd_generic_relax_section ++#define amiga_bfd_link_hash_table_create _bfd_generic_link_hash_table_create ++#define amiga_bfd_link_hash_table_free _bfd_generic_link_hash_table_free ++#define amiga_bfd_link_add_symbols _bfd_generic_link_add_symbols ++#define amiga_bfd_link_just_syms _bfd_generic_link_just_syms ++bfd_boolean amiga_final_link PARAMS ((bfd *, struct bfd_link_info *)); ++#define amiga_bfd_final_link amiga_final_link ++#define amiga_bfd_link_split_section _bfd_generic_link_split_section ++#define amiga_bfd_gc_sections bfd_generic_gc_sections ++#define amiga_bfd_merge_sections bfd_generic_merge_sections ++#define amiga_bfd_discard_group bfd_generic_discard_group ++ ++#if defined (amiga) ++#undef amiga /* So that the JUMP_TABLE() macros below can work. */ ++#endif ++ ++const bfd_target amiga_vec = ++{ ++ "amiga", /* name */ ++ bfd_target_amiga_flavour, ++ BFD_ENDIAN_BIG, /* data byte order */ ++ BFD_ENDIAN_BIG, /* header byte order */ ++ HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS | WP_TEXT, /* object flags */ ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA, /* section flags */ ++ '_', /* symbol leading char */ ++ ' ', /* ar_pad_char */ ++ 15, /* ar_max_namelen (15 for UNIX compatibility) */ ++ bfd_getb64, bfd_getb_signed_64, bfd_putb64, ++ bfd_getb32, bfd_getb_signed_32, bfd_putb32, ++ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ ++ bfd_getb64, bfd_getb_signed_64, bfd_putb64, ++ bfd_getb32, bfd_getb_signed_32, bfd_putb32, ++ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ ++ { ++ /* bfd_check_format */ ++ _bfd_dummy_target, ++ amiga_object_p, ++ amiga_archive_p, ++ _bfd_dummy_target ++ }, ++ { ++ /* bfd_set_format */ ++ bfd_false, ++ amiga_mkobject, ++ amiga_mkarchive, ++ bfd_false ++ }, ++ { ++ /* bfd_write_contents */ ++ bfd_false, ++ amiga_write_object_contents, ++ amiga_write_archive_contents, ++ bfd_false ++ }, ++ BFD_JUMP_TABLE_GENERIC (amiga), ++ BFD_JUMP_TABLE_COPY (amiga), ++ BFD_JUMP_TABLE_CORE (_bfd_nocore), ++ BFD_JUMP_TABLE_ARCHIVE (amiga), ++ BFD_JUMP_TABLE_SYMBOLS (amiga), ++ BFD_JUMP_TABLE_RELOCS (amiga), ++ BFD_JUMP_TABLE_WRITE (amiga), ++ BFD_JUMP_TABLE_LINK (amiga), ++ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), ++ NULL, ++ NULL ++}; +diff --git a/bfd/amigaoslink.c b/bfd/amigaoslink.c +new file mode 100644 +index 0000000000000000000000000000000000000000..9067a0a06b933c67bfd3542b299d1adb281182c3 +--- /dev/null ++++ bfd/amigaoslink.c +@@ -0,0 +1,1032 @@ ++/* BFD back-end for Commodore-Amiga AmigaOS binaries. Linker routines. ++ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 ++ Free Software Foundation, Inc. ++ Contributed by Stephan Thesing. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++ ++/* ++INODE ++amigalink, , implementation, amiga ++SECTION ++ amigalink ++ ++This is the description of the linker routines for the amiga. ++In fact, this includes a description of the changes made to the ++a.out code, in order to build a working linker for the Amiga. ++@menu ++@* alterations:: ++@end menu ++ ++INODE ++alterations, , , amigalink ++SUBSECTION ++ alterations ++ ++The file @file{aout-amiga.c} defines the amiga a.out backend. It differs from ++the sun3 backend only in these details: ++ o The @code{final_link} routine is @code{amiga_final_link}. ++ o The routine to get the relocated section contents is ++ @code{get_relocated_section_contents}. ++ ++This ensures that the link is performed properly, but has the side effect of ++loosing performance. ++ ++The amiga bfd code uses the same functions since they check for the used flavour. ++@@* ++ ++The usage of a special linker code has one reason: ++The bfd library assumes that a program is always loaded at a known memory ++address. This is not a case on an Amiga. So the Amiga format has to take over ++some relocs to an executable output file. ++This is not the case with a.out formats, so there relocations can be applied at link time, ++not at run time, like on the Amiga. ++The special routines compensate this: instead of applying the relocations, they are ++copied to the output file, if neccessary. ++As as consequence, @code{final_link} and @code{get_relocated_section_contents} are nearly identical to ++the original routines from @file{linker.c} and @file{reloc.c}. ++*/ ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "libbfd.h" ++#include "bfdlink.h" ++#include "genlink.h" ++#include "libamiga.h" ++ ++#define bfd_msg (*_bfd_error_handler) ++ ++/*#define DEBUG_AMIGA 1*/ ++#if DEBUG_AMIGA ++#include <stdarg.h> ++static void ++error_print (const char *fmt, ...) ++{ ++ va_list args; ++ va_start (args, fmt); ++ vfprintf (stderr, fmt, args); ++ va_end (args); ++} ++#define DPRINT(L,x) if (L>=DEBUG_AMIGA) error_print x ++#else ++#define DPRINT(L,x) ++#endif ++ ++/* This one is used by the linker and tells us, if a debug hunk should be ++ written out */ ++int write_debug_hunk = 1; ++ ++/* This is also used by the linker to set the attribute of sections */ ++int amiga_attribute = 0; ++ ++/* This one is used to indicate base-relative linking */ ++int amiga_base_relative = 0; ++ ++/* This one is used to indicate -resident linking */ ++int amiga_resident = 0; ++ ++bfd_boolean ++default_indirect_link_order PARAMS ((bfd *, struct bfd_link_info *, ++ asection *, struct bfd_link_order *, bfd_boolean)); ++bfd_byte * ++get_relocated_section_contents PARAMS ((bfd *, struct bfd_link_info *, ++ struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **)); ++bfd_boolean ++amiga_final_link PARAMS ((bfd *, struct bfd_link_info *)); ++bfd_boolean ++aout_amiga_final_link PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static bfd_reloc_status_type ++my_add_to PARAMS ((arelent *, PTR, int, int)); ++static bfd_reloc_status_type ++amiga_perform_reloc PARAMS ((bfd *, arelent *, PTR, sec_ptr, bfd *, char **)); ++static bfd_reloc_status_type ++aout_perform_reloc PARAMS ((bfd *, arelent *, PTR, sec_ptr, bfd *, char **)); ++static bfd_boolean ++amiga_reloc_link_order PARAMS ((bfd *, struct bfd_link_info *, asection *, ++ struct bfd_link_order *)); ++ ++enum { ADDEND_UNSIGNED=0x01, RELOC_SIGNED=0x02 }; ++ ++ ++/* This one is nearly identical to bfd_generic_get_relocated_section_contents ++ in reloc.c */ ++bfd_byte * ++get_relocated_section_contents (abfd, link_info, link_order, data, ++ relocateable, symbols) ++ bfd *abfd; ++ struct bfd_link_info *link_info; ++ struct bfd_link_order *link_order; ++ bfd_byte *data; ++ bfd_boolean relocateable; ++ asymbol **symbols; ++{ ++ /* Get enough memory to hold the stuff. */ ++ bfd *input_bfd = link_order->u.indirect.section->owner; ++ asection *input_section = link_order->u.indirect.section; ++ ++ long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); ++ arelent **reloc_vector = NULL; ++ long reloc_count; ++ bfd_reloc_status_type (*reloc_func)(bfd *, arelent *, PTR, sec_ptr, ++ bfd *, char **); ++ ++ DPRINT(5,("Entering get_rel_sec_cont\n")); ++ ++ if (reloc_size < 0) ++ goto error_return; ++ ++ if (bfd_get_flavour (input_bfd) == bfd_target_amiga_flavour) ++ reloc_func = amiga_perform_reloc; ++ else if (bfd_get_flavour (input_bfd) == bfd_target_aout_flavour) ++ reloc_func = aout_perform_reloc; ++ else ++ { ++ bfd_set_error (bfd_error_bad_value); ++ goto error_return; ++ } ++ ++ reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size); ++ if (reloc_vector == NULL && reloc_size != 0) ++ goto error_return; ++ ++ DPRINT(5,("GRSC: GetSecCont()\n")); ++ /* Read in the section. */ ++ if (!bfd_get_section_contents (input_bfd, ++ input_section, ++ (PTR) data, ++ (bfd_vma) 0, ++ input_section->_raw_size)) ++ goto error_return; ++ ++ /* We're not relaxing the section, so just copy the size info. */ ++ input_section->_cooked_size = input_section->_raw_size; ++ input_section->reloc_done = TRUE; ++ ++ DPRINT(5,("GRSC: CanReloc\n")); ++ reloc_count = bfd_canonicalize_reloc (input_bfd, ++ input_section, ++ reloc_vector, ++ symbols); ++ if (reloc_count < 0) ++ goto error_return; ++ ++ if (reloc_count > 0) ++ { ++ arelent **parent; ++ ++ DPRINT(5,("reloc_count=%ld\n",reloc_count)); ++ ++ for (parent = reloc_vector; *parent != (arelent *) NULL; ++ parent++) ++ { ++ char *error_message = (char *) NULL; ++ bfd_reloc_status_type r; ++ ++ DPRINT(5,("Applying a reloc\nparent=%lx, reloc_vector=%lx, " ++ "*parent=%lx\n",parent,reloc_vector,*parent)); ++ r=(*reloc_func) (input_bfd, ++ *parent, ++ (PTR) data, ++ input_section, ++ relocateable ? abfd : (bfd *) NULL, ++ &error_message); ++ if (relocateable) ++ { ++ asection *os = input_section->output_section; ++ ++ DPRINT(5,("Keeping reloc\n")); ++ /* A partial link, so keep the relocs. */ ++ os->orelocation[os->reloc_count] = *parent; ++ os->reloc_count++; ++ } ++ ++ if (r != bfd_reloc_ok) ++ { ++ switch (r) ++ { ++ case bfd_reloc_undefined: ++ if (!((*link_info->callbacks->undefined_symbol) ++ (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), ++ input_bfd, input_section, (*parent)->address, ++ TRUE))) ++ goto error_return; ++ break; ++ case bfd_reloc_dangerous: ++ BFD_ASSERT (error_message != (char *) NULL); ++ if (!((*link_info->callbacks->reloc_dangerous) ++ (link_info, error_message, input_bfd, input_section, ++ (*parent)->address))) ++ goto error_return; ++ break; ++ case bfd_reloc_overflow: ++ if (!((*link_info->callbacks->reloc_overflow) ++ (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), ++ (*parent)->howto->name, (*parent)->addend, ++ input_bfd, input_section, (*parent)->address))) ++ goto error_return; ++ break; ++ case bfd_reloc_outofrange: ++ default: ++ DPRINT(10,("get_rel_sec_cont fails, perform reloc " ++ "returned $%x\n",r)); ++ abort (); ++ break; ++ } ++ ++ } ++ } ++ } ++ if (reloc_vector != NULL) ++ free (reloc_vector); ++ DPRINT(5,("GRSC: Returning ok\n")); ++ return data; ++ ++error_return: ++ DPRINT(5,("GRSC: Error_return\n")); ++ if (reloc_vector != NULL) ++ free (reloc_vector); ++ return NULL; ++} ++ ++ ++/* Add a value to a location */ ++static bfd_reloc_status_type ++my_add_to (r, data, add, flags) ++ arelent *r; ++ PTR data; ++ int add, flags; ++{ ++ bfd_reloc_status_type ret=bfd_reloc_ok; ++ bfd_byte *p=((bfd_byte *)data)+r->address; ++ int val; ++ ++ DPRINT(5,("Entering add_value\n")); ++ ++ switch (r->howto->size) ++ { ++ case 0: /* byte size */ ++ if ((flags & ADDEND_UNSIGNED) == 0) ++ val = ((*p & 0xff) ^ 0x80) - 0x80 + add; ++ else ++ val = (*p & 0xff) + add; ++ /* check for overflow */ ++ if ((flags & RELOC_SIGNED) != 0) { ++ if (val<-0x80 || val>0x7f) ++ ret = bfd_reloc_overflow; ++ } ++ else { ++ if ((val&0xffffff00)!=0 && (val&0xffffff00)!=0xffffff00) ++ ret=bfd_reloc_overflow; ++ } ++ /* set the value */ ++ *p = val & 0xff; ++ break; ++ ++ case 1: /* word size */ ++ if ((flags & ADDEND_UNSIGNED) == 0) ++ val = bfd_getb_signed_16 (p) + add; ++ else ++ val = bfd_getb16 (p) + add; ++ /* check for overflow */ ++ if ((flags & RELOC_SIGNED) != 0) { ++ if (val<-0x8000 || val>0x7fff) ++ ret = bfd_reloc_overflow; ++ } ++ else { ++ if ((val&0xffff0000)!=0 && (val&0xffff0000)!=0xffff0000) ++ ret=bfd_reloc_overflow; ++ } ++ /* set the value */ ++ bfd_putb16 (val, p); ++ break; ++ ++ case 2: /* long word */ ++ val = bfd_getb_signed_32 (p) + add; ++ /* If we are linking a resident program, then we limit the reloc size ++ to about +/- 1 GB. ++ ++ When linking a shared library all variables defined in other ++ libraries are placed in memory >0x80000000, so if the library ++ tries to use one of those variables an error is output. ++ ++ Without this it would be much more difficult to check for ++ incorrect references. */ ++ if (amiga_resident && ++ (val & 0xc0000000)!=0 && (val&0xc0000000)!=0xc0000000) /* Overflow */ ++ { ++ ret=bfd_reloc_overflow; ++ } ++ bfd_putb32 (val, p); ++ break; ++ ++ default: /* Error */ ++ ret=bfd_reloc_notsupported; ++ break; ++ }/* Of switch */ ++ ++ DPRINT(5,("Leaving add_value\n")); ++ return ret; ++} ++ ++ ++/* Perform an Amiga relocation */ ++static bfd_reloc_status_type ++amiga_perform_reloc (abfd, r, data, sec, obfd, error_message) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ arelent *r; ++ PTR data; ++ sec_ptr sec; ++ bfd *obfd; ++ char **error_message ATTRIBUTE_UNUSED; ++{ ++ asymbol *sym; /* Reloc is relative to sym */ ++ sec_ptr target_section; /* reloc is relative to this section */ ++ bfd_reloc_status_type ret; ++ bfd_boolean copy; ++ int relocation,flags; ++ ++ DPRINT(5,("Entering APR\nflavour is %d (amiga_flavour=%d, aout_flavour=%d)\n", ++ bfd_get_flavour (sec->owner), bfd_target_amiga_flavour, ++ bfd_target_aout_flavour)); ++ ++ /* If obfd==NULL: Apply the reloc, if possible. */ ++ /* Else: Modify it and return */ ++ ++ if (obfd!=NULL) /* Only modify the reloc */ ++ { ++ r->address+=sec->output_offset; ++ sec->output_section->flags|=SEC_RELOC; ++ DPRINT(5,("Leaving amiga_perf_reloc, modified\n")); ++ return bfd_reloc_ok; ++ } ++ ++ /* Try to apply the reloc */ ++ ++ sym=*(r->sym_ptr_ptr); ++ ++ /* FIXME: XXX */ ++ if (0 && sym->udata.p) ++ sym = ((struct generic_link_hash_entry *) sym->udata.p)->sym; ++ ++ target_section=sym->section; ++ ++ if (bfd_is_und_section(target_section)) /* Error */ ++ { ++ DPRINT(10,("amiga_perf_reloc: target_sec==UND\n")); ++ return bfd_reloc_undefined; ++ } ++ ++ relocation=0; flags=RELOC_SIGNED; copy=FALSE; ret=bfd_reloc_ok; ++ ++ DPRINT(5,("%s: size=%u\n",r->howto->name,bfd_get_reloc_size(r->howto))); ++ switch (r->howto->type) ++ { ++ case H_ABS32: ++ if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */ ++ relocation=sym->value; ++ else if (bfd_is_com_section(target_section)) /* ref to common */ ++ { ++ relocation=0; ++ copy=TRUE; ++ } ++ else ++ { ++ /* If we access a symbol in the .bss section, we have to convert ++ this to an access to .data section */ ++ /* This is done through a change to the output section of ++ the symbol.. */ ++ if (amiga_base_relative ++ && !strcmp(target_section->output_section->name,".bss")) ++ { ++ /* get value for .data section */ ++ bfd *ibfd; ++ sec_ptr s; ++ ++ ibfd=target_section->output_section->owner; ++ for (s=ibfd->sections;s!=NULL;s=s->next) ++ if (!strcmp(s->name,".data")) ++ { ++ target_section->output_offset=s->_raw_size; ++ target_section->output_section=s; ++ } ++ } ++ relocation=0; ++ copy=TRUE; ++ } ++ break; ++ ++ case H_PC8: /* pcrel */ ++ case H_PC16: ++ case H_PC32: ++ if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */ ++ relocation=sym->value; ++ else if (bfd_is_com_section(target_section)) /* Error.. */ ++ { ++ ret=bfd_reloc_undefined; ++ } ++ else if (sec->output_section!=target_section->output_section) /* Error */ ++ { ++ DPRINT(5,("pc relative, but out-of-range\n")); ++ ret=bfd_reloc_outofrange; ++ } ++ else /* Same section */ ++ { ++ DPRINT(5,("PC relative\n")); ++ relocation = sym->value + target_section->output_offset ++ - (r->address + sec->output_offset); ++ } ++ break; ++ ++ case H_SD8: /* baserel */ ++ case H_SD16: ++ case H_SD32: ++ /* Relocs are always relative to the symbol ___a4_init */ ++ /* Relocs to .bss section are converted to a reloc to .data section, ++ since .bss section contains only COMMON sections...... and should ++ be following .data section.. */ ++ if (bfd_is_abs_section(target_section)) ++ relocation=sym->value; ++ else if (!AMIGA_DATA(target_section->output_section->owner)->baserel) ++ { ++ bfd_msg ("Base symbol for base relative reloc not defined: " ++ "section %s, reloc to symbol %s",sec->name,sym->name); ++ ret=bfd_reloc_notsupported; ++ } ++ else if ((target_section->flags&SEC_CODE)!=0) ++ { ++ bfd_msg ("%s: baserelative text relocation to \"%s\"", ++ abfd->filename, sym->name); ++ ret=bfd_reloc_notsupported; ++ } ++ else ++ { ++ /* If target->out is .bss, add the value of the .data section to ++ sym->value and set new output_section */ ++ if (!strcmp(target_section->output_section->name,".bss")) ++ { ++ bfd *ibfd; ++ sec_ptr s; ++ ++ ibfd=target_section->output_section->owner; ++ for (s=ibfd->sections;s!=NULL;s=s->next) ++ if (!strcmp(s->name,".data")) ++ { ++ target_section->output_offset=s->_raw_size; ++ target_section->output_section=s; ++ } ++ } ++ ++ relocation = sym->value + target_section->output_offset ++ - (AMIGA_DATA(target_section->output_section->owner))->a4init ++ + r->addend; ++ flags|=ADDEND_UNSIGNED; ++ } ++ break; ++ ++ default: ++ bfd_msg ("Error: unsupported reloc: %s(%d)",r->howto->name,r->howto->size); ++ ret=bfd_reloc_notsupported; ++ break; ++ }/* Of switch */ ++ ++ /* Add in relocation */ ++ if (relocation!=0) ++ ret = my_add_to (r, data, relocation, flags); ++ ++ if (copy) /* Copy reloc to output section */ ++ { ++ DPRINT(5,("Copying reloc\n")); ++ target_section=sec->output_section; ++ r->address+=sec->output_offset; ++ target_section->orelocation[target_section->reloc_count++]=r; ++ target_section->flags|=SEC_RELOC; ++ } ++ DPRINT(5,("Leaving amiga_perf_reloc with %d (OK=%d)\n",ret,bfd_reloc_ok)); ++ return ret; ++} ++ ++ ++/* Perform an a.out relocation */ ++static bfd_reloc_status_type ++aout_perform_reloc (abfd, r, data, sec, obfd, error_message) ++ bfd *abfd; ++ arelent *r; ++ PTR data; ++ sec_ptr sec; ++ bfd *obfd; ++ char **error_message ATTRIBUTE_UNUSED; ++{ ++ asymbol *sym; /* Reloc is relative to sym */ ++ sec_ptr target_section; /* reloc is relative to this section */ ++ bfd_reloc_status_type ret; ++ bfd_boolean copy; ++ int relocation,flags; ++ ++ DPRINT(5,("Entering aout_perf_reloc\n")); ++ ++ /* If obfd==NULL: Apply the reloc, if possible. */ ++ /* Else: Modify it and return */ ++ ++ if (obfd!=NULL) /* Only modify the reloc */ ++ { ++ r->address+=sec->output_offset; ++ DPRINT(5,("Leaving aout_perf_reloc, modified\n")); ++ return bfd_reloc_ok; ++ } ++ ++ /* Try to apply the reloc */ ++ ++ sym=*(r->sym_ptr_ptr); ++ target_section=sym->section; ++ ++ if (bfd_is_und_section(target_section)) /* Error */ ++ { ++ if ((sym->flags & BSF_WEAK) == 0) ++ { ++ DPRINT(10,("aout_perf_reloc: target_sec==UND\n")); ++ return bfd_reloc_undefined; ++ } ++ target_section=bfd_abs_section_ptr; ++ } ++ ++ relocation=0; flags=RELOC_SIGNED; copy=FALSE; ret=bfd_reloc_ok; ++ ++ DPRINT(10,("RELOC: %s: size=%u\n",r->howto->name,bfd_get_reloc_size(r->howto))); ++ switch (r->howto->type) ++ { ++ case H_ABS8: /* 8/16 bit reloc, pc relative or absolute */ ++ case H_ABS16: ++ if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */ ++ relocation=sym->value; ++ else if (bfd_is_com_section(target_section)) /* Error.. */ ++ { ++ bfd_msg ("pc relative relocation to common symbol \"%s\" in " ++ "section %s",sym->name,sec->name); ++ DPRINT(10,("Ref to common symbol...aout_perf_reloc\n")); ++ ret=bfd_reloc_undefined; ++ } ++ else if (sec->output_section!=target_section->output_section) ++ { ++ if ((target_section->output_section->flags&SEC_DATA)!=0) ++ goto baserel; /* Dirty, but no code duplication.. */ ++ bfd_msg ("pc relative relocation out-of-range in section %s. " ++ "Relocation was to symbol %s",sec->name,sym->name); ++ DPRINT(10,("Section %s, target %s: Reloc out-of-range...not same " ++ "section, aout_perf\nsec->out=%s, target->out=%s, " ++ "offset=%lx\n",sec->name,target_section->name, ++ sec->output_section->name, ++ target_section->output_section->name,r->address)); ++ ret=bfd_reloc_outofrange; ++ } ++ else ++ { ++ /* Same section, this is a pc relative hunk... */ ++ DPRINT(5,("Reloc to same section...\n")); ++ relocation=-(r->address+sec->output_offset); ++ } ++ break; ++ ++ case H_ABS32: /* 32 bit reloc, pc relative or absolute */ ++ if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */ ++ relocation=sym->value; ++ else if (bfd_is_com_section(target_section)) /* ref to common */ ++ { ++ relocation=0; ++ copy=TRUE; ++ } ++ else ++ { ++ /* If we access a symbol in the .bss section, we have to convert ++ this to an access to .data section */ ++ /* This is done through a change to the output section of ++ the symbol.. */ ++ if (amiga_base_relative ++ && !strcmp(target_section->output_section->name,".bss")) ++ { ++ /* get value for .data section */ ++ bfd *ibfd; ++ sec_ptr s; ++ ++ ibfd=target_section->output_section->owner; ++ for (s=ibfd->sections;s!=NULL;s=s->next) ++ if (!strcmp(s->name,".data")) ++ { ++ target_section->output_offset+=s->_raw_size; ++ target_section->output_section=s; ++ } ++ } ++ relocation=0; ++ copy=TRUE; ++ } ++ DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n", ++ target_section->output_section->name, ++ target_section->output_section,sec->output_section->name, ++ sec->output_section,sym->name)); ++ break; ++ ++ case H_PC8: /* pcrel */ ++ case H_PC16: ++ case H_PC32: ++ if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */ ++ relocation=sym->value; ++ else ++ { ++ relocation = sym->value + target_section->output_offset ++ - sec->output_offset; ++ } ++ break; ++ ++ case H_SD16: /* baserel */ ++ case H_SD32: ++ baserel: ++ /* We use the symbol ___a4_init as base */ ++ if (bfd_is_abs_section(target_section)) ++ relocation=sym->value; ++ else if (bfd_is_com_section(target_section)) /* Error.. */ ++ { ++ bfd_msg ("baserelative relocation to common \"%s\"",sym->name); ++ DPRINT(10,("Ref to common symbol...aout_perf_reloc\n")); ++ ret=bfd_reloc_undefined; ++ } ++ else if (!AMIGA_DATA(target_section->output_section->owner)->baserel) ++ { ++ bfd_msg ("Base symbol for base relative reloc not defined: " ++ "section %s, reloc to symbol %s",sec->name,sym->name); ++ ret=bfd_reloc_notsupported; ++ } ++ else if ((target_section->flags&SEC_CODE)!=0) ++ { ++ bfd_msg ("%s: baserelative text relocation to \"%s\"", ++ abfd->filename, sym->name); ++ ret=bfd_reloc_notsupported; ++ } ++ else /* Target section and sec need not be the same.. */ ++ { ++ /* If target->out is .bss, add the value of the .data section to ++ sym->value and set new output_section */ ++ if (!strcmp(target_section->output_section->name,".bss")) ++ { ++ bfd *ibfd; ++ sec_ptr s; ++ ++ ibfd=target_section->output_section->owner; ++ for (s=ibfd->sections;s!=NULL;s=s->next) ++ if (!strcmp(s->name,".data")) ++ { ++ target_section->output_offset+=s->_raw_size; ++ target_section->output_section=s; ++ } ++ } ++ ++ relocation = sym->value + target_section->output_offset ++ - (AMIGA_DATA(target_section->output_section->owner))->a4init; ++ /* if the symbol is in .bss, subtract the offset that gas has put ++ into the opcode */ ++ if (target_section->index == 2) ++ relocation -= adata(abfd).datasec->_raw_size; ++ DPRINT(20,("symbol=%s (0x%lx)\nsection %s (0x%lx; %s; output=0x%lx)" ++ "\nrelocation @0x%lx\n", sym->name, sym->value, ++ target_section->name, target_section, ++ target_section->owner->filename, target_section->output_offset, ++ r->address)); ++ flags|=ADDEND_UNSIGNED; ++ } ++ DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n", ++ target_section->output_section->name, ++ target_section->output_section,sec->output_section->name, ++ sec->output_section,sym->name)); ++ break; ++ ++ default: ++ bfd_msg ("Error: unsupported reloc: %s(%d)",r->howto->name,r->howto->size); ++ ret=bfd_reloc_notsupported; ++ break; ++ }/* Of switch */ ++ ++ /* Add in relocation */ ++ if (relocation!=0) ++ ret = my_add_to (r, data, relocation, flags); ++ ++ if (copy) /* Copy reloc to output section */ ++ { ++ DPRINT(5,("Copying reloc\n")); ++ target_section=sec->output_section; ++ r->address+=sec->output_offset; ++ target_section->orelocation[target_section->reloc_count++]=r; ++ } ++ DPRINT(5,("Leaving aout_perf_reloc with %d (OK=%d)\n",ret,bfd_reloc_ok)); ++ return ret; ++} ++ ++ ++/* The final link routine, used both by Amiga and a.out backend */ ++/* This is nearly a copy of linker.c/_bfd_generic_final_link */ ++bfd_boolean ++amiga_final_link (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ bfd *sub; ++ asection *o; ++ struct bfd_link_order *p; ++ size_t outsymalloc; ++ struct generic_write_global_symbol_info wginfo; ++ struct bfd_link_hash_entry *h = ++ bfd_link_hash_lookup (info->hash, "___a4_init", FALSE, FALSE, TRUE); ++ ++ if (amiga_base_relative && h && h->type == bfd_link_hash_defined) { ++ AMIGA_DATA(abfd)->baserel = TRUE; ++ AMIGA_DATA(abfd)->a4init = h->u.def.value; ++ } ++ else ++ AMIGA_DATA(abfd)->baserel = FALSE; ++ ++ DPRINT(5,("Entering final_link\n")); ++ ++ if (bfd_get_flavour (abfd) == bfd_target_aout_flavour) ++ return aout_amiga_final_link (abfd, info); ++ ++ bfd_get_outsymbols (abfd) = (asymbol **) NULL; ++ bfd_get_symcount (abfd) = 0; ++ outsymalloc = 0; ++ ++ /* Mark all sections which will be included in the output file. */ ++ for (o = abfd->sections; o != NULL; o = o->next) ++ for (p = o->link_order_head; p != NULL; p = p->next) ++ if (p->type == bfd_indirect_link_order) ++ p->u.indirect.section->linker_mark = TRUE; ++ ++ /* Build the output symbol table. */ ++ for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next) ++ if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc)) ++ return FALSE; ++ ++ DPRINT(10,("Did build output symbol table\n")); ++ ++ /* Accumulate the global symbols. */ ++ wginfo.info = info; ++ wginfo.output_bfd = abfd; ++ wginfo.psymalloc = &outsymalloc; ++ _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info), ++ _bfd_generic_link_write_global_symbol, ++ (PTR) &wginfo); ++ ++ DPRINT(10,("Accumulated global symbols\n")); ++ ++ DPRINT(10,("Output bfd is %s(%lx)\n",abfd->filename,abfd)); ++ ++ if (1) ++ { ++ /* Allocate space for the output relocs for each section. */ ++ /* We also handle base-relative linking special, by setting the .data ++ sections real length to it's length + .bss length */ ++ /* This is different to bfd_generic_final_link: We ALWAYS alloc space ++ for the relocs, because we may need it anyway */ ++ for (o = abfd->sections; ++ o != (asection *) NULL; ++ o = o->next) ++ { ++ /* If section is .data, find .bss and add that length */ ++ if (!info->relocateable && amiga_base_relative && ++ !strcmp(o->name,".data")) ++ { ++ if (bfd_get_flavour(abfd)!=bfd_target_amiga_flavour) /* oops */ ++ { ++ bfd_msg ("You can't use base relative linking with " ++ "partial links."); ++ } ++ else if (0) /* XXX */ ++ { ++ asection *act_sec; ++ for (act_sec=abfd->sections; act_sec!=NULL;act_sec=act_sec->next) ++ if (!strcmp(act_sec->name,".bss")) ++ amiga_per_section(o)->disk_size = o->_raw_size + ++ act_sec->_raw_size; ++ } ++ }/* Of base-relative linking */ ++ ++ DPRINT(10,("Section in output bfd is %s (%lx)\n",o->name,o)); ++ ++ o->reloc_count = 0; ++ for (p = o->link_order_head; ++ p != (struct bfd_link_order *) NULL; ++ p = p->next) ++ { ++ if (p->type == bfd_section_reloc_link_order ++ || p->type == bfd_symbol_reloc_link_order) ++ ++o->reloc_count; ++ else if (p->type == bfd_indirect_link_order) ++ { ++ asection *input_section; ++ bfd *input_bfd; ++ long relsize; ++ arelent **relocs; ++ asymbol **symbols; ++ long reloc_count; ++ ++ input_section = p->u.indirect.section; ++ input_bfd = input_section->owner; ++ ++ DPRINT(10,("\tIndirect section from bfd %s, section is %s(%lx) " ++ "(COM=%lx)\n", ++ input_bfd->filename,input_section->name,input_section, ++ bfd_com_section_ptr)); ++ ++ relsize = bfd_get_reloc_upper_bound (input_bfd, ++ input_section); ++ if (relsize < 0) ++ { ++ DPRINT(10,("Relsize<0.I..in bfd %s, sec %s\n", ++ input_bfd->filename, input_section->name)); ++ return FALSE; ++ } ++ relocs = (arelent **) bfd_malloc ((bfd_size_type) relsize); ++ if (!relocs && relsize != 0) ++ return FALSE; ++ symbols = _bfd_generic_link_get_symbols (input_bfd); ++ reloc_count = bfd_canonicalize_reloc (input_bfd, ++ input_section, ++ relocs, ++ symbols); ++ free (relocs); ++ if (reloc_count < 0) ++ { ++ DPRINT(10,("Relsize<0.II..in bfd %s, sec %s\n", ++ input_bfd->filename, input_section->name)); ++ return FALSE; ++ } ++ BFD_ASSERT ((unsigned long) reloc_count ++ == input_section->reloc_count); ++ o->reloc_count += reloc_count; ++ } ++ } ++ if (o->reloc_count > 0) ++ { ++ bfd_size_type amt; ++ ++ amt = o->reloc_count; ++ amt *= sizeof (arelent *); ++ o->orelocation = (arelent **) bfd_alloc (abfd, amt); ++ if (!o->orelocation) ++ return FALSE; ++ /* o->flags |= SEC_RELOC; There may be no relocs. This can ++ be determined later only */ ++ /* Reset the count so that it can be used as an index ++ when putting in the output relocs. */ ++ o->reloc_count = 0; ++ } ++ } ++ } ++ ++ DPRINT(10,("Got all relocs\n")); ++ ++ /* Handle all the link order information for the sections. */ ++ for (o = abfd->sections; ++ o != (asection *) NULL; ++ o = o->next) ++ { ++ for (p = o->link_order_head; ++ p != (struct bfd_link_order *) NULL; ++ p = p->next) ++ { ++ switch (p->type) ++ { ++ case bfd_section_reloc_link_order: ++ case bfd_symbol_reloc_link_order: ++ if (! amiga_reloc_link_order (abfd, info, o, p)) /* We use an own routine */ ++ return FALSE; ++ break; ++ case bfd_indirect_link_order: ++ if (! default_indirect_link_order (abfd, info, o, p, FALSE)) ++ /* Calls our get_relocated_section_contents */ ++ return FALSE; ++ break; ++ default: ++ if (! _bfd_default_link_order (abfd, info, o, p)) ++ return FALSE; ++ break; ++ } ++ } ++ } ++ ++ if (bfd_get_flavour(abfd)==bfd_target_amiga_flavour&&!info->relocateable) ++ AMIGA_DATA(abfd)->IsLoadFile = TRUE; ++ ++ DPRINT(10,("Leaving final_link\n")); ++ return TRUE; ++} ++ ++ ++/* Handle reloc link order. ++ This is nearly a copy of linker.c/_bfd_generic_reloc_link_order */ ++static bfd_boolean ++amiga_reloc_link_order (abfd, info, sec, link_order) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ asection *sec; ++ struct bfd_link_order *link_order; ++{ ++ arelent *r; ++ ++ DPRINT(5,("Entering amiga_reloc_link_order\n")); ++ ++ if (sec->orelocation == (arelent **) NULL) ++ { ++ DPRINT(10,("aborting, since orelocation==NULL\n")); ++ abort (); ++ } ++ ++ /* We generate a new ***AMIGA*** style reloc */ ++ r = (arelent *) bfd_zalloc (abfd, (bfd_size_type) sizeof (amiga_reloc_type)); ++ if (r == (arelent *) NULL) ++ { ++ DPRINT(5,("Leaving amiga_reloc_link, no mem\n")); ++ return FALSE; ++ } ++ ++ r->address = link_order->offset; ++ r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc); ++ if (r->howto == 0) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ DPRINT(5,("Leaving amiga_reloc_link, bad value\n")); ++ return FALSE; ++ } ++ ++ /* Get the symbol to use for the relocation. */ ++ if (link_order->type == bfd_section_reloc_link_order) ++ r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr; ++ else ++ { ++ struct generic_link_hash_entry *h; ++ ++ h = ((struct generic_link_hash_entry *) ++ bfd_wrapped_link_hash_lookup (abfd, info, ++ link_order->u.reloc.p->u.name, ++ FALSE, FALSE, TRUE)); ++ if (h == (struct generic_link_hash_entry *) NULL ++ || ! h->written) ++ { ++ if (! ((*info->callbacks->unattached_reloc) ++ (info, link_order->u.reloc.p->u.name, ++ (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) ++ return FALSE; ++ bfd_set_error (bfd_error_bad_value); ++ DPRINT(5,("Leaving amiga_reloc_link, bad value in hash lookup\n")); ++ return FALSE; ++ } ++ r->sym_ptr_ptr = &h->sym; ++ } ++ DPRINT(5,("Got symbol for relocation\n")); ++ /* Store the addend */ ++ r->addend = link_order->u.reloc.p->addend; ++ ++ /* If we are generating relocateable output, just add the reloc */ ++ if (info->relocateable) ++ { ++ DPRINT(5,("Adding reloc\n")); ++ sec->orelocation[sec->reloc_count] = r; ++ ++sec->reloc_count; ++ sec->flags|=SEC_RELOC; ++ } ++ else /* Try to apply the reloc */ ++ { ++ PTR data=(PTR)sec->contents; ++ bfd_reloc_status_type ret; ++ char *em=NULL; ++ ++ DPRINT(5,("Apply link_order_reloc\n")); ++ ++ /* FIXME: Maybe, we have to get the section contents, before we ++ use them, if they have not been set by now.. */ ++ BFD_ASSERT (data!=NULL); ++ ++ if (bfd_get_flavour(abfd)==bfd_target_amiga_flavour) ++ ret=amiga_perform_reloc(abfd,r,data,sec,NULL,&em); ++ else ++ ret=aout_perform_reloc(abfd,r,data,sec,NULL,&em); ++ ++ if (ret!=bfd_reloc_ok) ++ { ++ DPRINT(5,("Leaving amiga_reloc_link, value FALSE\n")); ++ return FALSE; ++ } ++ } ++ DPRINT(5,("Leaving amiga_reloc_link\n")); ++ return TRUE; ++} +diff --git a/bfd/aout-amiga.c b/bfd/aout-amiga.c +new file mode 100644 +index 0000000000000000000000000000000000000000..ced7584521b89943b1636d2b4c9b884242cd81c6 +--- /dev/null ++++ bfd/aout-amiga.c +@@ -0,0 +1,152 @@ ++/* BFD back-end for Amiga style m68k a.out binaries. ++ Copyright (C) 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. ++ Contributed by Stephan Thesing. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++ ++#define TARGETNAME "a.out-amiga" ++#define MACHTYPE_OK(m) ((m)==M_UNKNOWN || (m)==M_68010 || (m)==M_68020) ++#define TARGET_IS_BIG_ENDIAN_P ++#define TARGET_PAGE_SIZE 0x2000 ++#define N_HEADER_IN_TEXT(x) 0 ++#define N_SHARED_LIB(x) 0 ++#define TEXT_START_ADDR 0 ++ ++/* Do not "beautify" the CONCAT* macro args. Traditional C will not ++ remove whitespace added here, and thus will fail to concatenate ++ the tokens. */ ++#define MY(OP) CONCAT2 (aout_amiga_,OP) ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "libbfd.h" ++#include "libaout.h" ++#include "aout/aout64.h" ++ ++bfd_boolean ++MY(final_link) PARAMS ((bfd *, struct bfd_link_info *)); ++ ++bfd_boolean ++amiga_final_link PARAMS ((bfd *, struct bfd_link_info *)); ++#define MY_bfd_final_link amiga_final_link ++ ++bfd_byte * ++get_relocated_section_contents PARAMS ((bfd *, struct bfd_link_info *, ++ struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **)); ++#define MY_bfd_get_relocated_section_contents get_relocated_section_contents ++ ++static unsigned long MY(get_mach) PARAMS ((enum machine_type)); ++static bfd_boolean MY(write_object_contents) PARAMS ((bfd *)); ++static bfd_boolean MY(set_sizes) PARAMS ((bfd *)); ++static bfd_boolean MY(link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *)); ++#define MY_bfd_link_add_symbols aout_amiga_link_add_symbols ++ ++static unsigned long ++MY(get_mach) (machtype) ++ enum machine_type machtype; ++{ ++ unsigned long machine; ++ switch (machtype) ++ { ++ default: ++ case M_UNKNOWN: ++ /* Some Sun3s make magic numbers without cpu types in them, so ++ we'll default to the 68000. */ ++ machine = bfd_mach_m68000; ++ break; ++ ++ case M_68010: ++ machine = bfd_mach_m68010; ++ break; ++ ++ case M_68020: ++ machine = bfd_mach_m68020; ++ break; ++ } ++ return machine; ++} ++#define SET_ARCH_MACH(ABFD, EXEC) \ ++ bfd_set_arch_mach (ABFD, bfd_arch_m68k, MY(get_mach) (N_MACHTYPE (EXEC))) ++ ++static bfd_boolean ++MY(write_object_contents) (abfd) ++ bfd *abfd; ++{ ++ struct external_exec exec_bytes; ++ struct internal_exec *execp = exec_hdr (abfd); ++ ++ /* Magic number, maestro, please! */ ++ switch (bfd_get_arch (abfd)) ++ { ++ case bfd_arch_m68k: ++ switch (bfd_get_mach (abfd)) ++ { ++ case bfd_mach_m68000: ++ N_SET_MACHTYPE (*execp, M_UNKNOWN); ++ break; ++ case bfd_mach_m68010: ++ N_SET_MACHTYPE (*execp, M_68010); ++ break; ++ default: ++ case bfd_mach_m68020: ++ N_SET_MACHTYPE (*execp, M_68020); ++ break; ++ } ++ break; ++ default: ++ N_SET_MACHTYPE (*execp, M_UNKNOWN); ++ } ++ ++ WRITE_HEADERS (abfd, execp); ++ ++ return TRUE; ++} ++#define MY_write_object_contents MY(write_object_contents) ++ ++static bfd_boolean ++MY(set_sizes) (abfd) ++ bfd *abfd; ++{ ++ adata (abfd).page_size = TARGET_PAGE_SIZE; ++ adata (abfd).segment_size = TARGET_PAGE_SIZE; ++ adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; ++ return TRUE; ++} ++#define MY_set_sizes MY(set_sizes) ++ ++/* Include the usual a.out support. */ ++#include "aout-target.h" ++ ++/* Add symbols from an object file to the global hash table. */ ++static bfd_boolean ++MY(link_add_symbols) (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ if (info->hash->creator->flavour == bfd_target_amiga_flavour) ++ return _bfd_generic_link_add_symbols (abfd, info); ++ return NAME(aout,link_add_symbols) (abfd, info); ++} ++ ++/* Public final_link routine. */ ++bfd_boolean ++MY(final_link) (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ return NAME(aout,final_link) (abfd, info, MY_final_link_callback); ++} +diff --git a/bfd/aoutx.h b/bfd/aoutx.h +index 1e0ad38f95bcf990a9ffd4cfb89eae3f6496740c..2641f975fd575d0a651540dc886eeee68cf4b173 100644 +--- bfd/aoutx.h ++++ bfd/aoutx.h +@@ -127,12 +127,16 @@ DESCRIPTION + #include "libaout.h" + #include "libbfd.h" + #include "aout/aout64.h" + #include "aout/stab_gnu.h" + #include "aout/ar.h" + ++/*Amiga hack - used in amigaos.c, must be global */ ++/*static*/ bfd_boolean translate_to_native_sym_flags ++ PARAMS ((bfd *, asymbol *, struct external_nlist *)); ++ + /* + SUBSECTION + Relocations + + DESCRIPTION + The file @file{aoutx.h} provides for both the @emph{standard} +@@ -1550,13 +1554,13 @@ translate_from_native_sym_flags (bfd *abfd, aout_symbol_type *cache_ptr) + + return TRUE; + } + + /* Set the fields of SYM_POINTER according to CACHE_PTR. */ + +-static bfd_boolean ++bfd_boolean + translate_to_native_sym_flags (bfd *abfd, + asymbol *cache_ptr, + struct external_nlist *sym_pointer) + { + bfd_vma value = cache_ptr->value; + asection *sec; +@@ -1946,16 +1950,32 @@ NAME (aout, swap_std_reloc_out) (bfd *abfd, + asection *output_section = sym->section->output_section; + + PUT_WORD (abfd, g->address, natptr->r_address); + + r_length = g->howto->size ; /* Size as a power of two. */ + r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ ++#if 1 ++ /* FIXME! "#if 1" is the wrong way to select this Amiga specific code. */ ++ switch (bfd_asymbol_flavour(sym)) ++ { ++ case bfd_target_amiga_flavour: ++ case bfd_target_aout_flavour: ++ r_baserel = (g->howto->type & 8) != 0; ++ r_jmptable = (g->howto->type & 16) != 0; ++ r_relative = (g->howto->type & 32) != 0; ++ break; ++ default: ++ r_baserel=r_jmptable=r_relative=0; ++ break; ++ } ++#else + /* XXX This relies on relocs coming from a.out files. */ + r_baserel = (g->howto->type & 8) != 0; + r_jmptable = (g->howto->type & 16) != 0; + r_relative = (g->howto->type & 32) != 0; ++#endif + + /* Name was clobbered by aout_write_syms to be symbol index. */ + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + +@@ -2251,14 +2271,18 @@ NAME (aout, swap_std_reloc_in) (bfd *abfd, + else + cache_ptr->howto = NULL; + + /* Base relative relocs are always against the symbol table, + regardless of the setting of r_extern. r_extern just reflects + whether the symbol the reloc is against is local or global. */ ++#if 0 ++ /* FIXME! "#if 0" is the wrong way to disable this code. See comment ++ earlier in file. */ + if (r_baserel) + r_extern = 1; ++#endif + + if (r_extern && r_index > symcount) + { + /* We could arrange to return an error, but it might be useful + to see the file even if it is bad. */ + r_extern = 0; +diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h +index e496083d6ebb0842cfe0a7777dc76cdbd18c7134..8a4d566298f86c56c4a2d21895a39e0d7c5002d7 100644 +--- bfd/bfd-in2.h ++++ bfd/bfd-in2.h +@@ -3128,12 +3128,16 @@ instruction. */ + BFD_RELOC_PPC_EMB_RELSEC16, + BFD_RELOC_PPC_EMB_RELST_LO, + BFD_RELOC_PPC_EMB_RELST_HI, + BFD_RELOC_PPC_EMB_RELST_HA, + BFD_RELOC_PPC_EMB_BIT_FLD, + BFD_RELOC_PPC_EMB_RELSDA, ++ BFD_RELOC_PPC_MORPHOS_DREL, ++ BFD_RELOC_PPC_MORPHOS_DREL_LO, ++ BFD_RELOC_PPC_MORPHOS_DREL_HI, ++ BFD_RELOC_PPC_MORPHOS_DREL_HA, + BFD_RELOC_PPC_VLE_REL8, + BFD_RELOC_PPC_VLE_REL15, + BFD_RELOC_PPC_VLE_REL24, + BFD_RELOC_PPC_VLE_LO16A, + BFD_RELOC_PPC_VLE_LO16D, + BFD_RELOC_PPC_VLE_HI16A, +@@ -3213,12 +3217,18 @@ instruction. */ + BFD_RELOC_PPC64_DTPREL16_LO_DS, + BFD_RELOC_PPC64_DTPREL16_HIGHER, + BFD_RELOC_PPC64_DTPREL16_HIGHERA, + BFD_RELOC_PPC64_DTPREL16_HIGHEST, + BFD_RELOC_PPC64_DTPREL16_HIGHESTA, + ++/* AmigaOS4 specific relocations */ ++ BFD_RELOC_PPC_AMIGAOS_BREL, ++ BFD_RELOC_PPC_AMIGAOS_BREL_LO, ++ BFD_RELOC_PPC_AMIGAOS_BREL_HI, ++ BFD_RELOC_PPC_AMIGAOS_BREL_HA, ++ + /* IBM 370/390 relocations */ + BFD_RELOC_I370_D12, + + /* The type of reloc used to build a constructor table - at the moment + probably a 32 bit wide absolute relocation, but the target can choose. + It generally does map to one of the other relocation types. */ +@@ -5904,12 +5914,13 @@ struct bfd + struct mach_o_data_struct *mach_o_data; + struct mach_o_fat_data_struct *mach_o_fat_data; + struct plugin_data_struct *plugin_data; + struct bfd_pef_data_struct *pef_data; + struct bfd_pef_xlib_data_struct *pef_xlib_data; + struct bfd_sym_data_struct *sym_data; ++ struct amiga_data_struct *amiga_data; + void *any; + } + tdata; + + /* Used by the application to hold private data. */ + void *usrdata; +@@ -6215,12 +6226,13 @@ bfd_boolean generic_core_file_matches_executable_p + (bfd_assert (__FILE__,__LINE__), NULL)) + #endif + + enum bfd_flavour + { + bfd_target_unknown_flavour, ++ bfd_target_amiga_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_xcoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, +diff --git a/bfd/bfd.c b/bfd/bfd.c +index eed18960855bdc51be8b57ddba27975afb6b02ef..3487694a541417ec20453ca9116bbb86c383f979 100644 +--- bfd/bfd.c ++++ bfd/bfd.c +@@ -261,12 +261,13 @@ CODE_FRAGMENT + . struct mach_o_data_struct *mach_o_data; + . struct mach_o_fat_data_struct *mach_o_fat_data; + . struct plugin_data_struct *plugin_data; + . struct bfd_pef_data_struct *pef_data; + . struct bfd_pef_xlib_data_struct *pef_xlib_data; + . struct bfd_sym_data_struct *sym_data; ++. struct amiga_data_struct *amiga_data; + . void *any; + . } + . tdata; + . + . {* Used by the application to hold private data. *} + . void *usrdata; +diff --git a/bfd/bfdio.c b/bfd/bfdio.c +index be05581aeb4026addd3f4caf2b185ae73d893a24..a15208b16635c7174592b6ccf26685c4b1d05bc8 100644 +--- bfd/bfdio.c ++++ bfd/bfdio.c +@@ -325,12 +325,37 @@ bfd_seek (bfd *abfd, file_ptr position, int direction) + + if (abfd->iovec) + result = abfd->iovec->bseek (abfd, file_position, direction); + else + result = -1; + ++/* FIXME: The following code was previously used on AmigaOS. It pads the output file */ ++#if 0 ++ { ++ struct stat stat_buf; ++ if (direction == SEEK_CUR) ++ file_position += ftell (f); ++ fflush (f); ++ if (!(result = fstat (fileno (f), &stat_buf)) && ++ file_position > stat_buf.st_size && ++ !(result = fseek (f, stat_buf.st_size, SEEK_SET))) { ++ int zeroes = file_position - stat_buf.st_size; ++ char *buf = calloc (4096, 1); ++ if (buf) { ++ while (zeroes > 0) { ++ int r, x = (zeroes > 4096? 4096 : zeroes); ++ if ((r = write (fileno (f), buf, x))<=0) ++ break; ++ zeroes -= r; ++ } ++ free (buf); ++ } ++ } ++ result = fseek (f, file_position, SEEK_SET); ++ } ++#endif + if (result != 0) + { + int hold_errno = errno; + + /* Force redetermination of `where' field. */ + bfd_tell (abfd); +diff --git a/bfd/config.bfd b/bfd/config.bfd +index 6025f2641b47915c79a7d643963e9d9080e0ed5c..fcbbce847bc65a44ee68deedd93b2943aac9f77f 100644 +--- bfd/config.bfd ++++ bfd/config.bfd +@@ -78,15 +78,17 @@ c30*) targ_archs=bfd_tic30_arch ;; + c4x*) targ_archs=bfd_tic4x_arch ;; + c54x*) targ_archs=bfd_tic54x_arch ;; + cr16*) targ_archs=bfd_cr16_arch ;; + crisv32) targ_archs=bfd_cris_arch ;; + crx*) targ_archs=bfd_crx_arch ;; + dlx*) targ_archs=bfd_dlx_arch ;; ++i[3456]86*) targ_archs=bfd_i386_arch ;; ++i370) targ_archs=bfd_i370_arch ;; + fido*) targ_archs=bfd_m68k_arch ;; + hppa*) targ_archs=bfd_hppa_arch ;; +-i[3-7]86) targ_archs=bfd_i386_arch ;; ++i[3-7]86*) targ_archs=bfd_i386_arch ;; + i370) targ_archs=bfd_i370_arch ;; + lm32) targ_archs=bfd_lm32_arch ;; + m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;; + m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;; + m68*) targ_archs=bfd_m68k_arch ;; + m88*) targ_archs=bfd_m88k_arch ;; +@@ -719,12 +721,17 @@ case "${targ}" in + ;; + i[3-7]86-*-chaos) + targ_defvec=bfd_elf32_i386_vec + targ_selfvecs=i386chaos_vec + ;; + ++ i[3456]86be-*-amithlon*) ++ targ_defvec=bfd_elf32_i386be_amithlon_vec ++ targ_selvecs="bfd_elf32_i386_vec bfd_elf32_i386be_amithlon_vec" ++ ;; ++ + i860-*-mach3* | i860-*-osf1* | i860-*-coff*) + targ_defvec=i860coff_vec + ;; + i860-stardent-sysv4* | i860-stardent-elf*) + targ_defvec=bfd_elf32_i860_little_vec + targ_selvecs="bfd_elf32_i860_vec bfd_elf32_i860_little_vec" +@@ -800,12 +807,17 @@ case "${targ}" in + targ_selvecs="bfd_elf32_m68hc11_vec bfd_elf32_m68hc12_vec" + ;; + + m68*-motorola-sysv*) + targ_defvec=m68ksysvcoff_vec + ;; ++ m68*-*-amigaos*) ++ targ_defvec=amiga_vec ++ targ_selvecs="aout_amiga_vec amiga_vec" ++ targ_underscore=yes ++ ;; + m68*-hp-bsd*) + targ_defvec=hp300bsd_vec + targ_underscore=yes + ;; + m68*-*-aout*) + targ_defvec=aout0_big_vec +@@ -871,13 +883,13 @@ case "${targ}" in + ;; + m68*-ericsson-*) + targ_defvec=sunos_big_vec + targ_selvecs="m68kcoff_vec versados_vec tekhex_vec" + targ_underscore=yes + ;; +- m68*-cbm-*) ++ m68*-cbm-amix) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs=m68kcoff_vec + ;; + m68*-*-psos*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs=ieee_vec +@@ -1164,12 +1176,24 @@ case "${targ}" in + *-*-aix4.[3456789]* | *-*-aix[56789]*) + want64=true;; + *) + targ_cflags=-DSMALL_ARCHIVE;; + esac + ;; ++ powerpc-*-amigaoshunk*) ++ targ_defvec=amiga_vec ++ targ_selvecs="bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec aout_amiga_vec" ++ ;; ++ powerpc-*-amiga*) ++ targ_defvec=bfd_elf32_amigaos_vec ++ targ_selvecs="bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec" ++ ;; ++ powerpc-*-morphos*) ++ targ_defvec=bfd_elf32_morphos_vec ++ targ_selvecs="bfd_elf32_morphos_vec" ++ ;; + #ifdef BFD64 + powerpc64-*-aix*) + targ_defvec=rs6000coff64_vec + targ_selvecs=rs6000coff_vec + want64=true + ;; +diff --git a/bfd/configure b/bfd/configure +index e965796ef43d9346cd917bf20243707633fc632e..018a5913f1d96081342c66a64f0167b11cdb1add 100755 +--- bfd/configure ++++ bfd/configure +@@ -15172,13 +15172,15 @@ do + case "$vec" in + # This list is alphabetized to make it easy to compare + # with the two vector lists in targets.c. For the same reason, + # use one entry per line, even though this leads to long lines. + a_out_adobe_vec) tb="$tb aout-adobe.lo aout32.lo" ;; + aix5coff64_vec) tb="$tb coff64-rs6000.lo xcofflink.lo aix5ppc-core.lo"; target_size=64 ;; ++ amiga_vec) tb="$tb amigaos.lo amigaoslink.lo" ;; + aout0_big_vec) tb="$tb aout0.lo aout32.lo" ;; ++ aout_amiga_vec) tb="$tb aout-amiga.lo aout32.lo";; + aout_arm_big_vec) tb="$tb aout-arm.lo aout32.lo" ;; + aout_arm_little_vec) tb="$tb aout-arm.lo aout32.lo" ;; + apollocoff_vec) tb="$tb coff-apollo.lo" ;; + arm_epoc_pe_big_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;; + arm_epoc_pe_little_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;; + arm_epoc_pei_big_vec) tb="$tb epoc-pei-arm.lo peigen.lo cofflink.lo " ;; +@@ -15195,12 +15197,13 @@ do + armpei_big_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;; + armpei_little_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;; + b_out_vec_big_host) tb="$tb bout.lo aout32.lo" ;; + b_out_vec_little_host) tb="$tb bout.lo aout32.lo" ;; + bfd_pei_ia64_vec) tb="$tb pei-ia64.lo pepigen.lo cofflink.lo"; target_size=64 ;; + bfd_elf32_am33lin_vec) tb="$tb elf32-am33lin.lo elf32.lo $elf" ;; ++ bfd_elf32_amigaos_vec) tb="$tb elf32-amigaos.lo elf32.lo $elf" ;; + bfd_elf32_avr_vec) tb="$tb elf32-avr.lo elf32.lo $elf" ;; + bfd_elf32_bfin_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;; + bfd_elf32_bfinfdpic_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;; + bfd_elf32_big_generic_vec) tb="$tb elf32-gen.lo elf32.lo $elf" ;; + bfd_elf32_bigarc_vec) tb="$tb elf32-arc.lo elf32.lo $elf" ;; + bfd_elf32_bigarm_vec) tb="$tb elf32-arm.lo elf32.lo elf-nacl.lo elf-vxworks.lo $elf" ;; +@@ -15231,12 +15234,13 @@ do + bfd_elf32_i370_vec) tb="$tb elf32-i370.lo elf32.lo $elf" ;; + bfd_elf32_i386_sol2_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_freebsd_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_nacl_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_vxworks_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; ++ bfd_elf32_i386be_amithlon_vec) tb="$tb elf32-i386-amithlon.lo elf32.lo $elf" ;; + bfd_elf32_i860_little_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; + bfd_elf32_i860_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; + bfd_elf32_i960_vec) tb="$tb elf32-i960.lo elf32.lo $elf" ;; + bfd_elf32_ia64_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf" ;; + bfd_elf32_ia64_hpux_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf";; + bfd_elf32_ip2k_vec) tb="$tb elf32-ip2k.lo elf32.lo $elf" ;; +@@ -15267,12 +15271,13 @@ do + bfd_elf32_mcore_little_vec) tb="$tb elf32-mcore.lo elf32.lo $elf" ;; + bfd_elf32_mep_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;; + bfd_elf32_mep_little_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;; + bfd_elf32_microblaze_vec) tb="$tb elf32-microblaze.lo elf32.lo $elf" ;; + bfd_elf32_mn10200_vec) tb="$tb elf-m10200.lo elf32.lo $elf" ;; + bfd_elf32_mn10300_vec) tb="$tb elf-m10300.lo elf32.lo $elf" ;; ++ bfd_elf32_morphos_vec) tb="$tb elf32-morphos.lo elf32.lo $elf";; + bfd_elf32_mt_vec) tb="$tb elf32-mt.lo elf32.lo $elf" ;; + bfd_elf32_msp430_vec) tb="$tb elf32-msp430.lo elf32.lo $elf" ;; + bfd_elf32_nbigmips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; + bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; + bfd_elf32_ntradbigmips_vec | bfd_elf32_ntradbigmips_freebsd_vec) + tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; +diff --git a/bfd/configure.host b/bfd/configure.host +index 7c63de58397426d08501dd7a0fd527cb59a9809c..afa7c909a787d9121d01e4e99d8047cf7f11f0b7 100644 +--- bfd/configure.host ++++ bfd/configure.host +@@ -53,12 +53,13 @@ mips64*-*-linux*) host64=true;; + mips64*-*-freebsd* | mips64*-*-kfreebsd*-gnu) host64=true;; + mips*-*-sysv4*) ;; + mips*-*-sysv*) HDEFINES="-G 4" ;; + mips*-*-riscos*) HDEFINES="-G 4" ;; + + m68*-hp-hpux*) HDEFINES=-DHOST_HP300HPUX ;; ++m68*-*-amigaos*) HDEFINES=-mstackextend ;; + + # Some Solaris systems (osol0906 at least) have a libc that doesn't recognise + # the "MS-ANSI" code page name, so we define an override for CP_ACP (sets the + # default code page used by windres/windmc when not specified by a commandline + # option) to select the "WINDOWS-1252" name instead. See PR11280 for details. + *-*-solaris2.11) HDEFINES=-DCP_ACP=1 ;; +diff --git a/bfd/configure.in b/bfd/configure.in +index 4b4cb617ef74f5fb33e4de13856d685f5ffba025..5d882b3701b6e0d93f97be655123a2bb2728d63a 100644 +--- bfd/configure.in ++++ bfd/configure.in +@@ -664,13 +664,15 @@ do + case "$vec" in + # This list is alphabetized to make it easy to compare + # with the two vector lists in targets.c. For the same reason, + # use one entry per line, even though this leads to long lines. + a_out_adobe_vec) tb="$tb aout-adobe.lo aout32.lo" ;; + aix5coff64_vec) tb="$tb coff64-rs6000.lo xcofflink.lo aix5ppc-core.lo"; target_size=64 ;; ++ amiga_vec) tb="$tb amigaos.lo amigaoslink.lo" ;; + aout0_big_vec) tb="$tb aout0.lo aout32.lo" ;; ++ aout_amiga_vec) tb="$tb aout-amiga.lo aout32.lo";; + aout_arm_big_vec) tb="$tb aout-arm.lo aout32.lo" ;; + aout_arm_little_vec) tb="$tb aout-arm.lo aout32.lo" ;; + apollocoff_vec) tb="$tb coff-apollo.lo" ;; + arm_epoc_pe_big_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;; + arm_epoc_pe_little_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;; + arm_epoc_pei_big_vec) tb="$tb epoc-pei-arm.lo peigen.lo cofflink.lo " ;; +@@ -687,12 +689,13 @@ do + armpei_big_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;; + armpei_little_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;; + b_out_vec_big_host) tb="$tb bout.lo aout32.lo" ;; + b_out_vec_little_host) tb="$tb bout.lo aout32.lo" ;; + bfd_pei_ia64_vec) tb="$tb pei-ia64.lo pepigen.lo cofflink.lo"; target_size=64 ;; + bfd_elf32_am33lin_vec) tb="$tb elf32-am33lin.lo elf32.lo $elf" ;; ++ bfd_elf32_amigaos_vec) tb="$tb elf32-amigaos.lo elf32.lo $elf" ;; + bfd_elf32_avr_vec) tb="$tb elf32-avr.lo elf32.lo $elf" ;; + bfd_elf32_bfin_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;; + bfd_elf32_bfinfdpic_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;; + bfd_elf32_big_generic_vec) tb="$tb elf32-gen.lo elf32.lo $elf" ;; + bfd_elf32_bigarc_vec) tb="$tb elf32-arc.lo elf32.lo $elf" ;; + bfd_elf32_bigarm_vec) tb="$tb elf32-arm.lo elf32.lo elf-nacl.lo elf-vxworks.lo $elf" ;; +@@ -723,12 +726,13 @@ do + bfd_elf32_i370_vec) tb="$tb elf32-i370.lo elf32.lo $elf" ;; + bfd_elf32_i386_sol2_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_freebsd_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_nacl_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_vxworks_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; ++ bfd_elf32_i386be_amithlon_vec) tb="$tb elf32-i386-amithlon.lo elf32.lo $elf" ;; + bfd_elf32_i860_little_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; + bfd_elf32_i860_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; + bfd_elf32_i960_vec) tb="$tb elf32-i960.lo elf32.lo $elf" ;; + bfd_elf32_ia64_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf" ;; + bfd_elf32_ia64_hpux_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf";; + bfd_elf32_ip2k_vec) tb="$tb elf32-ip2k.lo elf32.lo $elf" ;; +@@ -759,12 +763,13 @@ do + bfd_elf32_mcore_little_vec) tb="$tb elf32-mcore.lo elf32.lo $elf" ;; + bfd_elf32_mep_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;; + bfd_elf32_mep_little_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;; + bfd_elf32_microblaze_vec) tb="$tb elf32-microblaze.lo elf32.lo $elf" ;; + bfd_elf32_mn10200_vec) tb="$tb elf-m10200.lo elf32.lo $elf" ;; + bfd_elf32_mn10300_vec) tb="$tb elf-m10300.lo elf32.lo $elf" ;; ++ bfd_elf32_morphos_vec) tb="$tb elf32-morphos.lo elf32.lo $elf";; + bfd_elf32_mt_vec) tb="$tb elf32-mt.lo elf32.lo $elf" ;; + bfd_elf32_msp430_vec) tb="$tb elf32-msp430.lo elf32.lo $elf" ;; + bfd_elf32_nbigmips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; + bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; + bfd_elf32_ntradbigmips_vec | bfd_elf32_ntradbigmips_freebsd_vec) + tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; +diff --git a/bfd/doc/Makefile.am b/bfd/doc/Makefile.am +index 7476ee5bab710b6b418072124b473cf0d340b247..1ddc9e3d2153b55f6f26645e5fc584074bb369fd 100644 +--- bfd/doc/Makefile.am ++++ bfd/doc/Makefile.am +@@ -1,11 +1,11 @@ + ## Process this file with automake to generate Makefile.in + + AUTOMAKE_OPTIONS = 1.9 cygnus + +-DOCFILES = aoutx.texi archive.texi archures.texi \ ++DOCFILES = amiga.texi amigalink.texi aoutx.texi archive.texi archures.texi \ + bfdt.texi cache.texi coffcode.texi \ + core.texi elf.texi elfcode.texi format.texi \ + libbfd.texi bfdwin.texi bfdio.texi \ + opncls.texi reloc.texi section.texi \ + syms.texi targets.texi init.texi hash.texi linker.texi \ + mmo.texi \ +@@ -26,12 +26,13 @@ IPROTOS = cache.ip libbfd.ip reloc.ip init.ip archures.ip coffcode.ip + SRCDOC = $(srcdir)/../aoutx.h $(srcdir)/../archive.c \ + $(srcdir)/../archures.c $(srcdir)/../bfd.c \ + $(srcdir)/../bfdio.c $(srcdir)/../bfdwin.c \ + $(srcdir)/../cache.c $(srcdir)/../coffcode.h \ + $(srcdir)/../corefile.c $(srcdir)/../elf.c \ + $(srcdir)/../elfcode.h $(srcdir)/../format.c \ ++ $(srcdir)/../amigaos.c $(srcdir)/../amigaoslink.c \ + $(srcdir)/../libbfd.c $(srcdir)/../opncls.c \ + $(srcdir)/../reloc.c $(srcdir)/../section.c \ + $(srcdir)/../syms.c $(srcdir)/../targets.c \ + $(srcdir)/../hash.c $(srcdir)/../linker.c \ + $(srcdir)/../mmo.c + +@@ -183,12 +184,24 @@ hash.texi: chew.c $(srcdir)/../hash.c $(srcdir)/doc.str + + linker.texi: chew.c $(srcdir)/../linker.c $(srcdir)/doc.str + $(MAKE) $(MKDOC) + ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../linker.c >linker.tmp + $(SHELL) $(srcdir)/../../move-if-change linker.tmp linker.texi + ++s-amiga: $(MKDOC) $(srcdir)/../amigaos.c $(srcdir)/doc.str ++ ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaos.c >amiga.tmp ++ $(srcdir)/../../move-if-change amiga.tmp amiga.texi ++ touch s-amiga ++amiga.texi: s-amiga ++ ++s-amigalink: $(MKDOC) $(srcdir)/../amigaoslink.c $(srcdir)/doc.str ++ ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaoslink.c >amigalink.tmp ++ $(srcdir)/../../move-if-change amigalink.tmp amigalink.texi ++ touch s-amigalink ++amigalink.texi: s-amigalink ++ + LIBBFD_H_DEP = \ + $(srcdir)/../libbfd-in.h \ + $(srcdir)/../init.c \ + $(srcdir)/../libbfd.c \ + $(srcdir)/../bfdio.c \ + $(srcdir)/../bfdwin.c \ +diff --git a/bfd/doc/Makefile.in b/bfd/doc/Makefile.in +index 7ba351d742bf53f9e5f51ad7ef74150295519f1a..67db3caf9886839b8d8f52a2a1878de878bb2f6a 100644 +--- bfd/doc/Makefile.in ++++ bfd/doc/Makefile.in +@@ -268,13 +268,13 @@ target_vendor = @target_vendor@ + tdefaults = @tdefaults@ + top_build_prefix = @top_build_prefix@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ + wordsize = @wordsize@ + AUTOMAKE_OPTIONS = 1.9 cygnus +-DOCFILES = aoutx.texi archive.texi archures.texi \ ++DOCFILES = amiga.texi amigalink.texi aoutx.texi archive.texi archures.texi \ + bfdt.texi cache.texi coffcode.texi \ + core.texi elf.texi elfcode.texi format.texi \ + libbfd.texi bfdwin.texi bfdio.texi \ + opncls.texi reloc.texi section.texi \ + syms.texi targets.texi init.texi hash.texi linker.texi \ + mmo.texi \ +@@ -295,12 +295,13 @@ IPROTOS = cache.ip libbfd.ip reloc.ip init.ip archures.ip coffcode.ip + SRCDOC = $(srcdir)/../aoutx.h $(srcdir)/../archive.c \ + $(srcdir)/../archures.c $(srcdir)/../bfd.c \ + $(srcdir)/../bfdio.c $(srcdir)/../bfdwin.c \ + $(srcdir)/../cache.c $(srcdir)/../coffcode.h \ + $(srcdir)/../corefile.c $(srcdir)/../elf.c \ + $(srcdir)/../elfcode.h $(srcdir)/../format.c \ ++ $(srcdir)/../amigaos.c $(srcdir)/../amigaoslink.c \ + $(srcdir)/../libbfd.c $(srcdir)/../opncls.c \ + $(srcdir)/../reloc.c $(srcdir)/../section.c \ + $(srcdir)/../syms.c $(srcdir)/../targets.c \ + $(srcdir)/../hash.c $(srcdir)/../linker.c \ + $(srcdir)/../mmo.c + +@@ -880,12 +881,24 @@ hash.texi: chew.c $(srcdir)/../hash.c $(srcdir)/doc.str + + linker.texi: chew.c $(srcdir)/../linker.c $(srcdir)/doc.str + $(MAKE) $(MKDOC) + ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../linker.c >linker.tmp + $(SHELL) $(srcdir)/../../move-if-change linker.tmp linker.texi + ++s-amiga: $(MKDOC) $(srcdir)/../amigaos.c $(srcdir)/doc.str ++ ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaos.c >amiga.tmp ++ $(srcdir)/../../move-if-change amiga.tmp amiga.texi ++ touch s-amiga ++amiga.texi: s-amiga ++ ++s-amigalink: $(MKDOC) $(srcdir)/../amigaoslink.c $(srcdir)/doc.str ++ ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaoslink.c >amigalink.tmp ++ $(srcdir)/../../move-if-change amigalink.tmp amigalink.texi ++ touch s-amigalink ++amigalink.texi: s-amigalink ++ + libbfd.h: $(LIBBFD_H_DEP) + echo "$(LIBBFD_H_DEP)" | sed -f $(srcdir)/header.sed > $@ + for file in $(LIBBFD_H_DEP); do \ + case $$file in \ + *-in.h) cat $$file >> $@ ;; \ + */header.sed) break ;; \ +diff --git a/bfd/doc/bfd.texinfo b/bfd/doc/bfd.texinfo +index 45ffa73240ea22a74debe916fcd7e068a947a7dc..7b9774b71a3cb9b3c154c8c75a41de29a6813146 100644 +--- bfd/doc/bfd.texinfo ++++ bfd/doc/bfd.texinfo +@@ -286,12 +286,13 @@ structures. + @chapter BFD back ends + @menu + * What to Put Where:: + * aout :: a.out backends + * coff :: coff backends + * elf :: elf backends ++* amiga :: amigaos backend + * mmo :: mmo backend + @ignore + * oasys :: oasys backends + * ieee :: ieee backend + * srecord :: s-record backend + @end ignore +@@ -303,18 +304,22 @@ All of BFD lives in one directory. + @node aout, coff, What to Put Where, BFD back ends + @include aoutx.texi + + @node coff, elf, aout, BFD back ends + @include coffcode.texi + +-@node elf, mmo, coff, BFD back ends ++@node elf, amiga, coff, BFD back ends + @include elf.texi + @c Leave this out until the file has some actual contents... + @c @include elfcode.texi + +-@node mmo, , elf, BFD back ends ++@node amiga, mmo, elf, BFD back ends ++@include amiga.texi ++@include amigalink.texi ++ ++@node mmo, , amiga, BFD back ends + @include mmo.texi + + @node GNU Free Documentation License, BFD Index, BFD back ends, Top + @include fdl.texi + + @node BFD Index, , GNU Free Documentation License, Top +diff --git a/bfd/elf32-amiga.c b/bfd/elf32-amiga.c +new file mode 100644 +index 0000000000000000000000000000000000000000..cf6c6cb9efdd15c786932adedd2476ec3a4bc08d +--- /dev/null ++++ bfd/elf32-amiga.c +@@ -0,0 +1,3844 @@ ++/* PowerPC-specific support for 32-bit ELF ++ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 ++ Free Software Foundation, Inc. ++ Written by Ian Lance Taylor, Cygnus Support. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++/* This file is based on a preliminary PowerPC ELF ABI. The ++ information may not match the final PowerPC ELF ABI. It includes ++ suggestions from the in-progress Embedded PowerPC ABI, and that ++ information may also not match. */ ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "bfdlink.h" ++#include "libbfd.h" ++#include "elf-bfd.h" ++#include "elf/ppc.h" ++ ++#define USE_RELA /* we want RELA relocations, not REL */ ++ ++static reloc_howto_type *ppc_elf_reloc_type_lookup ++ PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); ++static void ppc_elf_info_to_howto ++ PARAMS ((bfd *abfd, arelent *cache_ptr, Elf32_Internal_Rela *dst)); ++static void ppc_elf_howto_init PARAMS ((void)); ++static int ppc_elf_sort_rela PARAMS ((const PTR, const PTR)); ++static boolean ppc_elf_relax_section ++ PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *)); ++static bfd_reloc_status_type ppc_elf_addr16_ha_reloc ++ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); ++static boolean ppc_elf_object_p PARAMS ((bfd *)); ++static boolean ppc_elf_set_private_flags PARAMS ((bfd *, flagword)); ++static boolean ppc_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *)); ++ ++static int ppc_elf_additional_program_headers PARAMS ((bfd *)); ++static boolean ppc_elf_modify_segment_map PARAMS ((bfd *)); ++ ++static asection *ppc_elf_create_got ++ PARAMS ((bfd *, struct bfd_link_info *)); ++static boolean ppc_elf_create_dynamic_sections ++ PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static boolean ppc_elf_section_from_shdr PARAMS ((bfd *, ++ Elf32_Internal_Shdr *, ++ const char *)); ++static boolean ppc_elf_fake_sections ++ PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *)); ++ ++static elf_linker_section_t *ppc_elf_create_linker_section ++ PARAMS ((bfd *abfd, ++ struct bfd_link_info *info, ++ enum elf_linker_section_enum)); ++ ++static boolean ppc_elf_check_relocs PARAMS ((bfd *, ++ struct bfd_link_info *, ++ asection *, ++ const Elf_Internal_Rela *)); ++ ++static asection * ppc_elf_gc_mark_hook PARAMS ((asection *sec, ++ struct bfd_link_info *info, ++ Elf_Internal_Rela *rel, ++ struct elf_link_hash_entry *h, ++ Elf_Internal_Sym *sym)); ++ ++static boolean ppc_elf_gc_sweep_hook PARAMS ((bfd *abfd, ++ struct bfd_link_info *info, ++ asection *sec, ++ const Elf_Internal_Rela *relocs)); ++ ++static boolean ppc_elf_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, ++ struct elf_link_hash_entry *)); ++ ++static boolean ppc_elf_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static boolean ppc_elf_relocate_section PARAMS ((bfd *, ++ struct bfd_link_info *info, ++ bfd *, ++ asection *, ++ bfd_byte *, ++ Elf_Internal_Rela *relocs, ++ Elf_Internal_Sym *local_syms, ++ asection **)); ++ ++static boolean ppc_elf_add_symbol_hook PARAMS ((bfd *, ++ struct bfd_link_info *, ++ const Elf_Internal_Sym *, ++ const char **, ++ flagword *, ++ asection **, ++ bfd_vma *)); ++ ++static boolean ppc_elf_finish_dynamic_symbol PARAMS ((bfd *, ++ struct bfd_link_info *, ++ struct elf_link_hash_entry *, ++ Elf_Internal_Sym *)); ++ ++static boolean ppc_elf_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); ++static enum elf_reloc_type_class ppc_elf_reloc_type_class ++ PARAMS ((const Elf_Internal_Rela *)); ++static boolean ppc_elf_grok_prstatus ++ PARAMS ((bfd *abfd, Elf_Internal_Note *note)); ++static boolean ppc_elf_grok_psinfo ++ PARAMS ((bfd *abfd, Elf_Internal_Note *note)); ++ ++#define BRANCH_PREDICT_BIT 0x200000 /* branch prediction bit for branch taken relocs */ ++#define RA_REGISTER_MASK 0x001f0000 /* mask to set RA in memory instructions */ ++#define RA_REGISTER_SHIFT 16 /* value to shift register by to insert RA */ ++ ++/* The name of the dynamic interpreter. This is put in the .interp ++ section. */ ++ ++#define ELF_DYNAMIC_INTERPRETER "sys:libs/runtime-linker" ++ ++/* The size in bytes of an entry in the procedure linkage table. */ ++#define PLT_ENTRY_SIZE 12 ++/* The initial size of the plt reserved for the dynamic linker. */ ++#define PLT_INITIAL_ENTRY_SIZE 72 ++/* The size of the gap between entries in the PLT. */ ++#define PLT_SLOT_SIZE 8 ++/* The number of single-slot PLT entries (the rest use two slots). */ ++#define PLT_NUM_SINGLE_ENTRIES 8192 ++ ++/* Will references to this symbol always reference the symbol ++ in this object? */ ++#define SYMBOL_REFERENCES_LOCAL(INFO, H) \ ++ ((! INFO->shared \ ++ || INFO->symbolic \ ++ || H->dynindx == -1 \ ++ || ELF_ST_VISIBILITY (H->other) == STV_INTERNAL \ ++ || ELF_ST_VISIBILITY (H->other) == STV_HIDDEN) \ ++ && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) ++ ++/* Will _calls_ to this symbol always call the version in this object? */ ++#define SYMBOL_CALLS_LOCAL(INFO, H) \ ++ ((! INFO->shared \ ++ || INFO->symbolic \ ++ || H->dynindx == -1 \ ++ || ELF_ST_VISIBILITY (H->other) != STV_DEFAULT) \ ++ && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) ++ ++static reloc_howto_type *ppc_elf_howto_table[(int) R_PPC_max]; ++ ++static reloc_howto_type ppc_elf_howto_raw[] = { ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_NONE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_NONE", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A standard 32 bit relocation. */ ++ HOWTO (R_PPC_ADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 26 bit branch; the lower two bits must be zero. ++ FIXME: we don't check that, we just clear them. */ ++ HOWTO (R_PPC_ADDR24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A standard 16 bit relocation. */ ++ HOWTO (R_PPC_ADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A 16 bit relocation without overflow. */ ++ HOWTO (R_PPC_ADDR16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of an address. */ ++ HOWTO (R_PPC_ADDR16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of an address, plus 1 if the contents of ++ the low 16 bits, treated as a signed number, is negative. */ ++ HOWTO (R_PPC_ADDR16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_ADDR16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch; the lower two bits must be zero. ++ FIXME: we don't check that, we just clear them. */ ++ HOWTO (R_PPC_ADDR14, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch, for which bit 10 should be set to ++ indicate that the branch is expected to be taken. The lower two ++ bits must be zero. */ ++ HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14_BRTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch, for which bit 10 should be set to ++ indicate that the branch is not expected to be taken. The lower ++ two bits must be zero. */ ++ HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14_BRNTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A relative 26 bit branch; the lower two bits must be zero. */ ++ HOWTO (R_PPC_REL24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch; the lower two bits must be zero. */ ++ HOWTO (R_PPC_REL14, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch. Bit 10 should be set to indicate that ++ the branch is expected to be taken. The lower two bits must be ++ zero. */ ++ HOWTO (R_PPC_REL14_BRTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14_BRTAKEN", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch. Bit 10 should be set to indicate that ++ the branch is not expected to be taken. The lower two bits must ++ be zero. */ ++ HOWTO (R_PPC_REL14_BRNTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14_BRNTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16, but referring to the GOT table entry for the ++ symbol. */ ++ HOWTO (R_PPC_GOT16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_GOT16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_REL24, but referring to the procedure linkage table ++ entry for the symbol. */ ++ HOWTO (R_PPC_PLTREL24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* This is used only by the dynamic linker. The symbol should exist ++ both in the object being run and in some shared library. The ++ dynamic linker copies the data addressed by the symbol from the ++ shared library into the object, because the object being ++ run has to have the data at some particular address. */ ++ HOWTO (R_PPC_COPY, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_COPY", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR32, but used when setting global offset table ++ entries. */ ++ HOWTO (R_PPC_GLOB_DAT, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GLOB_DAT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Marks a procedure linkage table entry for a symbol. */ ++ HOWTO (R_PPC_JMP_SLOT, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_JMP_SLOT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Used only by the dynamic linker. When the object is run, this ++ longword is set to the load address of the object, plus the ++ addend. */ ++ HOWTO (R_PPC_RELATIVE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_RELATIVE", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_REL24, but uses the value of the symbol within the ++ object rather than the final value. Normally used for ++ _GLOBAL_OFFSET_TABLE_. */ ++ HOWTO (R_PPC_LOCAL24PC, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_LOCAL24PC", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR32, but may be unaligned. */ ++ HOWTO (R_PPC_UADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_UADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16, but may be unaligned. */ ++ HOWTO (R_PPC_UADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_UADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 32-bit PC relative */ ++ HOWTO (R_PPC_REL32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* 32-bit relocation to the symbol's procedure linkage table. ++ FIXME: not supported. */ ++ HOWTO (R_PPC_PLT32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 32-bit PC relative relocation to the symbol's procedure linkage table. ++ FIXME: not supported. */ ++ HOWTO (R_PPC_PLTREL32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_PLT16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A sign-extended 16 bit value relative to _SDA_BASE_, for use with ++ small data items. */ ++ HOWTO (R_PPC_SDAREL16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SDAREL16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit lower half section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit upper half section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit upper half adjusted section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++ ++ /* 32 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_ADDR16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of the result of the addend minus the address, ++ plus 1 if the contents of the low 16 bits, treated as a signed number, ++ is negative. */ ++ HOWTO (R_PPC_EMB_NADDR16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from allocating a 4 byte word to hold an ++ address in the .sdata section, and returning the offset from ++ _SDA_BASE_ for that relocation */ ++ HOWTO (R_PPC_EMB_SDAI16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDAI16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from allocating a 4 byte word to hold an ++ address in the .sdata2 section, and returning the offset from ++ _SDA2_BASE_ for that relocation */ ++ HOWTO (R_PPC_EMB_SDA2I16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2I16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with ++ small data items. */ ++ HOWTO (R_PPC_EMB_SDA2REL, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2REL", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit ++ signed offset from the appropriate base, and filling in the register ++ field with the appropriate register (0, 2, or 13). */ ++ HOWTO (R_PPC_EMB_SDA21, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA21", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Relocation not handled: R_PPC_EMB_MRKREF */ ++ /* Relocation not handled: R_PPC_EMB_RELSEC16 */ ++ /* Relocation not handled: R_PPC_EMB_RELST_LO */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HI */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HA */ ++ /* Relocation not handled: R_PPC_EMB_BIT_FLD */ ++ ++ /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling ++ in the 16 bit signed offset from the appropriate base, and filling in the ++ register field with the appropriate register (0, 2, or 13). */ ++ HOWTO (R_PPC_EMB_RELSDA, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_RELSDA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* GNU extension to record C++ vtable hierarchy */ ++ HOWTO (R_PPC_GNU_VTINHERIT, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ NULL, /* special_function */ ++ "R_PPC_GNU_VTINHERIT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* GNU extension to record C++ vtable member usage */ ++ HOWTO (R_PPC_GNU_VTENTRY, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ NULL, /* special_function */ ++ "R_PPC_GNU_VTENTRY", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Phony reloc to handle AIX style TOC entries */ ++ HOWTO (R_PPC_TOC16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_TOC16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++}; ++ ++/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ ++ ++static void ++ppc_elf_howto_init () ++{ ++ unsigned int i, type; ++ ++ for (i = 0; i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); i++) ++ { ++ type = ppc_elf_howto_raw[i].type; ++ BFD_ASSERT (type < sizeof (ppc_elf_howto_table) / sizeof (ppc_elf_howto_table[0])); ++ ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i]; ++ } ++} ++ ++/* This function handles relaxing for the PPC with option --mpc860c0[=<n>]. ++ ++ The MPC860, revision C0 or earlier contains a bug in the die. ++ If all of the following conditions are true, the next instruction ++ to be executed *may* be treated as a no-op. ++ 1/ A forward branch is executed. ++ 2/ The branch is predicted as not taken. ++ 3/ The branch is taken. ++ 4/ The branch is located in the last 5 words of a page. ++ (The EOP limit is 5 by default but may be specified as any value from 1-10.) ++ ++ Our software solution is to detect these problematic branches in a ++ linker pass and modify them as follows: ++ 1/ Unconditional branches - Since these are always predicted taken, ++ there is no problem and no action is required. ++ 2/ Conditional backward branches - No problem, no action required. ++ 3/ Conditional forward branches - Ensure that the "inverse prediction ++ bit" is set (ensure it is predicted taken). ++ 4/ Conditional register branches - Ensure that the "y bit" is set ++ (ensure it is predicted taken). ++*/ ++ ++/* Sort sections by address. */ ++ ++static int ++ppc_elf_sort_rela (arg1, arg2) ++ const PTR arg1; ++ const PTR arg2; ++{ ++ const Elf_Internal_Rela **rela1 = (const Elf_Internal_Rela**) arg1; ++ const Elf_Internal_Rela **rela2 = (const Elf_Internal_Rela**) arg2; ++ ++ /* Sort by offset. */ ++ return ((*rela1)->r_offset - (*rela2)->r_offset); ++} ++ ++static boolean ++ppc_elf_relax_section (abfd, isec, link_info, again) ++ bfd *abfd; ++ asection *isec; ++ struct bfd_link_info *link_info; ++ boolean *again; ++{ ++#define PAGESIZE 0x1000 ++ ++ bfd_byte *contents = NULL; ++ bfd_byte *free_contents = NULL; ++ Elf_Internal_Rela *internal_relocs = NULL; ++ Elf_Internal_Rela *free_relocs = NULL; ++ Elf_Internal_Rela **rela_comb = NULL; ++ int comb_curr, comb_count; ++ ++ /* We never have to do this more than once per input section. */ ++ *again = false; ++ ++ /* If needed, initialize this section's cooked size. */ ++ if (isec->_cooked_size == 0) ++ isec->_cooked_size = isec->_raw_size; ++ ++ /* We're only interested in text sections which overlap the ++ troublesome area at the end of a page. */ ++ if (link_info->mpc860c0 && (isec->flags & SEC_CODE) && isec->_cooked_size) ++ { ++ bfd_vma dot, end_page, end_section; ++ boolean section_modified; ++ ++ /* Get the section contents. */ ++ /* Get cached copy if it exists. */ ++ if (elf_section_data (isec)->this_hdr.contents != NULL) ++ contents = elf_section_data (isec)->this_hdr.contents; ++ else ++ { ++ /* Go get them off disk. */ ++ contents = (bfd_byte *) bfd_malloc (isec->_raw_size); ++ if (contents == NULL) ++ goto error_return; ++ free_contents = contents; ++ ++ if (! bfd_get_section_contents (abfd, isec, contents, ++ (file_ptr) 0, isec->_raw_size)) ++ goto error_return; ++ } ++ ++ comb_curr = 0; ++ comb_count = 0; ++ if (isec->reloc_count) ++ { ++ unsigned n; ++ bfd_size_type amt; ++ ++ /* Get a copy of the native relocations. */ ++ internal_relocs = _bfd_elf32_link_read_relocs ( ++ abfd, isec, (PTR) NULL, (Elf_Internal_Rela *) NULL, ++ link_info->keep_memory); ++ if (internal_relocs == NULL) ++ goto error_return; ++ if (! link_info->keep_memory) ++ free_relocs = internal_relocs; ++ ++ /* Setup a faster access method for the reloc info we need. */ ++ amt = isec->reloc_count; ++ amt *= sizeof (Elf_Internal_Rela*); ++ rela_comb = (Elf_Internal_Rela**) bfd_malloc (amt); ++ if (rela_comb == NULL) ++ goto error_return; ++ for (n = 0; n < isec->reloc_count; ++n) ++ { ++ long r_type; ++ ++ r_type = ELF32_R_TYPE (internal_relocs[n].r_info); ++ if (r_type < 0 || r_type >= (int) R_PPC_max) ++ goto error_return; ++ ++ /* Prologue constants are sometimes present in the ".text" ++ sections and they can be identified by their associated relocation. ++ We don't want to process those words and some others which ++ can also be identified by their relocations. However, not all ++ conditional branches will have a relocation so we will ++ only ignore words that 1) have a reloc, and 2) the reloc ++ is not applicable to a conditional branch. ++ The array rela_comb is built here for use in the EOP scan loop. */ ++ switch (r_type) ++ { ++ case R_PPC_ADDR14_BRNTAKEN: /* absolute, predicted not taken */ ++ case R_PPC_REL14: /* relative cond. br. */ ++ case R_PPC_REL14_BRNTAKEN: /* rel. cond. br., predicted not taken */ ++ /* We should check the instruction. */ ++ break; ++ default: ++ /* The word is not a conditional branch - ignore it. */ ++ rela_comb[comb_count++] = &internal_relocs[n]; ++ break; ++ } ++ } ++ if (comb_count > 1) ++ qsort (rela_comb, (size_t) comb_count, sizeof (int), ppc_elf_sort_rela); ++ } ++ ++ /* Enumerate each EOP region that overlaps this section. */ ++ end_section = isec->vma + isec->_cooked_size; ++ dot = end_page = (isec->vma | (PAGESIZE - 1)) + 1; ++ dot -= link_info->mpc860c0; ++ section_modified = false; ++ if (dot < isec->vma) /* Increment the start position if this section */ ++ dot = isec->vma; /* begins in the middle of its first EOP region. */ ++ for (; ++ dot < end_section; ++ dot += PAGESIZE, end_page += PAGESIZE) ++ { ++ ++ /* Check each word in this EOP region. */ ++ for (; dot < end_page; dot += 4) ++ { ++ bfd_vma isec_offset; ++ unsigned long insn; ++ boolean skip, modified; ++ ++ /* Don't process this word if there is a relocation for it and ++ the relocation indicates the word is not a conditional branch. */ ++ skip = false; ++ isec_offset = dot - isec->vma; ++ for (; comb_curr<comb_count; ++comb_curr) ++ { ++ bfd_vma r_offset; ++ ++ r_offset = rela_comb[comb_curr]->r_offset; ++ if (r_offset >= isec_offset) ++ { ++ if (r_offset == isec_offset) skip = true; ++ break; ++ } ++ } ++ if (skip) continue; ++ ++ /* Check the current word for a problematic conditional branch. */ ++#define BO0(insn) ((insn) & 0x02000000) ++#define BO2(insn) ((insn) & 0x00800000) ++#define BO4(insn) ((insn) & 0x00200000) ++ insn = (unsigned long) bfd_get_32 (abfd, contents + isec_offset); ++ modified = false; ++ if ((insn & 0xFc000000) == 0x40000000) ++ { ++ /* Instruction is BCx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ bfd_vma target; ++ /* This branch is predicted as "normal". ++ If this is a forward branch, it is problematic. */ ++ ++ target = insn & 0x0000Fffc; /*extract*/ ++ target = (target ^ 0x8000) - 0x8000; /*sign extend*/ ++ if ((insn & 0x00000002) == 0) ++ target += dot; /*convert to abs*/ ++ if (target > dot) ++ { ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++ } ++ else if ((insn & 0xFc00Fffe) == 0x4c000420) ++ { ++ /* Instruction is BCCTRx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ /* This branch is predicted as not-taken. ++ If this is a forward branch, it is problematic. ++ Since we can't tell statically if it will branch forward, ++ always set the prediction bit. */ ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++ else if ((insn & 0xFc00Fffe) == 0x4c000020) ++ { ++ /* Instruction is BCLRx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ /* This branch is predicted as not-taken. ++ If this is a forward branch, it is problematic. ++ Since we can't tell statically if it will branch forward, ++ always set the prediction bit. */ ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++#undef BO0 ++#undef BO2 ++#undef BO4 ++ if (modified) ++ { ++ bfd_put_32 (abfd, (bfd_vma) insn, contents + isec_offset); ++ section_modified = true; ++ } ++ } ++ } ++ if (section_modified) ++ { ++ elf_section_data (isec)->this_hdr.contents = contents; ++ free_contents = NULL; ++ } ++ } ++ ++ if (rela_comb != NULL) ++ { ++ free (rela_comb); ++ rela_comb = NULL; ++ } ++ ++ if (free_relocs != NULL) ++ { ++ free (free_relocs); ++ free_relocs = NULL; ++ } ++ ++ if (free_contents != NULL) ++ { ++ if (! link_info->keep_memory) ++ free (free_contents); ++ else ++ { ++ /* Cache the section contents for elf_link_input_bfd. */ ++ elf_section_data (isec)->this_hdr.contents = contents; ++ } ++ free_contents = NULL; ++ } ++ ++ return true; ++ ++error_return: ++ if (rela_comb != NULL) ++ free (rela_comb); ++ if (free_relocs != NULL) ++ free (free_relocs); ++ if (free_contents != NULL) ++ free (free_contents); ++ return false; ++} ++ ++static reloc_howto_type * ++ppc_elf_reloc_type_lookup (abfd, code) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ bfd_reloc_code_real_type code; ++{ ++ enum elf_ppc_reloc_type ppc_reloc = R_PPC_NONE; ++ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ switch ((int) code) ++ { ++ default: ++ return (reloc_howto_type *) NULL; ++ ++ case BFD_RELOC_NONE: ppc_reloc = R_PPC_NONE; break; ++ case BFD_RELOC_32: ppc_reloc = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC_BA26: ppc_reloc = R_PPC_ADDR24; break; ++ case BFD_RELOC_16: ppc_reloc = R_PPC_ADDR16; break; ++ case BFD_RELOC_LO16: ppc_reloc = R_PPC_ADDR16_LO; break; ++ case BFD_RELOC_HI16: ppc_reloc = R_PPC_ADDR16_HI; break; ++ case BFD_RELOC_HI16_S: ppc_reloc = R_PPC_ADDR16_HA; break; ++ case BFD_RELOC_PPC_BA16: ppc_reloc = R_PPC_ADDR14; break; ++ case BFD_RELOC_PPC_BA16_BRTAKEN: ppc_reloc = R_PPC_ADDR14_BRTAKEN; break; ++ case BFD_RELOC_PPC_BA16_BRNTAKEN: ppc_reloc = R_PPC_ADDR14_BRNTAKEN; break; ++ case BFD_RELOC_PPC_B26: ppc_reloc = R_PPC_REL24; break; ++ case BFD_RELOC_PPC_B16: ppc_reloc = R_PPC_REL14; break; ++ case BFD_RELOC_PPC_B16_BRTAKEN: ppc_reloc = R_PPC_REL14_BRTAKEN; break; ++ case BFD_RELOC_PPC_B16_BRNTAKEN: ppc_reloc = R_PPC_REL14_BRNTAKEN; break; ++ case BFD_RELOC_16_GOTOFF: ppc_reloc = R_PPC_GOT16; break; ++ case BFD_RELOC_LO16_GOTOFF: ppc_reloc = R_PPC_GOT16_LO; break; ++ case BFD_RELOC_HI16_GOTOFF: ppc_reloc = R_PPC_GOT16_HI; break; ++ case BFD_RELOC_HI16_S_GOTOFF: ppc_reloc = R_PPC_GOT16_HA; break; ++ case BFD_RELOC_24_PLT_PCREL: ppc_reloc = R_PPC_PLTREL24; break; ++ case BFD_RELOC_PPC_COPY: ppc_reloc = R_PPC_COPY; break; ++ case BFD_RELOC_PPC_GLOB_DAT: ppc_reloc = R_PPC_GLOB_DAT; break; ++ case BFD_RELOC_PPC_LOCAL24PC: ppc_reloc = R_PPC_LOCAL24PC; break; ++ case BFD_RELOC_32_PCREL: ppc_reloc = R_PPC_REL32; break; ++ case BFD_RELOC_32_PLTOFF: ppc_reloc = R_PPC_PLT32; break; ++ case BFD_RELOC_32_PLT_PCREL: ppc_reloc = R_PPC_PLTREL32; break; ++ case BFD_RELOC_LO16_PLTOFF: ppc_reloc = R_PPC_PLT16_LO; break; ++ case BFD_RELOC_HI16_PLTOFF: ppc_reloc = R_PPC_PLT16_HI; break; ++ case BFD_RELOC_HI16_S_PLTOFF: ppc_reloc = R_PPC_PLT16_HA; break; ++ case BFD_RELOC_GPREL16: ppc_reloc = R_PPC_SDAREL16; break; ++ case BFD_RELOC_16_BASEREL: ppc_reloc = R_PPC_SECTOFF; break; ++ case BFD_RELOC_LO16_BASEREL: ppc_reloc = R_PPC_SECTOFF_LO; break; ++ case BFD_RELOC_HI16_BASEREL: ppc_reloc = R_PPC_SECTOFF_HI; break; ++ case BFD_RELOC_HI16_S_BASEREL: ppc_reloc = R_PPC_SECTOFF_HA; break; ++ case BFD_RELOC_CTOR: ppc_reloc = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC_TOC16: ppc_reloc = R_PPC_TOC16; break; ++ case BFD_RELOC_PPC_EMB_NADDR32: ppc_reloc = R_PPC_EMB_NADDR32; break; ++ case BFD_RELOC_PPC_EMB_NADDR16: ppc_reloc = R_PPC_EMB_NADDR16; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_LO: ppc_reloc = R_PPC_EMB_NADDR16_LO; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HI: ppc_reloc = R_PPC_EMB_NADDR16_HI; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HA: ppc_reloc = R_PPC_EMB_NADDR16_HA; break; ++ case BFD_RELOC_PPC_EMB_SDAI16: ppc_reloc = R_PPC_EMB_SDAI16; break; ++ case BFD_RELOC_PPC_EMB_SDA2I16: ppc_reloc = R_PPC_EMB_SDA2I16; break; ++ case BFD_RELOC_PPC_EMB_SDA2REL: ppc_reloc = R_PPC_EMB_SDA2REL; break; ++ case BFD_RELOC_PPC_EMB_SDA21: ppc_reloc = R_PPC_EMB_SDA21; break; ++ case BFD_RELOC_PPC_EMB_MRKREF: ppc_reloc = R_PPC_EMB_MRKREF; break; ++ case BFD_RELOC_PPC_EMB_RELSEC16: ppc_reloc = R_PPC_EMB_RELSEC16; break; ++ case BFD_RELOC_PPC_EMB_RELST_LO: ppc_reloc = R_PPC_EMB_RELST_LO; break; ++ case BFD_RELOC_PPC_EMB_RELST_HI: ppc_reloc = R_PPC_EMB_RELST_HI; break; ++ case BFD_RELOC_PPC_EMB_RELST_HA: ppc_reloc = R_PPC_EMB_RELST_HA; break; ++ case BFD_RELOC_PPC_EMB_BIT_FLD: ppc_reloc = R_PPC_EMB_BIT_FLD; break; ++ case BFD_RELOC_PPC_EMB_RELSDA: ppc_reloc = R_PPC_EMB_RELSDA; break; ++ case BFD_RELOC_VTABLE_INHERIT: ppc_reloc = R_PPC_GNU_VTINHERIT; break; ++ case BFD_RELOC_VTABLE_ENTRY: ppc_reloc = R_PPC_GNU_VTENTRY; break; ++ } ++ ++ return ppc_elf_howto_table[(int) ppc_reloc]; ++}; ++ ++/* Set the howto pointer for a PowerPC ELF reloc. */ ++ ++static void ++ppc_elf_info_to_howto (abfd, cache_ptr, dst) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ arelent *cache_ptr; ++ Elf32_Internal_Rela *dst; ++{ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); ++ cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; ++} ++ ++/* Handle the R_PPC_ADDR16_HA reloc. */ ++ ++static bfd_reloc_status_type ++ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section, ++ output_bfd, error_message) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ arelent *reloc_entry; ++ asymbol *symbol; ++ PTR data ATTRIBUTE_UNUSED; ++ asection *input_section; ++ bfd *output_bfd; ++ char **error_message ATTRIBUTE_UNUSED; ++{ ++ bfd_vma relocation; ++ ++ if (output_bfd != NULL) ++ { ++ reloc_entry->address += input_section->output_offset; ++ return bfd_reloc_ok; ++ } ++ ++ if (reloc_entry->address > input_section->_cooked_size) ++ return bfd_reloc_outofrange; ++ ++ if (bfd_is_com_section (symbol->section)) ++ relocation = 0; ++ else ++ relocation = symbol->value; ++ ++ relocation += symbol->section->output_section->vma; ++ relocation += symbol->section->output_offset; ++ relocation += reloc_entry->addend; ++ ++ reloc_entry->addend += (relocation & 0x8000) << 1; ++ ++ return bfd_reloc_continue; ++} ++ ++/* Fix bad default arch selected for a 32 bit input bfd when the ++ default is 64 bit. */ ++ ++static boolean ++ppc_elf_object_p (abfd) ++ bfd *abfd; ++{ ++ if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64) ++ { ++ Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); ++ ++ if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32) ++ { ++ /* Relies on arch after 64 bit default being 32 bit default. */ ++ abfd->arch_info = abfd->arch_info->next; ++ BFD_ASSERT (abfd->arch_info->bits_per_word == 32); ++ } ++ } ++ return true; ++} ++ ++/* Function to set whether a module needs the -mrelocatable bit set. */ ++ ++static boolean ++ppc_elf_set_private_flags (abfd, flags) ++ bfd *abfd; ++ flagword flags; ++{ ++ BFD_ASSERT (!elf_flags_init (abfd) ++ || elf_elfheader (abfd)->e_flags == flags); ++ ++ elf_elfheader (abfd)->e_flags = flags; ++ elf_flags_init (abfd) = true; ++ return true; ++} ++ ++/* Merge backend specific data from an object file to the output ++ object file when linking */ ++static boolean ++ppc_elf_merge_private_bfd_data (ibfd, obfd) ++ bfd *ibfd; ++ bfd *obfd; ++{ ++ flagword old_flags; ++ flagword new_flags; ++ boolean error; ++ ++ /* Check if we have the same endianess */ ++ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) ++ return false; ++ ++ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour ++ || bfd_get_flavour (obfd) != bfd_target_elf_flavour) ++ return true; ++ ++ new_flags = elf_elfheader (ibfd)->e_flags; ++ old_flags = elf_elfheader (obfd)->e_flags; ++ if (!elf_flags_init (obfd)) /* First call, no flags set */ ++ { ++ elf_flags_init (obfd) = true; ++ elf_elfheader (obfd)->e_flags = new_flags; ++ } ++ ++ else if (new_flags == old_flags) /* Compatible flags are ok */ ++ ; ++ ++ else /* Incompatible flags */ ++ { ++ /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib to be linked ++ with either. */ ++ error = false; ++ if ((new_flags & EF_PPC_RELOCATABLE) != 0 ++ && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: compiled with -mrelocatable and linked with modules compiled normally"), ++ bfd_archive_filename (ibfd)); ++ } ++ else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0 ++ && (old_flags & EF_PPC_RELOCATABLE) != 0) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: compiled normally and linked with modules compiled with -mrelocatable"), ++ bfd_archive_filename (ibfd)); ++ } ++ ++ /* The output is -mrelocatable-lib iff both the input files are. */ ++ if (! (new_flags & EF_PPC_RELOCATABLE_LIB)) ++ elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB; ++ ++ /* The output is -mrelocatable iff it can't be -mrelocatable-lib, ++ but each input file is either -mrelocatable or -mrelocatable-lib. */ ++ if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB) ++ && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)) ++ && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))) ++ elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE; ++ ++ /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if any module uses it */ ++ elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB); ++ ++ new_flags &= ~ (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ old_flags &= ~ (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ ++ /* Warn about any other mismatches */ ++ if (new_flags != old_flags) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"), ++ bfd_archive_filename (ibfd), (long) new_flags, (long) old_flags); ++ } ++ ++ if (error) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++/* Handle a PowerPC specific section when reading an object file. This ++ is called when elfcode.h finds a section with an unknown type. */ ++ ++static boolean ++ppc_elf_section_from_shdr (abfd, hdr, name) ++ bfd *abfd; ++ Elf32_Internal_Shdr *hdr; ++ const char *name; ++{ ++ asection *newsect; ++ flagword flags; ++ ++ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) ++ return false; ++ ++ newsect = hdr->bfd_section; ++ flags = bfd_get_section_flags (abfd, newsect); ++ if (hdr->sh_flags & SHF_EXCLUDE) ++ flags |= SEC_EXCLUDE; ++ ++ if (hdr->sh_type == SHT_ORDERED) ++ flags |= SEC_SORT_ENTRIES; ++ ++ bfd_set_section_flags (abfd, newsect, flags); ++ return true; ++} ++ ++/* Set up any other section flags and such that may be necessary. */ ++ ++static boolean ++ppc_elf_fake_sections (abfd, shdr, asect) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ Elf32_Internal_Shdr *shdr; ++ asection *asect; ++{ ++ if ((asect->flags & SEC_EXCLUDE) != 0) ++ shdr->sh_flags |= SHF_EXCLUDE; ++ ++ if ((asect->flags & SEC_SORT_ENTRIES) != 0) ++ shdr->sh_type = SHT_ORDERED; ++ ++ return true; ++} ++ ++/* Create a special linker section */ ++static elf_linker_section_t * ++ppc_elf_create_linker_section (abfd, info, which) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ enum elf_linker_section_enum which; ++{ ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ elf_linker_section_t *lsect; ++ ++ /* Record the first bfd section that needs the special section */ ++ if (!dynobj) ++ dynobj = elf_hash_table (info)->dynobj = abfd; ++ ++ /* If this is the first time, create the section */ ++ lsect = elf_linker_section (dynobj, which); ++ if (!lsect) ++ { ++ elf_linker_section_t defaults; ++ static elf_linker_section_t zero_section; ++ ++ defaults = zero_section; ++ defaults.which = which; ++ defaults.hole_written_p = false; ++ defaults.alignment = 2; ++ ++ /* Both of these sections are (technically) created by the user ++ putting data in them, so they shouldn't be marked ++ SEC_LINKER_CREATED. ++ ++ The linker creates them so it has somewhere to attach their ++ respective symbols. In fact, if they were empty it would ++ be OK to leave the symbol set to 0 (or any random number), because ++ the appropriate register should never be used. */ ++ defaults.flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY); ++ ++ switch (which) ++ { ++ default: ++ (*_bfd_error_handler) (_("%s: Unknown special linker type %d"), ++ bfd_get_filename (abfd), ++ (int) which); ++ ++ bfd_set_error (bfd_error_bad_value); ++ return (elf_linker_section_t *) 0; ++ ++ case LINKER_SECTION_SDATA: /* .sdata/.sbss section */ ++ defaults.name = ".sdata"; ++ defaults.rel_name = ".rela.sdata"; ++ defaults.bss_name = ".sbss"; ++ defaults.sym_name = "_SDA_BASE_"; ++ defaults.sym_offset = 32768; ++ break; ++ ++ case LINKER_SECTION_SDATA2: /* .sdata2/.sbss2 section */ ++ defaults.name = ".sdata2"; ++ defaults.rel_name = ".rela.sdata2"; ++ defaults.bss_name = ".sbss2"; ++ defaults.sym_name = "_SDA2_BASE_"; ++ defaults.sym_offset = 32768; ++ defaults.flags |= SEC_READONLY; ++ break; ++ } ++ ++ lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults); ++ } ++ ++ return lsect; ++} ++ ++/* If we have a non-zero sized .sbss2 or .PPC.EMB.sbss0 sections, we ++ need to bump up the number of section headers. */ ++ ++static int ++ppc_elf_additional_program_headers (abfd) ++ bfd *abfd; ++{ ++ asection *s; ++ int ret; ++ ++ ret = 0; ++ ++ s = bfd_get_section_by_name (abfd, ".interp"); ++ if (s != NULL) ++ ++ret; ++ ++ s = bfd_get_section_by_name (abfd, ".sbss2"); ++ if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0) ++ ++ret; ++ ++ s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0"); ++ if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0) ++ ++ret; ++ ++ return ret; ++} ++ ++/* Modify the segment map if needed. */ ++ ++static boolean ++ppc_elf_modify_segment_map (abfd) ++ bfd *abfd ATTRIBUTE_UNUSED; ++{ ++ return true; ++} ++ ++/* The powerpc .got has a blrl instruction in it. Mark it executable. */ ++ ++static asection * ++ppc_elf_create_got (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ register asection *s; ++ flagword flags; ++ ++ if (!_bfd_elf_create_got_section (abfd, info)) ++ return NULL; ++ ++ s = bfd_get_section_by_name (abfd, ".got"); ++ if (s == NULL) ++ abort (); ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED); ++ if (!bfd_set_section_flags (abfd, s, flags)) ++ return NULL; ++ return s; ++} ++ ++/* We have to create .dynsbss and .rela.sbss here so that they get mapped ++ to output sections (just like _bfd_elf_create_dynamic_sections has ++ to create .dynbss and .rela.bss). */ ++ ++static boolean ++ppc_elf_create_dynamic_sections (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ register asection *s; ++ flagword flags; ++ ++ if (!ppc_elf_create_got (abfd, info)) ++ return false; ++ ++ if (!_bfd_elf_create_dynamic_sections (abfd, info)) ++ return false; ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED); ++ ++ s = bfd_make_section (abfd, ".dynsbss"); ++ if (s == NULL ++ || ! bfd_set_section_flags (abfd, s, SEC_ALLOC)) ++ return false; ++ ++ if (! info->shared) ++ { ++ s = bfd_make_section (abfd, ".rela.sbss"); ++ if (s == NULL ++ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) ++ || ! bfd_set_section_alignment (abfd, s, 2)) ++ return false; ++ } ++ ++ s = bfd_get_section_by_name (abfd, ".plt"); ++ if (s == NULL) ++ abort (); ++ ++ flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED; ++ return bfd_set_section_flags (abfd, s, flags); ++} ++ ++/* Adjust a symbol defined by a dynamic object and referenced by a ++ regular object. The current definition is in some section of the ++ dynamic object, but we're not including those sections. We have to ++ change the definition to something the rest of the link can ++ understand. */ ++ ++static boolean ++ppc_elf_adjust_dynamic_symbol (info, h) ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++{ ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ asection *s; ++ unsigned int power_of_two; ++ bfd_vma plt_offset; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n", h->root.root.string); ++#endif ++ ++ /* Make sure we know what is going on here. */ ++ BFD_ASSERT (dynobj != NULL ++ && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) ++ || h->weakdef != NULL ++ || ((h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_DYNAMIC) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_REF_REGULAR) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_REGULAR) == 0))); ++ ++ /* If this is a function, put it in the procedure linkage table. We ++ will fill in the contents of the procedure linkage table later, ++ when we know the address of the .got section. */ ++ if (h->type == STT_FUNC ++ || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) ++ { ++ if (! elf_hash_table (info)->dynamic_sections_created ++ || SYMBOL_CALLS_LOCAL (info, h) ++ || (info->shared && h->plt.refcount <= 0)) ++ { ++ /* A PLT entry is not required/allowed when: ++ ++ 1. We are not using ld.so; because then the PLT entry ++ can't be set up, so we can't use one. ++ ++ 2. We know for certain that a call to this symbol ++ will go to this object. ++ ++ 3. GC has rendered the entry unused. ++ Note, however, that in an executable all references to the ++ symbol go to the PLT, so we can't turn it off in that case. ++ ??? The correct thing to do here is to reference count ++ all uses of the symbol, not just those to the GOT or PLT. */ ++ h->plt.offset = (bfd_vma) -1; ++ h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; ++ return true; ++ } ++ ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ { ++ if (! bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ } ++ BFD_ASSERT (h->dynindx != -1); ++ ++ s = bfd_get_section_by_name (dynobj, ".plt"); ++ BFD_ASSERT (s != NULL); ++ ++ /* If this is the first .plt entry, make room for the special ++ first entry. */ ++ if (s->_raw_size == 0) ++ s->_raw_size += PLT_INITIAL_ENTRY_SIZE; ++ ++ /* The PowerPC PLT is actually composed of two parts, the first part ++ is 2 words (for a load and a jump), and then there is a remaining ++ word available at the end. */ ++ plt_offset = (PLT_INITIAL_ENTRY_SIZE ++ + (PLT_SLOT_SIZE ++ * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) ++ / PLT_ENTRY_SIZE))); ++ ++ /* If this symbol is not defined in a regular file, and we are ++ not generating a shared library, then set the symbol to this ++ location in the .plt. This is required to make function ++ pointers compare as equal between the normal executable and ++ the shared library. */ ++ if (! info->shared ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ { ++ h->root.u.def.section = s; ++ h->root.u.def.value = plt_offset; ++ } ++ ++ h->plt.offset = plt_offset; ++ ++ /* Make room for this entry. After the 8192nd entry, room ++ for two entries is allocated. */ ++ if ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE ++ >= PLT_NUM_SINGLE_ENTRIES) ++ s->_raw_size += 2 * PLT_ENTRY_SIZE; ++ else ++ s->_raw_size += PLT_ENTRY_SIZE; ++ ++ /* We also need to make an entry in the .rela.plt section. */ ++ s = bfd_get_section_by_name (dynobj, ".rela.plt"); ++ BFD_ASSERT (s != NULL); ++ s->_raw_size += sizeof (Elf32_External_Rela); ++ ++ return true; ++ } ++ else ++ h->plt.offset = (bfd_vma) -1; ++ ++ /* If this is a weak symbol, and there is a real definition, the ++ processor independent code will have arranged for us to see the ++ real definition first, and we can just use the same value. */ ++ if (h->weakdef != NULL) ++ { ++ BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined ++ || h->weakdef->root.type == bfd_link_hash_defweak); ++ h->root.u.def.section = h->weakdef->root.u.def.section; ++ h->root.u.def.value = h->weakdef->root.u.def.value; ++ return true; ++ } ++ ++ /* This is a reference to a symbol defined by a dynamic object which ++ is not a function. */ ++ ++ /* If we are creating a shared library, we must presume that the ++ only references to the symbol are via the global offset table. ++ For such cases we need not do anything here; the relocations will ++ be handled correctly by relocate_section. */ ++ if (info->shared) ++ return true; ++ ++ /* We must allocate the symbol in our .dynbss section, which will ++ become part of the .bss section of the executable. There will be ++ an entry for this symbol in the .dynsym section. The dynamic ++ object will contain position independent code, so all references ++ from the dynamic object to this symbol will go through the global ++ offset table. The dynamic linker will use the .dynsym entry to ++ determine the address it must put in the global offset table, so ++ both the dynamic object and the regular object will refer to the ++ same memory location for the variable. ++ ++ Of course, if the symbol is sufficiently small, we must instead ++ allocate it in .sbss. FIXME: It would be better to do this if and ++ only if there were actually SDAREL relocs for that symbol. */ ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ s = bfd_get_section_by_name (dynobj, ".dynsbss"); ++ else ++ s = bfd_get_section_by_name (dynobj, ".dynbss"); ++ BFD_ASSERT (s != NULL); ++ ++ /* We must generate a R_PPC_COPY reloc to tell the dynamic linker to ++ copy the initial value out of the dynamic object and into the ++ runtime process image. We need to remember the offset into the ++ .rela.bss section we are going to use. */ ++ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) ++ { ++ asection *srel; ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ srel = bfd_get_section_by_name (dynobj, ".rela.sbss"); ++ else ++ srel = bfd_get_section_by_name (dynobj, ".rela.bss"); ++ BFD_ASSERT (srel != NULL); ++ srel->_raw_size += sizeof (Elf32_External_Rela); ++ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; ++ } ++ ++ /* We need to figure out the alignment required for this symbol. I ++ have no idea how ELF linkers handle this. */ ++ power_of_two = bfd_log2 (h->size); ++ if (power_of_two > 4) ++ power_of_two = 4; ++ ++ /* Apply the required alignment. */ ++ s->_raw_size = BFD_ALIGN (s->_raw_size, ++ (bfd_size_type) (1 << power_of_two)); ++ if (power_of_two > bfd_get_section_alignment (dynobj, s)) ++ { ++ if (! bfd_set_section_alignment (dynobj, s, power_of_two)) ++ return false; ++ } ++ ++ /* Define the symbol as being at this point in the section. */ ++ h->root.u.def.section = s; ++ h->root.u.def.value = s->_raw_size; ++ ++ /* Increment the section size to make room for the symbol. */ ++ s->_raw_size += h->size; ++ ++ return true; ++} ++ ++/* Set the sizes of the dynamic sections. */ ++ ++static boolean ++ppc_elf_size_dynamic_sections (output_bfd, info) ++ bfd *output_bfd ATTRIBUTE_UNUSED; ++ struct bfd_link_info *info; ++{ ++ bfd *dynobj; ++ asection *s; ++ boolean plt; ++ boolean relocs; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections called\n"); ++#endif ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ BFD_ASSERT (dynobj != NULL); ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ /* Set the contents of the .interp section to the interpreter. */ ++ if (! info->shared) ++ { ++ s = bfd_get_section_by_name (dynobj, ".interp"); ++ BFD_ASSERT (s != NULL); ++ s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; ++ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; ++ } ++ } ++ else ++ { ++ /* We may have created entries in the .rela.got, .rela.sdata, and ++ .rela.sdata2 sections. However, if we are not creating the ++ dynamic sections, we will not actually use these entries. Reset ++ the size of .rela.got, et al, which will cause it to get ++ stripped from the output file below. */ ++ static char *rela_sections[] = { ".rela.got", ".rela.sdata", ++ ".rela.sdata2", ".rela.sbss", ++ (char *) 0 }; ++ char **p; ++ ++ for (p = rela_sections; *p != (char *) 0; p++) ++ { ++ s = bfd_get_section_by_name (dynobj, *p); ++ if (s != NULL) ++ s->_raw_size = 0; ++ } ++ } ++ ++ /* The check_relocs and adjust_dynamic_symbol entry points have ++ determined the sizes of the various dynamic sections. Allocate ++ memory for them. */ ++ plt = false; ++ relocs = false; ++ for (s = dynobj->sections; s != NULL; s = s->next) ++ { ++ const char *name; ++ boolean strip; ++ ++ if ((s->flags & SEC_LINKER_CREATED) == 0) ++ continue; ++ ++ /* It's OK to base decisions on the section name, because none ++ of the dynobj section names depend upon the input files. */ ++ name = bfd_get_section_name (dynobj, s); ++ ++ strip = false; ++ ++ if (strcmp (name, ".plt") == 0) ++ { ++ if (s->_raw_size == 0) ++ { ++ /* Strip this section if we don't need it; see the ++ comment below. */ ++ strip = true; ++ } ++ else ++ { ++ /* Remember whether there is a PLT. */ ++ plt = true; ++ } ++ } ++ else if (strncmp (name, ".rela", 5) == 0) ++ { ++ if (s->_raw_size == 0) ++ { ++ /* If we don't need this section, strip it from the ++ output file. This is mostly to handle .rela.bss and ++ .rela.plt. We must create both sections in ++ create_dynamic_sections, because they must be created ++ before the linker maps input sections to output ++ sections. The linker does that before ++ adjust_dynamic_symbol is called, and it is that ++ function which decides whether anything needs to go ++ into these sections. */ ++ strip = true; ++ } ++ else ++ { ++ /* Remember whether there are any relocation sections. */ ++ relocs = true; ++ ++ /* We use the reloc_count field as a counter if we need ++ to copy relocs into the output file. */ ++ s->reloc_count = 0; ++ } ++ } ++ else if (strcmp (name, ".got") != 0 ++ && strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sdata2") != 0) ++ { ++ /* It's not one of our sections, so don't allocate space. */ ++ continue; ++ } ++ ++ if (strip) ++ { ++ _bfd_strip_section_from_output (info, s); ++ continue; ++ } ++ ++ /* Allocate memory for the section contents. */ ++ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); ++ if (s->contents == NULL && s->_raw_size != 0) ++ return false; ++ } ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ /* Add some entries to the .dynamic section. We fill in the ++ values later, in ppc_elf_finish_dynamic_sections, but we ++ must add the entries now so that we get the correct size for ++ the .dynamic section. The DT_DEBUG entry is filled in by the ++ dynamic linker and used by the debugger. */ ++#define add_dynamic_entry(TAG, VAL) \ ++ bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL)) ++ ++ if (!info->shared) ++ { ++ if (!add_dynamic_entry (DT_DEBUG, 0)) ++ return false; ++ } ++ ++ if (plt) ++ { ++ if (!add_dynamic_entry (DT_PLTGOT, 0) ++ || !add_dynamic_entry (DT_PLTRELSZ, 0) ++ || !add_dynamic_entry (DT_PLTREL, DT_RELA) ++ || !add_dynamic_entry (DT_JMPREL, 0)) ++ return false; ++ } ++ ++ if (relocs) ++ { ++ if (!add_dynamic_entry (DT_RELA, 0) ++ || !add_dynamic_entry (DT_RELASZ, 0) ++ || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) ++ return false; ++ } ++ ++ if ((info->flags & DF_TEXTREL) != 0) ++ { ++ if (!add_dynamic_entry (DT_TEXTREL, 0)) ++ return false; ++ info->flags |= DF_TEXTREL; ++ } ++ } ++#undef add_dynamic_entry ++ ++ return true; ++} ++ ++/* Look through the relocs for a section during the first phase, and ++ allocate space in the global offset table or procedure linkage ++ table. */ ++ ++static boolean ++ppc_elf_check_relocs (abfd, info, sec, relocs) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ asection *sec; ++ const Elf_Internal_Rela *relocs; ++{ ++ bfd *dynobj; ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; ++ const Elf_Internal_Rela *rel; ++ const Elf_Internal_Rela *rel_end; ++ bfd_signed_vma *local_got_refcounts; ++ elf_linker_section_t *sdata; ++ elf_linker_section_t *sdata2; ++ asection *sreloc; ++ asection *sgot = NULL; ++ asection *srelgot = NULL; ++ ++ if (info->relocateable) ++ return true; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_check_relocs called for section %s in %s\n", ++ bfd_get_section_name (abfd, sec), ++ bfd_archive_filename (abfd)); ++#endif ++ ++ /* Create the linker generated sections all the time so that the ++ special symbols are created. */ ++ ++ if ((sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA)) == NULL) ++ { ++ sdata = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); ++ if (!sdata) ++ return false; ++ } ++ ++ if ((sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2)) == NULL) ++ { ++ sdata2 = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA2); ++ if (!sdata2) ++ return false; ++ } ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ local_got_refcounts = elf_local_got_refcounts (abfd); ++ ++ sym_hashes = elf_sym_hashes (abfd); ++ sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym); ++ if (!elf_bad_symtab (abfd)) ++ sym_hashes_end -= symtab_hdr->sh_info; ++ ++ sreloc = NULL; ++ ++ rel_end = relocs + sec->reloc_count; ++ for (rel = relocs; rel < rel_end; rel++) ++ { ++ unsigned long r_symndx; ++ struct elf_link_hash_entry *h; ++ ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx < symtab_hdr->sh_info) ++ h = NULL; ++ else ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ ++ /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. ++ This shows up in particular in an R_PPC_ADDR32 in the eabi ++ startup code. */ ++ if (h && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) ++ { ++ if (sgot == NULL) ++ { ++ if (dynobj == NULL) ++ elf_hash_table (info)->dynobj = dynobj = abfd; ++ sgot = ppc_elf_create_got (dynobj, info); ++ if (sgot == NULL) ++ return false; ++ } ++ } ++ ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ /* GOT16 relocations */ ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ /* This symbol requires a global offset table entry. */ ++ ++ if (sgot == NULL) ++ { ++ if (dynobj == NULL) ++ elf_hash_table (info)->dynobj = dynobj = abfd; ++ sgot = ppc_elf_create_got (dynobj, info); ++ if (sgot == NULL) ++ return false; ++ } ++ ++ if (srelgot == NULL ++ && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (h != NULL) ++ { ++ if (h->got.refcount == 0) ++ { ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ if (!bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ ++ /* Allocate space in the .got. */ ++ sgot->_raw_size += 4; ++ /* Allocate relocation space. */ ++ srelgot->_raw_size += sizeof (Elf32_External_Rela); ++ } ++ h->got.refcount++; ++ } ++ else ++ { ++ /* This is a global offset table entry for a local symbol. */ ++ if (local_got_refcounts == NULL) ++ { ++ bfd_size_type size; ++ ++ size = symtab_hdr->sh_info; ++ size *= sizeof (bfd_signed_vma); ++ local_got_refcounts ++ = (bfd_signed_vma *) bfd_zalloc (abfd, size); ++ if (local_got_refcounts == NULL) ++ return false; ++ elf_local_got_refcounts (abfd) = local_got_refcounts; ++ } ++ if (local_got_refcounts[r_symndx] == 0) ++ { ++ sgot->_raw_size += 4; ++ ++ /* If we are generating a shared object, we need to ++ output a R_PPC_RELATIVE reloc so that the ++ dynamic linker can adjust this GOT entry. */ ++ if (info->shared) ++ srelgot->_raw_size += sizeof (Elf32_External_Rela); ++ } ++ local_got_refcounts[r_symndx]++; ++ } ++ break; ++ ++ /* Indirect .sdata relocation */ ++ case R_PPC_EMB_SDAI16: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), "R_PPC_EMB_SDAI16")); ++ return false; ++ } ++ ++ if (srelgot == NULL && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata, h, rel)) ++ return false; ++ ++ break; ++ ++ /* Indirect .sdata2 relocation */ ++ case R_PPC_EMB_SDA2I16: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), "R_PPC_EMB_SDA2I16")); ++ return false; ++ } ++ ++ if (srelgot == NULL && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata2, h, rel)) ++ return false; ++ ++ break; ++ ++ case R_PPC_SDAREL16: ++ case R_PPC_EMB_SDA2REL: ++ case R_PPC_EMB_SDA21: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), ++ ppc_elf_howto_table[(int) ELF32_R_TYPE (rel->r_info)]->name)); ++ return false; ++ } ++ break; ++ ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL24: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++#ifdef DEBUG ++ fprintf (stderr, "Reloc requires a PLT entry\n"); ++#endif ++ /* This symbol requires a procedure linkage table entry. We ++ actually build the entry in adjust_dynamic_symbol, ++ because this might be a case of linking PIC code without ++ linking in any dynamic objects, in which case we don't ++ need to generate a procedure linkage table after all. */ ++ ++ if (h == NULL) ++ { ++ /* It does not make sense to have a procedure linkage ++ table entry for a local symbol. */ ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ { ++ if (! bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ } ++ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; ++ h->plt.refcount++; ++ break; ++ ++ /* The following relocations don't need to propagate the ++ relocation if linking a shared object since they are ++ section relative. */ ++ case R_PPC_SECTOFF: ++ case R_PPC_SECTOFF_LO: ++ case R_PPC_SECTOFF_HI: ++ case R_PPC_SECTOFF_HA: ++ break; ++ ++ /* This refers only to functions defined in the shared library */ ++ case R_PPC_LOCAL24PC: ++ break; ++ ++ /* This relocation describes the C++ object vtable hierarchy. ++ Reconstruct it for later use during GC. */ ++ case R_PPC_GNU_VTINHERIT: ++ if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) ++ return false; ++ break; ++ ++ /* This relocation describes which C++ vtable entries are actually ++ used. Record for later use during GC. */ ++ case R_PPC_GNU_VTENTRY: ++ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend)) ++ return false; ++ break; ++ ++ /* When creating a shared object, we must copy these ++ relocs into the output file. We create a reloc ++ section in dynobj and make room for the reloc. */ ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ case R_PPC_REL32: ++ if (h == NULL ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || SYMBOL_REFERENCES_LOCAL (info, h)) ++ break; ++ /* fall through */ ++ ++ default: ++ if (info->shared) ++ { ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_check_relocs need to create relocation for %s\n", ++ (h && h->root.root.string) ? h->root.root.string : "<unknown>"); ++#endif ++ if (sreloc == NULL) ++ { ++ const char *name; ++ ++ name = (bfd_elf_string_from_elf_section ++ (abfd, ++ elf_elfheader (abfd)->e_shstrndx, ++ elf_section_data (sec)->rel_hdr.sh_name)); ++ if (name == NULL) ++ return false; ++ ++ BFD_ASSERT (strncmp (name, ".rela", 5) == 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ++ name + 5) == 0); ++ ++ sreloc = bfd_get_section_by_name (dynobj, name); ++ if (sreloc == NULL) ++ { ++ flagword flags; ++ ++ sreloc = bfd_make_section (dynobj, name); ++ flags = (SEC_HAS_CONTENTS | SEC_READONLY ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ if ((sec->flags & SEC_ALLOC) != 0) ++ flags |= SEC_ALLOC | SEC_LOAD; ++ if (sreloc == NULL ++ || ! bfd_set_section_flags (dynobj, sreloc, flags) ++ || ! bfd_set_section_alignment (dynobj, sreloc, 2)) ++ return false; ++ } ++ if (sec->flags & SEC_READONLY) ++ info->flags |= DF_TEXTREL; ++ } ++ ++ sreloc->_raw_size += sizeof (Elf32_External_Rela); ++ ++ /* FIXME: We should here do what the m68k and i386 ++ backends do: if the reloc is pc-relative, record it ++ in case it turns out that the reloc is unnecessary ++ because the symbol is forced local by versioning or ++ we are linking with -Bdynamic. Fortunately this ++ case is not frequent. */ ++ } ++ ++ break; ++ } ++ } ++ ++ return true; ++} ++ ++/* Return the section that should be marked against GC for a given ++ relocation. */ ++ ++static asection * ++ppc_elf_gc_mark_hook (sec, info, rel, h, sym) ++ asection *sec; ++ struct bfd_link_info *info ATTRIBUTE_UNUSED; ++ Elf_Internal_Rela *rel; ++ struct elf_link_hash_entry *h; ++ Elf_Internal_Sym *sym; ++{ ++ if (h != NULL) ++ { ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_PPC_GNU_VTINHERIT: ++ case R_PPC_GNU_VTENTRY: ++ break; ++ ++ default: ++ switch (h->root.type) ++ { ++ case bfd_link_hash_defined: ++ case bfd_link_hash_defweak: ++ return h->root.u.def.section; ++ ++ case bfd_link_hash_common: ++ return h->root.u.c.p->section; ++ ++ default: ++ break; ++ } ++ } ++ } ++ else ++ return bfd_section_from_elf_index (sec->owner, sym->st_shndx); ++ ++ return NULL; ++} ++ ++/* Update the got entry reference counts for the section being removed. */ ++ ++static boolean ++ppc_elf_gc_sweep_hook (abfd, info, sec, relocs) ++ bfd *abfd; ++ struct bfd_link_info *info ATTRIBUTE_UNUSED; ++ asection *sec; ++ const Elf_Internal_Rela *relocs; ++{ ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes; ++ bfd_signed_vma *local_got_refcounts; ++ const Elf_Internal_Rela *rel, *relend; ++ unsigned long r_symndx; ++ struct elf_link_hash_entry *h; ++ ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ sym_hashes = elf_sym_hashes (abfd); ++ local_got_refcounts = elf_local_got_refcounts (abfd); ++ ++ relend = relocs + sec->reloc_count; ++ for (rel = relocs; rel < relend; rel++) ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ if (h->got.refcount > 0) ++ h->got.refcount--; ++ } ++ else if (local_got_refcounts != NULL) ++ { ++ if (local_got_refcounts[r_symndx] > 0) ++ local_got_refcounts[r_symndx]--; ++ } ++ break; ++ ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL24: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ if (h->plt.refcount > 0) ++ h->plt.refcount--; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return true; ++} ++ ++/* Hook called by the linker routine which adds symbols from an object ++ file. We use it to put .comm items in .sbss, and not .bss. */ ++ ++static boolean ++ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ const Elf_Internal_Sym *sym; ++ const char **namep ATTRIBUTE_UNUSED; ++ flagword *flagsp ATTRIBUTE_UNUSED; ++ asection **secp; ++ bfd_vma *valp; ++{ ++ if (sym->st_shndx == SHN_COMMON ++ && !info->relocateable ++ && sym->st_size <= elf_gp_size (abfd) ++ && info->hash->creator->flavour == bfd_target_elf_flavour) ++ { ++ /* Common symbols less than or equal to -G nn bytes are automatically ++ put into .sdata. */ ++ elf_linker_section_t *sdata ++ = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); ++ ++ if (!sdata->bss_section) ++ { ++ bfd_size_type amt; ++ ++ /* We don't go through bfd_make_section, because we don't ++ want to attach this common section to DYNOBJ. The linker ++ will move the symbols to the appropriate output section ++ when it defines common symbols. */ ++ amt = sizeof (asection); ++ sdata->bss_section = (asection *) bfd_zalloc (abfd, amt); ++ if (sdata->bss_section == NULL) ++ return false; ++ sdata->bss_section->name = sdata->bss_name; ++ sdata->bss_section->flags = SEC_IS_COMMON; ++ sdata->bss_section->output_section = sdata->bss_section; ++ amt = sizeof (asymbol); ++ sdata->bss_section->symbol = (asymbol *) bfd_zalloc (abfd, amt); ++ amt = sizeof (asymbol *); ++ sdata->bss_section->symbol_ptr_ptr = ++ (asymbol **) bfd_zalloc (abfd, amt); ++ if (sdata->bss_section->symbol == NULL ++ || sdata->bss_section->symbol_ptr_ptr == NULL) ++ return false; ++ sdata->bss_section->symbol->name = sdata->bss_name; ++ sdata->bss_section->symbol->flags = BSF_SECTION_SYM; ++ sdata->bss_section->symbol->section = sdata->bss_section; ++ *sdata->bss_section->symbol_ptr_ptr = sdata->bss_section->symbol; ++ } ++ ++ *secp = sdata->bss_section; ++ *valp = sym->st_size; ++ } ++ ++ return true; ++} ++ ++/* Finish up dynamic symbol handling. We set the contents of various ++ dynamic sections here. */ ++ ++static boolean ++ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++ Elf_Internal_Sym *sym; ++{ ++ bfd *dynobj; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s", ++ h->root.root.string); ++#endif ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ BFD_ASSERT (dynobj != NULL); ++ ++ if (h->plt.offset != (bfd_vma) -1) ++ { ++ asection *splt; ++ asection *srela; ++ Elf_Internal_Rela rela; ++ bfd_vma reloc_index; ++ ++#ifdef DEBUG ++ fprintf (stderr, ", plt_offset = %d", h->plt.offset); ++#endif ++ ++ /* This symbol has an entry in the procedure linkage table. Set ++ it up. */ ++ ++ BFD_ASSERT (h->dynindx != -1); ++ ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ srela = bfd_get_section_by_name (dynobj, ".rela.plt"); ++ BFD_ASSERT (splt != NULL && srela != NULL); ++ ++ /* We don't need to fill in the .plt. The ppc dynamic linker ++ will fill it in. */ ++ ++ /* Fill in the entry in the .rela.plt section. */ ++ rela.r_offset = (splt->output_section->vma ++ + splt->output_offset ++ + h->plt.offset); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); ++ rela.r_addend = 0; ++ ++ reloc_index = (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_SLOT_SIZE; ++ if (reloc_index > PLT_NUM_SINGLE_ENTRIES) ++ reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) srela->contents ++ + reloc_index)); ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ { ++ /* Mark the symbol as undefined, rather than as defined in ++ the .plt section. Leave the value alone. */ ++ sym->st_shndx = SHN_UNDEF; ++ /* If the symbol is weak, we do need to clear the value. ++ Otherwise, the PLT entry would provide a definition for ++ the symbol even if the symbol wasn't defined anywhere, ++ and so the symbol would never be NULL. */ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) ++ == 0) ++ sym->st_value = 0; ++ } ++ } ++ ++ if (h->got.offset != (bfd_vma) -1) ++ { ++ asection *sgot; ++ asection *srela; ++ Elf_Internal_Rela rela; ++ ++ /* This symbol has an entry in the global offset table. Set it ++ up. */ ++ ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ srela = bfd_get_section_by_name (dynobj, ".rela.got"); ++ BFD_ASSERT (sgot != NULL && srela != NULL); ++ ++ rela.r_offset = (sgot->output_section->vma ++ + sgot->output_offset ++ + (h->got.offset &~ (bfd_vma) 1)); ++ ++ /* If this is a -Bsymbolic link, and the symbol is defined ++ locally, we just want to emit a RELATIVE reloc. The entry in ++ the global offset table will already have been initialized in ++ the relocate_section function. */ ++ if (info->shared ++ && SYMBOL_REFERENCES_LOCAL (info, h)) ++ { ++ rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ rela.r_addend = (h->root.u.def.value ++ + h->root.u.def.section->output_section->vma ++ + h->root.u.def.section->output_offset); ++ } ++ else ++ { ++ BFD_ASSERT ((h->got.offset & 1) == 0); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_GLOB_DAT); ++ rela.r_addend = 0; ++ } ++ ++ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) srela->contents ++ + srela->reloc_count)); ++ ++srela->reloc_count; ++ } ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) ++ { ++ asection *s; ++ Elf_Internal_Rela rela; ++ ++ /* This symbols needs a copy reloc. Set it up. */ ++ ++#ifdef DEBUG ++ fprintf (stderr, ", copy"); ++#endif ++ ++ BFD_ASSERT (h->dynindx != -1); ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ s = bfd_get_section_by_name (h->root.u.def.section->owner, ++ ".rela.sbss"); ++ else ++ s = bfd_get_section_by_name (h->root.u.def.section->owner, ++ ".rela.bss"); ++ BFD_ASSERT (s != NULL); ++ ++ rela.r_offset = (h->root.u.def.value ++ + h->root.u.def.section->output_section->vma ++ + h->root.u.def.section->output_offset); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY); ++ rela.r_addend = 0; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) s->contents ++ + s->reloc_count)); ++ ++s->reloc_count; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ /* Mark some specially defined symbols as absolute. */ ++ if (strcmp (h->root.root.string, "_DYNAMIC") == 0 ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0) ++ sym->st_shndx = SHN_ABS; ++ ++ return true; ++} ++ ++/* Finish up the dynamic sections. */ ++ ++static boolean ++ppc_elf_finish_dynamic_sections (output_bfd, info) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++{ ++ asection *sdyn; ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ asection *sgot = bfd_get_section_by_name (dynobj, ".got"); ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); ++#endif ++ ++ sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ asection *splt; ++ Elf32_External_Dyn *dyncon, *dynconend; ++ ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ BFD_ASSERT (splt != NULL && sdyn != NULL); ++ ++ dyncon = (Elf32_External_Dyn *) sdyn->contents; ++ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); ++ for (; dyncon < dynconend; dyncon++) ++ { ++ Elf_Internal_Dyn dyn; ++ const char *name; ++ boolean size; ++ ++ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); ++ ++ switch (dyn.d_tag) ++ { ++ case DT_PLTGOT: name = ".plt"; size = false; break; ++ case DT_PLTRELSZ: name = ".rela.plt"; size = true; break; ++ case DT_JMPREL: name = ".rela.plt"; size = false; break; ++ default: name = NULL; size = false; break; ++ } ++ ++ if (name != NULL) ++ { ++ asection *s; ++ ++ s = bfd_get_section_by_name (output_bfd, name); ++ if (s == NULL) ++ dyn.d_un.d_val = 0; ++ else ++ { ++ if (! size) ++ dyn.d_un.d_ptr = s->vma; ++ else ++ { ++ if (s->_cooked_size != 0) ++ dyn.d_un.d_val = s->_cooked_size; ++ else ++ dyn.d_un.d_val = s->_raw_size; ++ } ++ } ++ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); ++ } ++ } ++ } ++ ++ /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can ++ easily find the address of the _GLOBAL_OFFSET_TABLE_. */ ++ if (sgot) ++ { ++ unsigned char *contents = sgot->contents; ++ bfd_put_32 (output_bfd, (bfd_vma) 0x4e800021 /* blrl */, contents); ++ ++ if (sdyn == NULL) ++ bfd_put_32 (output_bfd, (bfd_vma) 0, contents+4); ++ else ++ bfd_put_32 (output_bfd, ++ sdyn->output_section->vma + sdyn->output_offset, ++ contents+4); ++ ++ elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; ++ } ++ ++ return true; ++} ++ ++/* The RELOCATE_SECTION function is called by the ELF backend linker ++ to handle the relocations for a section. ++ ++ The relocs are always passed as Rela structures; if the section ++ actually uses Rel structures, the r_addend field will always be ++ zero. ++ ++ This function is responsible for adjust the section contents as ++ necessary, and (if using Rela relocs and generating a ++ relocateable output file) adjusting the reloc addend as ++ necessary. ++ ++ This function does not have to worry about setting the reloc ++ address or the reloc symbol index. ++ ++ LOCAL_SYMS is a pointer to the swapped in local symbols. ++ ++ LOCAL_SECTIONS is an array giving the section in the input file ++ corresponding to the st_shndx field of each local symbol. ++ ++ The global hash table entry for the global symbols can be found ++ via elf_sym_hashes (input_bfd). ++ ++ When generating relocateable output, this function must handle ++ STB_LOCAL/STT_SECTION symbols specially. The output symbol is ++ going to be the section symbol corresponding to the output ++ section, which means that the addend must be adjusted ++ accordingly. */ ++ ++static boolean ++ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, ++ contents, relocs, local_syms, local_sections) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ bfd *input_bfd; ++ asection *input_section; ++ bfd_byte *contents; ++ Elf_Internal_Rela *relocs; ++ Elf_Internal_Sym *local_syms; ++ asection **local_sections; ++{ ++ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ elf_linker_section_t *sdata = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA) : NULL; ++ elf_linker_section_t *sdata2 = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA2) : NULL; ++ Elf_Internal_Rela *rel = relocs; ++ Elf_Internal_Rela *relend = relocs + input_section->reloc_count; ++ asection *sreloc = NULL; ++ asection *splt; ++ asection *sgot; ++ bfd_vma *local_got_offsets; ++ boolean ret = true; ++ long insn; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_relocate_section called for %s section %s, %ld relocations%s\n", ++ bfd_archive_filename (input_bfd), ++ bfd_section_name(input_bfd, input_section), ++ (long) input_section->reloc_count, ++ (info->relocateable) ? " (relocatable)" : ""); ++#endif ++ ++ if (info->relocateable) ++ return true; ++ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ local_got_offsets = elf_local_got_offsets (input_bfd); ++ ++ splt = sgot = NULL; ++ if (dynobj != NULL) ++ { ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ } ++ ++ for (; rel < relend; rel++) ++ { ++ enum elf_ppc_reloc_type r_type = (enum elf_ppc_reloc_type)ELF32_R_TYPE (rel->r_info); ++ bfd_vma offset = rel->r_offset; ++ bfd_vma addend = rel->r_addend; ++ bfd_reloc_status_type r = bfd_reloc_other; ++ Elf_Internal_Sym *sym = (Elf_Internal_Sym *) 0; ++ asection *sec = (asection *) 0; ++ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) 0; ++ const char *sym_name = (const char *) 0; ++ reloc_howto_type *howto; ++ unsigned long r_symndx; ++ bfd_vma relocation; ++ int will_become_local; ++ ++ /* Unknown relocation handling */ ++ if ((unsigned) r_type >= (unsigned) R_PPC_max ++ || !ppc_elf_howto_table[(int) r_type]) ++ { ++ (*_bfd_error_handler) (_("%s: unknown relocation type %d"), ++ bfd_archive_filename (input_bfd), ++ (int) r_type); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ ++ howto = ppc_elf_howto_table[(int) r_type]; ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ ++ if (r_symndx < symtab_hdr->sh_info) ++ { ++ sym = local_syms + r_symndx; ++ sec = local_sections[r_symndx]; ++ sym_name = "<local symbol>"; ++ ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ addend = rel->r_addend; ++ /* Relocs to local symbols are always resolved. */ ++ will_become_local = 1; ++ } ++ else ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ sym_name = h->root.root.string; ++ ++ /* Can this relocation be resolved immediately? */ ++ will_become_local = SYMBOL_REFERENCES_LOCAL (info, h); ++ ++ if (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ { ++ sec = h->root.u.def.section; ++ if (((r_type == R_PPC_PLT32 ++ || r_type == R_PPC_PLTREL24) ++ && splt != NULL ++ && h->plt.offset != (bfd_vma) -1) ++ || (r_type == R_PPC_LOCAL24PC ++ && sec->output_section == NULL) ++ || ((r_type == R_PPC_GOT16 ++ || r_type == R_PPC_GOT16_LO ++ || r_type == R_PPC_GOT16_HI ++ || r_type == R_PPC_GOT16_HA) ++ && elf_hash_table (info)->dynamic_sections_created ++ && (! info->shared || ! will_become_local)) ++ || (info->shared ++ && ! will_become_local ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ /* Testing SEC_DEBUGGING here may be wrong. ++ It's here to avoid a crash when ++ generating a shared library with DWARF ++ debugging information. */ ++ || ((input_section->flags & SEC_DEBUGGING) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_DYNAMIC) != 0)) ++ && (r_type == R_PPC_ADDR32 ++ || r_type == R_PPC_ADDR24 ++ || r_type == R_PPC_ADDR16 ++ || r_type == R_PPC_ADDR16_LO ++ || r_type == R_PPC_ADDR16_HI ++ || r_type == R_PPC_ADDR16_HA ++ || r_type == R_PPC_ADDR14 ++ || r_type == R_PPC_ADDR14_BRTAKEN ++ || r_type == R_PPC_ADDR14_BRNTAKEN ++ || r_type == R_PPC_COPY ++ || r_type == R_PPC_GLOB_DAT ++ || r_type == R_PPC_JMP_SLOT ++ || r_type == R_PPC_UADDR32 ++ || r_type == R_PPC_UADDR16 ++ || r_type == R_PPC_SDAREL16 ++ || r_type == R_PPC_EMB_NADDR32 ++ || r_type == R_PPC_EMB_NADDR16 ++ || r_type == R_PPC_EMB_NADDR16_LO ++ || r_type == R_PPC_EMB_NADDR16_HI ++ || r_type == R_PPC_EMB_NADDR16_HA ++ || r_type == R_PPC_EMB_SDAI16 ++ || r_type == R_PPC_EMB_SDA2I16 ++ || r_type == R_PPC_EMB_SDA2REL ++ || r_type == R_PPC_EMB_SDA21 ++ || r_type == R_PPC_EMB_MRKREF ++ || r_type == R_PPC_EMB_BIT_FLD ++ || r_type == R_PPC_EMB_RELSDA ++ || ((r_type == R_PPC_REL24 ++ || r_type == R_PPC_REL32 ++ || r_type == R_PPC_REL14 ++ || r_type == R_PPC_REL14_BRTAKEN ++ || r_type == R_PPC_REL14_BRNTAKEN ++ || r_type == R_PPC_RELATIVE) ++ && strcmp (h->root.root.string, ++ "_GLOBAL_OFFSET_TABLE_") != 0)))) ++ { ++ /* In these cases, we don't need the relocation ++ value. We check specially because in some ++ obscure cases sec->output_section will be NULL. */ ++ relocation = 0; ++ } ++ else if (sec->output_section == NULL) ++ { ++ (*_bfd_error_handler) ++ (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"), ++ bfd_archive_filename (input_bfd), h->root.root.string, ++ bfd_get_section_name (input_bfd, input_section)); ++ relocation = 0; ++ } ++ else ++ relocation = (h->root.u.def.value ++ + sec->output_section->vma ++ + sec->output_offset); ++ } ++ else if (h->root.type == bfd_link_hash_undefweak) ++ relocation = 0; ++ else if (info->shared ++ && (!info->symbolic || info->allow_shlib_undefined) ++ && !info->no_undefined ++ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) ++ relocation = 0; ++ else ++ { ++ if (! (*info->callbacks->undefined_symbol) (info, ++ h->root.root.string, ++ input_bfd, ++ input_section, ++ rel->r_offset, ++ (!info->shared ++ || info->no_undefined ++ || ELF_ST_VISIBILITY (h->other)))) ++ return false; ++ relocation = 0; ++ } ++ } ++ ++ switch ((int) r_type) ++ { ++ default: ++ (*_bfd_error_handler) (_("%s: unknown relocation type %d for symbol %s"), ++ bfd_archive_filename (input_bfd), ++ (int) r_type, sym_name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ ++ case (int) R_PPC_NONE: ++ continue; ++ ++ /* Relocations that need no special processing. */ ++ case (int) R_PPC_LOCAL24PC: ++ /* It makes no sense to point a local relocation ++ at a symbol not in this object. */ ++ if (h != NULL ++ && (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && sec->output_section == NULL) ++ { ++ if (! (*info->callbacks->undefined_symbol) (info, ++ h->root.root.string, ++ input_bfd, ++ input_section, ++ rel->r_offset, ++ true)) ++ return false; ++ continue; ++ } ++ break; ++ ++ /* Relocations that may need to be propagated if this is a shared ++ object. */ ++ case (int) R_PPC_REL24: ++ case (int) R_PPC_REL32: ++ case (int) R_PPC_REL14: ++ /* If these relocations are not to a named symbol, they can be ++ handled right here, no need to bother the dynamic linker. */ ++ if (h == NULL ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || SYMBOL_REFERENCES_LOCAL (info, h)) ++ break; ++ /* fall through */ ++ ++ /* Relocations that always need to be propagated if this is a shared ++ object. */ ++ case (int) R_PPC_ADDR32: ++ case (int) R_PPC_ADDR24: ++ case (int) R_PPC_ADDR16: ++ case (int) R_PPC_ADDR16_LO: ++ case (int) R_PPC_ADDR16_HI: ++ case (int) R_PPC_ADDR16_HA: ++ case (int) R_PPC_ADDR14: ++ case (int) R_PPC_UADDR32: ++ case (int) R_PPC_UADDR16: ++ if (info->shared && r_symndx != 0) ++ { ++ Elf_Internal_Rela outrel; ++ int skip; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_relocate_section need to create relocation for %s\n", ++ (h && h->root.root.string) ? h->root.root.string : "<unknown>"); ++#endif ++ ++ /* When generating a shared object, these relocations ++ are copied into the output file to be resolved at run ++ time. */ ++ ++ if (sreloc == NULL) ++ { ++ const char *name; ++ ++ name = (bfd_elf_string_from_elf_section ++ (input_bfd, ++ elf_elfheader (input_bfd)->e_shstrndx, ++ elf_section_data (input_section)->rel_hdr.sh_name)); ++ if (name == NULL) ++ return false; ++ ++ BFD_ASSERT (strncmp (name, ".rela", 5) == 0 ++ && strcmp (bfd_get_section_name (input_bfd, ++ input_section), ++ name + 5) == 0); ++ ++ sreloc = bfd_get_section_by_name (dynobj, name); ++ BFD_ASSERT (sreloc != NULL); ++ } ++ ++ skip = 0; ++ ++ outrel.r_offset = ++ _bfd_elf_section_offset (output_bfd, info, input_section, ++ rel->r_offset); ++ if (outrel.r_offset == (bfd_vma) -1 ++ || outrel.r_offset == (bfd_vma) -2) ++ skip = (int) outrel.r_offset; ++ outrel.r_offset += (input_section->output_section->vma ++ + input_section->output_offset); ++ ++ if (skip) ++ memset (&outrel, 0, sizeof outrel); ++ /* h->dynindx may be -1 if this symbol was marked to ++ become local. */ ++ else if (! will_become_local) ++ { ++ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); ++ outrel.r_addend = rel->r_addend; ++ } ++ else ++ { ++ if (r_type == R_PPC_ADDR32) ++ { ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ outrel.r_addend = relocation + rel->r_addend; ++ } ++ else ++ { ++ long indx; ++ ++ if (h == NULL) ++ sec = local_sections[r_symndx]; ++ else ++ { ++ BFD_ASSERT (h->root.type == bfd_link_hash_defined ++ || (h->root.type ++ == bfd_link_hash_defweak)); ++ sec = h->root.u.def.section; ++ } ++ if (sec != NULL && bfd_is_abs_section (sec)) ++ indx = 0; ++ else if (sec == NULL || sec->owner == NULL) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ else ++ { ++ asection *osec; ++ ++ osec = sec->output_section; ++ indx = elf_section_data (osec)->dynindx; ++ BFD_ASSERT (indx > 0); ++#ifdef DEBUG ++ if (indx <= 0) ++ { ++ printf ("indx=%d section=%s flags=%08x name=%s\n", ++ indx, osec->name, osec->flags, ++ h->root.root.string); ++ } ++#endif ++ } ++ ++ outrel.r_info = ELF32_R_INFO (indx, r_type); ++ outrel.r_addend = relocation + rel->r_addend; ++ } ++ } ++ ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, ++ (((Elf32_External_Rela *) ++ sreloc->contents) ++ + sreloc->reloc_count)); ++ ++sreloc->reloc_count; ++ ++ if (skip == -1) ++ continue; ++ ++ /* This reloc will be computed at runtime. We clear the memory ++ so that it contains predictable value. */ ++ if (! skip ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ || ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE)) ++ { ++ relocation = howto->pc_relative ? outrel.r_offset : 0; ++ addend = 0; ++ break; ++ } ++ } ++ ++ /* Arithmetic adjust relocations that aren't going into a ++ shared object. */ ++ if (r_type == R_PPC_ADDR16_HA ++ /* It's just possible that this symbol is a weak symbol ++ that's not actually defined anywhere. In that case, ++ 'sec' would be NULL, and we should leave the symbol ++ alone (it will be set to zero elsewhere in the link). */ ++ && sec != NULL) ++ { ++ addend += ((relocation + addend) & 0x8000) << 1; ++ } ++ break; ++ ++ /* branch taken prediction relocations */ ++ case (int) R_PPC_ADDR14_BRTAKEN: ++ case (int) R_PPC_REL14_BRTAKEN: ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ if ((relocation - offset) & 0x8000) ++ insn &= ~BRANCH_PREDICT_BIT; ++ else ++ insn |= BRANCH_PREDICT_BIT; ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ break; ++ ++ /* branch not taken predicition relocations */ ++ case (int) R_PPC_ADDR14_BRNTAKEN: ++ case (int) R_PPC_REL14_BRNTAKEN: ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ if ((relocation - offset) & 0x8000) ++ insn |= BRANCH_PREDICT_BIT; ++ else ++ insn &= ~BRANCH_PREDICT_BIT; ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ break; ++ ++ /* GOT16 relocations */ ++ case (int) R_PPC_GOT16: ++ case (int) R_PPC_GOT16_LO: ++ case (int) R_PPC_GOT16_HI: ++ case (int) R_PPC_GOT16_HA: ++ /* Relocation is to the entry for this symbol in the global ++ offset table. */ ++ BFD_ASSERT (sgot != NULL); ++ ++ if (h != NULL) ++ { ++ bfd_vma off; ++ ++ off = h->got.offset; ++ BFD_ASSERT (off != (bfd_vma) -1); ++ ++ if (! elf_hash_table (info)->dynamic_sections_created ++ || (info->shared ++ && SYMBOL_REFERENCES_LOCAL (info, h))) ++ { ++ /* This is actually a static link, or it is a ++ -Bsymbolic link and the symbol is defined ++ locally. We must initialize this entry in the ++ global offset table. Since the offset must ++ always be a multiple of 4, we use the least ++ significant bit to record whether we have ++ initialized it already. ++ ++ When doing a dynamic link, we create a .rela.got ++ relocation entry to initialize the value. This ++ is done in the finish_dynamic_symbol routine. */ ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ bfd_put_32 (output_bfd, relocation, ++ sgot->contents + off); ++ h->got.offset |= 1; ++ } ++ } ++ ++ relocation = sgot->output_offset + off - 4; ++ } ++ else ++ { ++ bfd_vma off; ++ ++ BFD_ASSERT (local_got_offsets != NULL ++ && local_got_offsets[r_symndx] != (bfd_vma) -1); ++ ++ off = local_got_offsets[r_symndx]; ++ ++ /* The offset must always be a multiple of 4. We use ++ the least significant bit to record whether we have ++ already processed this entry. */ ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ ++ if (info->shared) ++ { ++ asection *srelgot; ++ Elf_Internal_Rela outrel; ++ ++ /* We need to generate a R_PPC_RELATIVE reloc ++ for the dynamic linker. */ ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ BFD_ASSERT (srelgot != NULL); ++ ++ outrel.r_offset = (sgot->output_section->vma ++ + sgot->output_offset ++ + off); ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ outrel.r_addend = relocation; ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, ++ (((Elf32_External_Rela *) ++ srelgot->contents) ++ + srelgot->reloc_count)); ++ ++srelgot->reloc_count; ++ relocation = 0; ++ } ++ ++ bfd_put_32 (output_bfd, relocation, sgot->contents + off); ++ local_got_offsets[r_symndx] |= 1; ++ } ++ ++ relocation = sgot->output_offset + off - 4; ++ } ++ break; ++ ++ /* Indirect .sdata relocation */ ++ case (int) R_PPC_EMB_SDAI16: ++ BFD_ASSERT (sdata != NULL); ++ relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, ++ sdata, h, relocation, rel, ++ R_PPC_RELATIVE); ++ break; ++ ++ /* Indirect .sdata2 relocation */ ++ case (int) R_PPC_EMB_SDA2I16: ++ BFD_ASSERT (sdata2 != NULL); ++ relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, ++ sdata2, h, relocation, rel, ++ R_PPC_RELATIVE); ++ break; ++ ++ /* Handle the TOC16 reloc. We want to use the offset within the .got ++ section, not the actual VMA. This is appropriate when generating ++ an embedded ELF object, for which the .got section acts like the ++ AIX .toc section. */ ++ case (int) R_PPC_TOC16: /* phony GOT16 relocations */ ++ BFD_ASSERT (sec != (asection *) 0); ++ BFD_ASSERT (bfd_is_und_section (sec) ++ || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 ++ || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0) ++ ++ addend -= sec->output_section->vma + sec->output_offset + 0x8000; ++ break; ++ ++ case (int) R_PPC_PLTREL24: ++ /* Relocation is to the entry for this symbol in the ++ procedure linkage table. */ ++ BFD_ASSERT (h != NULL); ++ ++ if (h->plt.offset == (bfd_vma) -1 ++ || splt == NULL) ++ { ++ /* We didn't make a PLT entry for this symbol. This ++ happens when statically linking PIC code, or when ++ using -Bsymbolic. */ ++ break; ++ } ++ ++ relocation = (splt->output_section->vma ++ + splt->output_offset ++ + h->plt.offset); ++ break; ++ ++ /* relocate against _SDA_BASE_ */ ++ case (int) R_PPC_SDAREL16: ++ { ++ const char *name; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sbss") != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ } ++ addend -= (sdata->sym_hash->root.u.def.value ++ + sdata->sym_hash->root.u.def.section->output_section->vma ++ + sdata->sym_hash->root.u.def.section->output_offset); ++ } ++ break; ++ ++ /* relocate against _SDA2_BASE_ */ ++ case (int) R_PPC_EMB_SDA2REL: ++ { ++ const char *name; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata2") != 0 && strcmp (name, ".sbss2") != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ addend -= (sdata2->sym_hash->root.u.def.value ++ + sdata2->sym_hash->root.u.def.section->output_section->vma ++ + sdata2->sym_hash->root.u.def.section->output_offset); ++ } ++ break; ++ ++ /* relocate against either _SDA_BASE_, _SDA2_BASE_, or 0 */ ++ case (int) R_PPC_EMB_SDA21: ++ case (int) R_PPC_EMB_RELSDA: ++ { ++ const char *name; ++ int reg; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0) ++ { ++ reg = 13; ++ addend -= (sdata->sym_hash->root.u.def.value ++ + sdata->sym_hash->root.u.def.section->output_section->vma ++ + sdata->sym_hash->root.u.def.section->output_offset); ++ } ++ ++ else if (strcmp (name, ".sdata2") == 0 ++ || strcmp (name, ".sbss2") == 0) ++ { ++ reg = 2; ++ addend -= (sdata2->sym_hash->root.u.def.value ++ + sdata2->sym_hash->root.u.def.section->output_section->vma ++ + sdata2->sym_hash->root.u.def.section->output_offset); ++ } ++ ++ else if (strcmp (name, ".PPC.EMB.sdata0") == 0 ++ || strcmp (name, ".PPC.EMB.sbss0") == 0) ++ { ++ reg = 0; ++ } ++ ++ else ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ ++ if (r_type == R_PPC_EMB_SDA21) ++ { /* fill in register field */ ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ } ++ } ++ break; ++ ++ /* Relocate against the beginning of the section */ ++ case (int) R_PPC_SECTOFF: ++ case (int) R_PPC_SECTOFF_LO: ++ case (int) R_PPC_SECTOFF_HI: ++ BFD_ASSERT (sec != (asection *) 0); ++ addend -= sec->output_section->vma; ++ break; ++ ++ case (int) R_PPC_SECTOFF_HA: ++ BFD_ASSERT (sec != (asection *) 0); ++ addend -= sec->output_section->vma; ++ addend += ((relocation + addend) & 0x8000) << 1; ++ break; ++ ++ /* Negative relocations */ ++ case (int) R_PPC_EMB_NADDR32: ++ case (int) R_PPC_EMB_NADDR16: ++ case (int) R_PPC_EMB_NADDR16_LO: ++ case (int) R_PPC_EMB_NADDR16_HI: ++ addend -= 2 * relocation; ++ break; ++ ++ case (int) R_PPC_EMB_NADDR16_HA: ++ addend -= 2 * relocation; ++ addend += ((relocation + addend) & 0x8000) << 1; ++ break; ++ ++ /* NOP relocation that prevents garbage collecting linkers from omitting a ++ reference. */ ++ case (int) R_PPC_EMB_MRKREF: ++ continue; ++ ++ case (int) R_PPC_COPY: ++ case (int) R_PPC_GLOB_DAT: ++ case (int) R_PPC_JMP_SLOT: ++ case (int) R_PPC_RELATIVE: ++ case (int) R_PPC_PLT32: ++ case (int) R_PPC_PLTREL32: ++ case (int) R_PPC_PLT16_LO: ++ case (int) R_PPC_PLT16_HI: ++ case (int) R_PPC_PLT16_HA: ++ case (int) R_PPC_EMB_RELSEC16: ++ case (int) R_PPC_EMB_RELST_LO: ++ case (int) R_PPC_EMB_RELST_HI: ++ case (int) R_PPC_EMB_RELST_HA: ++ case (int) R_PPC_EMB_BIT_FLD: ++ (*_bfd_error_handler) (_("%s: Relocation %s is not yet supported for symbol %s."), ++ bfd_archive_filename (input_bfd), ++ ppc_elf_howto_table[(int) r_type]->name, ++ sym_name); ++ ++ bfd_set_error (bfd_error_invalid_operation); ++ ret = false; ++ continue; ++ ++ case (int) R_PPC_GNU_VTINHERIT: ++ case (int) R_PPC_GNU_VTENTRY: ++ /* These are no-ops in the end. */ ++ continue; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, offset = %ld, addend = %ld\n", ++ howto->name, ++ (int) r_type, ++ sym_name, ++ r_symndx, ++ (long) offset, ++ (long) addend); ++#endif ++ ++ r = _bfd_final_link_relocate (howto, ++ input_bfd, ++ input_section, ++ contents, ++ offset, ++ relocation, ++ addend); ++ ++ if (r == bfd_reloc_ok) ++ ; ++ else if (r == bfd_reloc_overflow) ++ { ++ const char *name; ++ ++ if (h != NULL) ++ { ++ if (h->root.type == bfd_link_hash_undefweak ++ && howto->pc_relative) ++ { ++ /* Assume this is a call protected by other code that ++ detect the symbol is undefined. If this is the case, ++ we can safely ignore the overflow. If not, the ++ program is hosed anyway, and a little warning isn't ++ going to help. */ ++ ++ continue; ++ } ++ ++ name = h->root.root.string; ++ } ++ else ++ { ++ name = bfd_elf_string_from_elf_section (input_bfd, ++ symtab_hdr->sh_link, ++ sym->st_name); ++ if (name == NULL) ++ continue; ++ if (*name == '\0') ++ name = bfd_section_name (input_bfd, sec); ++ } ++ ++ if (! (*info->callbacks->reloc_overflow) (info, ++ name, ++ howto->name, ++ (bfd_vma) 0, ++ input_bfd, ++ input_section, ++ offset)) ++ return false; ++ } ++ else ++ ret = false; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ return ret; ++} ++ ++static enum elf_reloc_type_class ++ppc_elf_reloc_type_class (rela) ++ const Elf_Internal_Rela *rela; ++{ ++ switch ((int) ELF32_R_TYPE (rela->r_info)) ++ { ++ case R_PPC_RELATIVE: ++ return reloc_class_relative; ++ case R_PPC_REL24: ++ case R_PPC_ADDR24: ++ case R_PPC_JMP_SLOT: ++ return reloc_class_plt; ++ case R_PPC_COPY: ++ return reloc_class_copy; ++ default: ++ return reloc_class_normal; ++ } ++} ++ ++/* Support for core dump NOTE sections */ ++static boolean ++ppc_elf_grok_prstatus (abfd, note) ++ bfd *abfd; ++ Elf_Internal_Note *note; ++{ ++ int offset; ++ unsigned int raw_size; ++ ++ switch (note->descsz) ++ { ++ default: ++ return false; ++ ++ case 268: /* Linux/PPC */ ++ /* pr_cursig */ ++ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); ++ ++ /* pr_pid */ ++ elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); ++ ++ /* pr_reg */ ++ offset = 72; ++ raw_size = 192; ++ ++ break; ++ } ++ ++ /* Make a ".reg/999" section. */ ++ return _bfd_elfcore_make_pseudosection (abfd, ".reg", ++ raw_size, note->descpos + offset); ++} ++ ++static boolean ++ppc_elf_grok_psinfo (abfd, note) ++ bfd *abfd; ++ Elf_Internal_Note *note; ++{ ++ switch (note->descsz) ++ { ++ default: ++ return false; ++ ++ case 128: /* Linux/PPC elf_prpsinfo */ ++ elf_tdata (abfd)->core_program ++ = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); ++ elf_tdata (abfd)->core_command ++ = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); ++ } ++ ++ /* Note that for some reason, a spurious space is tacked ++ onto the end of the args in some (at least one anyway) ++ implementations, so strip it off if it exists. */ ++ ++ { ++ char *command = elf_tdata (abfd)->core_command; ++ int n = strlen (command); ++ ++ if (0 < n && command[n - 1] == ' ') ++ command[n - 1] = '\0'; ++ } ++ ++ return true; ++} ++ ++#define TARGET_BIG_SYM bfd_elf32_amiga_vec ++#define TARGET_BIG_NAME "elf32-amiga" ++#define ELF_ARCH bfd_arch_powerpc ++#define ELF_MACHINE_CODE EM_PPC ++#define ELF_MAXPAGESIZE 0x10000 ++#define elf_info_to_howto ppc_elf_info_to_howto ++ ++#ifdef EM_CYGNUS_POWERPC ++#define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC ++#endif ++ ++#ifdef EM_PPC_OLD ++#define ELF_MACHINE_ALT2 EM_PPC_OLD ++#endif ++ ++#define elf_backend_plt_not_loaded 1 ++#define elf_backend_got_symbol_offset 4 ++#define elf_backend_can_gc_sections 1 ++#define elf_backend_can_refcount 1 ++#define elf_backend_got_header_size 12 ++#define elf_backend_plt_header_size PLT_INITIAL_ENTRY_SIZE ++#define elf_backend_rela_normal 1 ++ ++#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data ++#define bfd_elf32_bfd_relax_section ppc_elf_relax_section ++#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup ++#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags ++#define bfd_elf32_bfd_final_link _bfd_elf32_gc_common_final_link ++ ++#define elf_backend_object_p ppc_elf_object_p ++#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook ++#define elf_backend_gc_sweep_hook ppc_elf_gc_sweep_hook ++#define elf_backend_section_from_shdr ppc_elf_section_from_shdr ++#define elf_backend_relocate_section ppc_elf_relocate_section ++#define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections ++#define elf_backend_check_relocs ppc_elf_check_relocs ++#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol ++#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook ++#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections ++#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol ++#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections ++#define elf_backend_fake_sections ppc_elf_fake_sections ++#define elf_backend_additional_program_headers ppc_elf_additional_program_headers ++#define elf_backend_modify_segment_map ppc_elf_modify_segment_map ++#define elf_backend_grok_prstatus ppc_elf_grok_prstatus ++#define elf_backend_grok_psinfo ppc_elf_grok_psinfo ++#define elf_backend_reloc_type_class ppc_elf_reloc_type_class ++ ++#include "elf32-target.h" +diff --git a/bfd/elf32-i386-amithlon.c b/bfd/elf32-i386-amithlon.c +new file mode 100644 +index 0000000000000000000000000000000000000000..4e029a5e90187a96013ed97e078fba920d95db28 +--- /dev/null ++++ bfd/elf32-i386-amithlon.c +@@ -0,0 +1,198 @@ ++/* Intel IA-32 specific support for 32-bit big endian ELF on Amithlon. ++ Copyright 2002 Free Software Foundation, Inc. ++ Written by Martin Blom. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++#define TARGET_LITTLE_SYM bfd_elf32_i386_amithlon_vec ++#define TARGET_LITTLE_NAME "elf32-i386-amithlon" ++#define TARGET_BIG_SYM bfd_elf32_i386be_amithlon_vec ++#define TARGET_BIG_NAME "elf32-i386be-amithlon" ++#define ELF_ARCH bfd_arch_i386 ++#define ELF_MACHINE_CODE EM_386 ++#define ELF_MAXPAGESIZE 32 //0x1000 ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "elf-bfd.h" ++ ++/* Forward declarations */ ++extern const bfd_target bfd_elf32_i386_amithlon_vec; ++extern const bfd_target bfd_elf32_i386be_amithlon_vec; ++ ++static boolean elf_i386_relocate_section ++ PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, ++ Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); ++ ++static boolean elf_i386_finish_dynamic_sections ++ PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static boolean elf_i386_finish_dynamic_symbol ++ PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, ++ Elf_Internal_Sym *)); ++ ++boolean elf_link_output_relocs ++ PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *)); ++ ++#define swap_xvec(xvec,c) \ ++do { \ ++ xvec->bfd_getx64 = bfd_get ## c ## 64; \ ++ xvec->bfd_getx_signed_64 = bfd_get ## c ## _signed_64; \ ++ xvec->bfd_putx64 = bfd_put ## c ## 64; \ ++ xvec->bfd_getx32 = bfd_get ## c ## 32; \ ++ xvec->bfd_getx_signed_32 = bfd_get ## c ## _signed_32; \ ++ xvec->bfd_putx32 = bfd_put ## c ## 32; \ ++ xvec->bfd_getx16 = bfd_get ## c ## 16; \ ++ xvec->bfd_getx_signed_16 = bfd_get ## c ## _signed_16; \ ++ xvec->bfd_putx16 = bfd_put ## c ## 16; \ ++} while(0) ++ ++/* Relocate a big endian i386 ELF section. */ ++ ++static boolean ++amithlon_relocate_section (output_bfd, info, input_bfd, input_section, ++ contents, relocs, local_syms, local_sections) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ bfd *input_bfd; ++ asection *input_section; ++ bfd_byte *contents; ++ Elf_Internal_Rela *relocs; ++ Elf_Internal_Sym *local_syms; ++ asection **local_sections; ++{ ++ boolean switched_input = false; ++ boolean switched_output = false; ++ boolean rc; ++ ++ /* Since code sections are actually little endian, no matter what ++ endian mode we're operating in, this rather dirty hack is used to ++ make sure the correct data access routines are used. */ ++ ++ if ((bfd_get_section_flags (input_bfd, input_section) & SEC_CODE)) ++ { ++ if (input_bfd->xvec == &bfd_elf32_i386be_amithlon_vec) ++ { ++ switched_input = true; ++ ++ swap_xvec(input_bfd->xvec,l); ++ } ++ ++ if (output_bfd->xvec == &bfd_elf32_i386be_amithlon_vec) ++ { ++ switched_output = true; ++ ++ swap_xvec(output_bfd->xvec,l); ++ } ++ } ++ ++ rc = elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, ++ contents, relocs, ++ local_syms, local_sections); ++ ++ if (switched_input) ++ { ++ swap_xvec(input_bfd->xvec,b); ++ } ++ ++ if (switched_output) ++ { ++ swap_xvec(output_bfd->xvec,b); ++ } ++ ++ return rc; ++} ++ ++static boolean ++amithlon_finish_dynamic_sections (output_bfd, info) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++{ ++ boolean switched_output = false; ++ boolean rc; ++ ++ /* Since code sections are actually little endian, no matter what ++ endian mode we're operating in, this rather dirty hack is used to ++ make sure the correct data access routines are used. */ ++ ++ if (output_bfd->xvec == &bfd_elf32_i386be_amithlon_vec) ++ { ++ switched_output = true; ++ ++ swap_xvec(output_bfd->xvec,l); ++ } ++ ++ rc = elf_i386_finish_dynamic_sections (output_bfd, info); ++ ++ if (switched_output) ++ { ++ swap_xvec(output_bfd->xvec,b); ++ } ++ ++ return rc; ++} ++ ++static boolean ++amithlon_finish_dynamic_symbol (output_bfd, info, h, sym) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++ Elf_Internal_Sym *sym; ++{ ++ boolean switched_output = false; ++ boolean rc; ++ ++ /* Since code sections are actually little endian, no matter what ++ endian mode we're operating in, this rather dirty hack is used to ++ make sure the correct data access routines are used. */ ++ ++ if (output_bfd->xvec == &bfd_elf32_i386be_amithlon_vec) ++ { ++ switched_output = true; ++ ++ swap_xvec(output_bfd->xvec,l); ++ } ++ ++ rc = elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym); ++ ++ if (switched_output) ++ { ++ swap_xvec(output_bfd->xvec,b); ++ } ++ ++ return rc; ++} ++ ++static bfd_size_type ++amithlon_additional_program_headers (abfd) ++ bfd *abfd; ++{ ++// printf("big: %x little: %x\n", ++// &bfd_elf32_i386be_amithlon_vec, ++// &bfd_elf32_i386_amithlon_vec); ++ // headers, text, rodata, data+bss ++ return -2+4; ++} ++ ++#define elf_backend_relocate_section amithlon_relocate_section ++#define elf_backend_finish_dynamic_sections amithlon_finish_dynamic_sections ++#define elf_backend_finish_dynamic_symbol amithlon_finish_dynamic_symbol ++#define elf_backend_additional_program_headers amithlon_additional_program_headers ++ ++#define ELF32_I386_RELOCATABLE_EXECUTABLES 1 ++ ++#include "elf32-i386.c" +diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c +index 0a6b22ec19ec9daee29e49c64c5d3ba2299e99c1..46396c83d45bab97de1470ee44ffa21f9d03e4b4 100644 +--- bfd/elf32-i386.c ++++ bfd/elf32-i386.c +@@ -29,12 +29,16 @@ + #include "elf-vxworks.h" + #include "bfd_stdint.h" + #include "objalloc.h" + #include "hashtab.h" + #include "dwarf2.h" + ++#ifndef ELF32_I386_RELOCATABLE_EXECUTABLES ++#define ELF32_I386_RELOCATABLE_EXECUTABLES 0 ++#endif ++ + /* 386 uses REL relocations instead of RELA. */ + #define USE_REL 1 + + #include "elf/i386.h" + + static reloc_howto_type elf_howto_table[]= +@@ -1779,13 +1783,13 @@ elf_i386_check_relocs (bfd *abfd, + symbol local. + + If on the other hand, we are creating an executable, we + may need to keep relocations for symbols satisfied by a + dynamic library if we manage to avoid copy relocs for the + symbol. */ +- if ((info->shared ++ if (((ELF32_I386_RELOCATABLE_EXECUTABLES || info->shared) + && (sec->flags & SEC_ALLOC) != 0 + && (r_type != R_386_PC32 + || (h != NULL + && (! SYMBOLIC_BIND (info, h) + || h->root.type == bfd_link_hash_defweak + || !h->def_regular)))) +@@ -2410,13 +2414,13 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to be + defined in regular objects. For the normal shared case, discard + space for pc-relative relocs that have become local due to symbol + visibility changes. */ + +- if (info->shared) ++ if (ELF32_I386_RELOCATABLE_EXECUTABLES || info->shared) + { + /* The only reloc that uses pc_count is R_386_PC32, which will + appear on a call or on something like ".long foo - .". We + want calls to protected symbols to resolve directly to the + function rather than going via the plt. If people want + function pointer comparisons to work as expected then they +@@ -3592,13 +3596,13 @@ elf_i386_relocate_section (bfd *output_bfd, + case R_386_32: + case R_386_PC32: + if ((input_section->flags & SEC_ALLOC) == 0 + || is_vxworks_tls) + break; + +- if ((info->shared ++ if (((ELF32_I386_RELOCATABLE_EXECUTABLES || info->shared) + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && (r_type != R_386_PC32 + || !SYMBOL_CALLS_LOCAL (info, h))) + || (ELIMINATE_COPY_RELOCS +@@ -3633,12 +3637,13 @@ elf_i386_relocate_section (bfd *output_bfd, + + input_section->output_offset); + + if (skip) + memset (&outrel, 0, sizeof outrel); + else if (h != NULL + && h->dynindx != -1 ++ && !(ELF32_I386_RELOCATABLE_EXECUTABLES && !info->shared) + && (r_type == R_386_PC32 + || !info->shared + || !SYMBOLIC_BIND (info, h) + || !h->def_regular)) + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + else +@@ -4953,20 +4958,26 @@ elf_i386_add_symbol_hook (bfd * abfd, + #define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol + #define elf_backend_relocs_compatible _bfd_elf_relocs_compatible + #define elf_backend_check_relocs elf_i386_check_relocs + #define elf_backend_copy_indirect_symbol elf_i386_copy_indirect_symbol + #define elf_backend_create_dynamic_sections elf_i386_create_dynamic_sections + #define elf_backend_fake_sections elf_i386_fake_sections ++#ifndef elf_backend_finish_dynamic_sections + #define elf_backend_finish_dynamic_sections elf_i386_finish_dynamic_sections ++#endif ++#ifndef elf_backend_finish_dynamic_symbol + #define elf_backend_finish_dynamic_symbol elf_i386_finish_dynamic_symbol ++#endif + #define elf_backend_gc_mark_hook elf_i386_gc_mark_hook + #define elf_backend_gc_sweep_hook elf_i386_gc_sweep_hook + #define elf_backend_grok_prstatus elf_i386_grok_prstatus + #define elf_backend_grok_psinfo elf_i386_grok_psinfo + #define elf_backend_reloc_type_class elf_i386_reloc_type_class ++#ifndef elf_backend_relocate_section + #define elf_backend_relocate_section elf_i386_relocate_section ++#endif + #define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections + #define elf_backend_always_size_sections elf_i386_always_size_sections + #define elf_backend_omit_section_dynsym \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) + #define elf_backend_plt_sym_val elf_i386_plt_sym_val + #define elf_backend_hash_symbol elf_i386_hash_symbol +diff --git a/bfd/elf32-morphos.c b/bfd/elf32-morphos.c +new file mode 100644 +index 0000000000000000000000000000000000000000..accc2d426bede6c9441313115fcd5ab5f99630f9 +--- /dev/null ++++ bfd/elf32-morphos.c +@@ -0,0 +1,7137 @@ ++/* PowerPC-specific support for 32-bit ELF ++ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 ++ Free Software Foundation, Inc. ++ Written by Ian Lance Taylor, Cygnus Support. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++/* This file is based on a preliminary PowerPC ELF ABI. The ++ information may not match the final PowerPC ELF ABI. It includes ++ suggestions from the in-progress Embedded PowerPC ABI, and that ++ information may also not match. */ ++ ++#define ARCH_SIZE 32 ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "bfdlink.h" ++#include "genlink.h" ++#include "libbfd.h" ++#include "elf-bfd.h" ++#include "elf/ppc.h" ++ ++#define USE_RELA /* we want RELA relocations, not REL */ ++ ++/* Renaming structures, typedefs, macros and functions to be size-specific. */ ++#define Elf_External_Ehdr NAME(Elf,External_Ehdr) ++#define Elf_External_Sym NAME(Elf,External_Sym) ++#define Elf_External_Shdr NAME(Elf,External_Shdr) ++#define Elf_External_Phdr NAME(Elf,External_Phdr) ++#define Elf_External_Rel NAME(Elf,External_Rel) ++#define Elf_External_Rela NAME(Elf,External_Rela) ++#define Elf_External_Dyn NAME(Elf,External_Dyn) ++ ++#define elf_core_file_failing_command NAME(bfd_elf,core_file_failing_command) ++#define elf_core_file_failing_signal NAME(bfd_elf,core_file_failing_signal) ++#define elf_core_file_matches_executable_p \ ++ NAME(bfd_elf,core_file_matches_executable_p) ++#define elf_object_p NAME(bfd_elf,object_p) ++#define elf_core_file_p NAME(bfd_elf,core_file_p) ++#define elf_get_symtab_upper_bound NAME(bfd_elf,get_symtab_upper_bound) ++#define elf_get_dynamic_symtab_upper_bound \ ++ NAME(bfd_elf,get_dynamic_symtab_upper_bound) ++#define elf_swap_reloc_in NAME(bfd_elf,swap_reloc_in) ++#define elf_swap_reloca_in NAME(bfd_elf,swap_reloca_in) ++#define elf_swap_reloc_out NAME(bfd_elf,swap_reloc_out) ++#define elf_swap_reloca_out NAME(bfd_elf,swap_reloca_out) ++#define elf_swap_symbol_in NAME(bfd_elf,swap_symbol_in) ++#define elf_swap_symbol_out NAME(bfd_elf,swap_symbol_out) ++#define elf_swap_phdr_in NAME(bfd_elf,swap_phdr_in) ++#define elf_swap_phdr_out NAME(bfd_elf,swap_phdr_out) ++#define elf_swap_dyn_in NAME(bfd_elf,swap_dyn_in) ++#define elf_swap_dyn_out NAME(bfd_elf,swap_dyn_out) ++#define elf_get_reloc_upper_bound NAME(bfd_elf,get_reloc_upper_bound) ++#define elf_canonicalize_reloc NAME(bfd_elf,canonicalize_reloc) ++#define elf_slurp_symbol_table NAME(bfd_elf,slurp_symbol_table) ++#define elf_get_symtab NAME(bfd_elf,get_symtab) ++#define elf_canonicalize_dynamic_symtab \ ++ NAME(bfd_elf,canonicalize_dynamic_symtab) ++#define elf_make_empty_symbol NAME(bfd_elf,make_empty_symbol) ++#define elf_get_symbol_info NAME(bfd_elf,get_symbol_info) ++#define elf_get_lineno NAME(bfd_elf,get_lineno) ++#define elf_set_arch_mach NAME(bfd_elf,set_arch_mach) ++#define elf_find_nearest_line NAME(bfd_elf,find_nearest_line) ++#define elf_sizeof_headers NAME(bfd_elf,sizeof_headers) ++#define elf_set_section_contents NAME(bfd_elf,set_section_contents) ++#define elf_no_info_to_howto NAME(bfd_elf,no_info_to_howto) ++#define elf_no_info_to_howto_rel NAME(bfd_elf,no_info_to_howto_rel) ++#define elf_find_section NAME(bfd_elf,find_section) ++#define elf_bfd_link_add_symbols NAME(bfd_elf,bfd_link_add_symbols) ++#define elf_add_dynamic_entry NAME(bfd_elf,add_dynamic_entry) ++#define elf_write_shdrs_and_ehdr NAME(bfd_elf,write_shdrs_and_ehdr) ++#define elf_write_out_phdrs NAME(bfd_elf,write_out_phdrs) ++#define elf_write_relocs NAME(bfd_elf,write_relocs) ++#define elf_slurp_reloc_table NAME(bfd_elf,slurp_reloc_table) ++#define elf_link_create_dynamic_sections \ ++ NAME(bfd_elf,link_create_dynamic_sections) ++#define elf_bfd_discard_info NAME(bfd_elf,discard_info) ++#define elf_reloc_symbol_deleted_p NAME(_bfd_elf,reloc_symbol_deleted_p) ++#define elf_link_record_dynamic_symbol _bfd_elf_link_record_dynamic_symbol ++#define elf_bfd_final_link NAME(bfd_elf,bfd_final_link) ++#define elf_create_pointer_linker_section NAME(bfd_elf,create_pointer_linker_section) ++#define elf_finish_pointer_linker_section NAME(bfd_elf,finish_pointer_linker_section) ++#define elf_gc_sections NAME(_bfd_elf,gc_sections) ++#define elf_gc_common_finalize_got_offsets \ ++ NAME(_bfd_elf,gc_common_finalize_got_offsets) ++#define elf_gc_common_final_link NAME(_bfd_elf,gc_common_final_link) ++#define elf_gc_record_vtinherit NAME(_bfd_elf,gc_record_vtinherit) ++#define elf_gc_record_vtentry NAME(_bfd_elf,gc_record_vtentry) ++#define elf_link_record_local_dynamic_symbol \ ++ NAME(_bfd_elf,link_record_local_dynamic_symbol) ++ ++#define ELF_R_INFO(X,Y) ELF32_R_INFO(X,Y) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELFCLASS ELFCLASS32 ++#define FILE_ALIGN 4 ++#define LOG_FILE_ALIGN 2 ++ ++#define H_PUT_WORD H_PUT_32 ++#define H_PUT_SIGNED_WORD H_PUT_S32 ++#define H_GET_WORD H_GET_32 ++#define H_GET_SIGNED_WORD H_GET_S32 ++ ++#define elf_stringtab_init _bfd_elf_stringtab_init ++ ++#define section_from_elf_index bfd_section_from_elf_index ++ ++static int ddr_count; ++static unsigned *ddr_ptr; ++ ++static reloc_howto_type *ppc_elf_reloc_type_lookup ++ PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); ++static void ppc_elf_info_to_howto ++ PARAMS ((bfd *abfd, arelent *cache_ptr, Elf32_Internal_Rela *dst)); ++static void ppc_elf_howto_init PARAMS ((void)); ++static int ppc_elf_sort_rela PARAMS ((const PTR, const PTR)); ++static boolean ppc_elf_relax_section ++ PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *)); ++static bfd_reloc_status_type ppc_elf_addr16_ha_reloc ++ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); ++static boolean ppc_elf_object_p PARAMS ((bfd *)); ++static boolean ppc_elf_set_private_flags PARAMS ((bfd *, flagword)); ++static boolean ppc_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *)); ++ ++static int ppc_elf_additional_program_headers PARAMS ((bfd *)); ++static boolean ppc_elf_modify_segment_map PARAMS ((bfd *)); ++ ++static asection *ppc_elf_create_got ++ PARAMS ((bfd *, struct bfd_link_info *)); ++static boolean ppc_elf_create_dynamic_sections ++ PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static boolean ppc_elf_section_from_shdr PARAMS ((bfd *, ++ Elf32_Internal_Shdr *, ++ const char *)); ++static boolean ppc_elf_fake_sections ++ PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *)); ++ ++static elf_linker_section_t *ppc_elf_create_linker_section ++ PARAMS ((bfd *abfd, ++ struct bfd_link_info *info, ++ enum elf_linker_section_enum)); ++ ++static boolean ppc_elf_check_relocs PARAMS ((bfd *, ++ struct bfd_link_info *, ++ asection *, ++ const Elf_Internal_Rela *)); ++ ++static asection * ppc_elf_gc_mark_hook PARAMS ((asection *sec, ++ struct bfd_link_info *info, ++ Elf_Internal_Rela *rel, ++ struct elf_link_hash_entry *h, ++ Elf_Internal_Sym *sym)); ++ ++static boolean ppc_elf_gc_sweep_hook PARAMS ((bfd *abfd, ++ struct bfd_link_info *info, ++ asection *sec, ++ const Elf_Internal_Rela *relocs)); ++ ++static boolean ppc_elf_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, ++ struct elf_link_hash_entry *)); ++ ++static boolean ppc_elf_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static boolean ppc_elf_relocate_section PARAMS ((bfd *, ++ struct bfd_link_info *info, ++ bfd *, ++ asection *, ++ bfd_byte *, ++ Elf_Internal_Rela *relocs, ++ Elf_Internal_Sym *local_syms, ++ asection **)); ++ ++static boolean ppc_elf_add_symbol_hook PARAMS ((bfd *, ++ struct bfd_link_info *, ++ const Elf_Internal_Sym *, ++ const char **, ++ flagword *, ++ asection **, ++ bfd_vma *)); ++ ++static boolean ppc_elf_finish_dynamic_symbol PARAMS ((bfd *, ++ struct bfd_link_info *, ++ struct elf_link_hash_entry *, ++ Elf_Internal_Sym *)); ++ ++static boolean ppc_elf_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); ++static enum elf_reloc_type_class ppc_elf_reloc_type_class ++ PARAMS ((const Elf_Internal_Rela *)); ++static boolean ppc_elf_grok_prstatus ++ PARAMS ((bfd *abfd, Elf_Internal_Note *note)); ++static boolean ppc_elf_grok_psinfo ++ PARAMS ((bfd *abfd, Elf_Internal_Note *note)); ++ ++#define BRANCH_PREDICT_BIT 0x200000 /* branch prediction bit for branch taken relocs */ ++#define RA_REGISTER_MASK 0x001f0000 /* mask to set RA in memory instructions */ ++#define RA_REGISTER_SHIFT 16 /* value to shift register by to insert RA */ ++ ++/* The name of the dynamic interpreter. This is put in the .interp ++ section. */ ++ ++#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" ++ ++/* The size in bytes of an entry in the procedure linkage table. */ ++#define PLT_ENTRY_SIZE 12 ++/* The initial size of the plt reserved for the dynamic linker. */ ++#define PLT_INITIAL_ENTRY_SIZE 72 ++/* The size of the gap between entries in the PLT. */ ++#define PLT_SLOT_SIZE 8 ++/* The number of single-slot PLT entries (the rest use two slots). */ ++#define PLT_NUM_SINGLE_ENTRIES 8192 ++ ++/* Will references to this symbol always reference the symbol ++ in this object? */ ++#define SYMBOL_REFERENCES_LOCAL(INFO, H) \ ++ ((! INFO->shared \ ++ || INFO->symbolic \ ++ || H->dynindx == -1 \ ++ || ELF_ST_VISIBILITY (H->other) == STV_INTERNAL \ ++ || ELF_ST_VISIBILITY (H->other) == STV_HIDDEN) \ ++ && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) ++ ++/* Will _calls_ to this symbol always call the version in this object? */ ++#define SYMBOL_CALLS_LOCAL(INFO, H) \ ++ ((! INFO->shared \ ++ || INFO->symbolic \ ++ || H->dynindx == -1 \ ++ || ELF_ST_VISIBILITY (H->other) != STV_DEFAULT) \ ++ && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) ++ ++static reloc_howto_type *ppc_elf_howto_table[(int) R_PPC_max]; ++ ++static reloc_howto_type ppc_elf_howto_raw[] = { ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_NONE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_NONE", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A standard 32 bit relocation. */ ++ HOWTO (R_PPC_ADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 26 bit branch; the lower two bits must be zero. ++ FIXME: we don't check that, we just clear them. */ ++ HOWTO (R_PPC_ADDR24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A standard 16 bit relocation. */ ++ HOWTO (R_PPC_ADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A 16 bit relocation without overflow. */ ++ HOWTO (R_PPC_ADDR16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of an address. */ ++ HOWTO (R_PPC_ADDR16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of an address, plus 1 if the contents of ++ the low 16 bits, treated as a signed number, is negative. */ ++ HOWTO (R_PPC_ADDR16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_ADDR16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch; the lower two bits must be zero. ++ FIXME: we don't check that, we just clear them. */ ++ HOWTO (R_PPC_ADDR14, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch, for which bit 10 should be set to ++ indicate that the branch is expected to be taken. The lower two ++ bits must be zero. */ ++ HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14_BRTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch, for which bit 10 should be set to ++ indicate that the branch is not expected to be taken. The lower ++ two bits must be zero. */ ++ HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14_BRNTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A relative 26 bit branch; the lower two bits must be zero. */ ++ HOWTO (R_PPC_REL24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch; the lower two bits must be zero. */ ++ HOWTO (R_PPC_REL14, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch. Bit 10 should be set to indicate that ++ the branch is expected to be taken. The lower two bits must be ++ zero. */ ++ HOWTO (R_PPC_REL14_BRTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14_BRTAKEN", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch. Bit 10 should be set to indicate that ++ the branch is not expected to be taken. The lower two bits must ++ be zero. */ ++ HOWTO (R_PPC_REL14_BRNTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14_BRNTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16, but referring to the GOT table entry for the ++ symbol. */ ++ HOWTO (R_PPC_GOT16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_GOT16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_REL24, but referring to the procedure linkage table ++ entry for the symbol. */ ++ HOWTO (R_PPC_PLTREL24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* This is used only by the dynamic linker. The symbol should exist ++ both in the object being run and in some shared library. The ++ dynamic linker copies the data addressed by the symbol from the ++ shared library into the object, because the object being ++ run has to have the data at some particular address. */ ++ HOWTO (R_PPC_COPY, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_COPY", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR32, but used when setting global offset table ++ entries. */ ++ HOWTO (R_PPC_GLOB_DAT, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GLOB_DAT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Marks a procedure linkage table entry for a symbol. */ ++ HOWTO (R_PPC_JMP_SLOT, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_JMP_SLOT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Used only by the dynamic linker. When the object is run, this ++ longword is set to the load address of the object, plus the ++ addend. */ ++ HOWTO (R_PPC_RELATIVE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_RELATIVE", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_REL24, but uses the value of the symbol within the ++ object rather than the final value. Normally used for ++ _GLOBAL_OFFSET_TABLE_. */ ++ HOWTO (R_PPC_LOCAL24PC, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_LOCAL24PC", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR32, but may be unaligned. */ ++ HOWTO (R_PPC_UADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_UADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16, but may be unaligned. */ ++ HOWTO (R_PPC_UADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_UADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 32-bit PC relative */ ++ HOWTO (R_PPC_REL32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* 32-bit relocation to the symbol's procedure linkage table. ++ FIXME: not supported. */ ++ HOWTO (R_PPC_PLT32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 32-bit PC relative relocation to the symbol's procedure linkage table. ++ FIXME: not supported. */ ++ HOWTO (R_PPC_PLTREL32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_PLT16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A sign-extended 16 bit value relative to _SDA_BASE_, for use with ++ small data items. */ ++ HOWTO (R_PPC_SDAREL16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SDAREL16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit lower half section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit upper half section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit upper half adjusted section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++ ++ /* 32 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_ADDR16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of the result of the addend minus the address, ++ plus 1 if the contents of the low 16 bits, treated as a signed number, ++ is negative. */ ++ HOWTO (R_PPC_EMB_NADDR16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from allocating a 4 byte word to hold an ++ address in the .sdata section, and returning the offset from ++ _SDA_BASE_ for that relocation */ ++ HOWTO (R_PPC_EMB_SDAI16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDAI16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from allocating a 4 byte word to hold an ++ address in the .sdata2 section, and returning the offset from ++ _SDA2_BASE_ for that relocation */ ++ HOWTO (R_PPC_EMB_SDA2I16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2I16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with ++ small data items. */ ++ HOWTO (R_PPC_EMB_SDA2REL, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2REL", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit ++ signed offset from the appropriate base, and filling in the register ++ field with the appropriate register (0, 2, or 13). */ ++ HOWTO (R_PPC_EMB_SDA21, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA21", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Relocation not handled: R_PPC_EMB_MRKREF */ ++ /* Relocation not handled: R_PPC_EMB_RELSEC16 */ ++ /* Relocation not handled: R_PPC_EMB_RELST_LO */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HI */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HA */ ++ /* Relocation not handled: R_PPC_EMB_BIT_FLD */ ++ ++ /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling ++ in the 16 bit signed offset from the appropriate base, and filling in the ++ register field with the appropriate register (0, 2, or 13). */ ++ HOWTO (R_PPC_EMB_RELSDA, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_RELSDA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* GNU extension to record C++ vtable hierarchy */ ++ HOWTO (R_PPC_GNU_VTINHERIT, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ NULL, /* special_function */ ++ "R_PPC_GNU_VTINHERIT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* GNU extension to record C++ vtable member usage */ ++ HOWTO (R_PPC_GNU_VTENTRY, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ NULL, /* special_function */ ++ "R_PPC_GNU_VTENTRY", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Phony reloc to handle AIX style TOC entries */ ++ HOWTO (R_PPC_TOC16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_TOC16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 32-bit relocation relative to _SDA_BASE_ */ ++ HOWTO (R_PPC_MORPHOS_DREL, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_MORPHOS_DREL", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Lower 16 bits of a relocation relative to _SDA_BASE */ ++ HOWTO (R_PPC_MORPHOS_DREL_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ /*complain_overflow_bitfield,*/ /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_MORPHOS_DREL_LO",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Upper 16 bits of a relocation relative to _SDA_BASE */ ++ HOWTO (R_PPC_MORPHOS_DREL_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ /*complain_overflow_bitfield,*/ /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_MORPHOS_DREL_HI",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Upper 16 bits of a relocation relative to _SDA_BASE */ ++ HOWTO (R_PPC_MORPHOS_DREL_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ /*complain_overflow_bitfield,*/ /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_MORPHOS_DREL_HA",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++}; ++ ++/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ ++ ++static void ++ppc_elf_howto_init () ++{ ++ unsigned int i, type; ++ ++ for (i = 0; i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); i++) ++ { ++ type = ppc_elf_howto_raw[i].type; ++ BFD_ASSERT (type < sizeof (ppc_elf_howto_table) / sizeof (ppc_elf_howto_table[0])); ++ ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i]; ++ } ++} ++ ++/* This function handles relaxing for the PPC with option --mpc860c0[=<n>]. ++ ++ The MPC860, revision C0 or earlier contains a bug in the die. ++ If all of the following conditions are true, the next instruction ++ to be executed *may* be treated as a no-op. ++ 1/ A forward branch is executed. ++ 2/ The branch is predicted as not taken. ++ 3/ The branch is taken. ++ 4/ The branch is located in the last 5 words of a page. ++ (The EOP limit is 5 by default but may be specified as any value from 1-10.) ++ ++ Our software solution is to detect these problematic branches in a ++ linker pass and modify them as follows: ++ 1/ Unconditional branches - Since these are always predicted taken, ++ there is no problem and no action is required. ++ 2/ Conditional backward branches - No problem, no action required. ++ 3/ Conditional forward branches - Ensure that the "inverse prediction ++ bit" is set (ensure it is predicted taken). ++ 4/ Conditional register branches - Ensure that the "y bit" is set ++ (ensure it is predicted taken). ++*/ ++ ++/* Sort sections by address. */ ++ ++static int ++ppc_elf_sort_rela (arg1, arg2) ++ const PTR arg1; ++ const PTR arg2; ++{ ++ const Elf_Internal_Rela **rela1 = (const Elf_Internal_Rela**) arg1; ++ const Elf_Internal_Rela **rela2 = (const Elf_Internal_Rela**) arg2; ++ ++ /* Sort by offset. */ ++ return ((*rela1)->r_offset - (*rela2)->r_offset); ++} ++ ++static boolean ++ppc_elf_relax_section (abfd, isec, link_info, again) ++ bfd *abfd; ++ asection *isec; ++ struct bfd_link_info *link_info; ++ boolean *again; ++{ ++#define PAGESIZE 0x1000 ++ ++ bfd_byte *contents = NULL; ++ bfd_byte *free_contents = NULL; ++ Elf_Internal_Rela *internal_relocs = NULL; ++ Elf_Internal_Rela *free_relocs = NULL; ++ Elf_Internal_Rela **rela_comb = NULL; ++ int comb_curr, comb_count; ++ ++ /* We never have to do this more than once per input section. */ ++ *again = false; ++ ++ /* If needed, initialize this section's cooked size. */ ++ if (isec->_cooked_size == 0) ++ isec->_cooked_size = isec->_raw_size; ++ ++ /* We're only interested in text sections which overlap the ++ troublesome area at the end of a page. */ ++ if (link_info->mpc860c0 && (isec->flags & SEC_CODE) && isec->_cooked_size) ++ { ++ bfd_vma dot, end_page, end_section; ++ boolean section_modified; ++ ++ /* Get the section contents. */ ++ /* Get cached copy if it exists. */ ++ if (elf_section_data (isec)->this_hdr.contents != NULL) ++ contents = elf_section_data (isec)->this_hdr.contents; ++ else ++ { ++ /* Go get them off disk. */ ++ contents = (bfd_byte *) bfd_malloc (isec->_raw_size); ++ if (contents == NULL) ++ goto error_return; ++ free_contents = contents; ++ ++ if (! bfd_get_section_contents (abfd, isec, contents, ++ (file_ptr) 0, isec->_raw_size)) ++ goto error_return; ++ } ++ ++ comb_curr = 0; ++ comb_count = 0; ++ if (isec->reloc_count) ++ { ++ unsigned n; ++ bfd_size_type amt; ++ ++ /* Get a copy of the native relocations. */ ++ internal_relocs = _bfd_elf32_link_read_relocs ( ++ abfd, isec, (PTR) NULL, (Elf_Internal_Rela *) NULL, ++ link_info->keep_memory); ++ if (internal_relocs == NULL) ++ goto error_return; ++ if (! link_info->keep_memory) ++ free_relocs = internal_relocs; ++ ++ /* Setup a faster access method for the reloc info we need. */ ++ amt = isec->reloc_count; ++ amt *= sizeof (Elf_Internal_Rela*); ++ rela_comb = (Elf_Internal_Rela**) bfd_malloc (amt); ++ if (rela_comb == NULL) ++ goto error_return; ++ for (n = 0; n < isec->reloc_count; ++n) ++ { ++ long r_type; ++ ++ r_type = ELF32_R_TYPE (internal_relocs[n].r_info); ++ if (r_type < 0 || r_type >= (int) R_PPC_max) ++ goto error_return; ++ ++ /* Prologue constants are sometimes present in the ".text" ++ sections and they can be identified by their associated relocation. ++ We don't want to process those words and some others which ++ can also be identified by their relocations. However, not all ++ conditional branches will have a relocation so we will ++ only ignore words that 1) have a reloc, and 2) the reloc ++ is not applicable to a conditional branch. ++ The array rela_comb is built here for use in the EOP scan loop. */ ++ switch (r_type) ++ { ++ case R_PPC_ADDR14_BRNTAKEN: /* absolute, predicted not taken */ ++ case R_PPC_REL14: /* relative cond. br. */ ++ case R_PPC_REL14_BRNTAKEN: /* rel. cond. br., predicted not taken */ ++ /* We should check the instruction. */ ++ break; ++ default: ++ /* The word is not a conditional branch - ignore it. */ ++ rela_comb[comb_count++] = &internal_relocs[n]; ++ break; ++ } ++ } ++ if (comb_count > 1) ++ qsort (rela_comb, (size_t) comb_count, sizeof (int), ppc_elf_sort_rela); ++ } ++ ++ /* Enumerate each EOP region that overlaps this section. */ ++ end_section = isec->vma + isec->_cooked_size; ++ dot = end_page = (isec->vma | (PAGESIZE - 1)) + 1; ++ dot -= link_info->mpc860c0; ++ section_modified = false; ++ if (dot < isec->vma) /* Increment the start position if this section */ ++ dot = isec->vma; /* begins in the middle of its first EOP region. */ ++ for (; ++ dot < end_section; ++ dot += PAGESIZE, end_page += PAGESIZE) ++ { ++ ++ /* Check each word in this EOP region. */ ++ for (; dot < end_page; dot += 4) ++ { ++ bfd_vma isec_offset; ++ unsigned long insn; ++ boolean skip, modified; ++ ++ /* Don't process this word if there is a relocation for it and ++ the relocation indicates the word is not a conditional branch. */ ++ skip = false; ++ isec_offset = dot - isec->vma; ++ for (; comb_curr<comb_count; ++comb_curr) ++ { ++ bfd_vma r_offset; ++ ++ r_offset = rela_comb[comb_curr]->r_offset; ++ if (r_offset >= isec_offset) ++ { ++ if (r_offset == isec_offset) skip = true; ++ break; ++ } ++ } ++ if (skip) continue; ++ ++ /* Check the current word for a problematic conditional branch. */ ++#define BO0(insn) ((insn) & 0x02000000) ++#define BO2(insn) ((insn) & 0x00800000) ++#define BO4(insn) ((insn) & 0x00200000) ++ insn = (unsigned long) bfd_get_32 (abfd, contents + isec_offset); ++ modified = false; ++ if ((insn & 0xFc000000) == 0x40000000) ++ { ++ /* Instruction is BCx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ bfd_vma target; ++ /* This branch is predicted as "normal". ++ If this is a forward branch, it is problematic. */ ++ ++ target = insn & 0x0000Fffc; /*extract*/ ++ target = (target ^ 0x8000) - 0x8000; /*sign extend*/ ++ if ((insn & 0x00000002) == 0) ++ target += dot; /*convert to abs*/ ++ if (target > dot) ++ { ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++ } ++ else if ((insn & 0xFc00Fffe) == 0x4c000420) ++ { ++ /* Instruction is BCCTRx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ /* This branch is predicted as not-taken. ++ If this is a forward branch, it is problematic. ++ Since we can't tell statically if it will branch forward, ++ always set the prediction bit. */ ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++ else if ((insn & 0xFc00Fffe) == 0x4c000020) ++ { ++ /* Instruction is BCLRx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ /* This branch is predicted as not-taken. ++ If this is a forward branch, it is problematic. ++ Since we can't tell statically if it will branch forward, ++ always set the prediction bit. */ ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++#undef BO0 ++#undef BO2 ++#undef BO4 ++ if (modified) ++ { ++ bfd_put_32 (abfd, (bfd_vma) insn, contents + isec_offset); ++ section_modified = true; ++ } ++ } ++ } ++ if (section_modified) ++ { ++ elf_section_data (isec)->this_hdr.contents = contents; ++ free_contents = NULL; ++ } ++ } ++ ++ if (rela_comb != NULL) ++ { ++ free (rela_comb); ++ rela_comb = NULL; ++ } ++ ++ if (free_relocs != NULL) ++ { ++ free (free_relocs); ++ free_relocs = NULL; ++ } ++ ++ if (free_contents != NULL) ++ { ++ if (! link_info->keep_memory) ++ free (free_contents); ++ else ++ { ++ /* Cache the section contents for elf_link_input_bfd. */ ++ elf_section_data (isec)->this_hdr.contents = contents; ++ } ++ free_contents = NULL; ++ } ++ ++ return true; ++ ++error_return: ++ if (rela_comb != NULL) ++ free (rela_comb); ++ if (free_relocs != NULL) ++ free (free_relocs); ++ if (free_contents != NULL) ++ free (free_contents); ++ return false; ++} ++ ++static reloc_howto_type * ++ppc_elf_reloc_type_lookup (abfd, code) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ bfd_reloc_code_real_type code; ++{ ++ enum elf_ppc_reloc_type ppc_reloc = R_PPC_NONE; ++ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ switch ((int) code) ++ { ++ default: ++ return (reloc_howto_type *) NULL; ++ ++ case BFD_RELOC_NONE: ppc_reloc = R_PPC_NONE; break; ++ case BFD_RELOC_32: ppc_reloc = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC_BA26: ppc_reloc = R_PPC_ADDR24; break; ++ case BFD_RELOC_16: ppc_reloc = R_PPC_ADDR16; break; ++ case BFD_RELOC_LO16: ppc_reloc = R_PPC_ADDR16_LO; break; ++ case BFD_RELOC_HI16: ppc_reloc = R_PPC_ADDR16_HI; break; ++ case BFD_RELOC_HI16_S: ppc_reloc = R_PPC_ADDR16_HA; break; ++ case BFD_RELOC_PPC_BA16: ppc_reloc = R_PPC_ADDR14; break; ++ case BFD_RELOC_PPC_BA16_BRTAKEN: ppc_reloc = R_PPC_ADDR14_BRTAKEN; break; ++ case BFD_RELOC_PPC_BA16_BRNTAKEN: ppc_reloc = R_PPC_ADDR14_BRNTAKEN; break; ++ case BFD_RELOC_PPC_B26: ppc_reloc = R_PPC_REL24; break; ++ case BFD_RELOC_PPC_B16: ppc_reloc = R_PPC_REL14; break; ++ case BFD_RELOC_PPC_B16_BRTAKEN: ppc_reloc = R_PPC_REL14_BRTAKEN; break; ++ case BFD_RELOC_PPC_B16_BRNTAKEN: ppc_reloc = R_PPC_REL14_BRNTAKEN; break; ++ case BFD_RELOC_16_GOTOFF: ppc_reloc = R_PPC_GOT16; break; ++ case BFD_RELOC_LO16_GOTOFF: ppc_reloc = R_PPC_GOT16_LO; break; ++ case BFD_RELOC_HI16_GOTOFF: ppc_reloc = R_PPC_GOT16_HI; break; ++ case BFD_RELOC_HI16_S_GOTOFF: ppc_reloc = R_PPC_GOT16_HA; break; ++ case BFD_RELOC_24_PLT_PCREL: ppc_reloc = R_PPC_PLTREL24; break; ++ case BFD_RELOC_PPC_COPY: ppc_reloc = R_PPC_COPY; break; ++ case BFD_RELOC_PPC_GLOB_DAT: ppc_reloc = R_PPC_GLOB_DAT; break; ++ case BFD_RELOC_PPC_LOCAL24PC: ppc_reloc = R_PPC_LOCAL24PC; break; ++ case BFD_RELOC_32_PCREL: ppc_reloc = R_PPC_REL32; break; ++ case BFD_RELOC_32_PLTOFF: ppc_reloc = R_PPC_PLT32; break; ++ case BFD_RELOC_32_PLT_PCREL: ppc_reloc = R_PPC_PLTREL32; break; ++ case BFD_RELOC_LO16_PLTOFF: ppc_reloc = R_PPC_PLT16_LO; break; ++ case BFD_RELOC_HI16_PLTOFF: ppc_reloc = R_PPC_PLT16_HI; break; ++ case BFD_RELOC_HI16_S_PLTOFF: ppc_reloc = R_PPC_PLT16_HA; break; ++ case BFD_RELOC_GPREL16: ppc_reloc = R_PPC_SDAREL16; break; ++ case BFD_RELOC_16_BASEREL: ppc_reloc = R_PPC_SECTOFF; break; ++ case BFD_RELOC_LO16_BASEREL: ppc_reloc = R_PPC_SECTOFF_LO; break; ++ case BFD_RELOC_HI16_BASEREL: ppc_reloc = R_PPC_SECTOFF_HI; break; ++ case BFD_RELOC_HI16_S_BASEREL: ppc_reloc = R_PPC_SECTOFF_HA; break; ++ case BFD_RELOC_CTOR: ppc_reloc = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC_TOC16: ppc_reloc = R_PPC_TOC16; break; ++ case BFD_RELOC_PPC_EMB_NADDR32: ppc_reloc = R_PPC_EMB_NADDR32; break; ++ case BFD_RELOC_PPC_EMB_NADDR16: ppc_reloc = R_PPC_EMB_NADDR16; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_LO: ppc_reloc = R_PPC_EMB_NADDR16_LO; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HI: ppc_reloc = R_PPC_EMB_NADDR16_HI; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HA: ppc_reloc = R_PPC_EMB_NADDR16_HA; break; ++ case BFD_RELOC_PPC_EMB_SDAI16: ppc_reloc = R_PPC_EMB_SDAI16; break; ++ case BFD_RELOC_PPC_EMB_SDA2I16: ppc_reloc = R_PPC_EMB_SDA2I16; break; ++ case BFD_RELOC_PPC_EMB_SDA2REL: ppc_reloc = R_PPC_EMB_SDA2REL; break; ++ case BFD_RELOC_PPC_EMB_SDA21: ppc_reloc = R_PPC_EMB_SDA21; break; ++ case BFD_RELOC_PPC_EMB_MRKREF: ppc_reloc = R_PPC_EMB_MRKREF; break; ++ case BFD_RELOC_PPC_EMB_RELSEC16: ppc_reloc = R_PPC_EMB_RELSEC16; break; ++ case BFD_RELOC_PPC_EMB_RELST_LO: ppc_reloc = R_PPC_EMB_RELST_LO; break; ++ case BFD_RELOC_PPC_EMB_RELST_HI: ppc_reloc = R_PPC_EMB_RELST_HI; break; ++ case BFD_RELOC_PPC_EMB_RELST_HA: ppc_reloc = R_PPC_EMB_RELST_HA; break; ++ case BFD_RELOC_PPC_EMB_BIT_FLD: ppc_reloc = R_PPC_EMB_BIT_FLD; break; ++ case BFD_RELOC_PPC_EMB_RELSDA: ppc_reloc = R_PPC_EMB_RELSDA; break; ++ case BFD_RELOC_PPC_MORPHOS_DREL: ppc_reloc = R_PPC_MORPHOS_DREL; break; ++ case BFD_RELOC_PPC_MORPHOS_DREL_LO: ppc_reloc = R_PPC_MORPHOS_DREL_LO; break; ++ case BFD_RELOC_PPC_MORPHOS_DREL_HI: ppc_reloc = R_PPC_MORPHOS_DREL_HI; break; ++ case BFD_RELOC_PPC_MORPHOS_DREL_HA: ppc_reloc = R_PPC_MORPHOS_DREL_HA; break; ++ case BFD_RELOC_VTABLE_INHERIT: ppc_reloc = R_PPC_GNU_VTINHERIT; break; ++ case BFD_RELOC_VTABLE_ENTRY: ppc_reloc = R_PPC_GNU_VTENTRY; break; ++ } ++ ++ return ppc_elf_howto_table[(int) ppc_reloc]; ++}; ++ ++/* Set the howto pointer for a PowerPC ELF reloc. */ ++ ++static void ++ppc_elf_info_to_howto (abfd, cache_ptr, dst) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ arelent *cache_ptr; ++ Elf32_Internal_Rela *dst; ++{ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); ++ cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; ++} ++ ++/* Handle the R_PPC_ADDR16_HA reloc. */ ++ ++static bfd_reloc_status_type ++ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section, ++ output_bfd, error_message) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ arelent *reloc_entry; ++ asymbol *symbol; ++ PTR data ATTRIBUTE_UNUSED; ++ asection *input_section; ++ bfd *output_bfd; ++ char **error_message ATTRIBUTE_UNUSED; ++{ ++ /*bfd_vma relocation;*/ ++ ++ if (output_bfd != NULL) ++ { ++ reloc_entry->address += input_section->output_offset; ++ return bfd_reloc_ok; ++ } ++ else ++ { ++ reloc_entry->address += input_section->output_offset; ++ input_section->output_section->orelocation[input_section->output_section->reloc_count++]=reloc_entry; ++ return bfd_reloc_ok; ++ } ++ ++ /*if (reloc_entry->address > input_section->_cooked_size) ++ return bfd_reloc_outofrange; ++ ++ if (bfd_is_com_section (symbol->section)) ++ relocation = 0; ++ else ++ relocation = symbol->value; ++ ++ relocation += symbol->section->output_section->vma; ++ relocation += symbol->section->output_offset; ++ relocation += reloc_entry->addend; ++ ++ reloc_entry->addend += (relocation & 0x8000) << 1; ++ ++ return bfd_reloc_continue;*/ ++} ++ ++/* Fix bad default arch selected for a 32 bit input bfd when the ++ default is 64 bit. */ ++ ++static boolean ++ppc_elf_object_p (abfd) ++ bfd *abfd; ++{ ++ if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64) ++ { ++ Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); ++ ++ if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32) ++ { ++ /* Relies on arch after 64 bit default being 32 bit default. */ ++ abfd->arch_info = abfd->arch_info->next; ++ BFD_ASSERT (abfd->arch_info->bits_per_word == 32); ++ } ++ } ++ return true; ++} ++ ++/* Function to set whether a module needs the -mrelocatable bit set. */ ++ ++static boolean ++ppc_elf_set_private_flags (abfd, flags) ++ bfd *abfd; ++ flagword flags; ++{ ++ BFD_ASSERT (!elf_flags_init (abfd) ++ || elf_elfheader (abfd)->e_flags == flags); ++ ++ elf_elfheader (abfd)->e_flags = flags; ++ elf_flags_init (abfd) = true; ++ return true; ++} ++ ++/* Merge backend specific data from an object file to the output ++ object file when linking */ ++static boolean ++ppc_elf_merge_private_bfd_data (ibfd, obfd) ++ bfd *ibfd; ++ bfd *obfd; ++{ ++ flagword old_flags; ++ flagword new_flags; ++ boolean error; ++ ++ /* Check if we have the same endianess */ ++ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) ++ return false; ++ ++ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour ++ || bfd_get_flavour (obfd) != bfd_target_elf_flavour) ++ return true; ++ ++ new_flags = elf_elfheader (ibfd)->e_flags; ++ old_flags = elf_elfheader (obfd)->e_flags; ++ if (!elf_flags_init (obfd)) /* First call, no flags set */ ++ { ++ elf_flags_init (obfd) = true; ++ elf_elfheader (obfd)->e_flags = new_flags; ++ } ++ ++ else if (new_flags == old_flags) /* Compatible flags are ok */ ++ ; ++ ++ else /* Incompatible flags */ ++ { ++ /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib to be linked ++ with either. */ ++ error = false; ++ if ((new_flags & EF_PPC_RELOCATABLE) != 0 ++ && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: compiled with -mrelocatable and linked with modules compiled normally"), ++ bfd_archive_filename (ibfd)); ++ } ++ else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0 ++ && (old_flags & EF_PPC_RELOCATABLE) != 0) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: compiled normally and linked with modules compiled with -mrelocatable"), ++ bfd_archive_filename (ibfd)); ++ } ++ ++ /* The output is -mrelocatable-lib iff both the input files are. */ ++ if (! (new_flags & EF_PPC_RELOCATABLE_LIB)) ++ elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB; ++ ++ /* The output is -mrelocatable iff it can't be -mrelocatable-lib, ++ but each input file is either -mrelocatable or -mrelocatable-lib. */ ++ if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB) ++ && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)) ++ && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))) ++ elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE; ++ ++ /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if any module uses it */ ++ elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB); ++ ++ new_flags &= ~ (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ old_flags &= ~ (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ ++ /* Warn about any other mismatches */ ++ if (new_flags != old_flags) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"), ++ bfd_archive_filename (ibfd), (long) new_flags, (long) old_flags); ++ } ++ ++ if (error) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++/* Handle a PowerPC specific section when reading an object file. This ++ is called when elfcode.h finds a section with an unknown type. */ ++ ++static boolean ++ppc_elf_section_from_shdr (abfd, hdr, name) ++ bfd *abfd; ++ Elf32_Internal_Shdr *hdr; ++ const char *name; ++{ ++ asection *newsect; ++ flagword flags; ++ ++ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) ++ return false; ++ ++ newsect = hdr->bfd_section; ++ flags = bfd_get_section_flags (abfd, newsect); ++ if (hdr->sh_flags & SHF_EXCLUDE) ++ flags |= SEC_EXCLUDE; ++ ++ if (hdr->sh_type == SHT_ORDERED) ++ flags |= SEC_SORT_ENTRIES; ++ ++ bfd_set_section_flags (abfd, newsect, flags); ++ return true; ++} ++ ++/* Set up any other section flags and such that may be necessary. */ ++ ++static boolean ++ppc_elf_fake_sections (abfd, shdr, asect) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ Elf32_Internal_Shdr *shdr; ++ asection *asect; ++{ ++ if ((asect->flags & SEC_EXCLUDE) != 0) ++ shdr->sh_flags |= SHF_EXCLUDE; ++ ++ if ((asect->flags & SEC_SORT_ENTRIES) != 0) ++ shdr->sh_type = SHT_ORDERED; ++ ++ return true; ++} ++ ++/* Create a special linker section */ ++static elf_linker_section_t * ++ppc_elf_create_linker_section (abfd, info, which) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ enum elf_linker_section_enum which; ++{ ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ elf_linker_section_t *lsect; ++ ++ /* Record the first bfd section that needs the special section */ ++ if (!dynobj) ++ dynobj = elf_hash_table (info)->dynobj = abfd; ++ ++ /* If this is the first time, create the section */ ++ lsect = elf_linker_section (dynobj, which); ++ if (!lsect) ++ { ++ elf_linker_section_t defaults; ++ static elf_linker_section_t zero_section; ++ ++ defaults = zero_section; ++ defaults.which = which; ++ defaults.hole_written_p = false; ++ defaults.alignment = 2; ++ ++ /* Both of these sections are (technically) created by the user ++ putting data in them, so they shouldn't be marked ++ SEC_LINKER_CREATED. ++ ++ The linker creates them so it has somewhere to attach their ++ respective symbols. In fact, if they were empty it would ++ be OK to leave the symbol set to 0 (or any random number), because ++ the appropriate register should never be used. */ ++ defaults.flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY); ++ ++ switch (which) ++ { ++ default: ++ (*_bfd_error_handler) (_("%s: Unknown special linker type %d"), ++ bfd_get_filename (abfd), ++ (int) which); ++ ++ bfd_set_error (bfd_error_bad_value); ++ return (elf_linker_section_t *) 0; ++ ++ case LINKER_SECTION_SDATA: /* .sdata/.sbss section */ ++ defaults.name = ".sdata"; ++ defaults.rel_name = ".rela.sdata"; ++ defaults.bss_name = ".sbss"; ++ defaults.sym_name = "_SDA_BASE_"; ++ defaults.sym_offset = 32768; ++ break; ++ ++ case LINKER_SECTION_SDATA2: /* .sdata2/.sbss2 section */ ++ defaults.name = ".sdata2"; ++ defaults.rel_name = ".rela.sdata2"; ++ defaults.bss_name = ".sbss2"; ++ defaults.sym_name = "_SDA2_BASE_"; ++ defaults.sym_offset = 32768; ++ defaults.flags |= SEC_READONLY; ++ break; ++ } ++ ++ lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults); ++ } ++ ++ return lsect; ++} ++ ++/* If we have a non-zero sized .sbss2 or .PPC.EMB.sbss0 sections, we ++ need to bump up the number of section headers. */ ++ ++static int ++ppc_elf_additional_program_headers (abfd) ++ bfd *abfd; ++{ ++ asection *s; ++ int ret; ++ ++ ret = 0; ++ ++ s = bfd_get_section_by_name (abfd, ".interp"); ++ if (s != NULL) ++ ++ret; ++ ++ s = bfd_get_section_by_name (abfd, ".sbss2"); ++ if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0) ++ ++ret; ++ ++ s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0"); ++ if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0) ++ ++ret; ++ ++ return ret; ++} ++ ++/* Modify the segment map if needed. */ ++ ++static boolean ++ppc_elf_modify_segment_map (abfd) ++ bfd *abfd ATTRIBUTE_UNUSED; ++{ ++ return true; ++} ++ ++/* The powerpc .got has a blrl instruction in it. Mark it executable. */ ++ ++static asection * ++ppc_elf_create_got (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ register asection *s; ++ flagword flags; ++ ++ if (!_bfd_elf_create_got_section (abfd, info)) ++ return NULL; ++ ++ s = bfd_get_section_by_name (abfd, ".got"); ++ if (s == NULL) ++ abort (); ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED); ++ if (!bfd_set_section_flags (abfd, s, flags)) ++ return NULL; ++ return s; ++} ++ ++/* We have to create .dynsbss and .rela.sbss here so that they get mapped ++ to output sections (just like _bfd_elf_create_dynamic_sections has ++ to create .dynbss and .rela.bss). */ ++ ++static boolean ++ppc_elf_create_dynamic_sections (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ register asection *s; ++ flagword flags; ++ ++ if (!ppc_elf_create_got (abfd, info)) ++ return false; ++ ++ if (!_bfd_elf_create_dynamic_sections (abfd, info)) ++ return false; ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED); ++ ++ s = bfd_make_section (abfd, ".dynsbss"); ++ if (s == NULL ++ || ! bfd_set_section_flags (abfd, s, SEC_ALLOC)) ++ return false; ++ ++ if (! info->shared) ++ { ++ s = bfd_make_section (abfd, ".rela.sbss"); ++ if (s == NULL ++ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) ++ || ! bfd_set_section_alignment (abfd, s, 2)) ++ return false; ++ } ++ ++ s = bfd_get_section_by_name (abfd, ".plt"); ++ if (s == NULL) ++ abort (); ++ ++ flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED; ++ return bfd_set_section_flags (abfd, s, flags); ++} ++ ++/* Adjust a symbol defined by a dynamic object and referenced by a ++ regular object. The current definition is in some section of the ++ dynamic object, but we're not including those sections. We have to ++ change the definition to something the rest of the link can ++ understand. */ ++ ++static boolean ++ppc_elf_adjust_dynamic_symbol (info, h) ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++{ ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ asection *s; ++ unsigned int power_of_two; ++ bfd_vma plt_offset; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n", h->root.root.string); ++#endif ++ ++ /* Make sure we know what is going on here. */ ++ BFD_ASSERT (dynobj != NULL ++ && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) ++ || h->weakdef != NULL ++ || ((h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_DYNAMIC) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_REF_REGULAR) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_REGULAR) == 0))); ++ ++ /* If this is a function, put it in the procedure linkage table. We ++ will fill in the contents of the procedure linkage table later, ++ when we know the address of the .got section. */ ++ if (h->type == STT_FUNC ++ || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) ++ { ++ if (! elf_hash_table (info)->dynamic_sections_created ++ || SYMBOL_CALLS_LOCAL (info, h) ++ || (info->shared && h->plt.refcount <= 0)) ++ { ++ /* A PLT entry is not required/allowed when: ++ ++ 1. We are not using ld.so; because then the PLT entry ++ can't be set up, so we can't use one. ++ ++ 2. We know for certain that a call to this symbol ++ will go to this object. ++ ++ 3. GC has rendered the entry unused. ++ Note, however, that in an executable all references to the ++ symbol go to the PLT, so we can't turn it off in that case. ++ ??? The correct thing to do here is to reference count ++ all uses of the symbol, not just those to the GOT or PLT. */ ++ h->plt.offset = (bfd_vma) -1; ++ h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; ++ return true; ++ } ++ ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ { ++ if (! bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ } ++ BFD_ASSERT (h->dynindx != -1); ++ ++ s = bfd_get_section_by_name (dynobj, ".plt"); ++ BFD_ASSERT (s != NULL); ++ ++ /* If this is the first .plt entry, make room for the special ++ first entry. */ ++ if (s->_raw_size == 0) ++ s->_raw_size += PLT_INITIAL_ENTRY_SIZE; ++ ++ /* The PowerPC PLT is actually composed of two parts, the first part ++ is 2 words (for a load and a jump), and then there is a remaining ++ word available at the end. */ ++ plt_offset = (PLT_INITIAL_ENTRY_SIZE ++ + (PLT_SLOT_SIZE ++ * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) ++ / PLT_ENTRY_SIZE))); ++ ++ /* If this symbol is not defined in a regular file, and we are ++ not generating a shared library, then set the symbol to this ++ location in the .plt. This is required to make function ++ pointers compare as equal between the normal executable and ++ the shared library. */ ++ if (! info->shared ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ { ++ h->root.u.def.section = s; ++ h->root.u.def.value = plt_offset; ++ } ++ ++ h->plt.offset = plt_offset; ++ ++ /* Make room for this entry. After the 8192nd entry, room ++ for two entries is allocated. */ ++ if ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE ++ >= PLT_NUM_SINGLE_ENTRIES) ++ s->_raw_size += 2 * PLT_ENTRY_SIZE; ++ else ++ s->_raw_size += PLT_ENTRY_SIZE; ++ ++ /* We also need to make an entry in the .rela.plt section. */ ++ s = bfd_get_section_by_name (dynobj, ".rela.plt"); ++ BFD_ASSERT (s != NULL); ++ s->_raw_size += sizeof (Elf32_External_Rela); ++ ++ return true; ++ } ++ else ++ h->plt.offset = (bfd_vma) -1; ++ ++ /* If this is a weak symbol, and there is a real definition, the ++ processor independent code will have arranged for us to see the ++ real definition first, and we can just use the same value. */ ++ if (h->weakdef != NULL) ++ { ++ BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined ++ || h->weakdef->root.type == bfd_link_hash_defweak); ++ h->root.u.def.section = h->weakdef->root.u.def.section; ++ h->root.u.def.value = h->weakdef->root.u.def.value; ++ return true; ++ } ++ ++ /* This is a reference to a symbol defined by a dynamic object which ++ is not a function. */ ++ ++ /* If we are creating a shared library, we must presume that the ++ only references to the symbol are via the global offset table. ++ For such cases we need not do anything here; the relocations will ++ be handled correctly by relocate_section. */ ++ if (info->shared) ++ return true; ++ ++ /* We must allocate the symbol in our .dynbss section, which will ++ become part of the .bss section of the executable. There will be ++ an entry for this symbol in the .dynsym section. The dynamic ++ object will contain position independent code, so all references ++ from the dynamic object to this symbol will go through the global ++ offset table. The dynamic linker will use the .dynsym entry to ++ determine the address it must put in the global offset table, so ++ both the dynamic object and the regular object will refer to the ++ same memory location for the variable. ++ ++ Of course, if the symbol is sufficiently small, we must instead ++ allocate it in .sbss. FIXME: It would be better to do this if and ++ only if there were actually SDAREL relocs for that symbol. */ ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ s = bfd_get_section_by_name (dynobj, ".dynsbss"); ++ else ++ s = bfd_get_section_by_name (dynobj, ".dynbss"); ++ BFD_ASSERT (s != NULL); ++ ++ /* We must generate a R_PPC_COPY reloc to tell the dynamic linker to ++ copy the initial value out of the dynamic object and into the ++ runtime process image. We need to remember the offset into the ++ .rela.bss section we are going to use. */ ++ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) ++ { ++ asection *srel; ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ srel = bfd_get_section_by_name (dynobj, ".rela.sbss"); ++ else ++ srel = bfd_get_section_by_name (dynobj, ".rela.bss"); ++ BFD_ASSERT (srel != NULL); ++ srel->_raw_size += sizeof (Elf32_External_Rela); ++ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; ++ } ++ ++ /* We need to figure out the alignment required for this symbol. I ++ have no idea how ELF linkers handle this. */ ++ power_of_two = bfd_log2 (h->size); ++ if (power_of_two > 4) ++ power_of_two = 4; ++ ++ /* Apply the required alignment. */ ++ s->_raw_size = BFD_ALIGN (s->_raw_size, ++ (bfd_size_type) (1 << power_of_two)); ++ if (power_of_two > bfd_get_section_alignment (dynobj, s)) ++ { ++ if (! bfd_set_section_alignment (dynobj, s, power_of_two)) ++ return false; ++ } ++ ++ /* Define the symbol as being at this point in the section. */ ++ h->root.u.def.section = s; ++ h->root.u.def.value = s->_raw_size; ++ ++ /* Increment the section size to make room for the symbol. */ ++ s->_raw_size += h->size; ++ ++ return true; ++} ++ ++/* Set the sizes of the dynamic sections. */ ++ ++static boolean ++ppc_elf_size_dynamic_sections (output_bfd, info) ++ bfd *output_bfd ATTRIBUTE_UNUSED; ++ struct bfd_link_info *info; ++{ ++ bfd *dynobj; ++ asection *s; ++ boolean plt; ++ boolean relocs; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections called\n"); ++#endif ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ BFD_ASSERT (dynobj != NULL); ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ /* Set the contents of the .interp section to the interpreter. */ ++ if (! info->shared) ++ { ++ s = bfd_get_section_by_name (dynobj, ".interp"); ++ BFD_ASSERT (s != NULL); ++ s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; ++ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; ++ } ++ } ++ else ++ { ++ /* We may have created entries in the .rela.got, .rela.sdata, and ++ .rela.sdata2 sections. However, if we are not creating the ++ dynamic sections, we will not actually use these entries. Reset ++ the size of .rela.got, et al, which will cause it to get ++ stripped from the output file below. */ ++ static char *rela_sections[] = { ".rela.got", ".rela.sdata", ++ ".rela.sdata2", ".rela.sbss", ++ (char *) 0 }; ++ char **p; ++ ++ for (p = rela_sections; *p != (char *) 0; p++) ++ { ++ s = bfd_get_section_by_name (dynobj, *p); ++ if (s != NULL) ++ s->_raw_size = 0; ++ } ++ } ++ ++ /* The check_relocs and adjust_dynamic_symbol entry points have ++ determined the sizes of the various dynamic sections. Allocate ++ memory for them. */ ++ plt = false; ++ relocs = false; ++ for (s = dynobj->sections; s != NULL; s = s->next) ++ { ++ const char *name; ++ boolean strip; ++ ++ if ((s->flags & SEC_LINKER_CREATED) == 0) ++ continue; ++ ++ /* It's OK to base decisions on the section name, because none ++ of the dynobj section names depend upon the input files. */ ++ name = bfd_get_section_name (dynobj, s); ++ ++ strip = false; ++ ++ if (strcmp (name, ".plt") == 0) ++ { ++ if (s->_raw_size == 0) ++ { ++ /* Strip this section if we don't need it; see the ++ comment below. */ ++ strip = true; ++ } ++ else ++ { ++ /* Remember whether there is a PLT. */ ++ plt = true; ++ } ++ } ++ else if (strncmp (name, ".rela", 5) == 0) ++ { ++ if (s->_raw_size == 0) ++ { ++ /* If we don't need this section, strip it from the ++ output file. This is mostly to handle .rela.bss and ++ .rela.plt. We must create both sections in ++ create_dynamic_sections, because they must be created ++ before the linker maps input sections to output ++ sections. The linker does that before ++ adjust_dynamic_symbol is called, and it is that ++ function which decides whether anything needs to go ++ into these sections. */ ++ strip = true; ++ } ++ else ++ { ++ /* Remember whether there are any relocation sections. */ ++ relocs = true; ++ ++ /* We use the reloc_count field as a counter if we need ++ to copy relocs into the output file. */ ++ s->reloc_count = 0; ++ } ++ } ++ else if (strcmp (name, ".got") != 0 ++ && strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sdata2") != 0) ++ { ++ /* It's not one of our sections, so don't allocate space. */ ++ continue; ++ } ++ ++ if (strip) ++ { ++ _bfd_strip_section_from_output (info, s); ++ continue; ++ } ++ ++ /* Allocate memory for the section contents. */ ++ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); ++ if (s->contents == NULL && s->_raw_size != 0) ++ return false; ++ } ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ /* Add some entries to the .dynamic section. We fill in the ++ values later, in ppc_elf_finish_dynamic_sections, but we ++ must add the entries now so that we get the correct size for ++ the .dynamic section. The DT_DEBUG entry is filled in by the ++ dynamic linker and used by the debugger. */ ++#define add_dynamic_entry(TAG, VAL) \ ++ bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL)) ++ ++ if (!info->shared) ++ { ++ if (!add_dynamic_entry (DT_DEBUG, 0)) ++ return false; ++ } ++ ++ if (plt) ++ { ++ if (!add_dynamic_entry (DT_PLTGOT, 0) ++ || !add_dynamic_entry (DT_PLTRELSZ, 0) ++ || !add_dynamic_entry (DT_PLTREL, DT_RELA) ++ || !add_dynamic_entry (DT_JMPREL, 0)) ++ return false; ++ } ++ ++ if (relocs) ++ { ++ if (!add_dynamic_entry (DT_RELA, 0) ++ || !add_dynamic_entry (DT_RELASZ, 0) ++ || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) ++ return false; ++ } ++ ++ if ((info->flags & DF_TEXTREL) != 0) ++ { ++ if (!add_dynamic_entry (DT_TEXTREL, 0)) ++ return false; ++ info->flags |= DF_TEXTREL; ++ } ++ } ++#undef add_dynamic_entry ++ ++ return true; ++} ++ ++/* Look through the relocs for a section during the first phase, and ++ allocate space in the global offset table or procedure linkage ++ table. */ ++ ++static boolean ++ppc_elf_check_relocs (abfd, info, sec, relocs) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ asection *sec; ++ const Elf_Internal_Rela *relocs; ++{ ++ bfd *dynobj; ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; ++ const Elf_Internal_Rela *rel; ++ const Elf_Internal_Rela *rel_end; ++ bfd_signed_vma *local_got_refcounts; ++ elf_linker_section_t *sdata; ++ elf_linker_section_t *sdata2; ++ asection *sreloc; ++ asection *sgot = NULL; ++ asection *srelgot = NULL; ++ ++ if (info->relocateable) ++ return true; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_check_relocs called for section %s in %s\n", ++ bfd_get_section_name (abfd, sec), ++ bfd_archive_filename (abfd)); ++#endif ++ ++ /* Create the linker generated sections all the time so that the ++ special symbols are created. */ ++ ++ if ((sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA)) == NULL) ++ { ++ sdata = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); ++ if (!sdata) ++ return false; ++ } ++ ++ if ((sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2)) == NULL) ++ { ++ sdata2 = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA2); ++ if (!sdata2) ++ return false; ++ } ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ local_got_refcounts = elf_local_got_refcounts (abfd); ++ ++ sym_hashes = elf_sym_hashes (abfd); ++ sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym); ++ if (!elf_bad_symtab (abfd)) ++ sym_hashes_end -= symtab_hdr->sh_info; ++ ++ sreloc = NULL; ++ ++ rel_end = relocs + sec->reloc_count; ++ for (rel = relocs; rel < rel_end; rel++) ++ { ++ unsigned long r_symndx; ++ struct elf_link_hash_entry *h; ++ ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx < symtab_hdr->sh_info) ++ h = NULL; ++ else ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ ++ /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. ++ This shows up in particular in an R_PPC_ADDR32 in the eabi ++ startup code. */ ++ if (h && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) ++ { ++ if (sgot == NULL) ++ { ++ if (dynobj == NULL) ++ elf_hash_table (info)->dynobj = dynobj = abfd; ++ sgot = ppc_elf_create_got (dynobj, info); ++ if (sgot == NULL) ++ return false; ++ } ++ } ++ ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ /* GOT16 relocations */ ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ /* This symbol requires a global offset table entry. */ ++ ++ if (sgot == NULL) ++ { ++ if (dynobj == NULL) ++ elf_hash_table (info)->dynobj = dynobj = abfd; ++ sgot = ppc_elf_create_got (dynobj, info); ++ if (sgot == NULL) ++ return false; ++ } ++ ++ if (srelgot == NULL ++ && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (h != NULL) ++ { ++ if (h->got.refcount == 0) ++ { ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ if (!bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ ++ /* Allocate space in the .got. */ ++ sgot->_raw_size += 4; ++ /* Allocate relocation space. */ ++ srelgot->_raw_size += sizeof (Elf32_External_Rela); ++ } ++ h->got.refcount++; ++ } ++ else ++ { ++ /* This is a global offset table entry for a local symbol. */ ++ if (local_got_refcounts == NULL) ++ { ++ bfd_size_type size; ++ ++ size = symtab_hdr->sh_info; ++ size *= sizeof (bfd_signed_vma); ++ local_got_refcounts ++ = (bfd_signed_vma *) bfd_zalloc (abfd, size); ++ if (local_got_refcounts == NULL) ++ return false; ++ elf_local_got_refcounts (abfd) = local_got_refcounts; ++ } ++ if (local_got_refcounts[r_symndx] == 0) ++ { ++ sgot->_raw_size += 4; ++ ++ /* If we are generating a shared object, we need to ++ output a R_PPC_RELATIVE reloc so that the ++ dynamic linker can adjust this GOT entry. */ ++ if (info->shared) ++ srelgot->_raw_size += sizeof (Elf32_External_Rela); ++ } ++ local_got_refcounts[r_symndx]++; ++ } ++ break; ++ ++ /* Indirect .sdata relocation */ ++ case R_PPC_EMB_SDAI16: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), "R_PPC_EMB_SDAI16")); ++ return false; ++ } ++ ++ if (srelgot == NULL && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata, h, rel)) ++ return false; ++ ++ break; ++ ++ /* Indirect .sdata2 relocation */ ++ case R_PPC_EMB_SDA2I16: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), "R_PPC_EMB_SDA2I16")); ++ return false; ++ } ++ ++ if (srelgot == NULL && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata2, h, rel)) ++ return false; ++ ++ break; ++ ++ case R_PPC_SDAREL16: ++ case R_PPC_EMB_SDA2REL: ++ case R_PPC_EMB_SDA21: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), ++ ppc_elf_howto_table[(int) ELF32_R_TYPE (rel->r_info)]->name)); ++ return false; ++ } ++ break; ++ ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL24: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++#ifdef DEBUG ++ fprintf (stderr, "Reloc requires a PLT entry\n"); ++#endif ++ /* This symbol requires a procedure linkage table entry. We ++ actually build the entry in adjust_dynamic_symbol, ++ because this might be a case of linking PIC code without ++ linking in any dynamic objects, in which case we don't ++ need to generate a procedure linkage table after all. */ ++ ++ if (h == NULL) ++ { ++ /* It does not make sense to have a procedure linkage ++ table entry for a local symbol. */ ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ { ++ if (! bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ } ++ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; ++ h->plt.refcount++; ++ break; ++ ++ /* The following relocations don't need to propagate the ++ relocation if linking a shared object since they are ++ section relative. */ ++ case R_PPC_SECTOFF: ++ case R_PPC_SECTOFF_LO: ++ case R_PPC_SECTOFF_HI: ++ case R_PPC_SECTOFF_HA: ++ break; ++ ++ /* This refers only to functions defined in the shared library */ ++ case R_PPC_LOCAL24PC: ++ break; ++ ++ /* This relocation describes the C++ object vtable hierarchy. ++ Reconstruct it for later use during GC. */ ++ case R_PPC_GNU_VTINHERIT: ++ if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) ++ return false; ++ break; ++ ++ /* This relocation describes which C++ vtable entries are actually ++ used. Record for later use during GC. */ ++ case R_PPC_GNU_VTENTRY: ++ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend)) ++ return false; ++ break; ++ ++ /* When creating a shared object, we must copy these ++ relocs into the output file. We create a reloc ++ section in dynobj and make room for the reloc. */ ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ case R_PPC_REL32: ++ if (h == NULL ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || SYMBOL_REFERENCES_LOCAL (info, h)) ++ break; ++ /* fall through */ ++ ++ default: ++ if (info->shared) ++ { ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_check_relocs need to create relocation for %s\n", ++ (h && h->root.root.string) ? h->root.root.string : "<unknown>"); ++#endif ++ if (sreloc == NULL) ++ { ++ const char *name; ++ ++ name = (bfd_elf_string_from_elf_section ++ (abfd, ++ elf_elfheader (abfd)->e_shstrndx, ++ elf_section_data (sec)->rel_hdr.sh_name)); ++ if (name == NULL) ++ return false; ++ ++ BFD_ASSERT (strncmp (name, ".rela", 5) == 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ++ name + 5) == 0); ++ ++ sreloc = bfd_get_section_by_name (dynobj, name); ++ if (sreloc == NULL) ++ { ++ flagword flags; ++ ++ sreloc = bfd_make_section (dynobj, name); ++ flags = (SEC_HAS_CONTENTS | SEC_READONLY ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ if ((sec->flags & SEC_ALLOC) != 0) ++ flags |= SEC_ALLOC | SEC_LOAD; ++ if (sreloc == NULL ++ || ! bfd_set_section_flags (dynobj, sreloc, flags) ++ || ! bfd_set_section_alignment (dynobj, sreloc, 2)) ++ return false; ++ } ++ if (sec->flags & SEC_READONLY) ++ info->flags |= DF_TEXTREL; ++ } ++ ++ sreloc->_raw_size += sizeof (Elf32_External_Rela); ++ ++ /* FIXME: We should here do what the m68k and i386 ++ backends do: if the reloc is pc-relative, record it ++ in case it turns out that the reloc is unnecessary ++ because the symbol is forced local by versioning or ++ we are linking with -Bdynamic. Fortunately this ++ case is not frequent. */ ++ } ++ ++ break; ++ } ++ } ++ ++ return true; ++} ++ ++/* Return the section that should be marked against GC for a given ++ relocation. */ ++ ++static asection * ++ppc_elf_gc_mark_hook (sec, info, rel, h, sym) ++ asection *sec; ++ struct bfd_link_info *info ATTRIBUTE_UNUSED; ++ Elf_Internal_Rela *rel; ++ struct elf_link_hash_entry *h; ++ Elf_Internal_Sym *sym; ++{ ++ if (h != NULL) ++ { ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_PPC_GNU_VTINHERIT: ++ case R_PPC_GNU_VTENTRY: ++ break; ++ ++ default: ++ switch (h->root.type) ++ { ++ case bfd_link_hash_defined: ++ case bfd_link_hash_defweak: ++ return h->root.u.def.section; ++ ++ case bfd_link_hash_common: ++ return h->root.u.c.p->section; ++ ++ default: ++ break; ++ } ++ } ++ } ++ else ++ return bfd_section_from_elf_index (sec->owner, sym->st_shndx); ++ ++ return NULL; ++} ++ ++/* Update the got entry reference counts for the section being removed. */ ++ ++static boolean ++ppc_elf_gc_sweep_hook (abfd, info, sec, relocs) ++ bfd *abfd; ++ struct bfd_link_info *info ATTRIBUTE_UNUSED; ++ asection *sec; ++ const Elf_Internal_Rela *relocs; ++{ ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes; ++ bfd_signed_vma *local_got_refcounts; ++ const Elf_Internal_Rela *rel, *relend; ++ unsigned long r_symndx; ++ struct elf_link_hash_entry *h; ++ ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ sym_hashes = elf_sym_hashes (abfd); ++ local_got_refcounts = elf_local_got_refcounts (abfd); ++ ++ relend = relocs + sec->reloc_count; ++ for (rel = relocs; rel < relend; rel++) ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ if (h->got.refcount > 0) ++ h->got.refcount--; ++ } ++ else if (local_got_refcounts != NULL) ++ { ++ if (local_got_refcounts[r_symndx] > 0) ++ local_got_refcounts[r_symndx]--; ++ } ++ break; ++ ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL24: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ if (h->plt.refcount > 0) ++ h->plt.refcount--; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return true; ++} ++ ++/* Hook called by the linker routine which adds symbols from an object ++ file. We use it to put .comm items in .sbss, and not .bss. */ ++ ++static boolean ++ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ const Elf_Internal_Sym *sym; ++ const char **namep ATTRIBUTE_UNUSED; ++ flagword *flagsp ATTRIBUTE_UNUSED; ++ asection **secp; ++ bfd_vma *valp; ++{ ++ if (sym->st_shndx == SHN_COMMON ++ && !info->relocateable ++ && sym->st_size <= elf_gp_size (abfd) ++ && info->hash->creator->flavour == bfd_target_elf_flavour) ++ { ++ /* Common symbols less than or equal to -G nn bytes are automatically ++ put into .sdata. */ ++ elf_linker_section_t *sdata ++ = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); ++ ++ if (!sdata->bss_section) ++ { ++ bfd_size_type amt; ++ ++ /* We don't go through bfd_make_section, because we don't ++ want to attach this common section to DYNOBJ. The linker ++ will move the symbols to the appropriate output section ++ when it defines common symbols. */ ++ amt = sizeof (asection); ++ sdata->bss_section = (asection *) bfd_zalloc (abfd, amt); ++ if (sdata->bss_section == NULL) ++ return false; ++ sdata->bss_section->name = sdata->bss_name; ++ sdata->bss_section->flags = SEC_IS_COMMON; ++ sdata->bss_section->output_section = sdata->bss_section; ++ amt = sizeof (asymbol); ++ sdata->bss_section->symbol = (asymbol *) bfd_zalloc (abfd, amt); ++ amt = sizeof (asymbol *); ++ sdata->bss_section->symbol_ptr_ptr = ++ (asymbol **) bfd_zalloc (abfd, amt); ++ if (sdata->bss_section->symbol == NULL ++ || sdata->bss_section->symbol_ptr_ptr == NULL) ++ return false; ++ sdata->bss_section->symbol->name = sdata->bss_name; ++ sdata->bss_section->symbol->flags = BSF_SECTION_SYM; ++ sdata->bss_section->symbol->section = sdata->bss_section; ++ *sdata->bss_section->symbol_ptr_ptr = sdata->bss_section->symbol; ++ } ++ ++ *secp = sdata->bss_section; ++ *valp = sym->st_size; ++ } ++ ++ return true; ++} ++ ++/* Finish up dynamic symbol handling. We set the contents of various ++ dynamic sections here. */ ++ ++static boolean ++ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++ Elf_Internal_Sym *sym; ++{ ++ bfd *dynobj; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s", ++ h->root.root.string); ++#endif ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ BFD_ASSERT (dynobj != NULL); ++ ++ if (h->plt.offset != (bfd_vma) -1) ++ { ++ asection *splt; ++ asection *srela; ++ Elf_Internal_Rela rela; ++ bfd_vma reloc_index; ++ ++#ifdef DEBUG ++ fprintf (stderr, ", plt_offset = %d", h->plt.offset); ++#endif ++ ++ /* This symbol has an entry in the procedure linkage table. Set ++ it up. */ ++ ++ BFD_ASSERT (h->dynindx != -1); ++ ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ srela = bfd_get_section_by_name (dynobj, ".rela.plt"); ++ BFD_ASSERT (splt != NULL && srela != NULL); ++ ++ /* We don't need to fill in the .plt. The ppc dynamic linker ++ will fill it in. */ ++ ++ /* Fill in the entry in the .rela.plt section. */ ++ rela.r_offset = (splt->output_section->vma ++ + splt->output_offset ++ + h->plt.offset); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); ++ rela.r_addend = 0; ++ ++ reloc_index = (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_SLOT_SIZE; ++ if (reloc_index > PLT_NUM_SINGLE_ENTRIES) ++ reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) srela->contents ++ + reloc_index)); ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ { ++ /* Mark the symbol as undefined, rather than as defined in ++ the .plt section. Leave the value alone. */ ++ sym->st_shndx = SHN_UNDEF; ++ /* If the symbol is weak, we do need to clear the value. ++ Otherwise, the PLT entry would provide a definition for ++ the symbol even if the symbol wasn't defined anywhere, ++ and so the symbol would never be NULL. */ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) ++ == 0) ++ sym->st_value = 0; ++ } ++ } ++ ++ if (h->got.offset != (bfd_vma) -1) ++ { ++ asection *sgot; ++ asection *srela; ++ Elf_Internal_Rela rela; ++ ++ /* This symbol has an entry in the global offset table. Set it ++ up. */ ++ ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ srela = bfd_get_section_by_name (dynobj, ".rela.got"); ++ BFD_ASSERT (sgot != NULL && srela != NULL); ++ ++ rela.r_offset = (sgot->output_section->vma ++ + sgot->output_offset ++ + (h->got.offset &~ (bfd_vma) 1)); ++ ++ /* If this is a -Bsymbolic link, and the symbol is defined ++ locally, we just want to emit a RELATIVE reloc. The entry in ++ the global offset table will already have been initialized in ++ the relocate_section function. */ ++ if (info->shared ++ && SYMBOL_REFERENCES_LOCAL (info, h)) ++ { ++ rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ rela.r_addend = (h->root.u.def.value ++ + h->root.u.def.section->output_section->vma ++ + h->root.u.def.section->output_offset); ++ } ++ else ++ { ++ BFD_ASSERT ((h->got.offset & 1) == 0); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_GLOB_DAT); ++ rela.r_addend = 0; ++ } ++ ++ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) srela->contents ++ + srela->reloc_count)); ++ ++srela->reloc_count; ++ } ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) ++ { ++ asection *s; ++ Elf_Internal_Rela rela; ++ ++ /* This symbols needs a copy reloc. Set it up. */ ++ ++#ifdef DEBUG ++ fprintf (stderr, ", copy"); ++#endif ++ ++ BFD_ASSERT (h->dynindx != -1); ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ s = bfd_get_section_by_name (h->root.u.def.section->owner, ++ ".rela.sbss"); ++ else ++ s = bfd_get_section_by_name (h->root.u.def.section->owner, ++ ".rela.bss"); ++ BFD_ASSERT (s != NULL); ++ ++ rela.r_offset = (h->root.u.def.value ++ + h->root.u.def.section->output_section->vma ++ + h->root.u.def.section->output_offset); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY); ++ rela.r_addend = 0; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) s->contents ++ + s->reloc_count)); ++ ++s->reloc_count; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ /* Mark some specially defined symbols as absolute. */ ++ if (strcmp (h->root.root.string, "_DYNAMIC") == 0 ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0) ++ sym->st_shndx = SHN_ABS; ++ ++ return true; ++} ++ ++/* Finish up the dynamic sections. */ ++ ++static boolean ++ppc_elf_finish_dynamic_sections (output_bfd, info) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++{ ++ asection *sdyn; ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ asection *sgot = bfd_get_section_by_name (dynobj, ".got"); ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); ++#endif ++ ++ sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ asection *splt; ++ Elf32_External_Dyn *dyncon, *dynconend; ++ ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ BFD_ASSERT (splt != NULL && sdyn != NULL); ++ ++ dyncon = (Elf32_External_Dyn *) sdyn->contents; ++ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); ++ for (; dyncon < dynconend; dyncon++) ++ { ++ Elf_Internal_Dyn dyn; ++ const char *name; ++ boolean size; ++ ++ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); ++ ++ switch (dyn.d_tag) ++ { ++ case DT_PLTGOT: name = ".plt"; size = false; break; ++ case DT_PLTRELSZ: name = ".rela.plt"; size = true; break; ++ case DT_JMPREL: name = ".rela.plt"; size = false; break; ++ default: name = NULL; size = false; break; ++ } ++ ++ if (name != NULL) ++ { ++ asection *s; ++ ++ s = bfd_get_section_by_name (output_bfd, name); ++ if (s == NULL) ++ dyn.d_un.d_val = 0; ++ else ++ { ++ if (! size) ++ dyn.d_un.d_ptr = s->vma; ++ else ++ { ++ if (s->_cooked_size != 0) ++ dyn.d_un.d_val = s->_cooked_size; ++ else ++ dyn.d_un.d_val = s->_raw_size; ++ } ++ } ++ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); ++ } ++ } ++ } ++ ++ /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can ++ easily find the address of the _GLOBAL_OFFSET_TABLE_. */ ++ if (sgot) ++ { ++ unsigned char *contents = sgot->contents; ++ bfd_put_32 (output_bfd, (bfd_vma) 0x4e800021 /* blrl */, contents); ++ ++ if (sdyn == NULL) ++ bfd_put_32 (output_bfd, (bfd_vma) 0, contents+4); ++ else ++ bfd_put_32 (output_bfd, ++ sdyn->output_section->vma + sdyn->output_offset, ++ contents+4); ++ ++ elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; ++ } ++ ++ return true; ++} ++ ++/* The RELOCATE_SECTION function is called by the ELF backend linker ++ to handle the relocations for a section. ++ ++ The relocs are always passed as Rela structures; if the section ++ actually uses Rel structures, the r_addend field will always be ++ zero. ++ ++ This function is responsible for adjust the section contents as ++ necessary, and (if using Rela relocs and generating a ++ relocateable output file) adjusting the reloc addend as ++ necessary. ++ ++ This function does not have to worry about setting the reloc ++ address or the reloc symbol index. ++ ++ LOCAL_SYMS is a pointer to the swapped in local symbols. ++ ++ LOCAL_SECTIONS is an array giving the section in the input file ++ corresponding to the st_shndx field of each local symbol. ++ ++ The global hash table entry for the global symbols can be found ++ via elf_sym_hashes (input_bfd). ++ ++ When generating relocateable output, this function must handle ++ STB_LOCAL/STT_SECTION symbols specially. The output symbol is ++ going to be the section symbol corresponding to the output ++ section, which means that the addend must be adjusted ++ accordingly. */ ++ ++static boolean ++ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, ++ contents, relocs, local_syms, local_sections) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ bfd *input_bfd; ++ asection *input_section; ++ bfd_byte *contents; ++ Elf_Internal_Rela *relocs; ++ Elf_Internal_Sym *local_syms; ++ asection **local_sections; ++{ ++ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ elf_linker_section_t *sdata = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA) : NULL; ++ elf_linker_section_t *sdata2 = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA2) : NULL; ++ Elf_Internal_Rela *rel = relocs; ++ Elf_Internal_Rela *relend = relocs + input_section->reloc_count; ++ asection *sreloc = NULL; ++ asection *splt; ++ asection *sgot; ++ bfd_vma *local_got_offsets; ++ boolean ret = true; ++ long insn; ++ asection *sdata_sec = NULL; ++ asection *sbss_sec = NULL; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_relocate_section called for %s section %s, %ld relocations%s\n", ++ bfd_archive_filename (input_bfd), ++ bfd_section_name(input_bfd, input_section), ++ (long) input_section->reloc_count, ++ (info->relocateable) ? " (relocatable)" : ""); ++#endif ++ ++ if (info->relocateable) ++ return true; ++ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ if (!strcmp(bfd_section_name(output_bfd, input_section), ".sdata") || ++ !strcmp(bfd_section_name(output_bfd, input_section), ".sbss")) ++ { ++ sdata_sec = bfd_get_section_by_name(output_bfd, ".sdata"); ++ if (sdata_sec) ++ sdata_sec = sdata_sec->output_section; ++ sbss_sec = bfd_get_section_by_name(output_bfd, ".sbss"); ++ if (sbss_sec) ++ sbss_sec = sbss_sec->output_section; ++ } ++ ++ local_got_offsets = elf_local_got_offsets (input_bfd); ++ ++ splt = sgot = NULL; ++ if (dynobj != NULL) ++ { ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ } ++ ++ for (; rel < relend; rel++) ++ { ++ enum elf_ppc_reloc_type r_type = (enum elf_ppc_reloc_type)ELF32_R_TYPE (rel->r_info); ++ bfd_vma offset = rel->r_offset; ++ bfd_vma addend = rel->r_addend; ++ bfd_reloc_status_type r = bfd_reloc_other; ++ Elf_Internal_Sym *sym = (Elf_Internal_Sym *) 0; ++ asection *sec = (asection *) 0; ++ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) 0; ++ const char *sym_name = (const char *) 0; ++ boolean copy = false; ++ reloc_howto_type *howto; ++ unsigned long r_symndx; ++ bfd_vma relocation; ++ int will_become_local; ++ ++ /* Unknown relocation handling */ ++ if ((unsigned) r_type >= (unsigned) R_PPC_max ++ || !ppc_elf_howto_table[(int) r_type]) ++ { ++ (*_bfd_error_handler) (_("%s: unknown relocation type %d"), ++ bfd_archive_filename (input_bfd), ++ (int) r_type); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ ++ howto = ppc_elf_howto_table[(int) r_type]; ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ ++ if (r_symndx < symtab_hdr->sh_info) ++ { ++ sym = local_syms + r_symndx; ++ sec = local_sections[r_symndx]; ++ sym_name = "<local symbol>"; ++ ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ addend = rel->r_addend; ++ /* Relocs to local symbols are always resolved. */ ++ will_become_local = 1; ++ } ++ else ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ sym_name = h->root.root.string; ++ ++ /* Can this relocation be resolved immediately? */ ++ will_become_local = SYMBOL_REFERENCES_LOCAL (info, h); ++ ++ if (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ { ++ sec = h->root.u.def.section; ++ if (((r_type == R_PPC_PLT32 ++ || r_type == R_PPC_PLTREL24) ++ && splt != NULL ++ && h->plt.offset != (bfd_vma) -1) ++ || (r_type == R_PPC_LOCAL24PC ++ && sec->output_section == NULL) ++ || ((r_type == R_PPC_GOT16 ++ || r_type == R_PPC_GOT16_LO ++ || r_type == R_PPC_GOT16_HI ++ || r_type == R_PPC_GOT16_HA) ++ && elf_hash_table (info)->dynamic_sections_created ++ && (! info->shared || ! will_become_local)) ++ || (info->shared ++ && ! will_become_local ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ /* Testing SEC_DEBUGGING here may be wrong. ++ It's here to avoid a crash when ++ generating a shared library with DWARF ++ debugging information. */ ++ || ((input_section->flags & SEC_DEBUGGING) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_DYNAMIC) != 0)) ++ && (r_type == R_PPC_ADDR32 ++ || r_type == R_PPC_ADDR24 ++ || r_type == R_PPC_ADDR16 ++ || r_type == R_PPC_ADDR16_LO ++ || r_type == R_PPC_ADDR16_HI ++ || r_type == R_PPC_ADDR16_HA ++ || r_type == R_PPC_ADDR14 ++ || r_type == R_PPC_ADDR14_BRTAKEN ++ || r_type == R_PPC_ADDR14_BRNTAKEN ++ || r_type == R_PPC_COPY ++ || r_type == R_PPC_GLOB_DAT ++ || r_type == R_PPC_JMP_SLOT ++ || r_type == R_PPC_UADDR32 ++ || r_type == R_PPC_UADDR16 ++ || r_type == R_PPC_SDAREL16 ++ || r_type == R_PPC_EMB_NADDR32 ++ || r_type == R_PPC_EMB_NADDR16 ++ || r_type == R_PPC_EMB_NADDR16_LO ++ || r_type == R_PPC_EMB_NADDR16_HI ++ || r_type == R_PPC_EMB_NADDR16_HA ++ || r_type == R_PPC_EMB_SDAI16 ++ || r_type == R_PPC_EMB_SDA2I16 ++ || r_type == R_PPC_EMB_SDA2REL ++ || r_type == R_PPC_EMB_SDA21 ++ || r_type == R_PPC_EMB_MRKREF ++ || r_type == R_PPC_EMB_BIT_FLD ++ || r_type == R_PPC_EMB_RELSDA ++ || ((r_type == R_PPC_REL24 ++ || r_type == R_PPC_REL32 ++ || r_type == R_PPC_REL14 ++ || r_type == R_PPC_REL14_BRTAKEN ++ || r_type == R_PPC_REL14_BRNTAKEN ++ || r_type == R_PPC_RELATIVE) ++ && strcmp (h->root.root.string, ++ "_GLOBAL_OFFSET_TABLE_") != 0)))) ++ { ++ /* In these cases, we don't need the relocation ++ value. We check specially because in some ++ obscure cases sec->output_section will be NULL. */ ++ relocation = 0; ++ } ++ else if (sec->output_section == NULL) ++ { ++ (*_bfd_error_handler) ++ (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"), ++ bfd_archive_filename (input_bfd), h->root.root.string, ++ bfd_get_section_name (input_bfd, input_section)); ++ relocation = 0; ++ } ++ else ++ relocation = (h->root.u.def.value ++ + sec->output_section->vma ++ + sec->output_offset); ++ } ++ else if (h->root.type == bfd_link_hash_undefweak) ++ relocation = 0; ++ else if (info->shared ++ && (!info->symbolic || info->allow_shlib_undefined) ++ && !info->no_undefined ++ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) ++ relocation = 0; ++ else ++ { ++ if (! (*info->callbacks->undefined_symbol) (info, ++ h->root.root.string, ++ input_bfd, ++ input_section, ++ rel->r_offset, ++ (!info->shared ++ || info->no_undefined ++ || ELF_ST_VISIBILITY (h->other)))) ++ return false; ++ relocation = 0; ++ } ++ } ++ ++ switch ((int) r_type) ++ { ++ default: ++ (*_bfd_error_handler) (_("%s: unknown relocation type %d for symbol %s"), ++ bfd_archive_filename (input_bfd), ++ (int) r_type, sym_name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ ++ case (int) R_PPC_NONE: ++ continue; ++ ++ /* Relocations that need no special processing. */ ++ case (int) R_PPC_LOCAL24PC: ++ /* It makes no sense to point a local relocation ++ at a symbol not in this object. */ ++ if (h != NULL ++ && (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && sec->output_section == NULL) ++ { ++ if (! (*info->callbacks->undefined_symbol) (info, ++ h->root.root.string, ++ input_bfd, ++ input_section, ++ rel->r_offset, ++ true)) ++ return false; ++ continue; ++ } ++ break; ++ ++ /* Relocations that may need to be propagated if this is a shared ++ object. */ ++ case (int) R_PPC_REL24: ++ case (int) R_PPC_REL32: ++ case (int) R_PPC_REL14: ++ /* If these relocations are not to a named symbol, they can be ++ handled right here, no need to bother the dynamic linker. */ ++ if (info->shared && (h == NULL ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || SYMBOL_REFERENCES_LOCAL (info, h))) ++ break; ++ /* fall through */ ++ ++ /* Relocations that always need to be propagated if this is a shared ++ object. */ ++ case (int) R_PPC_ADDR32: ++ case (int) R_PPC_ADDR24: ++ case (int) R_PPC_ADDR16: ++ case (int) R_PPC_ADDR16_LO: ++ case (int) R_PPC_ADDR16_HI: ++ case (int) R_PPC_ADDR16_HA: ++ case (int) R_PPC_ADDR14: ++ case (int) R_PPC_UADDR32: ++ case (int) R_PPC_UADDR16: ++ if (info->shared && r_symndx != 0) ++ { ++ Elf_Internal_Rela outrel; ++ int skip; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_relocate_section need to create relocation for %s\n", ++ (h && h->root.root.string) ? h->root.root.string : "<unknown>"); ++#endif ++ ++ /* When generating a shared object, these relocations ++ are copied into the output file to be resolved at run ++ time. */ ++ ++ if (sreloc == NULL) ++ { ++ const char *name; ++ ++ name = (bfd_elf_string_from_elf_section ++ (input_bfd, ++ elf_elfheader (input_bfd)->e_shstrndx, ++ elf_section_data (input_section)->rel_hdr.sh_name)); ++ if (name == NULL) ++ return false; ++ ++ BFD_ASSERT (strncmp (name, ".rela", 5) == 0 ++ && strcmp (bfd_get_section_name (input_bfd, ++ input_section), ++ name + 5) == 0); ++ ++ sreloc = bfd_get_section_by_name (dynobj, name); ++ BFD_ASSERT (sreloc != NULL); ++ } ++ ++ skip = 0; ++ ++ outrel.r_offset = ++ _bfd_elf_section_offset (output_bfd, info, input_section, ++ rel->r_offset); ++ if (outrel.r_offset == (bfd_vma) -1 ++ || outrel.r_offset == (bfd_vma) -2) ++ skip = (int) outrel.r_offset; ++ outrel.r_offset += (input_section->output_section->vma ++ + input_section->output_offset); ++ ++ if (skip) ++ memset (&outrel, 0, sizeof outrel); ++ /* h->dynindx may be -1 if this symbol was marked to ++ become local. */ ++ else if (! will_become_local) ++ { ++ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); ++ outrel.r_addend = rel->r_addend; ++ } ++ else ++ { ++ if (r_type == R_PPC_ADDR32) ++ { ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ outrel.r_addend = relocation + rel->r_addend; ++ } ++ else ++ { ++ long indx; ++ ++ if (h == NULL) ++ sec = local_sections[r_symndx]; ++ else ++ { ++ BFD_ASSERT (h->root.type == bfd_link_hash_defined ++ || (h->root.type ++ == bfd_link_hash_defweak)); ++ sec = h->root.u.def.section; ++ } ++ if (sec != NULL && bfd_is_abs_section (sec)) ++ indx = 0; ++ else if (sec == NULL || sec->owner == NULL) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ else ++ { ++ asection *osec; ++ ++ osec = sec->output_section; ++ indx = elf_section_data (osec)->dynindx; ++ BFD_ASSERT (indx > 0); ++#ifdef DEBUG ++ if (indx <= 0) ++ { ++ printf ("indx=%d section=%s flags=%08x name=%s\n", ++ indx, osec->name, osec->flags, ++ h->root.root.string); ++ } ++#endif ++ } ++ ++ outrel.r_info = ELF32_R_INFO (indx, r_type); ++ outrel.r_addend = relocation + rel->r_addend; ++ } ++ } ++ ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, ++ (((Elf32_External_Rela *) ++ sreloc->contents) ++ + sreloc->reloc_count)); ++ ++sreloc->reloc_count; ++ ++ if (skip == -1) ++ continue; ++ ++ /* This reloc will be computed at runtime. We clear the memory ++ so that it contains predictable value. */ ++ if (! skip ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ || ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE)) ++ { ++ relocation = howto->pc_relative ? outrel.r_offset : 0; ++ addend = 0; ++ break; ++ } ++ } ++ else if (r_type == R_PPC_REL24 || r_type == R_PPC_REL14) ++ { ++ if (sec->output_section != input_section->output_section) ++ { ++ (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)", ++ bfd_get_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[ (int)r_type ]->name, ++ bfd_get_section_name (abfd, sec)); ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ break; ++ } ++ else if (r_type == R_PPC_REL32) ++ { ++ if (sec->output_section != input_section->output_section) ++ copy = true; ++ else ++ break; ++ } ++ else if (ddr_ptr && sec && r_type == R_PPC_ADDR32 && ++ (sec->output_section == sdata_sec || ++ sec->output_section == sbss_sec || ++ !strcmp(bfd_get_section_name(abfd, sec), "COMMON") || ++ !strcmp(bfd_get_section_name(abfd, sec), ".data") || ++ !strcmp(bfd_get_section_name(abfd, sec), ".bss")) && ++ (input_section->output_section == sdata_sec || ++ input_section->output_section == sbss_sec || ++ !strcmp(bfd_get_section_name(abfd, input_section), "COMMON") || ++ !strcmp(bfd_get_section_name(abfd, input_section), ".data") || ++ !strcmp(bfd_get_section_name(abfd, input_section), ".bss"))) ++ { ++ ++ddr_count; ++ *ddr_ptr++ = input_section->output_offset + offset; ++ copy = true; ++ break; ++ } ++ else if (sec && !bfd_is_abs_section(sec)) ++ { ++ copy = true; ++ break; ++ } ++ ++ if (copy && ddr_ptr && sec && ++ (sec->output_section == sdata_sec || ++ sec->output_section == sbss_sec || ++ !strcmp(bfd_get_section_name(abfd, sec), "COMMON") || ++ !strcmp(bfd_get_section_name(abfd, sec), ".data") || ++ !strcmp(bfd_get_section_name(abfd, sec), ".bss")) /*&& ++ (r_type != R_PPC_ADDR32 || ++ !(input_section->output_section == sdata_sec->output_section || ++ input_section->output_section == sbss_sec->output_section || ++ !strcmp(bfd_get_section_name(abfd, input_section), "COMMON") || ++ !strcmp(bfd_get_section_name(abfd, input_section), ".data") || ++ !strcmp(bfd_get_section_name(abfd, input_section), ".bss")))*/) ++ { ++ (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)", ++ bfd_get_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[ (int)r_type ]->name, ++ bfd_get_section_name (abfd, sec)); ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ ++ /* Arithmetic adjust relocations that aren't going into a ++ shared object. */ ++ if (r_type == R_PPC_ADDR16_HA ++ /* It's just possible that this symbol is a weak symbol ++ that's not actually defined anywhere. In that case, ++ 'sec' would be NULL, and we should leave the symbol ++ alone (it will be set to zero elsewhere in the link). */ ++ && sec != NULL) ++ { ++ addend += ((relocation + addend) & 0x8000) << 1; ++ } ++ break; ++ ++ /* branch taken prediction relocations */ ++ case (int) R_PPC_ADDR14_BRTAKEN: ++ case (int) R_PPC_REL14_BRTAKEN: ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ if ((relocation - offset) & 0x8000) ++ insn &= ~BRANCH_PREDICT_BIT; ++ else ++ insn |= BRANCH_PREDICT_BIT; ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ break; ++ ++ /* branch not taken predicition relocations */ ++ case (int) R_PPC_ADDR14_BRNTAKEN: ++ case (int) R_PPC_REL14_BRNTAKEN: ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ if ((relocation - offset) & 0x8000) ++ insn |= BRANCH_PREDICT_BIT; ++ else ++ insn &= ~BRANCH_PREDICT_BIT; ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ break; ++ ++ /* GOT16 relocations */ ++ case (int) R_PPC_GOT16: ++ case (int) R_PPC_GOT16_LO: ++ case (int) R_PPC_GOT16_HI: ++ case (int) R_PPC_GOT16_HA: ++ /* Relocation is to the entry for this symbol in the global ++ offset table. */ ++ BFD_ASSERT (sgot != NULL); ++ ++ if (h != NULL) ++ { ++ bfd_vma off; ++ ++ off = h->got.offset; ++ BFD_ASSERT (off != (bfd_vma) -1); ++ ++ if (! elf_hash_table (info)->dynamic_sections_created ++ || (info->shared ++ && SYMBOL_REFERENCES_LOCAL (info, h))) ++ { ++ /* This is actually a static link, or it is a ++ -Bsymbolic link and the symbol is defined ++ locally. We must initialize this entry in the ++ global offset table. Since the offset must ++ always be a multiple of 4, we use the least ++ significant bit to record whether we have ++ initialized it already. ++ ++ When doing a dynamic link, we create a .rela.got ++ relocation entry to initialize the value. This ++ is done in the finish_dynamic_symbol routine. */ ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ bfd_put_32 (output_bfd, relocation, ++ sgot->contents + off); ++ h->got.offset |= 1; ++ } ++ } ++ ++ relocation = sgot->output_offset + off - 4; ++ } ++ else ++ { ++ bfd_vma off; ++ ++ BFD_ASSERT (local_got_offsets != NULL ++ && local_got_offsets[r_symndx] != (bfd_vma) -1); ++ ++ off = local_got_offsets[r_symndx]; ++ ++ /* The offset must always be a multiple of 4. We use ++ the least significant bit to record whether we have ++ already processed this entry. */ ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ ++ if (info->shared) ++ { ++ asection *srelgot; ++ Elf_Internal_Rela outrel; ++ ++ /* We need to generate a R_PPC_RELATIVE reloc ++ for the dynamic linker. */ ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ BFD_ASSERT (srelgot != NULL); ++ ++ outrel.r_offset = (sgot->output_section->vma ++ + sgot->output_offset ++ + off); ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ outrel.r_addend = relocation; ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, ++ (((Elf32_External_Rela *) ++ srelgot->contents) ++ + srelgot->reloc_count)); ++ ++srelgot->reloc_count; ++ relocation = 0; ++ } ++ ++ bfd_put_32 (output_bfd, relocation, sgot->contents + off); ++ local_got_offsets[r_symndx] |= 1; ++ } ++ ++ relocation = sgot->output_offset + off - 4; ++ } ++ break; ++ ++ /* Indirect .sdata relocation */ ++ case (int) R_PPC_EMB_SDAI16: ++ BFD_ASSERT (sdata != NULL); ++ relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, ++ sdata, h, relocation, rel, ++ R_PPC_RELATIVE); ++ break; ++ ++ /* Indirect .sdata2 relocation */ ++ case (int) R_PPC_EMB_SDA2I16: ++ BFD_ASSERT (sdata2 != NULL); ++ relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, ++ sdata2, h, relocation, rel, ++ R_PPC_RELATIVE); ++ break; ++ ++ /* Handle the TOC16 reloc. We want to use the offset within the .got ++ section, not the actual VMA. This is appropriate when generating ++ an embedded ELF object, for which the .got section acts like the ++ AIX .toc section. */ ++ case (int) R_PPC_TOC16: /* phony GOT16 relocations */ ++ BFD_ASSERT (sec != (asection *) 0); ++ BFD_ASSERT (bfd_is_und_section (sec) ++ || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 ++ || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0) ++ ++ addend -= sec->output_section->vma + sec->output_offset + 0x8000; ++ break; ++ ++ case (int) R_PPC_PLTREL24: ++ /* Relocation is to the entry for this symbol in the ++ procedure linkage table. */ ++ BFD_ASSERT (h != NULL); ++ ++ if (h->plt.offset == (bfd_vma) -1 ++ || splt == NULL) ++ { ++ /* We didn't make a PLT entry for this symbol. This ++ happens when statically linking PIC code, or when ++ using -Bsymbolic. */ ++ break; ++ } ++ ++ relocation = (splt->output_section->vma ++ + splt->output_offset ++ + h->plt.offset); ++ break; ++ ++ /* relocate against _SDA_BASE_ */ ++ case (int) R_PPC_SDAREL16: ++ { ++ const char *name; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sbss") != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ } ++ addend -= (sdata->sym_hash->root.u.def.value ++ + sdata->sym_hash->root.u.def.section->output_section->vma ++ /*+ sdata->sym_hash->root.u.def.section->output_offset*/); ++ } ++ break; ++ ++ /* relocate against _SDA_BASE_, in large data mode */ ++ case (int)R_PPC_MORPHOS_DREL: ++ case (int)R_PPC_MORPHOS_DREL_LO: ++ case (int)R_PPC_MORPHOS_DREL_HI: ++ case (int)R_PPC_MORPHOS_DREL_HA: ++ BFD_ASSERT (sec != (asection *)0); ++ if (strcmp (bfd_get_section_name (abfd, sec), ".sdata") != 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ".data") != 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ".bss") != 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ".sbss") != 0 ++ && strcmp (bfd_get_section_name (abfd, sec), "COMMON") != 0) ++ { ++ (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)", ++ bfd_get_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[ (int)r_type ]->name, ++ bfd_get_section_name (abfd, sec)); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ /*printf("DREL: addend = %x, sdata->val = %x, vma = %x, output_offset = %x\n", ++ addend, sdata->sym_hash->root.u.def.value, ++ sdata->sym_hash->root.u.def.section->output_section->vma, ++ sdata->sym_hash->root.u.def.section->output_offset);*/ ++ addend -= (sdata->sym_hash->root.u.def.value ++ + sdata->sym_hash->root.u.def.section->output_section->vma ++ /*+ sdata->sym_hash->root.u.def.section->output_offset*/); ++ if (r_type == R_PPC_MORPHOS_DREL_HA) ++ addend += ((relocation + addend) & 0x8000) << 1; ++ break; ++ ++ /* relocate against _SDA2_BASE_ */ ++ case (int) R_PPC_EMB_SDA2REL: ++ { ++ const char *name; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata2") != 0 && strcmp (name, ".sbss2") != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ addend -= (sdata2->sym_hash->root.u.def.value ++ + sdata2->sym_hash->root.u.def.section->output_section->vma ++ + sdata2->sym_hash->root.u.def.section->output_offset); ++ } ++ break; ++ ++ /* relocate against either _SDA_BASE_, _SDA2_BASE_, or 0 */ ++ case (int) R_PPC_EMB_SDA21: ++ case (int) R_PPC_EMB_RELSDA: ++ { ++ const char *name; ++ int reg; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0) ++ { ++ reg = 13; ++ addend -= (sdata->sym_hash->root.u.def.value ++ + sdata->sym_hash->root.u.def.section->output_section->vma ++ + sdata->sym_hash->root.u.def.section->output_offset); ++ } ++ ++ else if (strcmp (name, ".sdata2") == 0 ++ || strcmp (name, ".sbss2") == 0) ++ { ++ reg = 2; ++ addend -= (sdata2->sym_hash->root.u.def.value ++ + sdata2->sym_hash->root.u.def.section->output_section->vma ++ + sdata2->sym_hash->root.u.def.section->output_offset); ++ } ++ ++ else if (strcmp (name, ".PPC.EMB.sdata0") == 0 ++ || strcmp (name, ".PPC.EMB.sbss0") == 0) ++ { ++ reg = 0; ++ } ++ ++ else ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ ++ if (r_type == R_PPC_EMB_SDA21) ++ { /* fill in register field */ ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ } ++ } ++ break; ++ ++ /* Relocate against the beginning of the section */ ++ case (int) R_PPC_SECTOFF: ++ case (int) R_PPC_SECTOFF_LO: ++ case (int) R_PPC_SECTOFF_HI: ++ BFD_ASSERT (sec != (asection *) 0); ++ addend -= sec->output_section->vma; ++ break; ++ ++ case (int) R_PPC_SECTOFF_HA: ++ BFD_ASSERT (sec != (asection *) 0); ++ addend -= sec->output_section->vma; ++ addend += ((relocation + addend) & 0x8000) << 1; ++ break; ++ ++ /* Negative relocations */ ++ case (int) R_PPC_EMB_NADDR32: ++ case (int) R_PPC_EMB_NADDR16: ++ case (int) R_PPC_EMB_NADDR16_LO: ++ case (int) R_PPC_EMB_NADDR16_HI: ++ addend -= 2 * relocation; ++ break; ++ ++ case (int) R_PPC_EMB_NADDR16_HA: ++ addend -= 2 * relocation; ++ addend += ((relocation + addend) & 0x8000) << 1; ++ break; ++ ++ /* NOP relocation that prevents garbage collecting linkers from omitting a ++ reference. */ ++ case (int) R_PPC_EMB_MRKREF: ++ continue; ++ ++ case (int) R_PPC_COPY: ++ case (int) R_PPC_GLOB_DAT: ++ case (int) R_PPC_JMP_SLOT: ++ case (int) R_PPC_RELATIVE: ++ case (int) R_PPC_PLT32: ++ case (int) R_PPC_PLTREL32: ++ case (int) R_PPC_PLT16_LO: ++ case (int) R_PPC_PLT16_HI: ++ case (int) R_PPC_PLT16_HA: ++ case (int) R_PPC_EMB_RELSEC16: ++ case (int) R_PPC_EMB_RELST_LO: ++ case (int) R_PPC_EMB_RELST_HI: ++ case (int) R_PPC_EMB_RELST_HA: ++ case (int) R_PPC_EMB_BIT_FLD: ++ (*_bfd_error_handler) (_("%s: Relocation %s is not yet supported for symbol %s."), ++ bfd_archive_filename (input_bfd), ++ ppc_elf_howto_table[(int) r_type]->name, ++ sym_name); ++ ++ bfd_set_error (bfd_error_invalid_operation); ++ ret = false; ++ continue; ++ ++ case (int) R_PPC_GNU_VTINHERIT: ++ case (int) R_PPC_GNU_VTENTRY: ++ /* These are no-ops in the end. */ ++ continue; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, offset = %ld, addend = %ld\n", ++ howto->name, ++ (int) r_type, ++ sym_name, ++ r_symndx, ++ (long) offset, ++ (long) addend); ++#endif ++ if (copy) ++ { ++ Elf_Internal_Rela outrel; ++ ++ if (sec == NULL) /* Don't know if it is possible... */ ++ abort(); ++ ++ /*printf("copying reloc %d, addend=%x, rel=%x, indx=%d, offset=%x, sec_vma=%x\n", ++ r_type,addend,relocation,sec->output_section->target_index, ++ sec->output_offset,sec->output_section->vma);*/ ++ ++ outrel.r_info = ELF32_R_INFO(sec->output_section->target_index, r_type); ++ outrel.r_addend = relocation + addend - sec->output_section->vma; ++ outrel.r_offset = input_section->output_offset + offset; ++ ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, ++ (((Elf32_External_Rela *) ++ elf_section_data(input_section->output_section)-> ++ rel_hdr.contents) ++ + input_section->output_section->reloc_count)); ++ ++input_section->output_section->reloc_count; ++ } ++ else ++ { ++ /*printf("applying reloc %d, sym=%s addend=%x, rel=%x, indx=%d, offset=%x, sec_vma=%x\n", ++ r_type,sym_name,addend,relocation,sec->output_section->target_index, ++ sec->output_offset,sec->output_section->vma);*/ ++ ++ r = _bfd_final_link_relocate (howto, ++ input_bfd, ++ input_section, ++ contents, ++ offset, ++ relocation, ++ addend); ++ ++ if (r == bfd_reloc_ok) ++ ; ++ else if (r == bfd_reloc_overflow) ++ { ++ const char *name; ++ ++ if (h != NULL) ++ { ++ if (h->root.type == bfd_link_hash_undefweak ++ && howto->pc_relative) ++ { ++ /* Assume this is a call protected by other code that ++ detect the symbol is undefined. If this is the case, ++ we can safely ignore the overflow. If not, the ++ program is hosed anyway, and a little warning isn't ++ going to help. */ ++ ++ continue; ++ } ++ ++ name = h->root.root.string; ++ } ++ else ++ { ++ name = bfd_elf_string_from_elf_section (input_bfd, ++ symtab_hdr->sh_link, ++ sym->st_name); ++ if (name == NULL) ++ continue; ++ if (*name == '\0') ++ name = bfd_section_name (input_bfd, sec); ++ } ++ ++ if (! (*info->callbacks->reloc_overflow) (info, ++ name, ++ howto->name, ++ (bfd_vma) 0, ++ input_bfd, ++ input_section, ++ offset)) ++ return false; ++ } ++ else ++ ret = false; ++ } ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ return ret; ++} ++ ++static enum elf_reloc_type_class ++ppc_elf_reloc_type_class (rela) ++ const Elf_Internal_Rela *rela; ++{ ++ switch ((int) ELF32_R_TYPE (rela->r_info)) ++ { ++ case R_PPC_RELATIVE: ++ return reloc_class_relative; ++ case R_PPC_REL24: ++ case R_PPC_ADDR24: ++ case R_PPC_JMP_SLOT: ++ return reloc_class_plt; ++ case R_PPC_COPY: ++ return reloc_class_copy; ++ default: ++ return reloc_class_normal; ++ } ++} ++ ++/* Support for core dump NOTE sections */ ++static boolean ++ppc_elf_grok_prstatus (abfd, note) ++ bfd *abfd; ++ Elf_Internal_Note *note; ++{ ++ int offset; ++ unsigned int raw_size; ++ ++ switch (note->descsz) ++ { ++ default: ++ return false; ++ ++ case 268: /* Linux/PPC */ ++ /* pr_cursig */ ++ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); ++ ++ /* pr_pid */ ++ elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); ++ ++ /* pr_reg */ ++ offset = 72; ++ raw_size = 192; ++ ++ break; ++ } ++ ++ /* Make a ".reg/999" section. */ ++ return _bfd_elfcore_make_pseudosection (abfd, ".reg", ++ raw_size, note->descpos + offset); ++} ++ ++static boolean ++ppc_elf_grok_psinfo (abfd, note) ++ bfd *abfd; ++ Elf_Internal_Note *note; ++{ ++ switch (note->descsz) ++ { ++ default: ++ return false; ++ ++ case 128: /* Linux/PPC elf_prpsinfo */ ++ elf_tdata (abfd)->core_program ++ = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); ++ elf_tdata (abfd)->core_command ++ = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); ++ } ++ ++ /* Note that for some reason, a spurious space is tacked ++ onto the end of the args in some (at least one anyway) ++ implementations, so strip it off if it exists. */ ++ ++ { ++ char *command = elf_tdata (abfd)->core_command; ++ int n = strlen (command); ++ ++ if (0 < n && command[n - 1] == ' ') ++ command[n - 1] = '\0'; ++ } ++ ++ return true; ++} ++ ++/* Special MorphOS final link routine. */ ++/* This is almost the same as the elf one, except for the hanling of relocations */ ++ ++/* A structure we use to avoid passing large numbers of arguments. */ ++ ++struct elf_final_link_info ++{ ++ /* General link information. */ ++ struct bfd_link_info *info; ++ /* Output BFD. */ ++ bfd *output_bfd; ++ /* Symbol string table. */ ++ struct bfd_strtab_hash *symstrtab; ++ /* .dynsym section. */ ++ asection *dynsym_sec; ++ /* .hash section. */ ++ asection *hash_sec; ++ /* symbol version section (.gnu.version). */ ++ asection *symver_sec; ++ /* first SHF_TLS section (if any). */ ++ asection *first_tls_sec; ++ /* Buffer large enough to hold contents of any section. */ ++ bfd_byte *contents; ++ /* Buffer large enough to hold external relocs of any section. */ ++ PTR external_relocs; ++ /* Buffer large enough to hold internal relocs of any section. */ ++ Elf_Internal_Rela *internal_relocs; ++ /* Buffer large enough to hold external local symbols of any input ++ BFD. */ ++ Elf_External_Sym *external_syms; ++ /* And a buffer for symbol section indices. */ ++ Elf_External_Sym_Shndx *locsym_shndx; ++ /* Buffer large enough to hold internal local symbols of any input ++ BFD. */ ++ Elf_Internal_Sym *internal_syms; ++ /* Array large enough to hold a symbol index for each local symbol ++ of any input BFD. */ ++ long *indices; ++ /* Array large enough to hold a section pointer for each local ++ symbol of any input BFD. */ ++ asection **sections; ++ /* Buffer to hold swapped out symbols. */ ++ Elf_External_Sym *symbuf; ++ /* And one for symbol section indices. */ ++ Elf_External_Sym_Shndx *symshndxbuf; ++ /* Number of swapped out symbols in buffer. */ ++ size_t symbuf_count; ++ /* Number of symbols which fit in symbuf. */ ++ size_t symbuf_size; ++}; ++ ++static boolean elf_link_output_sym ++ PARAMS ((struct elf_final_link_info *, const char *, ++ Elf_Internal_Sym *, asection *)); ++static boolean elf_link_flush_output_syms ++ PARAMS ((struct elf_final_link_info *)); ++static boolean elf_link_output_extsym ++ PARAMS ((struct elf_link_hash_entry *, PTR)); ++static boolean elf_link_sec_merge_syms ++ PARAMS ((struct elf_link_hash_entry *, PTR)); ++static boolean elf_link_check_versioned_symbol ++ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); ++static boolean elf_link_input_bfd ++ PARAMS ((struct elf_final_link_info *, bfd *)); ++static boolean elf_reloc_link_order ++ PARAMS ((bfd *, struct bfd_link_info *, asection *, ++ struct bfd_link_order *)); ++ ++static boolean elf_section_ignore_discarded_relocs ++ PARAMS ((asection *)); ++ ++/* This struct is used to pass information to elf_link_output_extsym. */ ++ ++struct elf_outext_info ++{ ++ boolean failed; ++ boolean localsyms; ++ struct elf_final_link_info *finfo; ++}; ++ ++/* Compute the size of, and allocate space for, REL_HDR which is the ++ section header for a section containing relocations for O. */ ++ ++static boolean ++elf_link_size_reloc_section (abfd, rel_hdr, o) ++ bfd *abfd; ++ Elf_Internal_Shdr *rel_hdr; ++ asection *o; ++{ ++ bfd_size_type reloc_count; ++ bfd_size_type num_rel_hashes; ++ ++ /* Figure out how many relocations there will be. */ ++ if (rel_hdr == &elf_section_data (o)->rel_hdr) ++ reloc_count = elf_section_data (o)->rel_count; ++ else ++ reloc_count = elf_section_data (o)->rel_count2; ++ ++ num_rel_hashes = o->reloc_count; ++ if (num_rel_hashes < reloc_count) ++ num_rel_hashes = reloc_count; ++ ++ /* That allows us to calculate the size of the section. */ ++ rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count; ++ ++ /* The contents field must last into write_object_contents, so we ++ allocate it with bfd_alloc rather than malloc. Also since we ++ cannot be sure that the contents will actually be filled in, ++ we zero the allocated space. */ ++ rel_hdr->contents = (PTR) bfd_zalloc (abfd, rel_hdr->sh_size); ++ if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0) ++ return false; ++ ++ /* We only allocate one set of hash entries, so we only do it the ++ first time we are called. */ ++ if (elf_section_data (o)->rel_hashes == NULL ++ && num_rel_hashes) ++ { ++ struct elf_link_hash_entry **p; ++ ++ p = ((struct elf_link_hash_entry **) ++ bfd_zmalloc (num_rel_hashes ++ * sizeof (struct elf_link_hash_entry *))); ++ if (p == NULL) ++ return false; ++ ++ elf_section_data (o)->rel_hashes = p; ++ } ++ ++ return true; ++} ++ ++/* When performing a relocateable link, the input relocations are ++ preserved. But, if they reference global symbols, the indices ++ referenced must be updated. Update all the relocations in ++ REL_HDR (there are COUNT of them), using the data in REL_HASH. */ ++ ++static void ++elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash) ++ bfd *abfd; ++ Elf_Internal_Shdr *rel_hdr; ++ unsigned int count; ++ struct elf_link_hash_entry **rel_hash; ++{ ++ unsigned int i; ++ struct elf_backend_data *bed = get_elf_backend_data (abfd); ++ Elf_Internal_Rel *irel; ++ Elf_Internal_Rela *irela; ++ bfd_size_type amt = sizeof (Elf_Internal_Rel) * bed->s->int_rels_per_ext_rel; ++ ++ irel = (Elf_Internal_Rel *) bfd_zmalloc (amt); ++ if (irel == NULL) ++ { ++ (*_bfd_error_handler) (_("Error: out of memory")); ++ abort (); ++ } ++ ++ amt = sizeof (Elf_Internal_Rela) * bed->s->int_rels_per_ext_rel; ++ irela = (Elf_Internal_Rela *) bfd_zmalloc (amt); ++ if (irela == NULL) ++ { ++ (*_bfd_error_handler) (_("Error: out of memory")); ++ abort (); ++ } ++ ++ for (i = 0; i < count; i++, rel_hash++) ++ { ++ if (*rel_hash == NULL) ++ continue; ++ ++ BFD_ASSERT ((*rel_hash)->indx >= 0); ++ ++ if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) ++ { ++ Elf_External_Rel *erel; ++ unsigned int j; ++ ++ erel = (Elf_External_Rel *) rel_hdr->contents + i; ++ if (bed->s->swap_reloc_in) ++ (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, irel); ++ else ++ elf_swap_reloc_in (abfd, erel, irel); ++ ++ for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) ++ irel[j].r_info = ELF_R_INFO ((*rel_hash)->indx, ++ ELF_R_TYPE (irel[j].r_info)); ++ ++ if (bed->s->swap_reloc_out) ++ (*bed->s->swap_reloc_out) (abfd, irel, (bfd_byte *) erel); ++ else ++ elf_swap_reloc_out (abfd, irel, erel); ++ } ++ else ++ { ++ Elf_External_Rela *erela; ++ unsigned int j; ++ ++ BFD_ASSERT (rel_hdr->sh_entsize ++ == sizeof (Elf_External_Rela)); ++ ++ erela = (Elf_External_Rela *) rel_hdr->contents + i; ++ if (bed->s->swap_reloca_in) ++ (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, irela); ++ else ++ elf_swap_reloca_in (abfd, erela, irela); ++ ++ for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) ++ irela[j].r_info = ELF_R_INFO ((*rel_hash)->indx, ++ ELF_R_TYPE (irela[j].r_info)); ++ ++ if (bed->s->swap_reloca_out) ++ (*bed->s->swap_reloca_out) (abfd, irela, (bfd_byte *) erela); ++ else ++ elf_swap_reloca_out (abfd, irela, erela); ++ } ++ } ++ ++ free (irel); ++ free (irela); ++} ++ ++struct elf_link_sort_rela ++{ ++ bfd_vma offset; ++ enum elf_reloc_type_class type; ++ union ++ { ++ Elf_Internal_Rel rel; ++ Elf_Internal_Rela rela; ++ } u; ++}; ++ ++static int ++elf_link_sort_cmp1 (A, B) ++ const PTR A; ++ const PTR B; ++{ ++ struct elf_link_sort_rela *a = (struct elf_link_sort_rela *) A; ++ struct elf_link_sort_rela *b = (struct elf_link_sort_rela *) B; ++ int relativea, relativeb; ++ ++ relativea = a->type == reloc_class_relative; ++ relativeb = b->type == reloc_class_relative; ++ ++ if (relativea < relativeb) ++ return 1; ++ if (relativea > relativeb) ++ return -1; ++ if (ELF_R_SYM (a->u.rel.r_info) < ELF_R_SYM (b->u.rel.r_info)) ++ return -1; ++ if (ELF_R_SYM (a->u.rel.r_info) > ELF_R_SYM (b->u.rel.r_info)) ++ return 1; ++ if (a->u.rel.r_offset < b->u.rel.r_offset) ++ return -1; ++ if (a->u.rel.r_offset > b->u.rel.r_offset) ++ return 1; ++ return 0; ++} ++ ++static int ++elf_link_sort_cmp2 (A, B) ++ const PTR A; ++ const PTR B; ++{ ++ struct elf_link_sort_rela *a = (struct elf_link_sort_rela *) A; ++ struct elf_link_sort_rela *b = (struct elf_link_sort_rela *) B; ++ int copya, copyb; ++ ++ if (a->offset < b->offset) ++ return -1; ++ if (a->offset > b->offset) ++ return 1; ++ copya = (a->type == reloc_class_copy) * 2 + (a->type == reloc_class_plt); ++ copyb = (b->type == reloc_class_copy) * 2 + (b->type == reloc_class_plt); ++ if (copya < copyb) ++ return -1; ++ if (copya > copyb) ++ return 1; ++ if (a->u.rel.r_offset < b->u.rel.r_offset) ++ return -1; ++ if (a->u.rel.r_offset > b->u.rel.r_offset) ++ return 1; ++ return 0; ++} ++ ++static size_t ++elf_link_sort_relocs (abfd, info, psec) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ asection **psec; ++{ ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ asection *reldyn, *o; ++ boolean rel = false; ++ bfd_size_type count, size; ++ size_t i, j, ret; ++ struct elf_link_sort_rela *rela; ++ struct elf_backend_data *bed = get_elf_backend_data (abfd); ++ ++ reldyn = bfd_get_section_by_name (abfd, ".rela.dyn"); ++ if (reldyn == NULL || reldyn->_raw_size == 0) ++ { ++ reldyn = bfd_get_section_by_name (abfd, ".rel.dyn"); ++ if (reldyn == NULL || reldyn->_raw_size == 0) ++ return 0; ++ rel = true; ++ count = reldyn->_raw_size / sizeof (Elf_External_Rel); ++ } ++ else ++ count = reldyn->_raw_size / sizeof (Elf_External_Rela); ++ ++ size = 0; ++ for (o = dynobj->sections; o != NULL; o = o->next) ++ if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)) ++ == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED) ++ && o->output_section == reldyn) ++ size += o->_raw_size; ++ ++ if (size != reldyn->_raw_size) ++ return 0; ++ ++ rela = (struct elf_link_sort_rela *) bfd_zmalloc (sizeof (*rela) * count); ++ if (rela == NULL) ++ { ++ (*info->callbacks->warning) ++ (info, _("Not enough memory to sort relocations"), 0, abfd, 0, ++ (bfd_vma) 0); ++ return 0; ++ } ++ ++ for (o = dynobj->sections; o != NULL; o = o->next) ++ if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)) ++ == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED) ++ && o->output_section == reldyn) ++ { ++ if (rel) ++ { ++ Elf_External_Rel *erel, *erelend; ++ struct elf_link_sort_rela *s; ++ ++ erel = (Elf_External_Rel *) o->contents; ++ erelend = (Elf_External_Rel *) (o->contents + o->_raw_size); ++ s = rela + o->output_offset / sizeof (Elf_External_Rel); ++ for (; erel < erelend; erel++, s++) ++ { ++ if (bed->s->swap_reloc_in) ++ (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &s->u.rel); ++ else ++ elf_swap_reloc_in (abfd, erel, &s->u.rel); ++ ++ s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela); ++ } ++ } ++ else ++ { ++ Elf_External_Rela *erela, *erelaend; ++ struct elf_link_sort_rela *s; ++ ++ erela = (Elf_External_Rela *) o->contents; ++ erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size); ++ s = rela + o->output_offset / sizeof (Elf_External_Rela); ++ for (; erela < erelaend; erela++, s++) ++ { ++ if (bed->s->swap_reloca_in) ++ (*bed->s->swap_reloca_in) (dynobj, (bfd_byte *) erela, ++ &s->u.rela); ++ else ++ elf_swap_reloca_in (dynobj, erela, &s->u.rela); ++ ++ s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela); ++ } ++ } ++ } ++ ++ qsort (rela, (size_t) count, sizeof (*rela), elf_link_sort_cmp1); ++ for (ret = 0; ret < count && rela[ret].type == reloc_class_relative; ret++) ++ ; ++ for (i = ret, j = ret; i < count; i++) ++ { ++ if (ELF_R_SYM (rela[i].u.rel.r_info) != ELF_R_SYM (rela[j].u.rel.r_info)) ++ j = i; ++ rela[i].offset = rela[j].u.rel.r_offset; ++ } ++ qsort (rela + ret, (size_t) count - ret, sizeof (*rela), elf_link_sort_cmp2); ++ ++ for (o = dynobj->sections; o != NULL; o = o->next) ++ if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)) ++ == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED) ++ && o->output_section == reldyn) ++ { ++ if (rel) ++ { ++ Elf_External_Rel *erel, *erelend; ++ struct elf_link_sort_rela *s; ++ ++ erel = (Elf_External_Rel *) o->contents; ++ erelend = (Elf_External_Rel *) (o->contents + o->_raw_size); ++ s = rela + o->output_offset / sizeof (Elf_External_Rel); ++ for (; erel < erelend; erel++, s++) ++ { ++ if (bed->s->swap_reloc_out) ++ (*bed->s->swap_reloc_out) (abfd, &s->u.rel, ++ (bfd_byte *) erel); ++ else ++ elf_swap_reloc_out (abfd, &s->u.rel, erel); ++ } ++ } ++ else ++ { ++ Elf_External_Rela *erela, *erelaend; ++ struct elf_link_sort_rela *s; ++ ++ erela = (Elf_External_Rela *) o->contents; ++ erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size); ++ s = rela + o->output_offset / sizeof (Elf_External_Rela); ++ for (; erela < erelaend; erela++, s++) ++ { ++ if (bed->s->swap_reloca_out) ++ (*bed->s->swap_reloca_out) (dynobj, &s->u.rela, ++ (bfd_byte *) erela); ++ else ++ elf_swap_reloca_out (dynobj, &s->u.rela, erela); ++ } ++ } ++ } ++ ++ free (rela); ++ *psec = reldyn; ++ return ret; ++} ++ ++/* Do the final step of an ELF link. */ ++ ++boolean ++ppc_elf_final_link (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ boolean dynamic; ++ boolean emit_relocs; ++ bfd *dynobj; ++ struct elf_final_link_info finfo; ++ register asection *o; ++ register struct bfd_link_order *p; ++ register bfd *sub; ++ bfd_size_type max_contents_size; ++ bfd_size_type max_external_reloc_size; ++ bfd_size_type max_internal_reloc_count; ++ bfd_size_type max_sym_count; ++ bfd_size_type max_sym_shndx_count; ++ bfd_size_type max_datadata_reloc_count; ++ file_ptr off; ++ Elf_Internal_Sym elfsym; ++ unsigned int i; ++ Elf_Internal_Shdr *symtab_hdr; ++ Elf_Internal_Shdr *symstrtab_hdr; ++ struct elf_backend_data *bed = get_elf_backend_data (abfd); ++ struct elf_outext_info eoinfo; ++ boolean merged; ++ size_t relativecount = 0; ++ asection *reldyn = 0; ++ bfd_size_type amt; ++ asection *ddr_sec; ++ asection *sdata_sec = NULL; ++ asection *sbss_sec = NULL; ++ ++ if (! is_elf_hash_table (info)) ++ return false; ++ ++ if (info->shared) ++ abfd->flags |= DYNAMIC; ++ ++ bfd_set_start_address(abfd, 0); ++ ++ dynamic = elf_hash_table (info)->dynamic_sections_created; ++ dynobj = elf_hash_table (info)->dynobj; ++ ++ emit_relocs = (info->relocateable ++ || info->emitrelocations ++ || bed->elf_backend_emit_relocs); ++ ++ finfo.info = info; ++ finfo.output_bfd = abfd; ++ finfo.symstrtab = elf_stringtab_init (); ++ if (finfo.symstrtab == NULL) ++ return false; ++ ++ if (! dynamic) ++ { ++ finfo.dynsym_sec = NULL; ++ finfo.hash_sec = NULL; ++ finfo.symver_sec = NULL; ++ } ++ else ++ { ++ finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym"); ++ finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash"); ++ BFD_ASSERT (finfo.dynsym_sec != NULL && finfo.hash_sec != NULL); ++ finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version"); ++ /* Note that it is OK if symver_sec is NULL. */ ++ } ++ ++ finfo.contents = NULL; ++ finfo.external_relocs = NULL; ++ finfo.internal_relocs = NULL; ++ finfo.external_syms = NULL; ++ finfo.locsym_shndx = NULL; ++ finfo.internal_syms = NULL; ++ finfo.indices = NULL; ++ finfo.sections = NULL; ++ finfo.symbuf = NULL; ++ finfo.symshndxbuf = NULL; ++ finfo.symbuf_count = 0; ++ finfo.first_tls_sec = NULL; ++ for (o = abfd->sections; o != (asection *) NULL; o = o->next) ++ if ((o->flags & SEC_THREAD_LOCAL) != 0 ++ && (o->flags & SEC_LOAD) != 0) ++ { ++ finfo.first_tls_sec = o; ++ break; ++ } ++ ++ ddr_sec = bfd_get_section_by_name(abfd, "ddrelocs"); ++ ++ /* Count up the number of relocations we will output for each output ++ section, so that we know the sizes of the reloc sections. We ++ also figure out some maximum sizes. */ ++ max_contents_size = 0; ++ max_external_reloc_size = 0; ++ max_internal_reloc_count = 0; ++ max_sym_count = 0; ++ max_sym_shndx_count = 0; ++ max_datadata_reloc_count = 0; ++ merged = false; ++ for (o = abfd->sections; o != (asection *) NULL; o = o->next) ++ { ++ o->reloc_count = 0; ++ ++ for (p = o->link_order_head; p != NULL; p = p->next) ++ { ++ if (p->type == bfd_section_reloc_link_order ++ || p->type == bfd_symbol_reloc_link_order) ++ ++o->reloc_count; ++ else if (p->type == bfd_indirect_link_order) ++ { ++ asection *sec; ++ ++ sec = p->u.indirect.section; ++ ++ /* Mark all sections which are to be included in the ++ link. This will normally be every section. We need ++ to do this so that we can identify any sections which ++ the linker has decided to not include. */ ++ sec->linker_mark = true; ++ ++ if (sec->flags & SEC_MERGE) ++ merged = true; ++ ++ /* Maximum number of relocations */ ++ if (1 || info->relocateable || info->emitrelocations) ++ o->reloc_count += sec->reloc_count; ++ else if (bed->elf_backend_count_relocs) ++ { ++ Elf_Internal_Rela * relocs; ++ ++ relocs = (NAME(_bfd_elf,link_read_relocs) ++ (abfd, sec, (PTR) NULL, ++ (Elf_Internal_Rela *) NULL, info->keep_memory)); ++ ++ o->reloc_count ++ += (*bed->elf_backend_count_relocs) (sec, relocs); ++ ++ if (elf_section_data (o)->relocs != relocs) ++ free (relocs); ++ } ++ ++ if (sec->_raw_size > max_contents_size) ++ max_contents_size = sec->_raw_size; ++ if (sec->_cooked_size > max_contents_size) ++ max_contents_size = sec->_cooked_size; ++ ++ /* We are interested in just local symbols, not all ++ symbols. */ ++ if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour ++ && (sec->owner->flags & DYNAMIC) == 0) ++ { ++ size_t sym_count; ++ ++ if (elf_bad_symtab (sec->owner)) ++ sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size ++ / sizeof (Elf_External_Sym)); ++ else ++ sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info; ++ ++ if (sym_count > max_sym_count) ++ max_sym_count = sym_count; ++ ++ if (sym_count > max_sym_shndx_count ++ && elf_symtab_shndx (sec->owner) != 0) ++ max_sym_shndx_count = sym_count; ++ ++ if ((sec->flags & SEC_RELOC) != 0) ++ { ++ size_t ext_size; ++ ++ ext_size = elf_section_data (sec)->rel_hdr.sh_size; ++ if (ext_size > max_external_reloc_size) ++ max_external_reloc_size = ext_size; ++ if (sec->reloc_count > max_internal_reloc_count) ++ max_internal_reloc_count = sec->reloc_count; ++ } ++ } ++ } ++ } ++ ++ if (!strcmp(bfd_section_name(abfd, o), ".sdata")) ++ sdata_sec = o; ++ else if(!strcmp(bfd_section_name(abfd, o), ".sbss")) ++ sbss_sec = o; ++ else ++ bfd_set_section_vma(abfd, o, 0); ++ ++ if (o->reloc_count > 0) ++ { ++ o->flags |= SEC_RELOC; ++ if (o == sdata_sec || o == sbss_sec) ++ max_datadata_reloc_count += o->reloc_count; ++ } ++ else ++ { ++ /* Explicitly clear the SEC_RELOC flag. The linker tends to ++ set it (this is probably a bug) and if it is set ++ assign_section_numbers will create a reloc section. */ ++ o->flags &=~ SEC_RELOC; ++ } ++ ++ /* If the SEC_ALLOC flag is not set, force the section VMA to ++ zero. This is done in elf_fake_sections as well, but forcing ++ the VMA to 0 here will ensure that relocs against these ++ sections are handled correctly. */ ++ if ((o->flags & SEC_ALLOC) == 0 ++ && ! o->user_set_vma) ++ o->vma = 0; ++ } ++ ++ if (sdata_sec) ++ { ++ if (sbss_sec) ++ bfd_set_section_vma(abfd, sbss_sec, sbss_sec->vma - sdata_sec->vma); ++ bfd_set_section_vma(abfd, sdata_sec, 0); ++ } ++ ++ if (! info->relocateable && merged) ++ elf_link_hash_traverse (elf_hash_table (info), ++ elf_link_sec_merge_syms, (PTR) abfd); ++ ++ /* Figure out the file positions for everything but the symbol table ++ and the relocs. We set symcount to force assign_section_numbers ++ to create a symbol table. */ ++ bfd_get_symcount (abfd) = 1; ++ BFD_ASSERT (! abfd->output_has_begun); ++ if (! _bfd_elf_compute_section_file_positions (abfd, info)) ++ goto error_return; ++ ++ /* Figure out how many relocations we will have in each section. ++ Just using RELOC_COUNT isn't good enough since that doesn't ++ maintain a separate value for REL vs. RELA relocations. */ ++ if (emit_relocs) ++ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) ++ for (o = sub->sections; o != NULL; o = o->next) ++ { ++ asection *output_section; ++ ++ if (! o->linker_mark) ++ { ++ /* This section was omitted from the link. */ ++ continue; ++ } ++ ++ output_section = o->output_section; ++ ++ if (output_section != NULL ++ && (o->flags & SEC_RELOC) != 0) ++ { ++ struct bfd_elf_section_data *esdi ++ = elf_section_data (o); ++ struct bfd_elf_section_data *esdo ++ = elf_section_data (output_section); ++ unsigned int *rel_count; ++ unsigned int *rel_count2; ++ bfd_size_type entsize; ++ bfd_size_type entsize2; ++ ++ /* We must be careful to add the relocations from the ++ input section to the right output count. */ ++ entsize = esdi->rel_hdr.sh_entsize; ++ entsize2 = esdi->rel_hdr2 ? esdi->rel_hdr2->sh_entsize : 0; ++ BFD_ASSERT ((entsize == sizeof (Elf_External_Rel) ++ || entsize == sizeof (Elf_External_Rela)) ++ && entsize2 != entsize ++ && (entsize2 == 0 ++ || entsize2 == sizeof (Elf_External_Rel) ++ || entsize2 == sizeof (Elf_External_Rela))); ++ if (entsize == esdo->rel_hdr.sh_entsize) ++ { ++ rel_count = &esdo->rel_count; ++ rel_count2 = &esdo->rel_count2; ++ } ++ else ++ { ++ rel_count = &esdo->rel_count2; ++ rel_count2 = &esdo->rel_count; ++ } ++ ++ *rel_count += NUM_SHDR_ENTRIES (& esdi->rel_hdr); ++ if (esdi->rel_hdr2) ++ *rel_count2 += NUM_SHDR_ENTRIES (esdi->rel_hdr2); ++ output_section->flags |= SEC_RELOC; ++ } ++ } ++ ++ /* That created the reloc sections. Set their sizes, and assign ++ them file positions, and allocate some buffers. */ ++ for (o = abfd->sections; o != NULL; o = o->next) ++ { ++ if ((o->flags & SEC_RELOC) != 0) ++ { ++ if (!elf_link_size_reloc_section (abfd, ++ &elf_section_data (o)->rel_hdr, ++ o)) ++ goto error_return; ++ ++ if (elf_section_data (o)->rel_hdr2 ++ && !elf_link_size_reloc_section (abfd, ++ elf_section_data (o)->rel_hdr2, ++ o)) ++ goto error_return; ++ } ++ ++ /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them ++ to count upwards while actually outputting the relocations. */ ++ elf_section_data (o)->rel_count = 0; ++ elf_section_data (o)->rel_count2 = 0; ++ } ++ ++ /* We have now assigned file positions for all the sections except ++ relocations, .symtab, and .strtab. We start the .symtab section ++ at the current file position, and write directly to it. We build ++ the .strtab section in memory. */ ++ bfd_get_symcount (abfd) = 0; ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ /* sh_name is set in prep_headers. */ ++ symtab_hdr->sh_type = SHT_SYMTAB; ++ symtab_hdr->sh_flags = 0; ++ symtab_hdr->sh_addr = 0; ++ symtab_hdr->sh_size = 0; ++ symtab_hdr->sh_entsize = sizeof (Elf_External_Sym); ++ /* sh_link is set in assign_section_numbers. */ ++ /* sh_info is set below. */ ++ /* sh_offset is set just below. */ ++ symtab_hdr->sh_addralign = bed->s->file_align; ++ ++ off = elf_tdata (abfd)->next_file_pos; ++ off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, true); ++ ++ /* Note that at this point elf_tdata (abfd)->next_file_pos is ++ incorrect. We do not yet know the size of the .symtab section. ++ We correct next_file_pos below, after we do know the size. */ ++ ++ /* Allocate a buffer to hold swapped out symbols. This is to avoid ++ continuously seeking to the right position in the file. */ ++ if (! info->keep_memory || max_sym_count < 20) ++ finfo.symbuf_size = 20; ++ else ++ finfo.symbuf_size = max_sym_count; ++ amt = finfo.symbuf_size; ++ amt *= sizeof (Elf_External_Sym); ++ finfo.symbuf = (Elf_External_Sym *) bfd_malloc (amt); ++ if (finfo.symbuf == NULL) ++ goto error_return; ++ if (elf_numsections (abfd) > SHN_LORESERVE) ++ { ++ amt = finfo.symbuf_size; ++ amt *= sizeof (Elf_External_Sym_Shndx); ++ finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_malloc (amt); ++ if (finfo.symshndxbuf == NULL) ++ goto error_return; ++ } ++ ++ /* Start writing out the symbol table. The first symbol is always a ++ dummy symbol. */ ++ elfsym.st_value = 0; ++ elfsym.st_size = 0; ++ elfsym.st_info = 0; ++ elfsym.st_other = 0; ++ elfsym.st_shndx = SHN_UNDEF; ++ if (! elf_link_output_sym (&finfo, (const char *) NULL, ++ &elfsym, bfd_und_section_ptr)) ++ goto error_return; ++ ++#if 0 ++ /* Some standard ELF linkers do this, but we don't because it causes ++ bootstrap comparison failures. */ ++ /* Output a file symbol for the output file as the second symbol. ++ We output this even if we are discarding local symbols, although ++ I'm not sure if this is correct. */ ++ elfsym.st_value = 0; ++ elfsym.st_size = 0; ++ elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); ++ elfsym.st_other = 0; ++ elfsym.st_shndx = SHN_ABS; ++ if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd), ++ &elfsym, bfd_abs_section_ptr)) ++ goto error_return; ++#endif ++ ++ /* Output a symbol for each section. We output these even if we are ++ discarding local symbols, since they are used for relocs. These ++ symbols have no names. We store the index of each one in the ++ index field of the section, so that we can find it again when ++ outputting relocs. */ ++ elfsym.st_size = 0; ++ elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); ++ elfsym.st_other = 0; ++ for (i = 1; i < elf_numsections (abfd); i++) ++ { ++ o = section_from_elf_index (abfd, i); ++ if (o != NULL) ++ o->target_index = bfd_get_symcount (abfd); ++ elfsym.st_shndx = i; ++ elfsym.st_value = 0; ++ if (! elf_link_output_sym (&finfo, (const char *) NULL, ++ &elfsym, o)) ++ goto error_return; ++ if (i == SHN_LORESERVE) ++ i += SHN_HIRESERVE + 1 - SHN_LORESERVE; ++ } ++ ++ /* Allocate some memory to hold information read in from the input ++ files. */ ++ if (max_contents_size != 0) ++ { ++ finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); ++ if (finfo.contents == NULL) ++ goto error_return; ++ } ++ ++ if (max_external_reloc_size != 0) ++ { ++ finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size); ++ if (finfo.external_relocs == NULL) ++ goto error_return; ++ } ++ ++ if (max_internal_reloc_count != 0) ++ { ++ amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel; ++ amt *= sizeof (Elf_Internal_Rela); ++ finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt); ++ if (finfo.internal_relocs == NULL) ++ goto error_return; ++ } ++ ++ if (max_sym_count != 0) ++ { ++ amt = max_sym_count * sizeof (Elf_External_Sym); ++ finfo.external_syms = (Elf_External_Sym *) bfd_malloc (amt); ++ if (finfo.external_syms == NULL) ++ goto error_return; ++ ++ amt = max_sym_count * sizeof (Elf_Internal_Sym); ++ finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt); ++ if (finfo.internal_syms == NULL) ++ goto error_return; ++ ++ amt = max_sym_count * sizeof (long); ++ finfo.indices = (long *) bfd_malloc (amt); ++ if (finfo.indices == NULL) ++ goto error_return; ++ ++ amt = max_sym_count * sizeof (asection *); ++ finfo.sections = (asection **) bfd_malloc (amt); ++ if (finfo.sections == NULL) ++ goto error_return; ++ } ++ ++ if (max_sym_shndx_count != 0) ++ { ++ amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx); ++ finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt); ++ if (finfo.locsym_shndx == NULL) ++ goto error_return; ++ } ++ ++ if (finfo.first_tls_sec) ++ { ++ unsigned int align = 0; ++ bfd_vma base = finfo.first_tls_sec->vma, end = 0; ++ asection *sec; ++ ++ for (sec = finfo.first_tls_sec; ++ sec && (sec->flags & SEC_THREAD_LOCAL); ++ sec = sec->next) ++ { ++ bfd_vma size = sec->_raw_size; ++ ++ if (bfd_get_section_alignment (abfd, sec) > align) ++ align = bfd_get_section_alignment (abfd, sec); ++ if (sec->_raw_size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0) ++ { ++ struct bfd_link_order *o; ++ ++ size = 0; ++ for (o = sec->link_order_head; o != NULL; o = o->next) ++ if (size < o->offset + o->size) ++ size = o->offset + o->size; ++ } ++ end = sec->vma + size; ++ } ++ elf_hash_table (info)->tls_segment ++ = bfd_zalloc (abfd, sizeof (struct elf_link_tls_segment)); ++ if (elf_hash_table (info)->tls_segment == NULL) ++ goto error_return; ++ elf_hash_table (info)->tls_segment->start = base; ++ elf_hash_table (info)->tls_segment->size = end - base; ++ elf_hash_table (info)->tls_segment->align = align; ++ } ++ ++ if (ddr_sec) ++ { ++ ddr_count = 0; ++ ddr_ptr = (unsigned *)bfd_alloc(abfd, 4 * max_datadata_reloc_count + 4); ++ if (ddr_ptr) ++ ++ddr_ptr; ++ else ++ goto error_return; ++ } ++ else ++ ddr_ptr = NULL; ++ ++ /* Since ELF permits relocations to be against local symbols, we ++ must have the local symbols available when we do the relocations. ++ Since we would rather only read the local symbols once, and we ++ would rather not keep them in memory, we handle all the ++ relocations for a single input file at the same time. ++ ++ Unfortunately, there is no way to know the total number of local ++ symbols until we have seen all of them, and the local symbol ++ indices precede the global symbol indices. This means that when ++ we are generating relocateable output, and we see a reloc against ++ a global symbol, we can not know the symbol index until we have ++ finished examining all the local symbols to see which ones we are ++ going to output. To deal with this, we keep the relocations in ++ memory, and don't output them until the end of the link. This is ++ an unfortunate waste of memory, but I don't see a good way around ++ it. Fortunately, it only happens when performing a relocateable ++ link, which is not the common case. FIXME: If keep_memory is set ++ we could write the relocs out and then read them again; I don't ++ know how bad the memory loss will be. */ ++ ++ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) ++ sub->output_has_begun = false; ++ for (o = abfd->sections; o != NULL; o = o->next) ++ { ++ for (p = o->link_order_head; p != NULL; p = p->next) ++ { ++ if (p->type == bfd_indirect_link_order ++ && (bfd_get_flavour ((sub = p->u.indirect.section->owner)) ++ == bfd_target_elf_flavour) ++ && elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass) ++ { ++ if (! sub->output_has_begun) ++ { ++ if (! elf_link_input_bfd (&finfo, sub)) ++ goto error_return; ++ sub->output_has_begun = true; ++ } ++ } ++ else if (p->type == bfd_section_reloc_link_order ++ || p->type == bfd_symbol_reloc_link_order) ++ { ++ if (! elf_reloc_link_order (abfd, info, o, p)) ++ goto error_return; ++ } ++ else ++ { ++ if (! _bfd_default_link_order (abfd, info, o, p)) ++ goto error_return; ++ } ++ } ++ } ++ ++ /* Output any global symbols that got converted to local in a ++ version script or due to symbol visibility. We do this in a ++ separate step since ELF requires all local symbols to appear ++ prior to any global symbols. FIXME: We should only do this if ++ some global symbols were, in fact, converted to become local. ++ FIXME: Will this work correctly with the Irix 5 linker? */ ++ eoinfo.failed = false; ++ eoinfo.finfo = &finfo; ++ eoinfo.localsyms = true; ++ elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym, ++ (PTR) &eoinfo); ++ if (eoinfo.failed) ++ return false; ++ ++ /* Set the vma of the sections to 0. We can't do that before, otherwise the ++ relocation doesn't work properly for .sbss. */ ++ { ++ int n = elf_elfheader(abfd)->e_shnum; ++ Elf_Internal_Shdr **hdr = elf_elfsections(abfd); ++ for (i = 1; i < n; ++i, ++hdr) ++ (*hdr)->sh_addr = 0; ++ } ++ ++ /* That wrote out all the local symbols. Finish up the symbol table ++ with the global symbols. Even if we want to strip everything we ++ can, we still need to deal with those global symbols that got ++ converted to local in a version script. */ ++ ++ /* The sh_info field records the index of the first non local symbol. */ ++ symtab_hdr->sh_info = bfd_get_symcount (abfd); ++ ++ if (dynamic ++ && finfo.dynsym_sec->output_section != bfd_abs_section_ptr) ++ { ++ Elf_Internal_Sym sym; ++ Elf_External_Sym *dynsym = ++ (Elf_External_Sym *) finfo.dynsym_sec->contents; ++ long last_local = 0; ++ ++ /* Write out the section symbols for the output sections. */ ++ if (info->shared) ++ { ++ asection *s; ++ ++ sym.st_size = 0; ++ sym.st_name = 0; ++ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); ++ sym.st_other = 0; ++ ++ for (s = abfd->sections; s != NULL; s = s->next) ++ { ++ int indx; ++ Elf_External_Sym *dest; ++ ++ indx = elf_section_data (s)->this_idx; ++ BFD_ASSERT (indx > 0); ++ sym.st_shndx = indx; ++ sym.st_value = s->vma; ++ dest = dynsym + elf_section_data (s)->dynindx; ++ elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0); ++ } ++ ++ last_local = bfd_count_sections (abfd); ++ } ++ ++ /* Write out the local dynsyms. */ ++ if (elf_hash_table (info)->dynlocal) ++ { ++ struct elf_link_local_dynamic_entry *e; ++ for (e = elf_hash_table (info)->dynlocal; e ; e = e->next) ++ { ++ asection *s; ++ Elf_External_Sym *dest; ++ ++ sym.st_size = e->isym.st_size; ++ sym.st_other = e->isym.st_other; ++ ++ /* Copy the internal symbol as is. ++ Note that we saved a word of storage and overwrote ++ the original st_name with the dynstr_index. */ ++ sym = e->isym; ++ ++ if (e->isym.st_shndx != SHN_UNDEF ++ && (e->isym.st_shndx < SHN_LORESERVE ++ || e->isym.st_shndx > SHN_HIRESERVE)) ++ { ++ s = bfd_section_from_elf_index (e->input_bfd, ++ e->isym.st_shndx); ++ ++ sym.st_shndx = ++ elf_section_data (s->output_section)->this_idx; ++ sym.st_value = (s->output_section->vma ++ + s->output_offset ++ + e->isym.st_value); ++ } ++ ++ if (last_local < e->dynindx) ++ last_local = e->dynindx; ++ ++ dest = dynsym + e->dynindx; ++ elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0); ++ } ++ } ++ ++ elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = ++ last_local + 1; ++ } ++ ++ /* We get the global symbols from the hash table. */ ++ eoinfo.failed = false; ++ eoinfo.localsyms = false; ++ eoinfo.finfo = &finfo; ++ elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym, ++ (PTR) &eoinfo); ++ if (eoinfo.failed) ++ return false; ++ ++ /* If backend needs to output some symbols not present in the hash ++ table, do it now. */ ++ if (bed->elf_backend_output_arch_syms) ++ { ++ typedef boolean (*out_sym_func) PARAMS ((PTR, const char *, ++ Elf_Internal_Sym *, ++ asection *)); ++ ++ if (! ((*bed->elf_backend_output_arch_syms) ++ (abfd, info, (PTR) &finfo, (out_sym_func) elf_link_output_sym))) ++ return false; ++ } ++ ++ /* Flush all symbols to the file. */ ++ if (! elf_link_flush_output_syms (&finfo)) ++ return false; ++ ++ /* Now we know the size of the symtab section. */ ++ off += symtab_hdr->sh_size; ++ ++ /* Add the __datadata_relocs table. */ ++ if (ddr_sec) ++ { ++ Elf_Internal_Shdr *hdr = elf_elfsections(abfd)[_bfd_elf_section_from_bfd_section(abfd, ddr_sec)]; ++ ddr_sec->_cooked_size = ddr_sec->_raw_size = hdr->sh_size = 4 * ddr_count + 4; ++ hdr->sh_addralign = 2; ++ off = _bfd_elf_assign_file_position_for_section (hdr, off, true); ++ ddr_ptr -= ddr_count + 1; ++ *ddr_ptr = ddr_count ? ddr_count : -1; ++ bfd_set_section_contents(abfd, ddr_sec, ddr_ptr, 0, hdr->sh_size); ++ } ++ ++ /* Finish up and write out the symbol string table (.strtab) ++ section. */ ++ symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; ++ /* sh_name was set in prep_headers. */ ++ symstrtab_hdr->sh_type = SHT_STRTAB; ++ symstrtab_hdr->sh_flags = 0; ++ symstrtab_hdr->sh_addr = 0; ++ symstrtab_hdr->sh_size = _bfd_stringtab_size (finfo.symstrtab); ++ symstrtab_hdr->sh_entsize = 0; ++ symstrtab_hdr->sh_link = 0; ++ symstrtab_hdr->sh_info = 0; ++ /* sh_offset is set just below. */ ++ symstrtab_hdr->sh_addralign = 1; ++ ++ off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, true); ++ elf_tdata (abfd)->next_file_pos = off; ++ ++ if (bfd_get_symcount (abfd) > 0) ++ { ++ if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0 ++ || ! _bfd_stringtab_emit (abfd, finfo.symstrtab)) ++ return false; ++ } ++ ++ /* Adjust the relocs to have the correct symbol indices. */ ++ for (o = abfd->sections; o != NULL; o = o->next) ++ { ++ if ((o->flags & SEC_RELOC) == 0) ++ continue; ++ ++ elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr, ++ elf_section_data (o)->rel_count, ++ elf_section_data (o)->rel_hashes); ++ if (elf_section_data (o)->rel_hdr2 != NULL) ++ elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2, ++ elf_section_data (o)->rel_count2, ++ (elf_section_data (o)->rel_hashes ++ + elf_section_data (o)->rel_count)); ++ ++ elf_section_data (o)->rel_hdr.sh_size = ++ o->reloc_count * elf_section_data (o)->rel_hdr.sh_entsize; ++ ++ /* Set the reloc_count field to 0 to prevent write_relocs from ++ trying to swap the relocs out itself. */ ++ o->reloc_count = 0; ++ } ++ ++ _bfd_elf_assign_file_positions_for_relocs (abfd); ++ ++ if (dynamic && info->combreloc && dynobj != NULL) ++ relativecount = elf_link_sort_relocs (abfd, info, &reldyn); ++ ++ /* If we are linking against a dynamic object, or generating a ++ shared library, finish up the dynamic linking information. */ ++ if (dynamic) ++ { ++ Elf_External_Dyn *dyncon, *dynconend; ++ ++ /* Fix up .dynamic entries. */ ++ o = bfd_get_section_by_name (dynobj, ".dynamic"); ++ BFD_ASSERT (o != NULL); ++ ++ dyncon = (Elf_External_Dyn *) o->contents; ++ dynconend = (Elf_External_Dyn *) (o->contents + o->_raw_size); ++ for (; dyncon < dynconend; dyncon++) ++ { ++ Elf_Internal_Dyn dyn; ++ const char *name; ++ unsigned int type; ++ ++ elf_swap_dyn_in (dynobj, dyncon, &dyn); ++ ++ switch (dyn.d_tag) ++ { ++ default: ++ break; ++ case DT_NULL: ++ if (relativecount > 0 && dyncon + 1 < dynconend) ++ { ++ switch (elf_section_data (reldyn)->this_hdr.sh_type) ++ { ++ case SHT_REL: dyn.d_tag = DT_RELCOUNT; break; ++ case SHT_RELA: dyn.d_tag = DT_RELACOUNT; break; ++ default: break; ++ } ++ if (dyn.d_tag != DT_NULL) ++ { ++ dyn.d_un.d_val = relativecount; ++ elf_swap_dyn_out (dynobj, &dyn, dyncon); ++ relativecount = 0; ++ } ++ } ++ break; ++ case DT_INIT: ++ name = info->init_function; ++ goto get_sym; ++ case DT_FINI: ++ name = info->fini_function; ++ get_sym: ++ { ++ struct elf_link_hash_entry *h; ++ ++ h = elf_link_hash_lookup (elf_hash_table (info), name, ++ false, false, true); ++ if (h != NULL ++ && (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak)) ++ { ++ dyn.d_un.d_val = h->root.u.def.value; ++ o = h->root.u.def.section; ++ if (o->output_section != NULL) ++ dyn.d_un.d_val += (o->output_section->vma ++ + o->output_offset); ++ else ++ { ++ /* The symbol is imported from another shared ++ library and does not apply to this one. */ ++ dyn.d_un.d_val = 0; ++ } ++ ++ elf_swap_dyn_out (dynobj, &dyn, dyncon); ++ } ++ } ++ break; ++ ++ case DT_PREINIT_ARRAYSZ: ++ name = ".preinit_array"; ++ goto get_size; ++ case DT_INIT_ARRAYSZ: ++ name = ".init_array"; ++ goto get_size; ++ case DT_FINI_ARRAYSZ: ++ name = ".fini_array"; ++ get_size: ++ o = bfd_get_section_by_name (abfd, name); ++ if (o == NULL) ++ { ++ (*_bfd_error_handler) ++ (_("%s: could not find output section %s"), ++ bfd_get_filename (abfd), name); ++ goto error_return; ++ } ++ if (o->_raw_size == 0) ++ (*_bfd_error_handler) ++ (_("warning: %s section has zero size"), name); ++ dyn.d_un.d_val = o->_raw_size; ++ elf_swap_dyn_out (dynobj, &dyn, dyncon); ++ break; ++ ++ case DT_PREINIT_ARRAY: ++ name = ".preinit_array"; ++ goto get_vma; ++ case DT_INIT_ARRAY: ++ name = ".init_array"; ++ goto get_vma; ++ case DT_FINI_ARRAY: ++ name = ".fini_array"; ++ goto get_vma; ++ ++ case DT_HASH: ++ name = ".hash"; ++ goto get_vma; ++ case DT_STRTAB: ++ name = ".dynstr"; ++ goto get_vma; ++ case DT_SYMTAB: ++ name = ".dynsym"; ++ goto get_vma; ++ case DT_VERDEF: ++ name = ".gnu.version_d"; ++ goto get_vma; ++ case DT_VERNEED: ++ name = ".gnu.version_r"; ++ goto get_vma; ++ case DT_VERSYM: ++ name = ".gnu.version"; ++ get_vma: ++ o = bfd_get_section_by_name (abfd, name); ++ if (o == NULL) ++ { ++ (*_bfd_error_handler) ++ (_("%s: could not find output section %s"), ++ bfd_get_filename (abfd), name); ++ goto error_return; ++ } ++ dyn.d_un.d_ptr = o->vma; ++ elf_swap_dyn_out (dynobj, &dyn, dyncon); ++ break; ++ ++ case DT_REL: ++ case DT_RELA: ++ case DT_RELSZ: ++ case DT_RELASZ: ++ if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ) ++ type = SHT_REL; ++ else ++ type = SHT_RELA; ++ dyn.d_un.d_val = 0; ++ for (i = 1; i < elf_numsections (abfd); i++) ++ { ++ Elf_Internal_Shdr *hdr; ++ ++ hdr = elf_elfsections (abfd)[i]; ++ if (hdr->sh_type == type ++ && (hdr->sh_flags & SHF_ALLOC) != 0) ++ { ++ if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) ++ dyn.d_un.d_val += hdr->sh_size; ++ else ++ { ++ if (dyn.d_un.d_val == 0 ++ || hdr->sh_addr < dyn.d_un.d_val) ++ dyn.d_un.d_val = hdr->sh_addr; ++ } ++ } ++ } ++ elf_swap_dyn_out (dynobj, &dyn, dyncon); ++ break; ++ } ++ } ++ } ++ ++ /* If we have created any dynamic sections, then output them. */ ++ if (dynobj != NULL) ++ { ++ if (! (*bed->elf_backend_finish_dynamic_sections) (abfd, info)) ++ goto error_return; ++ ++ for (o = dynobj->sections; o != NULL; o = o->next) ++ { ++ if ((o->flags & SEC_HAS_CONTENTS) == 0 ++ || o->_raw_size == 0 ++ || o->output_section == bfd_abs_section_ptr) ++ continue; ++ if ((o->flags & SEC_LINKER_CREATED) == 0) ++ { ++ /* At this point, we are only interested in sections ++ created by elf_link_create_dynamic_sections. */ ++ continue; ++ } ++ if ((elf_section_data (o->output_section)->this_hdr.sh_type ++ != SHT_STRTAB) ++ || strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0) ++ { ++ if (! bfd_set_section_contents (abfd, o->output_section, ++ o->contents, ++ (file_ptr) o->output_offset, ++ o->_raw_size)) ++ goto error_return; ++ } ++ else ++ { ++ /* The contents of the .dynstr section are actually in a ++ stringtab. */ ++ off = elf_section_data (o->output_section)->this_hdr.sh_offset; ++ if (bfd_seek (abfd, off, SEEK_SET) != 0 ++ || ! _bfd_elf_strtab_emit (abfd, ++ elf_hash_table (info)->dynstr)) ++ goto error_return; ++ } ++ } ++ } ++ ++ if (info->relocateable) ++ { ++ boolean failed = false; ++ ++ bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed); ++ if (failed) ++ goto error_return; ++ } ++ ++ /* If we have optimized stabs strings, output them. */ ++ if (elf_hash_table (info)->stab_info != NULL) ++ { ++ if (! _bfd_write_stab_strings (abfd, &elf_hash_table (info)->stab_info)) ++ goto error_return; ++ } ++ ++ if (info->eh_frame_hdr && elf_hash_table (info)->dynobj) ++ { ++ o = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ++ ".eh_frame_hdr"); ++ if (o ++ && (elf_section_data (o)->sec_info_type ++ == ELF_INFO_TYPE_EH_FRAME_HDR)) ++ { ++ if (! _bfd_elf_write_section_eh_frame_hdr (abfd, o)) ++ goto error_return; ++ } ++ } ++ ++ if (finfo.symstrtab != NULL) ++ _bfd_stringtab_free (finfo.symstrtab); ++ if (finfo.contents != NULL) ++ free (finfo.contents); ++ if (finfo.external_relocs != NULL) ++ free (finfo.external_relocs); ++ if (finfo.internal_relocs != NULL) ++ free (finfo.internal_relocs); ++ if (finfo.external_syms != NULL) ++ free (finfo.external_syms); ++ if (finfo.locsym_shndx != NULL) ++ free (finfo.locsym_shndx); ++ if (finfo.internal_syms != NULL) ++ free (finfo.internal_syms); ++ if (finfo.indices != NULL) ++ free (finfo.indices); ++ if (finfo.sections != NULL) ++ free (finfo.sections); ++ if (finfo.symbuf != NULL) ++ free (finfo.symbuf); ++ if (finfo.symshndxbuf != NULL) ++ free (finfo.symbuf); ++ for (o = abfd->sections; o != NULL; o = o->next) ++ { ++ if ((o->flags & SEC_RELOC) != 0 ++ && elf_section_data (o)->rel_hashes != NULL) ++ free (elf_section_data (o)->rel_hashes); ++ } ++ ++ elf_tdata (abfd)->linker = true; ++ ++ return true; ++ ++ error_return: ++ if (finfo.symstrtab != NULL) ++ _bfd_stringtab_free (finfo.symstrtab); ++ if (finfo.contents != NULL) ++ free (finfo.contents); ++ if (finfo.external_relocs != NULL) ++ free (finfo.external_relocs); ++ if (finfo.internal_relocs != NULL) ++ free (finfo.internal_relocs); ++ if (finfo.external_syms != NULL) ++ free (finfo.external_syms); ++ if (finfo.locsym_shndx != NULL) ++ free (finfo.locsym_shndx); ++ if (finfo.internal_syms != NULL) ++ free (finfo.internal_syms); ++ if (finfo.indices != NULL) ++ free (finfo.indices); ++ if (finfo.sections != NULL) ++ free (finfo.sections); ++ if (finfo.symbuf != NULL) ++ free (finfo.symbuf); ++ if (finfo.symshndxbuf != NULL) ++ free (finfo.symbuf); ++ for (o = abfd->sections; o != NULL; o = o->next) ++ { ++ if ((o->flags & SEC_RELOC) != 0 ++ && elf_section_data (o)->rel_hashes != NULL) ++ free (elf_section_data (o)->rel_hashes); ++ } ++ ++ return false; ++} ++ ++/* Add a symbol to the output symbol table. */ ++ ++static boolean ++elf_link_output_sym (finfo, name, elfsym, input_sec) ++ struct elf_final_link_info *finfo; ++ const char *name; ++ Elf_Internal_Sym *elfsym; ++ asection *input_sec; ++{ ++ Elf_External_Sym *dest; ++ Elf_External_Sym_Shndx *destshndx; ++ ++ boolean (*output_symbol_hook) PARAMS ((bfd *, ++ struct bfd_link_info *info, ++ const char *, ++ Elf_Internal_Sym *, ++ asection *)); ++ ++ output_symbol_hook = get_elf_backend_data (finfo->output_bfd)-> ++ elf_backend_link_output_symbol_hook; ++ if (output_symbol_hook != NULL) ++ { ++ if (! ((*output_symbol_hook) ++ (finfo->output_bfd, finfo->info, name, elfsym, input_sec))) ++ return false; ++ } ++ ++ if (name == (const char *) NULL || *name == '\0') ++ elfsym->st_name = 0; ++ else if (input_sec->flags & SEC_EXCLUDE) ++ elfsym->st_name = 0; ++ else ++ { ++ elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab, ++ name, true, false); ++ if (elfsym->st_name == (unsigned long) -1) ++ return false; ++ } ++ ++ if (finfo->symbuf_count >= finfo->symbuf_size) ++ { ++ if (! elf_link_flush_output_syms (finfo)) ++ return false; ++ } ++ ++ dest = finfo->symbuf + finfo->symbuf_count; ++ destshndx = finfo->symshndxbuf; ++ if (destshndx != NULL) ++ destshndx += finfo->symbuf_count; ++ elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx); ++ ++finfo->symbuf_count; ++ ++ ++ bfd_get_symcount (finfo->output_bfd); ++ ++ return true; ++} ++ ++/* Flush the output symbols to the file. */ ++ ++static boolean ++elf_link_flush_output_syms (finfo) ++ struct elf_final_link_info *finfo; ++{ ++ if (finfo->symbuf_count > 0) ++ { ++ Elf_Internal_Shdr *hdr; ++ file_ptr pos; ++ bfd_size_type amt; ++ ++ hdr = &elf_tdata (finfo->output_bfd)->symtab_hdr; ++ pos = hdr->sh_offset + hdr->sh_size; ++ amt = finfo->symbuf_count * sizeof (Elf_External_Sym); ++ if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0 ++ || bfd_bwrite ((PTR) finfo->symbuf, amt, finfo->output_bfd) != amt) ++ return false; ++ ++ hdr->sh_size += amt; ++ ++ if (finfo->symshndxbuf != NULL) ++ { ++ hdr = &elf_tdata (finfo->output_bfd)->symtab_shndx_hdr; ++ pos = hdr->sh_offset + hdr->sh_size; ++ amt = finfo->symbuf_count * sizeof (Elf_External_Sym_Shndx); ++ if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0 ++ || (bfd_bwrite ((PTR) finfo->symshndxbuf, amt, finfo->output_bfd) ++ != amt)) ++ return false; ++ ++ hdr->sh_size += amt; ++ } ++ ++ finfo->symbuf_count = 0; ++ } ++ ++ return true; ++} ++ ++/* Adjust all external symbols pointing into SEC_MERGE sections ++ to reflect the object merging within the sections. */ ++ ++static boolean ++elf_link_sec_merge_syms (h, data) ++ struct elf_link_hash_entry *h; ++ PTR data; ++{ ++ asection *sec; ++ ++ if (h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ ++ if ((h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && ((sec = h->root.u.def.section)->flags & SEC_MERGE) ++ && elf_section_data (sec)->sec_info_type == ELF_INFO_TYPE_MERGE) ++ { ++ bfd *output_bfd = (bfd *) data; ++ ++ h->root.u.def.value = ++ _bfd_merged_section_offset (output_bfd, ++ &h->root.u.def.section, ++ elf_section_data (sec)->sec_info, ++ h->root.u.def.value, (bfd_vma) 0); ++ } ++ ++ return true; ++} ++ ++/* For DSOs loaded in via a DT_NEEDED entry, emulate ld.so in ++ allowing an unsatisfied unversioned symbol in the DSO to match a ++ versioned symbol that would normally require an explicit version. */ ++ ++static boolean ++elf_link_check_versioned_symbol (info, h) ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++{ ++ bfd *undef_bfd = h->root.u.undef.abfd; ++ struct elf_link_loaded_list *loaded; ++ ++ if ((undef_bfd->flags & DYNAMIC) == 0 ++ || info->hash->creator->flavour != bfd_target_elf_flavour ++ || elf_dt_soname (h->root.u.undef.abfd) == NULL) ++ return false; ++ ++ for (loaded = elf_hash_table (info)->loaded; ++ loaded != NULL; ++ loaded = loaded->next) ++ { ++ bfd *input; ++ Elf_Internal_Shdr *hdr; ++ bfd_size_type symcount; ++ bfd_size_type extsymcount; ++ bfd_size_type extsymoff; ++ Elf_Internal_Shdr *versymhdr; ++ Elf_Internal_Sym *isym; ++ Elf_Internal_Sym *isymend; ++ Elf_Internal_Sym *isymbuf; ++ Elf_External_Versym *ever; ++ Elf_External_Versym *extversym; ++ ++ input = loaded->abfd; ++ ++ /* We check each DSO for a possible hidden versioned definition. */ ++ if (input == undef_bfd ++ || (input->flags & DYNAMIC) == 0 ++ || elf_dynversym (input) == 0) ++ continue; ++ ++ hdr = &elf_tdata (input)->dynsymtab_hdr; ++ ++ symcount = hdr->sh_size / sizeof (Elf_External_Sym); ++ if (elf_bad_symtab (input)) ++ { ++ extsymcount = symcount; ++ extsymoff = 0; ++ } ++ else ++ { ++ extsymcount = symcount - hdr->sh_info; ++ extsymoff = hdr->sh_info; ++ } ++ ++ if (extsymcount == 0) ++ continue; ++ ++ isymbuf = bfd_elf_get_elf_syms (input, hdr, extsymcount, extsymoff, ++ NULL, NULL, NULL); ++ if (isymbuf == NULL) ++ return false; ++ ++ /* Read in any version definitions. */ ++ versymhdr = &elf_tdata (input)->dynversym_hdr; ++ extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size); ++ if (extversym == NULL) ++ goto error_ret; ++ ++ if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0 ++ || (bfd_bread ((PTR) extversym, versymhdr->sh_size, input) ++ != versymhdr->sh_size)) ++ { ++ free (extversym); ++ error_ret: ++ free (isymbuf); ++ return false; ++ } ++ ++ ever = extversym + extsymoff; ++ isymend = isymbuf + extsymcount; ++ for (isym = isymbuf; isym < isymend; isym++, ever++) ++ { ++ const char *name; ++ Elf_Internal_Versym iver; ++ ++ if (ELF_ST_BIND (isym->st_info) == STB_LOCAL ++ || isym->st_shndx == SHN_UNDEF) ++ continue; ++ ++ name = bfd_elf_string_from_elf_section (input, ++ hdr->sh_link, ++ isym->st_name); ++ if (strcmp (name, h->root.root.string) != 0) ++ continue; ++ ++ _bfd_elf_swap_versym_in (input, ever, &iver); ++ ++ if ((iver.vs_vers & VERSYM_HIDDEN) == 0) ++ { ++ /* If we have a non-hidden versioned sym, then it should ++ have provided a definition for the undefined sym. */ ++ abort (); ++ } ++ ++ if ((iver.vs_vers & VERSYM_VERSION) == 2) ++ { ++ /* This is the oldest (default) sym. We can use it. */ ++ free (extversym); ++ free (isymbuf); ++ return true; ++ } ++ } ++ ++ free (extversym); ++ free (isymbuf); ++ } ++ ++ return false; ++} ++ ++/* Add an external symbol to the symbol table. This is called from ++ the hash table traversal routine. When generating a shared object, ++ we go through the symbol table twice. The first time we output ++ anything that might have been forced to local scope in a version ++ script. The second time we output the symbols that are still ++ global symbols. */ ++ ++static boolean ++elf_link_output_extsym (h, data) ++ struct elf_link_hash_entry *h; ++ PTR data; ++{ ++ struct elf_outext_info *eoinfo = (struct elf_outext_info *) data; ++ struct elf_final_link_info *finfo = eoinfo->finfo; ++ boolean strip; ++ Elf_Internal_Sym sym; ++ asection *input_sec; ++ ++ if (h->root.type == bfd_link_hash_warning) ++ { ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ if (h->root.type == bfd_link_hash_new) ++ return true; ++ } ++ ++ /* Decide whether to output this symbol in this pass. */ ++ if (eoinfo->localsyms) ++ { ++ if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) ++ return true; ++ } ++ else ++ { ++ if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) ++ return true; ++ } ++ ++ /* If we are not creating a shared library, and this symbol is ++ referenced by a shared library but is not defined anywhere, then ++ warn that it is undefined. If we do not do this, the runtime ++ linker will complain that the symbol is undefined when the ++ program is run. We don't have to worry about symbols that are ++ referenced by regular files, because we will already have issued ++ warnings for them. */ ++ if (! finfo->info->relocateable ++ && ! finfo->info->allow_shlib_undefined ++ && ! finfo->info->shared ++ && h->root.type == bfd_link_hash_undefined ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0 ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0 ++ && ! elf_link_check_versioned_symbol (finfo->info, h)) ++ { ++ if (! ((*finfo->info->callbacks->undefined_symbol) ++ (finfo->info, h->root.root.string, h->root.u.undef.abfd, ++ (asection *) NULL, (bfd_vma) 0, true))) ++ { ++ eoinfo->failed = true; ++ return false; ++ } ++ } ++ ++ /* We don't want to output symbols that have never been mentioned by ++ a regular file, or that we have been told to strip. However, if ++ h->indx is set to -2, the symbol is used by a reloc and we must ++ output it. */ ++ if (h->indx == -2) ++ strip = false; ++ else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 ++ || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) ++ strip = true; ++ else if (finfo->info->strip == strip_all ++ || (finfo->info->strip == strip_some ++ && bfd_hash_lookup (finfo->info->keep_hash, ++ h->root.root.string, ++ false, false) == NULL)) ++ strip = true; ++ else ++ strip = false; ++ ++ /* If we're stripping it, and it's not a dynamic symbol, there's ++ nothing else to do unless it is a forced local symbol. */ ++ if (strip ++ && h->dynindx == -1 ++ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) ++ return true; ++ ++ sym.st_value = 0; ++ sym.st_size = h->size; ++ sym.st_other = h->other; ++ if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) ++ sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type); ++ else if (h->root.type == bfd_link_hash_undefweak ++ || h->root.type == bfd_link_hash_defweak) ++ sym.st_info = ELF_ST_INFO (STB_WEAK, h->type); ++ else ++ sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type); ++ ++ switch (h->root.type) ++ { ++ default: ++ case bfd_link_hash_new: ++ case bfd_link_hash_warning: ++ abort (); ++ return false; ++ ++ case bfd_link_hash_undefined: ++ case bfd_link_hash_undefweak: ++ input_sec = bfd_und_section_ptr; ++ sym.st_shndx = SHN_UNDEF; ++ break; ++ ++ case bfd_link_hash_defined: ++ case bfd_link_hash_defweak: ++ { ++ input_sec = h->root.u.def.section; ++ if (input_sec->output_section != NULL) ++ { ++ sym.st_shndx = ++ _bfd_elf_section_from_bfd_section (finfo->output_bfd, ++ input_sec->output_section); ++ if (sym.st_shndx == SHN_BAD) ++ { ++ (*_bfd_error_handler) ++ (_("%s: could not find output section %s for input section %s"), ++ bfd_get_filename (finfo->output_bfd), ++ input_sec->output_section->name, ++ input_sec->name); ++ eoinfo->failed = true; ++ return false; ++ } ++ ++ /* ELF symbols in relocateable files are section relative, ++ but in nonrelocateable files they are virtual ++ addresses. */ ++ sym.st_value = h->root.u.def.value + input_sec->output_offset; ++#if 0 ++ if (! finfo->info->relocateable) ++ { ++ sym.st_value += input_sec->output_section->vma; ++ if (h->type == STT_TLS) ++ { ++ /* STT_TLS symbols are relative to PT_TLS segment ++ base. */ ++ BFD_ASSERT (finfo->first_tls_sec != NULL); ++ sym.st_value -= finfo->first_tls_sec->vma; ++ } ++ } ++#endif ++ } ++ else ++ { ++ BFD_ASSERT (input_sec->owner == NULL ++ || (input_sec->owner->flags & DYNAMIC) != 0); ++ sym.st_shndx = SHN_UNDEF; ++ input_sec = bfd_und_section_ptr; ++ } ++ } ++ break; ++ ++ case bfd_link_hash_common: ++ input_sec = h->root.u.c.p->section; ++ sym.st_shndx = SHN_COMMON; ++ sym.st_value = 1 << h->root.u.c.p->alignment_power; ++ break; ++ ++ case bfd_link_hash_indirect: ++ /* These symbols are created by symbol versioning. They point ++ to the decorated version of the name. For example, if the ++ symbol foo@@GNU_1.2 is the default, which should be used when ++ foo is used with no version, then we add an indirect symbol ++ foo which points to foo@@GNU_1.2. We ignore these symbols, ++ since the indirected symbol is already in the hash table. */ ++ return true; ++ } ++ ++ /* Give the processor backend a chance to tweak the symbol value, ++ and also to finish up anything that needs to be done for this ++ symbol. FIXME: Not calling elf_backend_finish_dynamic_symbol for ++ forced local syms when non-shared is due to a historical quirk. */ ++ if ((h->dynindx != -1 ++ || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) ++ && (finfo->info->shared ++ || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) ++ && elf_hash_table (finfo->info)->dynamic_sections_created) ++ { ++ struct elf_backend_data *bed; ++ ++ bed = get_elf_backend_data (finfo->output_bfd); ++ if (! ((*bed->elf_backend_finish_dynamic_symbol) ++ (finfo->output_bfd, finfo->info, h, &sym))) ++ { ++ eoinfo->failed = true; ++ return false; ++ } ++ } ++ ++ /* If we are marking the symbol as undefined, and there are no ++ non-weak references to this symbol from a regular object, then ++ mark the symbol as weak undefined; if there are non-weak ++ references, mark the symbol as strong. We can't do this earlier, ++ because it might not be marked as undefined until the ++ finish_dynamic_symbol routine gets through with it. */ ++ if (sym.st_shndx == SHN_UNDEF ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0 ++ && (ELF_ST_BIND (sym.st_info) == STB_GLOBAL ++ || ELF_ST_BIND (sym.st_info) == STB_WEAK)) ++ { ++ int bindtype; ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) != 0) ++ bindtype = STB_GLOBAL; ++ else ++ bindtype = STB_WEAK; ++ sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info)); ++ } ++ ++ /* If a symbol is not defined locally, we clear the visibility ++ field. */ ++ if (! finfo->info->relocateable ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ sym.st_other ^= ELF_ST_VISIBILITY (sym.st_other); ++ ++ /* If this symbol should be put in the .dynsym section, then put it ++ there now. We already know the symbol index. We also fill in ++ the entry in the .hash section. */ ++ if (h->dynindx != -1 ++ && elf_hash_table (finfo->info)->dynamic_sections_created) ++ { ++ size_t bucketcount; ++ size_t bucket; ++ size_t hash_entry_size; ++ bfd_byte *bucketpos; ++ bfd_vma chain; ++ Elf_External_Sym *esym; ++ ++ sym.st_name = h->dynstr_index; ++ esym = (Elf_External_Sym *) finfo->dynsym_sec->contents + h->dynindx; ++ elf_swap_symbol_out (finfo->output_bfd, &sym, (PTR) esym, (PTR) 0); ++ ++ bucketcount = elf_hash_table (finfo->info)->bucketcount; ++ bucket = h->elf_hash_value % bucketcount; ++ hash_entry_size ++ = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize; ++ bucketpos = ((bfd_byte *) finfo->hash_sec->contents ++ + (bucket + 2) * hash_entry_size); ++ chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos); ++ bfd_put (8 * hash_entry_size, finfo->output_bfd, (bfd_vma) h->dynindx, ++ bucketpos); ++ bfd_put (8 * hash_entry_size, finfo->output_bfd, chain, ++ ((bfd_byte *) finfo->hash_sec->contents ++ + (bucketcount + 2 + h->dynindx) * hash_entry_size)); ++ ++ if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL) ++ { ++ Elf_Internal_Versym iversym; ++ Elf_External_Versym *eversym; ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ { ++ if (h->verinfo.verdef == NULL) ++ iversym.vs_vers = 0; ++ else ++ iversym.vs_vers = h->verinfo.verdef->vd_exp_refno + 1; ++ } ++ else ++ { ++ if (h->verinfo.vertree == NULL) ++ iversym.vs_vers = 1; ++ else ++ iversym.vs_vers = h->verinfo.vertree->vernum + 1; ++ } ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HIDDEN) != 0) ++ iversym.vs_vers |= VERSYM_HIDDEN; ++ ++ eversym = (Elf_External_Versym *) finfo->symver_sec->contents; ++ eversym += h->dynindx; ++ _bfd_elf_swap_versym_out (finfo->output_bfd, &iversym, eversym); ++ } ++ } ++ ++ /* If we're stripping it, then it was just a dynamic symbol, and ++ there's nothing else to do. */ ++ if (strip || (input_sec->flags & SEC_EXCLUDE) != 0) ++ return true; ++ ++ h->indx = bfd_get_symcount (finfo->output_bfd); ++ ++ if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec)) ++ { ++ eoinfo->failed = true; ++ return false; ++ } ++ ++ return true; ++} ++ ++/* Copy the relocations indicated by the INTERNAL_RELOCS (which ++ originated from the section given by INPUT_REL_HDR) to the ++ OUTPUT_BFD. */ ++ ++static boolean ++elf_link_output_relocs (output_bfd, input_section, input_rel_hdr, ++ internal_relocs) ++ bfd *output_bfd; ++ asection *input_section; ++ Elf_Internal_Shdr *input_rel_hdr; ++ Elf_Internal_Rela *internal_relocs; ++{ ++ Elf_Internal_Rela *irela; ++ Elf_Internal_Rela *irelaend; ++ Elf_Internal_Shdr *output_rel_hdr; ++ asection *output_section; ++ unsigned int *rel_countp = NULL; ++ struct elf_backend_data *bed; ++ bfd_size_type amt; ++ ++ output_section = input_section->output_section; ++ output_rel_hdr = NULL; ++ ++ if (elf_section_data (output_section)->rel_hdr.sh_entsize ++ == input_rel_hdr->sh_entsize) ++ { ++ output_rel_hdr = &elf_section_data (output_section)->rel_hdr; ++ rel_countp = &elf_section_data (output_section)->rel_count; ++ } ++ else if (elf_section_data (output_section)->rel_hdr2 ++ && (elf_section_data (output_section)->rel_hdr2->sh_entsize ++ == input_rel_hdr->sh_entsize)) ++ { ++ output_rel_hdr = elf_section_data (output_section)->rel_hdr2; ++ rel_countp = &elf_section_data (output_section)->rel_count2; ++ } ++ else ++ { ++ (*_bfd_error_handler) ++ (_("%s: relocation size mismatch in %s section %s"), ++ bfd_get_filename (output_bfd), ++ bfd_archive_filename (input_section->owner), ++ input_section->name); ++ bfd_set_error (bfd_error_wrong_object_format); ++ return false; ++ } ++ ++ bed = get_elf_backend_data (output_bfd); ++ irela = internal_relocs; ++ irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) ++ * bed->s->int_rels_per_ext_rel); ++ ++ if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) ++ { ++ Elf_External_Rel *erel; ++ Elf_Internal_Rel *irel; ++ ++ amt = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rel); ++ irel = (Elf_Internal_Rel *) bfd_zmalloc (amt); ++ if (irel == NULL) ++ { ++ (*_bfd_error_handler) (_("Error: out of memory")); ++ abort (); ++ } ++ ++ erel = ((Elf_External_Rel *) output_rel_hdr->contents + *rel_countp); ++ for (; irela < irelaend; irela += bed->s->int_rels_per_ext_rel, erel++) ++ { ++ unsigned int i; ++ ++ for (i = 0; i < bed->s->int_rels_per_ext_rel; i++) ++ { ++ irel[i].r_offset = irela[i].r_offset; ++ irel[i].r_info = irela[i].r_info; ++ BFD_ASSERT (irela[i].r_addend == 0); ++ } ++ ++ if (bed->s->swap_reloc_out) ++ (*bed->s->swap_reloc_out) (output_bfd, irel, (PTR) erel); ++ else ++ elf_swap_reloc_out (output_bfd, irel, erel); ++ } ++ ++ free (irel); ++ } ++ else ++ { ++ Elf_External_Rela *erela; ++ ++ BFD_ASSERT (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rela)); ++ ++ erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp); ++ for (; irela < irelaend; irela += bed->s->int_rels_per_ext_rel, erela++) ++ if (bed->s->swap_reloca_out) ++ (*bed->s->swap_reloca_out) (output_bfd, irela, (PTR) erela); ++ else ++ elf_swap_reloca_out (output_bfd, irela, erela); ++ } ++ ++ /* Bump the counter, so that we know where to add the next set of ++ relocations. */ ++ *rel_countp += NUM_SHDR_ENTRIES (input_rel_hdr); ++ ++ return true; ++} ++ ++/* Link an input file into the linker output file. This function ++ handles all the sections and relocations of the input file at once. ++ This is so that we only have to read the local symbols once, and ++ don't have to keep them in memory. */ ++ ++static boolean ++elf_link_input_bfd (finfo, input_bfd) ++ struct elf_final_link_info *finfo; ++ bfd *input_bfd; ++{ ++ boolean (*relocate_section) PARAMS ((bfd *, struct bfd_link_info *, ++ bfd *, asection *, bfd_byte *, ++ Elf_Internal_Rela *, ++ Elf_Internal_Sym *, asection **)); ++ bfd *output_bfd; ++ Elf_Internal_Shdr *symtab_hdr; ++ size_t locsymcount; ++ size_t extsymoff; ++ Elf_Internal_Sym *isymbuf; ++ Elf_Internal_Sym *isym; ++ Elf_Internal_Sym *isymend; ++ long *pindex; ++ asection **ppsection; ++ asection *o; ++ struct elf_backend_data *bed; ++ boolean emit_relocs; ++ struct elf_link_hash_entry **sym_hashes; ++ ++ output_bfd = finfo->output_bfd; ++ bed = get_elf_backend_data (output_bfd); ++ relocate_section = bed->elf_backend_relocate_section; ++ ++ /* If this is a dynamic object, we don't want to do anything here: ++ we don't want the local symbols, and we don't want the section ++ contents. */ ++ if ((input_bfd->flags & DYNAMIC) != 0) ++ return true; ++ ++ emit_relocs = (finfo->info->relocateable ++ || finfo->info->emitrelocations ++ || bed->elf_backend_emit_relocs); ++ ++ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; ++ if (elf_bad_symtab (input_bfd)) ++ { ++ locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym); ++ extsymoff = 0; ++ } ++ else ++ { ++ locsymcount = symtab_hdr->sh_info; ++ extsymoff = symtab_hdr->sh_info; ++ } ++ ++ /* Read the local symbols. */ ++ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; ++ if (isymbuf == NULL && locsymcount != 0) ++ { ++ isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0, ++ finfo->internal_syms, ++ finfo->external_syms, ++ finfo->locsym_shndx); ++ if (isymbuf == NULL) ++ return false; ++ } ++ ++ /* Find local symbol sections and adjust values of symbols in ++ SEC_MERGE sections. Write out those local symbols we know are ++ going into the output file. */ ++ isymend = isymbuf + locsymcount; ++ for (isym = isymbuf, pindex = finfo->indices, ppsection = finfo->sections; ++ isym < isymend; ++ isym++, pindex++, ppsection++) ++ { ++ asection *isec; ++ const char *name; ++ Elf_Internal_Sym osym; ++ ++ *pindex = -1; ++ ++ if (elf_bad_symtab (input_bfd)) ++ { ++ if (ELF_ST_BIND (isym->st_info) != STB_LOCAL) ++ { ++ *ppsection = NULL; ++ continue; ++ } ++ } ++ ++ if (isym->st_shndx == SHN_UNDEF) ++ isec = bfd_und_section_ptr; ++ else if (isym->st_shndx < SHN_LORESERVE ++ || isym->st_shndx > SHN_HIRESERVE) ++ { ++ isec = section_from_elf_index (input_bfd, isym->st_shndx); ++ if (isec ++ && elf_section_data (isec)->sec_info_type == ELF_INFO_TYPE_MERGE ++ && ELF_ST_TYPE (isym->st_info) != STT_SECTION) ++ isym->st_value = ++ _bfd_merged_section_offset (output_bfd, &isec, ++ elf_section_data (isec)->sec_info, ++ isym->st_value, (bfd_vma) 0); ++ } ++ else if (isym->st_shndx == SHN_ABS) ++ isec = bfd_abs_section_ptr; ++ else if (isym->st_shndx == SHN_COMMON) ++ isec = bfd_com_section_ptr; ++ else ++ { ++ /* Who knows? */ ++ isec = NULL; ++ } ++ ++ *ppsection = isec; ++ ++ /* Don't output the first, undefined, symbol. */ ++ if (ppsection == finfo->sections) ++ continue; ++ ++ if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) ++ { ++ /* We never output section symbols. Instead, we use the ++ section symbol of the corresponding section in the output ++ file. */ ++ continue; ++ } ++ ++ /* If we are stripping all symbols, we don't want to output this ++ one. */ ++ if (finfo->info->strip == strip_all) ++ continue; ++ ++ /* If we are discarding all local symbols, we don't want to ++ output this one. If we are generating a relocateable output ++ file, then some of the local symbols may be required by ++ relocs; we output them below as we discover that they are ++ needed. */ ++ if (finfo->info->discard == discard_all) ++ continue; ++ ++ /* If this symbol is defined in a section which we are ++ discarding, we don't need to keep it, but note that ++ linker_mark is only reliable for sections that have contents. ++ For the benefit of the MIPS ELF linker, we check SEC_EXCLUDE ++ as well as linker_mark. */ ++ if ((isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE) ++ && isec != NULL ++ && ((! isec->linker_mark && (isec->flags & SEC_HAS_CONTENTS) != 0) ++ || (! finfo->info->relocateable ++ && (isec->flags & SEC_EXCLUDE) != 0))) ++ continue; ++ ++ /* Get the name of the symbol. */ ++ name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, ++ isym->st_name); ++ if (name == NULL) ++ return false; ++ ++ /* See if we are discarding symbols with this name. */ ++ if ((finfo->info->strip == strip_some ++ && (bfd_hash_lookup (finfo->info->keep_hash, name, false, false) ++ == NULL)) ++ || (((finfo->info->discard == discard_sec_merge ++ && (isec->flags & SEC_MERGE) && ! finfo->info->relocateable) ++ || finfo->info->discard == discard_l) ++ && bfd_is_local_label_name (input_bfd, name))) ++ continue; ++ ++ /* If we get here, we are going to output this symbol. */ ++ ++ osym = *isym; ++ ++ /* Adjust the section index for the output file. */ ++ osym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd, ++ isec->output_section); ++ if (osym.st_shndx == SHN_BAD) ++ return false; ++ ++ *pindex = bfd_get_symcount (output_bfd); ++ ++ /* ELF symbols in relocateable files are section relative, but ++ in executable files they are virtual addresses. Note that ++ this code assumes that all ELF sections have an associated ++ BFD section with a reasonable value for output_offset; below ++ we assume that they also have a reasonable value for ++ output_section. Any special sections must be set up to meet ++ these requirements. */ ++ osym.st_value += isec->output_offset; ++ if (! finfo->info->relocateable) ++ { ++ osym.st_value += isec->output_section->vma; ++ if (ELF_ST_TYPE (osym.st_info) == STT_TLS) ++ { ++ /* STT_TLS symbols are relative to PT_TLS segment base. */ ++ BFD_ASSERT (finfo->first_tls_sec != NULL); ++ osym.st_value -= finfo->first_tls_sec->vma; ++ } ++ } ++ ++ if (! elf_link_output_sym (finfo, name, &osym, isec)) ++ return false; ++ } ++ ++ /* Relocate the contents of each section. */ ++ sym_hashes = elf_sym_hashes (input_bfd); ++ for (o = input_bfd->sections; o != NULL; o = o->next) ++ { ++ bfd_byte *contents; ++ ++ if (! o->linker_mark) ++ { ++ /* This section was omitted from the link. */ ++ continue; ++ } ++ ++ if ((o->flags & SEC_HAS_CONTENTS) == 0 ++ || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0)) ++ continue; ++ ++ if ((o->flags & SEC_LINKER_CREATED) != 0) ++ { ++ /* Section was created by elf_link_create_dynamic_sections ++ or somesuch. */ ++ continue; ++ } ++ ++ /* Get the contents of the section. They have been cached by a ++ relaxation routine. Note that o is a section in an input ++ file, so the contents field will not have been set by any of ++ the routines which work on output files. */ ++ if (elf_section_data (o)->this_hdr.contents != NULL) ++ contents = elf_section_data (o)->this_hdr.contents; ++ else ++ { ++ contents = finfo->contents; ++ if (! bfd_get_section_contents (input_bfd, o, contents, ++ (file_ptr) 0, o->_raw_size)) ++ return false; ++ } ++ ++ if ((o->flags & SEC_RELOC) != 0) ++ { ++ Elf_Internal_Rela *internal_relocs; ++ ++ /* Get the swapped relocs. */ ++ internal_relocs = (NAME(_bfd_elf,link_read_relocs) ++ (input_bfd, o, finfo->external_relocs, ++ finfo->internal_relocs, false)); ++ if (internal_relocs == NULL ++ && o->reloc_count > 0) ++ return false; ++ ++ /* Run through the relocs looking for any against symbols ++ from discarded sections and section symbols from ++ removed link-once sections. Complain about relocs ++ against discarded sections. Zero relocs against removed ++ link-once sections. We should really complain if ++ anything in the final link tries to use it, but ++ DWARF-based exception handling might have an entry in ++ .eh_frame to describe a routine in the linkonce section, ++ and it turns out to be hard to remove the .eh_frame ++ entry too. FIXME. */ ++ if (!finfo->info->relocateable ++ && !elf_section_ignore_discarded_relocs (o)) ++ { ++ Elf_Internal_Rela *rel, *relend; ++ ++ rel = internal_relocs; ++ relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel; ++ for ( ; rel < relend; rel++) ++ { ++ unsigned long r_symndx = ELF_R_SYM (rel->r_info); ++ ++ if (r_symndx >= locsymcount ++ || (elf_bad_symtab (input_bfd) ++ && finfo->sections[r_symndx] == NULL)) ++ { ++ struct elf_link_hash_entry *h; ++ ++ h = sym_hashes[r_symndx - extsymoff]; ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ ++ /* Complain if the definition comes from a ++ discarded section. */ ++ if ((h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && elf_discarded_section (h->root.u.def.section)) ++ { ++ if ((o->flags & SEC_DEBUGGING) != 0) ++ { ++ BFD_ASSERT (r_symndx != 0); ++ memset (rel, 0, sizeof (*rel)); ++ } ++ else ++ { ++ if (! ((*finfo->info->callbacks->undefined_symbol) ++ (finfo->info, h->root.root.string, ++ input_bfd, o, rel->r_offset, ++ true))) ++ return false; ++ } ++ } ++ } ++ else ++ { ++ asection *sec = finfo->sections[r_symndx]; ++ ++ if (sec != NULL && elf_discarded_section (sec)) ++ { ++ if ((o->flags & SEC_DEBUGGING) != 0 ++ || (sec->flags & SEC_LINK_ONCE) != 0) ++ { ++ BFD_ASSERT (r_symndx != 0); ++ rel->r_info ++ = ELF_R_INFO (0, ELF_R_TYPE (rel->r_info)); ++ rel->r_addend = 0; ++ } ++ else ++ { ++ boolean ok; ++ const char *msg ++ = _("local symbols in discarded section %s"); ++ bfd_size_type amt ++ = strlen (sec->name) + strlen (msg) - 1; ++ char *buf = (char *) bfd_malloc (amt); ++ ++ if (buf != NULL) ++ sprintf (buf, msg, sec->name); ++ else ++ buf = (char *) sec->name; ++ ok = (*finfo->info->callbacks ++ ->undefined_symbol) (finfo->info, buf, ++ input_bfd, o, ++ rel->r_offset, ++ true); ++ if (buf != sec->name) ++ free (buf); ++ if (!ok) ++ return false; ++ } ++ } ++ } ++ } ++ } ++ ++ /* Relocate the section by invoking a back end routine. ++ ++ The back end routine is responsible for adjusting the ++ section contents as necessary, and (if using Rela relocs ++ and generating a relocateable output file) adjusting the ++ reloc addend as necessary. ++ ++ The back end routine does not have to worry about setting ++ the reloc address or the reloc symbol index. ++ ++ The back end routine is given a pointer to the swapped in ++ internal symbols, and can access the hash table entries ++ for the external symbols via elf_sym_hashes (input_bfd). ++ ++ When generating relocateable output, the back end routine ++ must handle STB_LOCAL/STT_SECTION symbols specially. The ++ output symbol is going to be a section symbol ++ corresponding to the output section, which will require ++ the addend to be adjusted. */ ++ ++ if (! (*relocate_section) (output_bfd, finfo->info, ++ input_bfd, o, contents, ++ internal_relocs, ++ isymbuf, ++ finfo->sections)) ++ return false; ++ ++ if (emit_relocs) ++ { ++ Elf_Internal_Rela *irela; ++ Elf_Internal_Rela *irelaend; ++ struct elf_link_hash_entry **rel_hash; ++ Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2; ++ unsigned int next_erel; ++ boolean (*reloc_emitter) PARAMS ((bfd *, asection *, ++ Elf_Internal_Shdr *, ++ Elf_Internal_Rela *)); ++ boolean rela_normal; ++ ++ input_rel_hdr = &elf_section_data (o)->rel_hdr; ++ rela_normal = (bed->rela_normal ++ && (input_rel_hdr->sh_entsize ++ == sizeof (Elf_External_Rela))); ++ ++ /* Adjust the reloc addresses and symbol indices. */ ++ ++ irela = internal_relocs; ++ irelaend = irela + o->reloc_count * bed->s->int_rels_per_ext_rel; ++ rel_hash = (elf_section_data (o->output_section)->rel_hashes ++ + elf_section_data (o->output_section)->rel_count ++ + elf_section_data (o->output_section)->rel_count2); ++ for (next_erel = 0; irela < irelaend; irela++, next_erel++) ++ { ++ unsigned long r_symndx; ++ asection *sec; ++ Elf_Internal_Sym sym; ++ ++ if (next_erel == bed->s->int_rels_per_ext_rel) ++ { ++ rel_hash++; ++ next_erel = 0; ++ } ++ ++ irela->r_offset += o->output_offset; ++ ++ /* Relocs in an executable have to be virtual addresses. */ ++ if (!finfo->info->relocateable) ++ irela->r_offset += o->output_section->vma; ++ ++ r_symndx = ELF_R_SYM (irela->r_info); ++ ++ if (r_symndx == 0) ++ continue; ++ ++ if (r_symndx >= locsymcount ++ || (elf_bad_symtab (input_bfd) ++ && finfo->sections[r_symndx] == NULL)) ++ { ++ struct elf_link_hash_entry *rh; ++ unsigned long indx; ++ ++ /* This is a reloc against a global symbol. We ++ have not yet output all the local symbols, so ++ we do not know the symbol index of any global ++ symbol. We set the rel_hash entry for this ++ reloc to point to the global hash table entry ++ for this symbol. The symbol index is then ++ set at the end of elf_bfd_final_link. */ ++ indx = r_symndx - extsymoff; ++ rh = elf_sym_hashes (input_bfd)[indx]; ++ while (rh->root.type == bfd_link_hash_indirect ++ || rh->root.type == bfd_link_hash_warning) ++ rh = (struct elf_link_hash_entry *) rh->root.u.i.link; ++ ++ /* Setting the index to -2 tells ++ elf_link_output_extsym that this symbol is ++ used by a reloc. */ ++ BFD_ASSERT (rh->indx < 0); ++ rh->indx = -2; ++ ++ *rel_hash = rh; ++ ++ continue; ++ } ++ ++ /* This is a reloc against a local symbol. */ ++ ++ *rel_hash = NULL; ++ sym = isymbuf[r_symndx]; ++ sec = finfo->sections[r_symndx]; ++ if (ELF_ST_TYPE (sym.st_info) == STT_SECTION) ++ { ++ /* I suppose the backend ought to fill in the ++ section of any STT_SECTION symbol against a ++ processor specific section. If we have ++ discarded a section, the output_section will ++ be the absolute section. */ ++ if (bfd_is_abs_section (sec) ++ || (sec != NULL ++ && bfd_is_abs_section (sec->output_section))) ++ r_symndx = 0; ++ else if (sec == NULL || sec->owner == NULL) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ else ++ { ++ r_symndx = sec->output_section->target_index; ++ BFD_ASSERT (r_symndx != 0); ++ } ++ ++ /* Adjust the addend according to where the ++ section winds up in the output section. */ ++ if (rela_normal) ++ irela->r_addend += sec->output_offset; ++ } ++ else ++ { ++ if (finfo->indices[r_symndx] == -1) ++ { ++ unsigned long shlink; ++ const char *name; ++ asection *osec; ++ ++ if (finfo->info->strip == strip_all) ++ { ++ /* You can't do ld -r -s. */ ++ bfd_set_error (bfd_error_invalid_operation); ++ return false; ++ } ++ ++ /* This symbol was skipped earlier, but ++ since it is needed by a reloc, we ++ must output it now. */ ++ shlink = symtab_hdr->sh_link; ++ name = (bfd_elf_string_from_elf_section ++ (input_bfd, shlink, sym.st_name)); ++ if (name == NULL) ++ return false; ++ ++ osec = sec->output_section; ++ sym.st_shndx = ++ _bfd_elf_section_from_bfd_section (output_bfd, ++ osec); ++ if (sym.st_shndx == SHN_BAD) ++ return false; ++ ++ sym.st_value += sec->output_offset; ++#if 0 ++ if (! finfo->info->relocateable) ++ { ++ sym.st_value += osec->vma; ++ if (ELF_ST_TYPE (sym.st_info) == STT_TLS) ++ { ++ /* STT_TLS symbols are relative to PT_TLS ++ segment base. */ ++ BFD_ASSERT (finfo->first_tls_sec != NULL); ++ sym.st_value -= finfo->first_tls_sec->vma; ++ } ++ } ++#endif ++ ++ finfo->indices[r_symndx] ++ = bfd_get_symcount (output_bfd); ++ ++ if (! elf_link_output_sym (finfo, name, &sym, sec)) ++ return false; ++ } ++ ++ r_symndx = finfo->indices[r_symndx]; ++ } ++ ++ irela->r_info = ELF_R_INFO (r_symndx, ++ ELF_R_TYPE (irela->r_info)); ++ } ++ ++ /* Swap out the relocs. */ ++ if (bed->elf_backend_emit_relocs ++ && !(finfo->info->relocateable ++ || finfo->info->emitrelocations)) ++ reloc_emitter = bed->elf_backend_emit_relocs; ++ else ++ reloc_emitter = elf_link_output_relocs; ++ ++ if (input_rel_hdr->sh_size != 0 ++ && ! (*reloc_emitter) (output_bfd, o, input_rel_hdr, ++ internal_relocs)) ++ return false; ++ ++ input_rel_hdr2 = elf_section_data (o)->rel_hdr2; ++ if (input_rel_hdr2 && input_rel_hdr2->sh_size != 0) ++ { ++ internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr) ++ * bed->s->int_rels_per_ext_rel); ++ if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr2, ++ internal_relocs)) ++ return false; ++ } ++ } ++ } ++ ++ /* Write out the modified section contents. */ ++ if (bed->elf_backend_write_section ++ && (*bed->elf_backend_write_section) (output_bfd, o, contents)) ++ { ++ /* Section written out. */ ++ } ++ else switch (elf_section_data (o)->sec_info_type) ++ { ++ case ELF_INFO_TYPE_STABS: ++ if (! (_bfd_write_section_stabs ++ (output_bfd, ++ &elf_hash_table (finfo->info)->stab_info, ++ o, &elf_section_data (o)->sec_info, contents))) ++ return false; ++ break; ++ case ELF_INFO_TYPE_MERGE: ++ if (! (_bfd_write_merged_section ++ (output_bfd, o, elf_section_data (o)->sec_info))) ++ return false; ++ break; ++ case ELF_INFO_TYPE_EH_FRAME: ++ { ++ asection *ehdrsec; ++ ++ ehdrsec ++ = bfd_get_section_by_name (elf_hash_table (finfo->info)->dynobj, ++ ".eh_frame_hdr"); ++ if (! (_bfd_elf_write_section_eh_frame (output_bfd, o, ehdrsec, ++ contents))) ++ return false; ++ } ++ break; ++ default: ++ { ++ bfd_size_type sec_size; ++ ++ sec_size = (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size); ++ if (! (o->flags & SEC_EXCLUDE) ++ && ! bfd_set_section_contents (output_bfd, o->output_section, ++ contents, ++ (file_ptr) o->output_offset, ++ sec_size)) ++ return false; ++ } ++ break; ++ } ++ } ++ ++ return true; ++} ++ ++/* Generate a reloc when linking an ELF file. This is a reloc ++ requested by the linker, and does come from any input file. This ++ is used to build constructor and destructor tables when linking ++ with -Ur. */ ++ ++static boolean ++elf_reloc_link_order (output_bfd, info, output_section, link_order) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ asection *output_section; ++ struct bfd_link_order *link_order; ++{ ++ reloc_howto_type *howto; ++ long indx; ++ bfd_vma offset; ++ bfd_vma addend; ++ struct elf_link_hash_entry **rel_hash_ptr; ++ Elf_Internal_Shdr *rel_hdr; ++ struct elf_backend_data *bed = get_elf_backend_data (output_bfd); ++ ++ howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); ++ if (howto == NULL) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ ++ addend = link_order->u.reloc.p->addend; ++ ++ /* Figure out the symbol index. */ ++ rel_hash_ptr = (elf_section_data (output_section)->rel_hashes ++ + elf_section_data (output_section)->rel_count ++ + elf_section_data (output_section)->rel_count2); ++ if (link_order->type == bfd_section_reloc_link_order) ++ { ++ indx = link_order->u.reloc.p->u.section->target_index; ++ BFD_ASSERT (indx != 0); ++ *rel_hash_ptr = NULL; ++ } ++ else ++ { ++ struct elf_link_hash_entry *h; ++ ++ /* Treat a reloc against a defined symbol as though it were ++ actually against the section. */ ++ h = ((struct elf_link_hash_entry *) ++ bfd_wrapped_link_hash_lookup (output_bfd, info, ++ link_order->u.reloc.p->u.name, ++ false, false, true)); ++ if (h != NULL ++ && (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak)) ++ { ++ asection *section; ++ ++ section = h->root.u.def.section; ++ indx = section->output_section->target_index; ++ *rel_hash_ptr = NULL; ++ /* It seems that we ought to add the symbol value to the ++ addend here, but in practice it has already been added ++ because it was passed to constructor_callback. */ ++ addend += section->output_section->vma + section->output_offset; ++ } ++ else if (h != NULL) ++ { ++ /* Setting the index to -2 tells elf_link_output_extsym that ++ this symbol is used by a reloc. */ ++ h->indx = -2; ++ *rel_hash_ptr = h; ++ indx = 0; ++ } ++ else ++ { ++ if (! ((*info->callbacks->unattached_reloc) ++ (info, link_order->u.reloc.p->u.name, (bfd *) NULL, ++ (asection *) NULL, (bfd_vma) 0))) ++ return false; ++ indx = 0; ++ } ++ } ++ ++ /* If this is an inplace reloc, we must write the addend into the ++ object file. */ ++ if (howto->partial_inplace && addend != 0) ++ { ++ bfd_size_type size; ++ bfd_reloc_status_type rstat; ++ bfd_byte *buf; ++ boolean ok; ++ const char *sym_name; ++ ++ size = bfd_get_reloc_size (howto); ++ buf = (bfd_byte *) bfd_zmalloc (size); ++ if (buf == (bfd_byte *) NULL) ++ return false; ++ rstat = _bfd_relocate_contents (howto, output_bfd, (bfd_vma) addend, buf); ++ switch (rstat) ++ { ++ case bfd_reloc_ok: ++ break; ++ ++ default: ++ case bfd_reloc_outofrange: ++ abort (); ++ ++ case bfd_reloc_overflow: ++ if (link_order->type == bfd_section_reloc_link_order) ++ sym_name = bfd_section_name (output_bfd, ++ link_order->u.reloc.p->u.section); ++ else ++ sym_name = link_order->u.reloc.p->u.name; ++ if (! ((*info->callbacks->reloc_overflow) ++ (info, sym_name, howto->name, addend, ++ (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) ++ { ++ free (buf); ++ return false; ++ } ++ break; ++ } ++ ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, ++ (file_ptr) link_order->offset, size); ++ free (buf); ++ if (! ok) ++ return false; ++ } ++ ++ /* The address of a reloc is relative to the section in a ++ relocateable file, and is a virtual address in an executable ++ file. */ ++ offset = link_order->offset; ++ if (! info->relocateable) ++ offset += output_section->vma; ++ ++ rel_hdr = &elf_section_data (output_section)->rel_hdr; ++ ++ if (rel_hdr->sh_type == SHT_REL) ++ { ++ bfd_size_type size; ++ Elf_Internal_Rel *irel; ++ Elf_External_Rel *erel; ++ unsigned int i; ++ ++ size = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rel); ++ irel = (Elf_Internal_Rel *) bfd_zmalloc (size); ++ if (irel == NULL) ++ return false; ++ ++ for (i = 0; i < bed->s->int_rels_per_ext_rel; i++) ++ irel[i].r_offset = offset; ++ irel[0].r_info = ELF_R_INFO (indx, howto->type); ++ ++ erel = ((Elf_External_Rel *) rel_hdr->contents ++ + elf_section_data (output_section)->rel_count); ++ ++ if (bed->s->swap_reloc_out) ++ (*bed->s->swap_reloc_out) (output_bfd, irel, (bfd_byte *) erel); ++ else ++ elf_swap_reloc_out (output_bfd, irel, erel); ++ ++ free (irel); ++ } ++ else ++ { ++ bfd_size_type size; ++ Elf_Internal_Rela *irela; ++ Elf_External_Rela *erela; ++ unsigned int i; ++ ++ size = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela); ++ irela = (Elf_Internal_Rela *) bfd_zmalloc (size); ++ if (irela == NULL) ++ return false; ++ ++ for (i = 0; i < bed->s->int_rels_per_ext_rel; i++) ++ irela[i].r_offset = offset; ++ irela[0].r_info = ELF_R_INFO (indx, howto->type); ++ irela[0].r_addend = addend; ++ ++ erela = ((Elf_External_Rela *) rel_hdr->contents ++ + elf_section_data (output_section)->rel_count); ++ ++ if (bed->s->swap_reloca_out) ++ (*bed->s->swap_reloca_out) (output_bfd, irela, (bfd_byte *) erela); ++ else ++ elf_swap_reloca_out (output_bfd, irela, erela); ++ } ++ ++ ++elf_section_data (output_section)->rel_count; ++ ++ return true; ++} ++ ++static boolean ++elf_section_ignore_discarded_relocs (sec) ++ asection *sec; ++{ ++ struct elf_backend_data *bed; ++ ++ switch (elf_section_data (sec)->sec_info_type) ++ { ++ case ELF_INFO_TYPE_STABS: ++ case ELF_INFO_TYPE_EH_FRAME: ++ return true; ++ default: ++ break; ++ } ++ ++ bed = get_elf_backend_data (sec->owner); ++ if (bed->elf_backend_ignore_discarded_relocs != NULL ++ && (*bed->elf_backend_ignore_discarded_relocs) (sec)) ++ return true; ++ ++ return false; ++} ++ ++#define TARGET_BIG_SYM bfd_elf32_morphos_vec ++#define TARGET_BIG_NAME "elf32-morphos" ++#define ELF_ARCH bfd_arch_powerpc ++#define ELF_MACHINE_CODE EM_PPC ++#define ELF_MAXPAGESIZE 0x10000 ++#define elf_info_to_howto ppc_elf_info_to_howto ++ ++#ifdef EM_CYGNUS_POWERPC ++#define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC ++#endif ++ ++#ifdef EM_PPC_OLD ++#define ELF_MACHINE_ALT2 EM_PPC_OLD ++#endif ++ ++#define elf_backend_plt_not_loaded 1 ++#define elf_backend_got_symbol_offset 4 ++#define elf_backend_can_gc_sections 1 ++#define elf_backend_can_refcount 1 ++#define elf_backend_got_header_size 12 ++#define elf_backend_plt_header_size PLT_INITIAL_ENTRY_SIZE ++#define elf_backend_rela_normal 1 ++ ++#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data ++#define bfd_elf32_bfd_relax_section ppc_elf_relax_section ++#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup ++#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags ++/*#define bfd_elf32_bfd_final_link _bfd_elf32_gc_common_final_link*/ ++#define bfd_elf32_bfd_final_link ppc_elf_final_link ++ ++#define elf_backend_object_p ppc_elf_object_p ++#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook ++#define elf_backend_gc_sweep_hook ppc_elf_gc_sweep_hook ++#define elf_backend_section_from_shdr ppc_elf_section_from_shdr ++#define elf_backend_relocate_section ppc_elf_relocate_section ++#define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections ++#define elf_backend_check_relocs ppc_elf_check_relocs ++#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol ++/*#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook*/ ++#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections ++#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol ++#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections ++#define elf_backend_fake_sections ppc_elf_fake_sections ++#define elf_backend_additional_program_headers ppc_elf_additional_program_headers ++#define elf_backend_modify_segment_map ppc_elf_modify_segment_map ++#define elf_backend_grok_prstatus ppc_elf_grok_prstatus ++#define elf_backend_grok_psinfo ppc_elf_grok_psinfo ++#define elf_backend_reloc_type_class ppc_elf_reloc_type_class ++ ++#include "elf32-target.h" +diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c +index 6454a8350da35adf6ed1e2209d9e4774ab7c50e3..5c92c53da7b3dec8f85a0a0b930190635f89dcfb 100644 +--- bfd/elf32-ppc.c ++++ bfd/elf32-ppc.c +@@ -4412,12 +4412,16 @@ ppc_elf_check_relocs (bfd *abfd, + p->count += 1; + if (!must_be_dyn_reloc (info, r_type)) + p->pc_count += 1; + } + + break; ++ ++ default: ++ fprintf(stderr,"Switch case not handled!\n"); ++ break; + } + } + + return TRUE; + } + +diff --git a/bfd/hosts/amigaos.h b/bfd/hosts/amigaos.h +new file mode 100644 +index 0000000000000000000000000000000000000000..dc62d7f837f333ae8d2c5b47d01144cb0d3625f2 +--- /dev/null ++++ bfd/hosts/amigaos.h +@@ -0,0 +1,5 @@ ++/* Host configuration for AmigaOS */ ++#ifndef hosts_amigaos_h ++#define hosts_amigaos_h ++#include "hosts/std-host.h" ++#endif /* hosts_amigaos_h */ +diff --git a/bfd/hosts/morphos.h b/bfd/hosts/morphos.h +new file mode 100644 +index 0000000000000000000000000000000000000000..d3c60ea9f5767ad0bfa22ba2c8c1e5ed9d94d481 +--- /dev/null ++++ bfd/hosts/morphos.h +@@ -0,0 +1,5 @@ ++/* Host configuration for MorphOS */ ++#ifndef hosts_morphos_h ++#define hosts_morphos_h ++#include "hosts/std-host.h" ++#endif /* hosts_morphos_h */ +diff --git a/bfd/libamiga.h b/bfd/libamiga.h +new file mode 100644 +index 0000000000000000000000000000000000000000..351f0fa16a45680982f5b5807c8ba756defe1764 +--- /dev/null ++++ bfd/libamiga.h +@@ -0,0 +1,187 @@ ++/* BFD back-end for Commodore-Amiga AmigaOS binaries. Data structures. ++ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998 ++ Free Software Foundation, Inc. ++ Contributed by Leonard Norrgard. ++ Extended by Stephan Thesing 11/1994. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++ ++/* Hunk ID numbers. */ ++ ++#define HUNK_UNIT 999 ++#define HUNK_NAME 1000 ++#define HUNK_CODE 1001 ++#define HUNK_DATA 1002 ++#define HUNK_BSS 1003 ++#define HUNK_RELOC32 1004 ++#define HUNK_ABSRELOC32 HUNK_RELOC32 ++#define HUNK_RELOC16 1005 ++#define HUNK_RELRELOC16 HUNK_RELOC16 ++#define HUNK_RELOC8 1006 ++#define HUNK_RELRELOC8 HUNK_RELOC8 ++#define HUNK_EXT 1007 ++#define HUNK_SYMBOL 1008 ++#define HUNK_DEBUG 1009 ++#define HUNK_END 1010 ++#define HUNK_HEADER 1011 ++#define HUNK_OVERLAY 1013 ++#define HUNK_BREAK 1014 ++#define HUNK_DREL32 1015 ++#define HUNK_DREL16 1016 ++#define HUNK_DREL8 1017 ++#define HUNK_LIB 1018 ++#define HUNK_INDEX 1019 ++#define HUNK_RELOC32SHORT 1020 ++#define HUNK_RELRELOC32 1021 ++#define HUNK_ABSRELOC16 1022 ++/* EHF extensions */ ++#define HUNK_PPC_CODE 1257 ++#define HUNK_RELRELOC26 1260 ++ ++/* The hunk ID part. */ ++ ++#define HUNK_VALUE(hunk_id) ((hunk_id) & 0x3fffffff) ++ ++/* Attributes of a hunk. */ ++ ++#define HUNK_ATTRIBUTE(hunk_id) ((hunk_id) >> 30) ++#define HUNK_ATTR_CHIP 0x01 /* hunk content must go into chip ram */ ++#define HUNK_ATTR_FAST 0x02 /* fast */ ++#define HUNK_ATTR_FOLLOWS 0x03 /* mem id follows */ ++ ++/* HUNK_EXT subtypes. */ ++ ++#define EXT_SYMB 0 ++#define EXT_DEF 1 ++#define EXT_ABS 2 ++#define EXT_RES 3 ++#define EXT_REF32 129 ++#define EXT_ABSREF32 EXT_REF32 ++#define EXT_COMMON 130 ++#define EXT_ABSCOMMON EXT_COMMON ++#define EXT_REF16 131 ++#define EXT_RELREF16 EXT_REF16 ++#define EXT_REF8 132 ++#define EXT_RELREF8 EXT_REF8 ++#define EXT_DEXT32 133 ++#define EXT_DEXT16 134 ++#define EXT_DEXT8 135 ++#define EXT_RELREF32 136 ++#define EXT_RELCOMMON 137 ++#define EXT_ABSREF16 138 ++#define EXT_ABSREF8 139 ++/* VBCC extensions */ ++#define EXT_DEXT32COMMON 208 ++#define EXT_DEXT16COMMON 209 ++#define EXT_DEXT8COMMON 210 ++/* EHF extensions */ ++#define EXT_RELREF26 229 ++ ++/* HOWTO types almost matching aoutx.h/howto_table_std. */ ++ ++enum { ++ H_ABS8=0,H_ABS16,H_ABS32,H_ABS32SHORT,H_PC8,H_PC16,H_PC32,H_PC26,H_SD8,H_SD16,H_SD32 ++}; ++ ++/* Various structures. */ ++ ++typedef struct amiga_reloc { ++ arelent relent; ++ struct amiga_reloc *next; ++ asymbol *symbol; ++} amiga_reloc_type; ++ ++/* Structure layout *must* match libaout.h/struct aout_symbol. */ ++ ++typedef struct amiga_symbol { ++ asymbol symbol; ++ short desc; ++ char other; ++ unsigned char type; ++ /* amiga data */ ++ unsigned long index,refnum; ++} amiga_symbol_type; ++ ++/* We take the address of the first element of an asymbol to ensure that the ++ macro is only ever applied to an asymbol. */ ++#define amiga_symbol(asymbol) ((amiga_symbol_type *)(&(asymbol)->the_bfd)) ++ ++typedef struct raw_reloc { ++ unsigned long num,pos; ++ struct raw_reloc *next; ++} raw_reloc_type; ++ ++typedef struct amiga_per_section { ++ amiga_reloc_type *reloc_tail; /* last reloc, first is in section->relocation */ ++ int attribute; /* Memory type required by this section */ ++ unsigned long disk_size; /* Section size on disk, _raw_size may be larger than this */ ++ amiga_symbol_type *amiga_symbols; /* the symbols for this section */ ++ unsigned long hunk_ext_pos; /* offset of hunk_ext in the bfd file */ ++ unsigned long hunk_symbol_pos; /* offset of hunk_symbol in the bfd file */ ++ raw_reloc_type *relocs; ++} amiga_per_section_type; ++ ++#define amiga_per_section(x) ((amiga_per_section_type *)((x)->used_by_bfd)) ++ ++/* Structure layout *must* match libaout.h/struct aoutdata. */ ++ ++struct amiga_data { ++ char *dummy[2]; ++ sec_ptr textsec; ++ sec_ptr datasec; ++ sec_ptr bsssec; ++ file_ptr sym_filepos; ++ file_ptr str_filepos; ++ /* rest intentionally omitted */ ++}; ++ ++typedef struct amiga_data_struct { ++ struct amiga_data a; ++ unsigned long symtab_size; ++ unsigned long stringtab_size; ++ amiga_symbol_type *symbols; ++ bfd_boolean IsLoadFile; /* If true, this is a load file (for output bfd only) */ ++ unsigned int nb_hunks; ++ /* The next two fields are set at final_link time (for the output bfd only) */ ++ bfd_boolean baserel;/* true if there is ___init_a4 in the global hash table */ ++ bfd_vma a4init; /* cache the value for efficiency */ ++} amiga_data_type; ++ ++#define adata(bfd) ((bfd)->tdata.amiga_data->a) ++#define AMIGA_DATA(bfd) ((bfd)->tdata.amiga_data) ++ ++#define HUNKB_ADVISORY 29 ++#define HUNKB_CHIP 30 ++#define HUNKB_FAST 31 ++#define HUNKF_ADVISORY (1L << HUNKB_ADVISORY) ++#define HUNKF_CHIP (1L << HUNKB_CHIP) ++#define HUNKF_FAST (1L << HUNKB_FAST) ++ ++#ifndef MEMF_ANY ++#define MEMF_ANY (0L) ++#define MEMF_PUBLIC (1L << 0) ++#define MEMF_CHIP (1L << 1) ++#define MEMF_FAST (1L << 2) ++#define MEMF_LOCAL (1L << 8) ++#define MEMF_24BITDMA (1L << 9) ++#define MEMF_KICK (1L << 10) ++#define MEMF_CLEAR (1L << 16) ++#define MEMF_LARGEST (1L << 17) ++#define MEMF_REVERSE (1L << 18) ++#define MEMF_TOTAL (1L << 19) ++#define MEMF_NO_EXPUNGE (1L << 31) ++#endif /* MEMF_ANY */ +diff --git a/bfd/libbfd.h b/bfd/libbfd.h +index 6c48d641f606b9ed6158b4567021769bacfbd54a..3cb9b36fe2379a5d7f118472e106c151d6153aea 100644 +--- bfd/libbfd.h ++++ bfd/libbfd.h +@@ -1345,12 +1345,16 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", + "BFD_RELOC_PPC_EMB_RELSEC16", + "BFD_RELOC_PPC_EMB_RELST_LO", + "BFD_RELOC_PPC_EMB_RELST_HI", + "BFD_RELOC_PPC_EMB_RELST_HA", + "BFD_RELOC_PPC_EMB_BIT_FLD", + "BFD_RELOC_PPC_EMB_RELSDA", ++ "BFD_RELOC_PPC_MORPHOS_DREL", ++ "BFD_RELOC_PPC_MORPHOS_DREL_LO", ++ "BFD_RELOC_PPC_MORPHOS_DREL_HI", ++ "BFD_RELOC_PPC_MORPHOS_DREL_HA", + "BFD_RELOC_PPC_VLE_REL8", + "BFD_RELOC_PPC_VLE_REL15", + "BFD_RELOC_PPC_VLE_REL24", + "BFD_RELOC_PPC_VLE_LO16A", + "BFD_RELOC_PPC_VLE_LO16D", + "BFD_RELOC_PPC_VLE_HI16A", +@@ -1427,12 +1431,16 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", + "BFD_RELOC_PPC64_DTPREL16_DS", + "BFD_RELOC_PPC64_DTPREL16_LO_DS", + "BFD_RELOC_PPC64_DTPREL16_HIGHER", + "BFD_RELOC_PPC64_DTPREL16_HIGHERA", + "BFD_RELOC_PPC64_DTPREL16_HIGHEST", + "BFD_RELOC_PPC64_DTPREL16_HIGHESTA", ++ "BFD_RELOC_PPC_AMIGAOS_BREL", ++ "BFD_RELOC_PPC_AMIGAOS_BREL_LO", ++ "BFD_RELOC_PPC_AMIGAOS_BREL_HI", ++ "BFD_RELOC_PPC_AMIGAOS_BREL_HA", + "BFD_RELOC_I370_D12", + "BFD_RELOC_CTOR", + "BFD_RELOC_ARM_PCREL_BRANCH", + "BFD_RELOC_ARM_PCREL_BLX", + "BFD_RELOC_THUMB_PCREL_BLX", + "BFD_RELOC_ARM_PCREL_CALL", +diff --git a/bfd/linker.c b/bfd/linker.c +index d3ef9a43a5bca8096221870248daf58007c6ef78..4f0aa188f5017ea68023530f6ae9eaa6b98b5b11 100644 +--- bfd/linker.c ++++ bfd/linker.c +@@ -430,13 +430,14 @@ static bfd_boolean generic_link_add_symbol_list + (bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **, + bfd_boolean); + static bfd_boolean generic_add_output_symbol + (bfd *, size_t *psymalloc, asymbol *); + static bfd_boolean default_data_link_order + (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *); +-static bfd_boolean default_indirect_link_order ++/*Amiga hack - used in amigaoslink.c so must be global */ ++/*static*/ bfd_boolean default_indirect_link_order + (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *, + bfd_boolean); + + /* The link hash table structure is defined in bfdlink.h. It provides + a base hash table which the backend specific hash tables are built + upon. */ +@@ -1294,12 +1295,19 @@ generic_link_check_archive_element (bfd *abfd, + return FALSE; + + size = bfd_asymbol_value (p); + h->u.c.size = size; + + power = bfd_log2 (size); ++ /* For the amiga, we don't want an alignment bigger than 2**2. ++ Doing this here is horrible kludgy, but IMHO the maximal ++ power alignment really should be target-dependant so that ++ we wouldn't have to do this -- daniel */ ++ if (info->output_bfd->xvec->flavour == bfd_target_amiga_flavour ++ && power > 2) ++ power = 2; + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + + if (p->section == bfd_com_section_ptr) + h->u.c.p->section = bfd_make_section_old_way (symbfd, "COMMON"); +@@ -1746,12 +1754,19 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, + /* Select a default alignment based on the size. This may + be overridden by the caller. */ + { + unsigned int power; + + power = bfd_log2 (value); ++ /* For the amiga, we don't want an alignment bigger than 2**2. ++ Doing this here is horrible kludgy, but IMHO the maximal ++ power alignment really should be target-dependant so that ++ we wouldn't have to do this -- daniel */ ++ if (info->output_bfd->xvec->flavour == bfd_target_amiga_flavour ++ && power > 2) ++ power = 2; + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + } + + /* The section of a common symbol is only used if the common +@@ -1799,12 +1814,19 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, + + h->u.c.size = value; + + /* Select a default alignment based on the size. This may + be overridden by the caller. */ + power = bfd_log2 (value); ++ /* For the amiga, we don't want an alignment bigger than 2**2. ++ Doing this here is horrible kludgy, but IMHO the maximal ++ power alignment really should be target-dependant so that ++ we wouldn't have to do this -- daniel */ ++ if (info->output_bfd->xvec->flavour == bfd_target_amiga_flavour ++ && power > 2) ++ power = 2; + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + + /* Some systems have special treatment for small commons, + hence we want to select the section used by the larger +@@ -2709,13 +2731,13 @@ default_data_link_order (bfd *abfd, + free (fill); + return result; + } + + /* Default routine to handle a bfd_indirect_link_order. */ + +-static bfd_boolean ++/*static*/ bfd_boolean + default_indirect_link_order (bfd *output_bfd, + struct bfd_link_info *info, + asection *output_section, + struct bfd_link_order *link_order, + bfd_boolean generic_linker) + { +diff --git a/bfd/reloc.c b/bfd/reloc.c +index 47d052d1345847a7178f4c7ebe4f529396ae0a4f..6c3bb68f2da65b201b6288b8709fd60d9b0d5b2c 100644 +--- bfd/reloc.c ++++ bfd/reloc.c +@@ -2803,12 +2803,20 @@ ENUMX + BFD_RELOC_PPC_EMB_RELST_HA + ENUMX + BFD_RELOC_PPC_EMB_BIT_FLD + ENUMX + BFD_RELOC_PPC_EMB_RELSDA + ENUMX ++ BFD_RELOC_PPC_MORPHOS_DREL ++ENUMX ++ BFD_RELOC_PPC_MORPHOS_DREL_LO ++ENUMX ++ BFD_RELOC_PPC_MORPHOS_DREL_HI ++ENUMX ++ BFD_RELOC_PPC_MORPHOS_DREL_HA ++ENUMX + BFD_RELOC_PPC_VLE_REL8 + ENUMX + BFD_RELOC_PPC_VLE_REL15 + ENUMX + BFD_RELOC_PPC_VLE_REL24 + ENUMX +@@ -2973,12 +2981,23 @@ ENUMX + ENUMX + BFD_RELOC_PPC64_DTPREL16_HIGHESTA + ENUMDOC + PowerPC and PowerPC64 thread-local storage relocations. + + ENUM ++ BFD_RELOC_PPC_AMIGAOS_BREL ++ENUMX ++ BFD_RELOC_PPC_AMIGAOS_BREL_LO ++ENUMX ++ BFD_RELOC_PPC_AMIGAOS_BREL_HI ++ENUMX ++ BFD_RELOC_PPC_AMIGAOS_BREL_HA ++ENUMDOC ++ AmigaOS4 PowerPC specific base-relative relocations. ++ ++ENUM + BFD_RELOC_I370_D12 + ENUMDOC + IBM 370/390 relocations + + ENUM + BFD_RELOC_CTOR +diff --git a/bfd/targets.c b/bfd/targets.c +index fa206d24bef3a22255f6be42221647db3142eb06..9df24504bab564048f724fbbb641ca13c5805602 100644 +--- bfd/targets.c ++++ bfd/targets.c +@@ -144,12 +144,13 @@ DESCRIPTION + the entry points which call them. Too bad we can't have one + macro to define them both! + + .enum bfd_flavour + .{ + . bfd_target_unknown_flavour, ++. bfd_target_amiga_flavour, + . bfd_target_aout_flavour, + . bfd_target_coff_flavour, + . bfd_target_ecoff_flavour, + . bfd_target_xcoff_flavour, + . bfd_target_elf_flavour, + . bfd_target_ieee_flavour, +@@ -568,12 +569,14 @@ to find an alternative output format that is suitable. + /* All known xvecs (even those that don't compile on all systems). + Alphabetized for easy reference. + They are listed a second time below, since + we can't intermix extern's and initializers. */ + extern const bfd_target a_out_adobe_vec; + extern const bfd_target aix5coff64_vec; ++extern const bfd_target amiga_vec; ++extern const bfd_target aout_amiga_vec; + extern const bfd_target aout0_big_vec; + extern const bfd_target aout_arm_big_vec; + extern const bfd_target aout_arm_little_vec; + extern const bfd_target aout_mips_big_vec; + extern const bfd_target aout_mips_little_vec; + extern const bfd_target apollocoff_vec; +@@ -592,12 +595,13 @@ extern const bfd_target armpe_big_vec; + extern const bfd_target armpe_little_vec; + extern const bfd_target armpei_big_vec; + extern const bfd_target armpei_little_vec; + extern const bfd_target b_out_vec_big_host; + extern const bfd_target b_out_vec_little_host; + extern const bfd_target bfd_pei_ia64_vec; ++extern const bfd_target bfd_elf32_amigaos_vec; + extern const bfd_target bfd_elf32_avr_vec; + extern const bfd_target bfd_elf32_bfin_vec; + extern const bfd_target bfd_elf32_bfinfdpic_vec; + extern const bfd_target bfd_elf32_big_generic_vec; + extern const bfd_target bfd_elf32_bigarc_vec; + extern const bfd_target bfd_elf32_bigarm_vec; +@@ -625,12 +629,13 @@ extern const bfd_target bfd_elf32_hppa_vec; + extern const bfd_target bfd_elf32_i370_vec; + extern const bfd_target bfd_elf32_i386_freebsd_vec; + extern const bfd_target bfd_elf32_i386_nacl_vec; + extern const bfd_target bfd_elf32_i386_sol2_vec; + extern const bfd_target bfd_elf32_i386_vxworks_vec; + extern const bfd_target bfd_elf32_i386_vec; ++extern const bfd_target bfd_elf32_i386be_amithlon_vec; + extern const bfd_target bfd_elf32_i860_little_vec; + extern const bfd_target bfd_elf32_i860_vec; + extern const bfd_target bfd_elf32_i960_vec; + extern const bfd_target bfd_elf32_ia64_big_vec; + extern const bfd_target bfd_elf32_ia64_hpux_big_vec; + extern const bfd_target bfd_elf32_ip2k_vec; +@@ -658,12 +663,13 @@ extern const bfd_target bfd_elf32_mcore_big_vec; + extern const bfd_target bfd_elf32_mcore_little_vec; + extern const bfd_target bfd_elf32_mep_vec; + extern const bfd_target bfd_elf32_mep_little_vec; + extern const bfd_target bfd_elf32_microblaze_vec; + extern const bfd_target bfd_elf32_mn10200_vec; + extern const bfd_target bfd_elf32_mn10300_vec; ++extern const bfd_target bfd_elf32_morphos_vec; + extern const bfd_target bfd_elf32_mt_vec; + extern const bfd_target bfd_elf32_msp430_vec; + extern const bfd_target bfd_elf32_nbigmips_vec; + extern const bfd_target bfd_elf32_nlittlemips_vec; + extern const bfd_target bfd_elf32_ntradbigmips_vec; + extern const bfd_target bfd_elf32_ntradlittlemips_vec; +@@ -929,12 +935,14 @@ static const bfd_target * const _bfd_target_vector[] = + should have an entry here with #if 0 around it, to show that + it wasn't omitted by mistake. */ + &a_out_adobe_vec, + #ifdef BFD64 + &aix5coff64_vec, + #endif ++ &amiga_vec, ++ &aout_amiga_vec, + &aout0_big_vec, + #if 0 + /* We have no way of distinguishing these from other a.out variants. */ + &aout_arm_big_vec, + &aout_arm_little_vec, + /* No one seems to use this. */ +@@ -961,12 +969,13 @@ static const bfd_target * const _bfd_target_vector[] = + &armpei_little_vec, + &b_out_vec_big_host, + &b_out_vec_little_host, + #ifdef BFD64 + &bfd_pei_ia64_vec, + #endif ++ &bfd_elf32_amigaos_vec, + &bfd_elf32_avr_vec, + &bfd_elf32_bfin_vec, + &bfd_elf32_bfinfdpic_vec, + + /* This, and other vectors, may not be used in any *.mt configuration. + But that does not mean they are unnecessary. If configured with +@@ -998,12 +1007,13 @@ static const bfd_target * const _bfd_target_vector[] = + &bfd_elf32_i370_vec, + &bfd_elf32_i386_freebsd_vec, + &bfd_elf32_i386_nacl_vec, + &bfd_elf32_i386_sol2_vec, + &bfd_elf32_i386_vxworks_vec, + &bfd_elf32_i386_vec, ++ &bfd_elf32_i386be_amithlon_vec, + &bfd_elf32_i860_little_vec, + &bfd_elf32_i860_vec, + &bfd_elf32_i960_vec, + #if 0 + &bfd_elf32_ia64_big_vec, + #endif +@@ -1032,12 +1042,13 @@ static const bfd_target * const _bfd_target_vector[] = + &bfd_elf32_mcore_big_vec, + &bfd_elf32_mcore_little_vec, + &bfd_elf32_mep_vec, + &bfd_elf32_microblaze_vec, + &bfd_elf32_mn10200_vec, + &bfd_elf32_mn10300_vec, ++ &bfd_elf32_morphos_vec, + &bfd_elf32_mt_vec, + &bfd_elf32_msp430_vec, + #ifdef BFD64 + &bfd_elf32_nbigmips_vec, + &bfd_elf32_nlittlemips_vec, + &bfd_elf32_ntradbigmips_vec, +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index 020d54d6fbe27a5c90600e1d034a93e8fade0ff6..88bd071eefa8b5426eaadfd6431e9de5d4a4591b 100644 +--- binutils/objcopy.c ++++ binutils/objcopy.c +@@ -1101,12 +1101,17 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, + bfd_boolean undefined; + bfd_boolean rem_leading_char; + bfd_boolean add_leading_char; + + undefined = bfd_is_und_section (bfd_get_section (sym)); + ++ if (strip_symbols == STRIP_ALL && undefined) ++ { ++ add_specific_symbol(name, keep_specific_htab); ++ } ++ + if (redefine_sym_list) + { + char *old_name, *new_name; + + old_name = (char *) bfd_asymbol_name (sym); + new_name = (char *) lookup_sym_redefinition (old_name); +@@ -1162,13 +1167,18 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, + strcpy (ptr, name); + bfd_asymbol_name (sym) = n; + name = n; + } + + if (strip_symbols == STRIP_ALL) +- keep = FALSE; ++ { ++ if (strcmp(name, "_start") == 0 || strcmp(name, "__amigaos4__") == 0 || strcmp(name, "_SDA_BASE_") == 0) ++ keep = TRUE; ++ else ++ keep = FALSE; ++ } + else if ((flags & BSF_KEEP) != 0 /* Used in relocation. */ + || ((flags & BSF_SECTION_SYM) != 0 + && ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags + & BSF_KEEP) != 0)) + { + keep = TRUE; +@@ -1925,13 +1935,13 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) + + Note we iterate over the input sections examining their + relocations since the relocations for the output sections + haven't been set yet. mark_symbols_used_in_relocations will + ignore input sections which have no corresponding output + section. */ +- if (strip_symbols != STRIP_ALL) ++// if (strip_symbols != STRIP_ALL) + bfd_map_over_sections (ibfd, + mark_symbols_used_in_relocations, + isympp); + osympp = (asymbol **) xmalloc ((symcount + 1) * sizeof (asymbol *)); + symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount); + } +@@ -2745,25 +2755,48 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg) + status = 1; + bfd_nonfatal_message (NULL, ibfd, isection, + _("relocation count is negative")); + return; + } + +- if (strip_symbols == STRIP_ALL) ++ /* Never, ever, strip reloc data on the Amiga! */ ++ if (strip_symbols == STRIP_ALL && ++ bfd_get_flavour(obfd) != bfd_target_amiga_flavour) + { + /* Remove relocations which are not in + keep_strip_specific_list. */ + arelent **temp_relpp; + long temp_relcount = 0; + long i; + + temp_relpp = (arelent **) xmalloc (relsize); + for (i = 0; i < relcount; i++) ++ { ++ asection *sec; ++ sec = bfd_get_section(*relpp[i]->sym_ptr_ptr); ++ ++// printf("%d: %s (0x%lx + 0x%lx) value 0x%lx (in section %s)\n", ++// i, bfd_asymbol_name (*relpp [i]->sym_ptr_ptr), relpp [i]->address, relpp [i]->addend, ++// bfd_asymbol_value(*relpp [i]->sym_ptr_ptr), ++// bfd_section_name(ibfd, sec)); ++ ++ /* Keep the symbol */ + if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr), + keep_specific_htab)) + temp_relpp [temp_relcount++] = relpp [i]; ++ else ++ { ++ /* Don't keep the symbol, but keep the reloc */ ++ temp_relpp [temp_relcount] = relpp[i]; ++ temp_relpp [temp_relcount]->addend = bfd_asymbol_value(*relpp [i]->sym_ptr_ptr) ++ - sec->vma ++ + relpp[i]->addend; ++ temp_relpp [temp_relcount]->sym_ptr_ptr = sec->symbol_ptr_ptr; ++ temp_relcount++; ++ } ++ } + relcount = temp_relcount; + free (relpp); + relpp = temp_relpp; + } + + bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount); +@@ -3155,13 +3188,17 @@ strip_main (int argc, char *argv[]) + + if (show_version) + print_version ("strip"); + + default_deterministic (); + +- /* Default is to strip all symbols. */ ++ add_specific_symbol("__amigaos4__", keep_specific_htab); ++ add_specific_symbol("_start", keep_specific_htab); ++ add_specific_symbol("_SDA_BASE_", keep_specific_htab); ++ ++ /* Default is to strip all unnecessary symbols. */ + if (strip_symbols == STRIP_UNDEF + && discard_locals == LOCALS_UNDEF + && htab_elements (strip_specific_htab) == 0) + strip_symbols = STRIP_ALL; + + if (output_target == NULL) +@@ -3992,12 +4029,17 @@ copy_main (int argc, char *argv[]) + if (show_version) + print_version ("objcopy"); + + if (interleave && copy_byte == -1) + fatal (_("interleave start byte must be set with --byte")); + ++ add_specific_symbol("__amigappc__", keep_specific_htab); ++ add_specific_symbol("__amigaos4__", keep_specific_htab); ++ add_specific_symbol("_start", keep_specific_htab); ++ add_specific_symbol("_SDA_BASE_", keep_specific_htab); ++ + if (copy_byte >= interleave) + fatal (_("byte number must be less than interleave")); + + if (copy_width > interleave - copy_byte) + fatal (_("interleave width must be less than or equal to interleave - byte`")); + +diff --git a/binutils/readelf.c b/binutils/readelf.c +index d9ec436af6fbea0bbc3dfa8e9cd40fcf9be140cf..f52d7168af3bc6559bd2483ff1fc126da385b38d 100644 +--- binutils/readelf.c ++++ binutils/readelf.c +@@ -150,12 +150,13 @@ + #include "elf/vax.h" + #include "elf/x86-64.h" + #include "elf/xc16x.h" + #include "elf/xgate.h" + #include "elf/xstormy16.h" + #include "elf/xtensa.h" ++#include "elf/amigaos.h" + + #include "getopt.h" + #include "libiberty.h" + #include "safe-ctype.h" + #include "filenames.h" + +@@ -1520,12 +1521,13 @@ static const char * + get_ppc_dynamic_type (unsigned long type) + { + switch (type) + { + case DT_PPC_GOT: return "PPC_GOT"; + case DT_PPC_TLSOPT: return "PPC_TLSOPT"; ++ case DT_AMIGAOS_DYNVERSION: return "AMIGAOS_DYNVERSION"; + default: + return NULL; + } + } + + static const char * +@@ -1789,12 +1791,15 @@ get_dynamic_type (unsigned long type) + && (type >= OLD_DT_LOOS) && (type <= OLD_DT_HIOS))) + { + const char * result; + + switch (elf_header.e_machine) + { ++ case EM_PPC: ++ result = get_ppc_dynamic_type (type); ++ break; + case EM_PARISC: + result = get_parisc_dynamic_type (type); + break; + case EM_IA_64: + result = get_ia64_dynamic_type (type); + break; +diff --git a/binutils/rename.c b/binutils/rename.c +index 5923a3f4ce2b2b5b0da96ff8225bf3c7750563bc..354b6fd1eab7f632995fed27698c76826ee8e753 100644 +--- binutils/rename.c ++++ binutils/rename.c +@@ -27,13 +27,13 @@ + #else /* ! HAVE_GOOD_UTIME_H */ + #ifdef HAVE_UTIMES + #include <sys/time.h> + #endif /* HAVE_UTIMES */ + #endif /* ! HAVE_GOOD_UTIME_H */ + +-#if ! defined (_WIN32) || defined (__CYGWIN32__) ++#if ! defined (_WIN32) && !defined(__amigaos4__) || defined (__CYGWIN32__) + static int simple_copy (const char *, const char *); + + /* The number of bytes to copy at once. */ + #define COPY_BUF 8192 + + /* Copy file FROM to file TO, performing no translations. +@@ -140,13 +140,13 @@ smart_rename (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNU + bfd_boolean exists; + struct stat s; + int ret = 0; + + exists = lstat (to, &s) == 0; + +-#if defined (_WIN32) && !defined (__CYGWIN32__) ++#if defined (_WIN32) && !defined (__CYGWIN32__) || defined (__amigaos4__) + /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but + fail instead. Also, chown is not present. */ + + if (exists) + remove (to); + +diff --git a/config.sub b/config.sub +index 59bb593f109c8d795df4cbb96b015222eed91c07..88ccfd90050ad0d8d341c091b9920f62fc5996f8 100755 +--- config.sub ++++ config.sub +@@ -353,13 +353,13 @@ case $basic_machine in + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. +- i*86 | x86_64) ++ i*86 | i*86be | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 +@@ -482,17 +482,14 @@ case $basic_machine in + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; +- amiga | amiga-*) +- basic_machine=m68k-unknown +- ;; +- amigaos | amigados) +- basic_machine=m68k-unknown ++ amigaos | amigados | amiga) ++ basic_machine=powerpc-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; +@@ -1345,13 +1342,13 @@ case $os in + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ +- | -aos* | -aros* \ ++ | -aos* | -amithlon* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ +diff --git a/config/mh-amigaos b/config/mh-amigaos +new file mode 100644 +index 0000000000000000000000000000000000000000..4889ea41c6889e2e15c06c8f355c30b5eb2aa5f4 +--- /dev/null ++++ config/mh-amigaos +@@ -0,0 +1,13 @@ ++# Host makefile fragment for Commodore Amiga running AmigaOS. ++ ++# There is no standard system compiler. Assume using GNU C. ++CC = gcc ++CFLAGS = -g -O2 -mstackextend ++ ++# We have both types of links under AmigaOS with GNU ++# utils, however the links need to be made in canonical ++# AmigaOS format (foo:bar/bell/file) rather than UNIX ++# format (/foo/bar/bell/file). When this is fixed, then ++# these can go away. ++SYMLINK = cp ++HARDLINK = cp +diff --git a/config/mh-morphos b/config/mh-morphos +new file mode 100644 +index 0000000000000000000000000000000000000000..c00202aec0389eaa067ea48818a7d8fa4fd5fc6b +--- /dev/null ++++ config/mh-morphos +@@ -0,0 +1,13 @@ ++# Host makefile fragment for Commodore Amiga running AmigaOS. ++ ++# There is no standard system compiler. Assume using GNU C. ++CC = gcc ++CFLAGS = -g -O2 ++ ++# We have both types of links under AmigaOS with GNU ++# utils, however the links need to be made in canonical ++# AmigaOS format (foo:bar/bell/file) rather than UNIX ++# format (/foo/bar/bell/file). When this is fixed, then ++# these can go away. ++SYMLINK = cp ++HARDLINK = cp +diff --git a/configure b/configure +index 6079e6c07511e12bb51ae5197e7110d79c36b098..9667d72a79baf032fa22e054b88fb03e64673b63 100755 +--- configure ++++ configure +@@ -3630,12 +3630,15 @@ case "${noconfigdirs}" in + esac + + # Work in distributions that contain no compiler tools, like Autoconf. + host_makefile_frag=/dev/null + if test -d ${srcdir}/config ; then + case "${host}" in ++ m68k-*-amigaos*) ++ host_makefile_frag="config/mh-amigaos" ++ ;; + i[3456789]86-*-msdosdjgpp*) + host_makefile_frag="config/mh-djgpp" + ;; + *-cygwin*) + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if cat works as expected" >&5 +@@ -3674,12 +3677,15 @@ fi + hppa*-*) + host_makefile_frag="config/mh-pa" + ;; + *-*-darwin*) + host_makefile_frag="config/mh-darwin" + ;; ++ *-morphos*) ++ host_makefile_frag="config/mh-morphos" ++ ;; + powerpc-*-aix*) + host_makefile_frag="config/mh-ppc-aix" + ;; + rs6000-*-aix*) + host_makefile_frag="config/mh-ppc-aix" + ;; +diff --git a/configure.ac b/configure.ac +index 5efb4a32f114f23b90f838a5108f5016dc01bf43..fea7239acf315d982587796d8b93de4c894a14d8 100644 +--- configure.ac ++++ configure.ac +@@ -1056,12 +1056,15 @@ case "${noconfigdirs}" in + esac + + # Work in distributions that contain no compiler tools, like Autoconf. + host_makefile_frag=/dev/null + if test -d ${srcdir}/config ; then + case "${host}" in ++ m68k-*-amigaos*) ++ host_makefile_frag="config/mh-amigaos" ++ ;; + i[[3456789]]86-*-msdosdjgpp*) + host_makefile_frag="config/mh-djgpp" + ;; + *-cygwin*) + ACX_CHECK_CYGWIN_CAT_WORKS + host_makefile_frag="config/mh-cygwin" +@@ -1081,12 +1084,15 @@ case "${host}" in + hppa*-*) + host_makefile_frag="config/mh-pa" + ;; + *-*-darwin*) + host_makefile_frag="config/mh-darwin" + ;; ++ *-morphos*) ++ host_makefile_frag="config/mh-morphos" ++ ;; + powerpc-*-aix*) + host_makefile_frag="config/mh-ppc-aix" + ;; + rs6000-*-aix*) + host_makefile_frag="config/mh-ppc-aix" + ;; +diff --git a/gas/ChangeLog-9697 b/gas/ChangeLog-9697 +index f39e99554e87446d7eb8f0869701984c5df2137d..08dbfbc1d36608ec8e553593d445431cb1792cc5 100644 +--- gas/ChangeLog-9697 ++++ gas/ChangeLog-9697 +@@ -874,12 +874,18 @@ Tue Aug 26 12:23:25 1997 Ian Lance Taylor <ian@cygnus.com> + Gabriel Paubert <paubert@iram.es>. + + * config/tc-i386.c (md_assemble): In JumpByte case, when looking + for a WORD_PREFIX_OPCODE, change it to ADDR_PREFIX_OPCODE if this + is jcxz or a loop instruction. + ++Mon Aug 25 16:32:00 1997 Steffen Opel <opel@rumms.uni-mannheim.de> ++ ++ * Makefile.in (guide, install-guide, clean-guide): New targets ++ for AmigaGuide documentation. ++ (install): Add install-info and install-guide. ++ + Mon Aug 25 16:04:14 1997 Nick Clifton <nickc@cygnus.com> + + * config/tc-v850.c (pre_defined_registers): Add 'hp' as alias for + r2. + (md_begin): Set up machine architecture and type. + +@@ -3386,12 +3392,18 @@ Mon Nov 18 15:22:28 1996 Michael Meissner <meissner@tiktok.cygnus.com> + * config/tc-d10v.c (parallel_ok): Branch and link instructions + modify r13. + (write_2_short): Call parallel_ok to check whether two short + instructions the user requested execute in parallel, can be + executed that way. + ++Sun Nov 17 21:09:55 1996 Kamil Iskra <iskra@student.uci.agh.edu.pl> ++ ++ * config/tc-m68k.c (md_estimate_size_before_relax): Do not ++ output 'bsrl' instructions for external function calls when ++ compiling with '-m68020' or higher. ++ + Thu Nov 14 11:17:49 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (write_2_short): Fix bug that wouldn't + allow a branch and link in parallel with an exe instruction. + + Fri Nov 8 13:55:03 1996 Martin M. Hunt <hunt@pizza.cygnus.com> +diff --git a/gas/ChangeLog-9899 b/gas/ChangeLog-9899 +index ae38e5dd9223cf4e26355263197ea9f2cd0296c0..76861df24938b7ec7a3051da5cf20c44465b145e 100644 +--- gas/ChangeLog-9899 ++++ gas/ChangeLog-9899 +@@ -3574,12 +3574,16 @@ Wed Jun 3 14:10:36 1998 Ian Lance Taylor <ian@cygnus.com> + + Wed Jun 3 09:16:00 1998 Catherine Moore <clm@cygnus.com> + + * config/tc-v850.c (md_begin): Don't create special + sections by default. + ++1998-06-02 David Zaroski <zaroski@firewall.ninemoons.com> ++ ++ * config/tc-m68k.c: Add missing param to add_fix in "case '_'" ++ + Tue Jun 2 14:52:56 1998 Jeffrey A Law (law@cygnus.com) + + * config/tc-mips.c (macro): For div and udiv, close the + reorder block as soon as possible. + + Tue Jun 2 15:36:13 1998 Ian Lance Taylor <ian@cygnus.com> +diff --git a/gas/Makefile.am b/gas/Makefile.am +index 256e2322fd80f84d8fa8fab735c85446dff4f506..851de3dc36be1138ad52026f7ace0ebd49da94b6 100644 +--- gas/Makefile.am ++++ gas/Makefile.am +@@ -245,23 +245,25 @@ TARGET_CPU_HFILES = \ + config/tc-z8k.h \ + config/xtensa-relax.h + + # OBJ files in config + + OBJ_FORMAT_CFILES = \ ++ config/obj-amigahunk.c \ + config/obj-aout.c \ + config/obj-coff.c \ + config/obj-ecoff.c \ + config/obj-elf.c \ + config/obj-evax.c \ + config/obj-fdpicelf.c \ + config/obj-macho.c \ + config/obj-multi.c \ + config/obj-som.c + + OBJ_FORMAT_HFILES = \ ++ config/obj-amigahunk.h \ + config/obj-aout.h \ + config/obj-coff.h \ + config/obj-ecoff.h \ + config/obj-elf.h \ + config/obj-evax.h \ + config/obj-fdpicelf.h \ +@@ -271,12 +273,13 @@ OBJ_FORMAT_HFILES = \ + + # Emulation header files in config + + TARG_ENV_HFILES = \ + config/te-386bsd.h \ + config/te-aix5.h \ ++ config/te-amiga.h \ + config/te-armeabi.h \ + config/te-armlinuxeabi.h \ + config/te-dynix.h \ + config/te-epoc-pe.h \ + config/te-freebsd.h \ + config/te-generic.h \ +@@ -342,13 +345,13 @@ EXTRA_SCRIPTS = .gdbinit + + EXTRA_DIST = m68k-parse.c itbl-parse.c itbl-parse.h itbl-lex.c \ + bfin-parse.c bfin-parse.h bfin-lex.c \ + rl78-parse.c rl78-parse.h \ + rx-parse.c rx-parse.h + +-diststuff: $(EXTRA_DIST) info ++diststuff: $(EXTRA_DIST) info guide + + DISTCLEANFILES = targ-cpu.h obj-format.h targ-env.h itbl-cpu.h cgen-desc.h + + # Now figure out from those variables how to compile and link. + + BASEDIR = $(srcdir)/.. +diff --git a/gas/Makefile.in b/gas/Makefile.in +index 94812d96db9cb13bdbdd0243a6b9a021e95e0a0b..c04f7d53feacb96ac3a82109375c3c94bcb15d56 100644 +--- gas/Makefile.in ++++ gas/Makefile.in +@@ -513,23 +513,25 @@ TARGET_CPU_HFILES = \ + config/tc-z8k.h \ + config/xtensa-relax.h + + + # OBJ files in config + OBJ_FORMAT_CFILES = \ ++ config/obj-amigahunk.c \ + config/obj-aout.c \ + config/obj-coff.c \ + config/obj-ecoff.c \ + config/obj-elf.c \ + config/obj-evax.c \ + config/obj-fdpicelf.c \ + config/obj-macho.c \ + config/obj-multi.c \ + config/obj-som.c + + OBJ_FORMAT_HFILES = \ ++ config/obj-amigahunk.h \ + config/obj-aout.h \ + config/obj-coff.h \ + config/obj-ecoff.h \ + config/obj-elf.h \ + config/obj-evax.h \ + config/obj-fdpicelf.h \ +@@ -539,12 +541,13 @@ OBJ_FORMAT_HFILES = \ + + + # Emulation header files in config + TARG_ENV_HFILES = \ + config/te-386bsd.h \ + config/te-aix5.h \ ++ config/te-amiga.h \ + config/te-armeabi.h \ + config/te-armlinuxeabi.h \ + config/te-dynix.h \ + config/te-epoc-pe.h \ + config/te-freebsd.h \ + config/te-generic.h \ +@@ -776,12 +779,13 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/itbl-parse.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listing.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/literal.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m68k-parse.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/macro.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/messages.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-amigahunk.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-aout.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-coff.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-ecoff.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-elf.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-evax.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj-fdpicelf.Po@am__quote@ +@@ -1836,12 +1840,26 @@ xtensa-relax.obj: config/xtensa-relax.c + @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xtensa-relax.obj -MD -MP -MF $(DEPDIR)/xtensa-relax.Tpo -c -o xtensa-relax.obj `if test -f 'config/xtensa-relax.c'; then $(CYGPATH_W) 'config/xtensa-relax.c'; else $(CYGPATH_W) '$(srcdir)/config/xtensa-relax.c'; fi` + @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xtensa-relax.Tpo $(DEPDIR)/xtensa-relax.Po + @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/xtensa-relax.c' object='xtensa-relax.obj' libtool=no @AMDEPBACKSLASH@ + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xtensa-relax.obj `if test -f 'config/xtensa-relax.c'; then $(CYGPATH_W) 'config/xtensa-relax.c'; else $(CYGPATH_W) '$(srcdir)/config/xtensa-relax.c'; fi` + ++obj-amigahunk.o: config/obj-amigahunk.c ++@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obj-amigahunk.o -MD -MP -MF $(DEPDIR)/obj-amigahunk.Tpo -c -o obj-amigahunk.o `test -f 'config/obj-amigahunk.c' || echo '$(srcdir)/'`config/obj-amigahunk.c ++@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/obj-amigahunk.Tpo $(DEPDIR)/obj-amigahunk.Po ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/obj-amigahunk.c' object='obj-amigahunk.o' libtool=no @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obj-amigahunk.o `test -f 'config/obj-amigahunk.c' || echo '$(srcdir)/'`config/obj-amigahunk.c ++ ++obj-amigahunk.obj: config/obj-amigahunk.c ++@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obj-amigahunk.obj -MD -MP -MF $(DEPDIR)/obj-amigahunk.Tpo -c -o obj-amigahunk.obj `if test -f 'config/obj-amigahunk.c'; then $(CYGPATH_W) 'config/obj-amigahunk.c'; else $(CYGPATH_W) '$(srcdir)/config/obj-amigahunk.c'; fi` ++@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/obj-amigahunk.Tpo $(DEPDIR)/obj-amigahunk.Po ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/obj-amigahunk.c' object='obj-amigahunk.obj' libtool=no @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obj-amigahunk.obj `if test -f 'config/obj-amigahunk.c'; then $(CYGPATH_W) 'config/obj-amigahunk.c'; else $(CYGPATH_W) '$(srcdir)/config/obj-amigahunk.c'; fi` ++ + obj-aout.o: config/obj-aout.c + @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obj-aout.o -MD -MP -MF $(DEPDIR)/obj-aout.Tpo -c -o obj-aout.o `test -f 'config/obj-aout.c' || echo '$(srcdir)/'`config/obj-aout.c + @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/obj-aout.Tpo $(DEPDIR)/obj-aout.Po + @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/obj-aout.c' object='obj-aout.o' libtool=no @AMDEPBACKSLASH@ + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obj-aout.o `test -f 'config/obj-aout.c' || echo '$(srcdir)/'`config/obj-aout.c +@@ -2411,13 +2429,13 @@ uninstall-am: + tags tags-recursive uninstall uninstall-am + + po/POTFILES.in: @MAINT@ Makefile + for f in $(POTFILES); do echo $$f; done | LC_ALL=C sort > tmp \ + && mv tmp $(srcdir)/po/POTFILES.in + +-diststuff: $(EXTRA_DIST) info ++diststuff: $(EXTRA_DIST) info guide + + check-DEJAGNU: site.exp + if [ -d testsuite ]; then \ + true; \ + else \ + mkdir testsuite; \ +diff --git a/gas/as.c b/gas/as.c +index fa4141f92bc887cfd403ec3eb93a7a20f26b642a..7b35f0e3f23662e09e8ce56c525239cf68b5dd3a 100644 +--- gas/as.c ++++ gas/as.c +@@ -105,12 +105,17 @@ int keep_it = 0; + segT reg_section; + segT expr_section; + segT text_section; + segT data_section; + segT bss_section; + ++#ifdef OBJ_AMIGAHUNK ++segT data_chip_section; ++segT bss_chip_section; ++#endif ++ + /* Name of listing file. */ + static char *listing_filename = NULL; + + static struct defsym_list *defsyms; + + #ifdef HAVE_ITBL_CPU +@@ -1046,22 +1051,31 @@ perform_an_assembly_pass (int argc, char ** argv) + #ifndef OBJ_MACH_O + /* Create the standard sections, and those the assembler uses + internally. */ + text_section = subseg_new (TEXT_SECTION_NAME, 0); + data_section = subseg_new (DATA_SECTION_NAME, 0); + bss_section = subseg_new (BSS_SECTION_NAME, 0); ++#ifdef OBJ_AMIGAHUNK ++ data_chip_section = subseg_new (".data_chip", 0); ++ bss_chip_section = subseg_new (".bss_chip", 0); ++#endif + /* @@ FIXME -- we're setting the RELOC flag so that sections are assumed + to have relocs, otherwise we don't find out in time. */ + applicable = bfd_applicable_section_flags (stdoutput); + bfd_set_section_flags (stdoutput, text_section, + applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_CODE | SEC_READONLY)); + bfd_set_section_flags (stdoutput, data_section, + applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_DATA)); + bfd_set_section_flags (stdoutput, bss_section, applicable & SEC_ALLOC); ++#ifdef OBJ_AMIGAHUNK ++ bfd_set_section_flags (stdoutput, data_chip_section, ++ applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)); ++ bfd_set_section_flags (stdoutput, bss_chip_section, applicable & SEC_ALLOC); ++#endif + seg_info (bss_section)->bss = 1; + #endif + subseg_new (BFD_ABS_SECTION_NAME, 0); + subseg_new (BFD_UND_SECTION_NAME, 0); + reg_section = subseg_new ("*GAS `reg' section*", 0); + expr_section = subseg_new ("*GAS `expr' section*", 0); +diff --git a/gas/config/m68k-parse.h b/gas/config/m68k-parse.h +index 4f91385f9222dc52c8cc9f490860729c2183e445..08e766c5523b90ac3cd2d685b239c0a7ed4d8230 100644 +--- gas/config/m68k-parse.h ++++ gas/config/m68k-parse.h +@@ -293,12 +293,15 @@ struct m68k_exp + /* The type of pic relocation if any. */ + enum pic_relocation pic_reloc; + #endif + + /* The expression itself. */ + expressionS exp; ++ ++ /* base-relative? */ ++ short baserel; + }; + + /* The operand modes. */ + + enum m68k_operand_type + { +diff --git a/gas/config/m68k-parse.y b/gas/config/m68k-parse.y +index 2c58266fb8e6bd8d57515fe5200daaf9a1e450a2..742cbf2eeaaa15766a4d44de76a9d58d56993367 100644 +--- gas/config/m68k-parse.y ++++ gas/config/m68k-parse.y +@@ -972,31 +972,35 @@ yylex () + else if (parens == 0 + && (*s == ',' || *s == ']')) + break; + } + + yylval.exp.size = SIZE_UNSPEC; ++ yylval.exp.baserel = 0; + if (s <= str + 2 + || (s[-2] != '.' && s[-2] != ':')) + tail = 0; + else + { + switch (s[-1]) + { ++ case 'B': ++ yylval.exp.baserel = 1; + case 's': + case 'S': + case 'b': +- case 'B': + yylval.exp.size = SIZE_BYTE; + break; +- case 'w': + case 'W': ++ yylval.exp.baserel = 1; ++ case 'w': + yylval.exp.size = SIZE_WORD; + break; +- case 'l': + case 'L': ++ yylval.exp.baserel = 1; ++ case 'l': + yylval.exp.size = SIZE_LONG; + break; + default: + break; + } + if (yylval.exp.size != SIZE_UNSPEC) +diff --git a/gas/config/obj-amigahunk.c b/gas/config/obj-amigahunk.c +new file mode 100644 +index 0000000000000000000000000000000000000000..8755475ecfdfd5aafbf876ed1f87c9d343b560e9 +--- /dev/null ++++ gas/config/obj-amigahunk.c +@@ -0,0 +1,212 @@ ++/* AmigaOS object file format ++ Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. ++ ++This file is part of GAS, the GNU Assembler. ++ ++GAS is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as ++published by the Free Software Foundation; either version 2, ++or (at your option) any later version. ++ ++GAS is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GAS; see the file COPYING. If not, write to the Free ++Software Foundation, 59 Temple Place - Suite 330, Boston, MA ++02111-1307, USA. */ ++ ++#include "as.h" ++ ++enum { ++ N_UNDF=0, ++/*N_ABS=2,*/ ++/*N_TEXT=4,*/ ++/*N_DATA=6,*/ ++/*N_BSS=8,*/ ++ N_INDR=0xa, ++/*N_COMM=0x12,*/ ++ N_SETA=0x14, ++ N_SETT=0x16, ++ N_SETD=0x18, ++ N_SETB=0x1a, ++/*N_SETV=0x1c,*/ ++ N_WARNING=0x1e, ++/*N_FN=0x1f*/ ++ N_EXT=1, ++ N_TYPE=0x1e, ++/*N_STAB=0xe0,*/ ++}; ++ ++static void obj_amiga_line PARAMS ((int)); ++static void obj_amiga_weak PARAMS ((int)); ++ ++const pseudo_typeS obj_pseudo_table[] = ++{ ++ {"line", obj_amiga_line, 0}, /* source code line number */ ++ {"weak", obj_amiga_weak, 0}, /* mark symbol as weak. */ ++ ++ /* other stuff */ ++ {"ABORT", s_abort, 0}, ++ ++ {NULL, NULL, 0} /* end sentinel */ ++}; ++ ++#ifdef BFD_ASSEMBLER ++ ++void ++obj_amiga_frob_symbol (sym, punt) ++ symbolS *sym; ++ int *punt ATTRIBUTE_UNUSED; ++{ ++ sec_ptr sec = S_GET_SEGMENT (sym); ++ unsigned int type = amiga_symbol (symbol_get_bfdsym (sym))->type; ++ ++ /* Only frob simple symbols this way right now. */ ++ if (! (type & ~ (N_TYPE | N_EXT))) ++ { ++ if (type == (N_UNDF | N_EXT) ++ && sec == &bfd_abs_section) ++ { ++ sec = bfd_und_section_ptr; ++ S_SET_SEGMENT (sym, sec); ++ } ++ ++ if ((type & N_TYPE) != N_INDR ++ && (type & N_TYPE) != N_SETA ++ && (type & N_TYPE) != N_SETT ++ && (type & N_TYPE) != N_SETD ++ && (type & N_TYPE) != N_SETB ++ && type != N_WARNING ++ && (sec == &bfd_abs_section ++ || sec == &bfd_und_section)) ++ return; ++ if (symbol_get_bfdsym (sym)->flags & BSF_EXPORT) ++ type |= N_EXT; ++ ++ switch (type & N_TYPE) ++ { ++ case N_SETA: ++ case N_SETT: ++ case N_SETD: ++ case N_SETB: ++ /* Set the debugging flag for constructor symbols so that ++ BFD leaves them alone. */ ++ symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; ++ ++ /* You can't put a common symbol in a set. The way a set ++ element works is that the symbol has a definition and a ++ name, and the linker adds the definition to the set of ++ that name. That does not work for a common symbol, ++ because the linker can't tell which common symbol the ++ user means. FIXME: Using as_bad here may be ++ inappropriate, since the user may want to force a ++ particular type without regard to the semantics of sets; ++ on the other hand, we certainly don't want anybody to be ++ mislead into thinking that their code will work. */ ++ if (S_IS_COMMON (sym)) ++ as_bad (_("Attempt to put a common symbol into set %s"), ++ S_GET_NAME (sym)); ++ /* Similarly, you can't put an undefined symbol in a set. */ ++ else if (! S_IS_DEFINED (sym)) ++ as_bad (_("Attempt to put an undefined symbol into set %s"), ++ S_GET_NAME (sym)); ++ ++ break; ++ case N_INDR: ++ /* Put indirect symbols in the indirect section. */ ++ S_SET_SEGMENT (sym, bfd_ind_section_ptr); ++ symbol_get_bfdsym (sym)->flags |= BSF_INDIRECT; ++ if (type & N_EXT) ++ { ++ symbol_get_bfdsym (sym)->flags |= BSF_EXPORT; ++ symbol_get_bfdsym (sym)->flags &=~ BSF_LOCAL; ++ } ++ break; ++ case N_WARNING: ++ /* Mark warning symbols. */ ++ symbol_get_bfdsym (sym)->flags |= BSF_WARNING; ++ break; ++ } ++ } ++ else ++ { ++ symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; ++ } ++ ++ amiga_symbol (symbol_get_bfdsym (sym))->type = type; ++ ++ /* Double check weak symbols. */ ++ if (S_IS_WEAK (sym)) ++ { ++ if (S_IS_COMMON (sym)) ++ as_bad (_("Symbol `%s' can not be both weak and common"), ++ S_GET_NAME (sym)); ++ } ++} ++ ++void ++obj_amiga_frob_file_before_fix () ++{ ++ /* Relocation processing may require knowing the VMAs of the sections. ++ Since writing to a section will cause the BFD back end to compute the ++ VMAs, fake it out here.... */ ++ bfd_byte b = 0; ++ bfd_boolean x = TRUE; ++ if (bfd_section_size (stdoutput, text_section) != 0) ++ { ++ x = bfd_set_section_contents (stdoutput, text_section, &b, (file_ptr) 0, ++ (bfd_size_type) 1); ++ } ++ else if (bfd_section_size (stdoutput, data_section) != 0) ++ { ++ x = bfd_set_section_contents (stdoutput, data_section, &b, (file_ptr) 0, ++ (bfd_size_type) 1); ++ } ++ assert (x); ++} ++ ++#endif /* BFD_ASSEMBLER */ ++ ++static void ++obj_amiga_line (ignore) ++ int ignore ATTRIBUTE_UNUSED; ++{ ++ /* Assume delimiter is part of expression. ++ BSD4.2 as fails with delightful bug, so we ++ are not being incompatible here. */ ++ new_logical_line ((char *) NULL, (int) (get_absolute_expression ())); ++ demand_empty_rest_of_line (); ++} /* obj_amiga_line() */ ++ ++/* Handle .weak. This is a GNU extension. */ ++ ++static void ++obj_amiga_weak (ignore) ++ int ignore ATTRIBUTE_UNUSED; ++{ ++ char *name; ++ int c; ++ symbolS *symbolP; ++ ++ do ++ { ++ name = input_line_pointer; ++ c = get_symbol_end (); ++ symbolP = symbol_find_or_make (name); ++ *input_line_pointer = c; ++ SKIP_WHITESPACE (); ++ S_SET_WEAK (symbolP); ++ if (c == ',') ++ { ++ input_line_pointer++; ++ SKIP_WHITESPACE (); ++ if (*input_line_pointer == '\n') ++ c = '\n'; ++ } ++ } ++ while (c == ','); ++ demand_empty_rest_of_line (); ++} +diff --git a/gas/config/obj-amigahunk.h b/gas/config/obj-amigahunk.h +new file mode 100644 +index 0000000000000000000000000000000000000000..0b7d80eeb291878dc871ce0591b2223bf6cb1de2 +--- /dev/null ++++ gas/config/obj-amigahunk.h +@@ -0,0 +1,54 @@ ++/* obj-amigahunk.h, AmigaOS object file format for gas, the assembler. ++ Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. ++ ++ This file is part of GAS, the GNU Assembler. ++ ++ GAS is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as ++ published by the Free Software Foundation; either version 2, ++ or (at your option) any later version. ++ ++ GAS is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ the GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with GAS; see the file COPYING. If not, write to the Free ++ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ++ 02111-1307, USA. */ ++ ++/* Tag to validate an amiga object file format processing */ ++#define OBJ_AMIGAHUNK 1 ++ ++#include "targ-cpu.h" ++ ++#ifdef BFD_ASSEMBLER ++ ++#include "bfd/libamiga.h" ++ ++#define OUTPUT_FLAVOR bfd_target_amiga_flavour ++ ++/* SYMBOL TABLE */ ++/* Symbol table macros and constants */ ++ ++#define S_SET_OTHER(S,V) (amiga_symbol (symbol_get_bfdsym (S))->other = (V)) ++#define S_SET_TYPE(S,T) (amiga_symbol (symbol_get_bfdsym (S))->type = (T)) ++#define S_SET_DESC(S,D) (amiga_symbol (symbol_get_bfdsym (S))->desc = (D)) ++#define S_GET_TYPE(S) (amiga_symbol (symbol_get_bfdsym (S))->type) ++ ++#define obj_frob_symbol(S,PUNT) obj_amiga_frob_symbol (S, &PUNT) ++extern void obj_amiga_frob_symbol PARAMS ((symbolS *, int *)); ++ ++#define obj_frob_file_before_fix() obj_amiga_frob_file_before_fix () ++extern void obj_amiga_frob_file_before_fix PARAMS ((void)); ++ ++#define obj_sec_sym_ok_for_reloc(SEC) (1) ++ ++#endif /* BFD_ASSEMBLER */ ++ ++#define obj_read_begin_hook() {;} ++#define obj_symbol_new_hook(s) {;} ++#define EMIT_SECTION_SYMBOLS (0) ++ ++#define AOUT_STABS +diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c +index d7c766513ccc4111f51904a7e01904b7ebe96a03..bb8d9d1ebee6b76deee86848202fd06d5b1a4dfa 100644 +--- gas/config/obj-elf.c ++++ gas/config/obj-elf.c +@@ -1390,13 +1390,13 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED) + if (bad) + return NULL; + + gas_assert (symbol_get_value_expression (csym)->X_op == O_constant); + return fix_new (symbol_get_frag (csym), + symbol_get_value_expression (csym)->X_add_number, +- 0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT); ++ 0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT, 0); + } + + /* This handles the .vtable_entry pseudo-op, which is used to indicate + to the linker that a vtable slot was used. The syntax is + ".vtable_entry tablename, offset". */ + +@@ -1423,13 +1423,13 @@ obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED) + + offset = get_absolute_expression (); + + demand_empty_rest_of_line (); + + return fix_new (frag_now, frag_now_fix (), 0, sym, offset, 0, +- BFD_RELOC_VTABLE_ENTRY); ++ BFD_RELOC_VTABLE_ENTRY, 0); + } + + void + elf_obj_read_begin_hook (void) + { + #ifdef NEED_ECOFF_DEBUG +diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h +index de132d69d7ac3f854ea517a15267e8c75365714d..14b67f0506eacf6d3dbb11dbd08689fa69354678 100644 +--- gas/config/tc-i386.h ++++ gas/config/tc-i386.h +@@ -24,13 +24,20 @@ + #define TC_I386 1 + + #include "opcodes/i386-opc.h" + + struct fix; + ++/* Set the endianness we are using. Default to little endian. */ ++#ifndef TARGET_BYTES_BIG_ENDIAN + #define TARGET_BYTES_BIG_ENDIAN 0 ++#endif ++ ++#if !defined(OBJ_ELF) && TARGET_BYTES_BIG_ENDIAN == 1 ++ #error Big endian i386 tested only for ELF! ++#endif + + #define TARGET_ARCH (i386_arch ()) + #define TARGET_MACH (i386_mach ()) + extern enum bfd_architecture i386_arch (void); + extern unsigned long i386_mach (void); + +@@ -64,12 +71,16 @@ extern unsigned long i386_mach (void); + #elif defined (TE_NACL) + #define ELF_TARGET_FORMAT "elf32-i386-nacl" + #define ELF_TARGET_FORMAT32 "elf32-x86-64-nacl" + #define ELF_TARGET_FORMAT64 "elf64-x86-64-nacl" + #endif + ++#ifdef TE_Amithlon ++#define ELF_TARGET_FORMAT "elf32-i386be-amithlon" ++#endif ++ + #ifdef TE_SOLARIS + #define ELF_TARGET_FORMAT "elf32-i386-sol2" + #define ELF_TARGET_FORMAT64 "elf64-x86-64-sol2" + #endif + + #ifndef ELF_TARGET_FORMAT +@@ -133,13 +144,13 @@ extern const char *i386_comment_chars; + + #if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && !defined (LEX_AT) + #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) x86_cons (EXP, NBYTES) + #endif + extern void x86_cons (expressionS *, int); + +-#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) x86_cons_fix_new(FRAG, OFF, LEN, EXP) ++#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP,BASEREL) x86_cons_fix_new(FRAG, OFF, LEN, EXP) + extern void x86_cons_fix_new + (fragS *, unsigned int, unsigned int, expressionS *); + + #define TC_ADDRESS_BYTES x86_address_bytes + extern int x86_address_bytes (void); + +@@ -220,13 +231,13 @@ if (fragP->fr_type == rs_align_code) \ + void i386_print_statistics (FILE *); + #define tc_print_statistics i386_print_statistics + + extern unsigned int i386_frag_max_var (fragS *); + #define md_frag_max_var i386_frag_max_var + +-#define md_number_to_chars number_to_chars_littleendian ++/* #define md_number_to_chars number_to_chars_littleendian */ + + enum processor_type + { + PROCESSOR_UNKNOWN, + PROCESSOR_I386, + PROCESSOR_I486, +diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c +index 21accf605b22ebc5af491e173faeef93888b6667..8b5f6c60f2141ee91d6e9d1d639815abdf4e5042 100644 +--- gas/config/tc-m68k.c ++++ gas/config/tc-m68k.c +@@ -35,12 +35,22 @@ + #endif + + #ifdef M68KCOFF + #include "obj-coff.h" + #endif + ++/* FIXME: delete this #define as soon as the code that references ++ N_TEXT is changed */ ++#ifdef BFD_ASSEMBLER ++#define N_TEXT 4 ++#endif ++ ++#ifndef OBJ_AMIGAHUNK ++#define OBJ_AMIGAHUNK 0 ++#endif ++ + #ifdef OBJ_ELF + static void m68k_elf_cons (int); + #endif + + /* This string holds the chars that always start a comment. If the + pre-processor is disabled, these aren't very useful. The macro +@@ -81,12 +91,13 @@ const char FLT_CHARS[] = "rRsSfFdDxXeEpP"; + to denote pic relocations. */ + int flag_want_pic; + + static int flag_short_refs; /* -l option. */ + static int flag_long_jumps; /* -S option. */ + static int flag_keep_pcrel; /* --pcrel option. */ ++static int flag_small_code; /* -sc option */ + + #ifdef REGISTER_PREFIX_OPTIONAL + int flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL; + #else + int flag_reg_prefix_optional; + #endif +@@ -388,12 +399,13 @@ struct m68k_it + int pcrel_fix; + #ifdef OBJ_ELF + /* Whether this expression needs special pic relocation, and if + so, which. */ + enum pic_relocation pic_reloc; + #endif ++ char baserel; + } + reloc[5]; /* Five is enough??? */ + }; + + #define cpu_of_arch(x) ((x) & (m68000up | mcfisa_a | fido_a)) + #define float_of_arch(x) ((x) & mfloat) +@@ -438,26 +450,27 @@ insop (int w, const struct m68k_incant *opcode) + the_ins.numo++; + } + + /* The numo+1 kludge is so we can hit the low order byte of the prev word. + Blecch. */ + static void +-add_fix (int width, struct m68k_exp *exp, int pc_rel, int pc_fix) ++add_fix (int width, struct m68k_exp *exp, int pc_rel, int pc_fix, int base_rel) + { + the_ins.reloc[the_ins.nrel].n = (width == 'B' || width == '3' + ? the_ins.numo * 2 - 1 + : (width == 'b' + ? the_ins.numo * 2 + 1 + : the_ins.numo * 2)); + the_ins.reloc[the_ins.nrel].exp = exp->exp; + the_ins.reloc[the_ins.nrel].wid = width; + the_ins.reloc[the_ins.nrel].pcrel_fix = pc_fix; + #ifdef OBJ_ELF + the_ins.reloc[the_ins.nrel].pic_reloc = exp->pic_reloc; + #endif +- the_ins.reloc[the_ins.nrel++].pcrel = pc_rel; ++ the_ins.reloc[the_ins.nrel].pcrel = pc_rel; ++ the_ins.reloc[the_ins.nrel++].baserel = base_rel; + } + + /* Cause an extra frag to be generated here, inserting up to 10 bytes + (that value is chosen in the frag_var call in md_assemble). TYPE + is the subtype of the frag to be generated; its primary type is + rs_machine_dependent. +@@ -807,12 +820,24 @@ static void m68k_init_arch (void); + + /* This relaxation is required for branches where there is no long + branch and we are in pcrel mode. We generate a bne/beq pair. */ + #define BRANCHBWPL 10 /* Branch byte, word or pair of longs + */ + ++/* ABSREL (nice name;-)) is used in small-code, it might be implemented ++ * base-relative (a4), pc-relative, or base-relative with an extra add ++ * instruction to add the base-register. ++ * ++ * IMMREL is the analogous mode for immediate addressing of variables. This ++ * one can lead into situations, where a replacement is not possible: ++ * addl #foo,a0 ++ * can't be made pc-relative, if foo is in the text segment. */ ++ ++#define ABSREL 11 ++#define IMMREL 12 ++ + /* Note that calls to frag_var need to specify the maximum expansion + needed; this is currently 12 bytes for bne/beq pair. */ + #define FRAG_VAR_SIZE 12 + + /* The fields are: + How far Forward this mode will reach: +@@ -869,17 +894,27 @@ relax_typeS md_relax_table[] = + { 1, 1, 0, 0 }, + + { 1, 1, 0, 0 }, /* ABSTOPCREL doesn't come BYTE. */ + { 32767, -32768, 2, TAB (ABSTOPCREL, LONG) }, + { 0, 0, 4, 0 }, + { 1, 1, 0, 0 }, +- ++ + { 127, -128, 0, TAB (BRANCHBWPL, SHORT) }, + { 32767, -32768, 2, TAB (BRANCHBWPL, LONG) }, + { 0, 0, 10, 0 }, + { 1, 1, 0, 0 }, ++ ++ { 127, -128, 0, 0 }, ++ { 32767, -32768, 2, TAB (ABSREL, LONG) }, ++ { 0, 0, 6, 0 }, ++ { 1, 1, 0, 0 }, ++ ++ { 127, -128, 0, 0 }, ++ { 32767, -32768, 2, TAB (IMMREL, LONG) }, ++ { 0, 0, 6, 0 }, ++ { 1, 1, 0, 0 }, + }; + + /* These are the machine dependent pseudo-ops. These are included so + the assembler can work on the output from the SUN C compiler, which + generates these. */ + +@@ -1314,12 +1349,23 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("Cannot make %s relocation PC relative"), + bfd_get_reloc_code_name (code)); + } + } + } ++ else if (fixp->tc_fix_data) ++ { ++ switch (fixp->fx_size) ++ { ++ case 1: code = BFD_RELOC_8_BASEREL; break; ++ case 2: code = BFD_RELOC_16_BASEREL; break; ++ case 4: code = BFD_RELOC_32_BASEREL; break; ++ default: ++ abort (); ++ } ++ } + else + { + #define F(SZ,PCREL) (((SZ) << 1) + (PCREL)) + switch (F (fixp->fx_size, fixp->fx_pcrel)) + { + #define MAP(SZ,PCREL,TYPE) case F(SZ,PCREL): code = (TYPE); break +@@ -2510,13 +2556,24 @@ m68k_ip (char *instring) + tmpreg = 0x3c; /* 7.4 */ + if (strchr ("bwl", s[1])) + nextword = get_num (&opP->disp, 90); + else + nextword = get_num (&opP->disp, 0); + if (isvar (&opP->disp)) +- add_fix (s[1], &opP->disp, 0, 0); ++ { ++/* This doesn't work when the symbol is N_UNDF! We ignore this for now. */ ++ if (0 && flag_small_code) ++ { ++ add_frag (adds (&opP->disp), ++ offs (&opP->disp), ++ TAB (IMMREL, SZ_UNDEF)); ++ break; ++ } ++ else ++ add_fix(s[1], &opP->disp, 0, 0, opP->disp.baserel); ++ } + switch (s[1]) + { + case 'b': + if (!isbyte (nextword)) + opP->error = _("operand out of range"); + addword (nextword); +@@ -2679,26 +2736,26 @@ m68k_ip (char *instring) + relocation it cannot be relaxed. */ + || opP->disp.pic_reloc != pic_none + #endif + ) + { + addword (0x0170); +- add_fix ('l', &opP->disp, 1, 2); ++ add_fix ('l', &opP->disp, 1, 2, opP->disp.baserel); + } + else + { + add_frag (adds (&opP->disp), + SEXT (offs (&opP->disp)), + TAB (PCREL1632, SZ_UNDEF)); + break; + } + } + else + { + addword (0x0170); +- add_fix ('l', &opP->disp, 0, 0); ++ add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel); + } + } + else + addword (0x0170); + addword (nextword >> 16); + } +@@ -2710,16 +2767,16 @@ m68k_ip (char *instring) + tmpreg = 0x28 + opP->reg - ADDR; /* 5.areg */ + + if (isvar (&opP->disp)) + { + if (opP->reg == PC) + { +- add_fix ('w', &opP->disp, 1, 0); ++ add_fix ('w', &opP->disp, 1, 0, opP->disp.baserel); + } + else +- add_fix ('w', &opP->disp, 0, 0); ++ add_fix ('w', &opP->disp, 0, 0, opP->disp.baserel); + } + } + addword (nextword); + break; + + case POST: +@@ -2823,15 +2880,15 @@ m68k_ip (char *instring) + if (isvar (&opP->disp)) + { + /* Do a byte relocation. If it doesn't + fit (possible on m68000) let the + fixup processing complain later. */ + if (opP->reg == PC) +- add_fix ('B', &opP->disp, 1, 1); ++ add_fix ('B', &opP->disp, 1, 1, 0); /* FIXME? -fnf */ + else +- add_fix ('B', &opP->disp, 0, 0); ++ add_fix ('B', &opP->disp, 0, 0, 0); /* FIXME? -fnf */ + } + else if (siz1 != SIZE_BYTE) + { + if (siz1 != SIZE_UNSPEC) + as_warn (_("Forcing byte displacement")); + if (! issbyte (baseo)) +@@ -2956,23 +3013,23 @@ m68k_ip (char *instring) + } + addword (nextword); + + if (siz1 != SIZE_UNSPEC && isvar (&opP->disp)) + { + if (opP->reg == PC || opP->reg == ZPC) +- add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 1, 2); ++ add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 1, 2, opP->disp.baserel); + else +- add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 0, 0); ++ add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 0, 0, opP->disp.baserel); + } + if (siz1 == SIZE_LONG) + addword (baseo >> 16); + if (siz1 != SIZE_UNSPEC) + addword (baseo); + + if (siz2 != SIZE_UNSPEC && isvar (&opP->odisp)) +- add_fix (siz2 == SIZE_LONG ? 'l' : 'w', &opP->odisp, 0, 0); ++ add_fix (siz2 == SIZE_LONG ? 'l' : 'w', &opP->odisp, 0, 0, opP->disp.baserel); + if (siz2 == SIZE_LONG) + addword (outro >> 16); + if (siz2 != SIZE_UNSPEC) + addword (outro); + + break; +@@ -3006,27 +3063,36 @@ m68k_ip (char *instring) + SEXT (offs (&opP->disp)), + TAB (ABSTOPCREL, SZ_UNDEF)); + break; + } + /* Fall through into long. */ + case SIZE_LONG: ++/* This doesn't work when the symbol is N_UNDF! We ignore this for now. */ ++ if (0 && flag_small_code) ++ { ++ tmpreg=0x3A; /* 7.2 */ ++ add_frag (adds (&opP->disp), ++ offs (&opP->disp), ++ TAB (ABSREL, SZ_UNDEF)); ++ break; ++ } + if (isvar (&opP->disp)) +- add_fix ('l', &opP->disp, 0, 0); ++ add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel); + + tmpreg = 0x39;/* 7.1 mode */ + addword (nextword >> 16); + addword (nextword); + break; + + case SIZE_BYTE: + as_bad (_("unsupported byte value; use a different suffix")); + /* Fall through. */ + + case SIZE_WORD: + if (isvar (&opP->disp)) +- add_fix ('w', &opP->disp, 0, 0); ++ add_fix ('w', &opP->disp, 0, 0, opP->disp.baserel); + + tmpreg = 0x38;/* 7.0 mode */ + addword (nextword); + break; + } + break; +@@ -3066,13 +3132,13 @@ m68k_ip (char *instring) + default: + tmpreg = 90; + break; + } + tmpreg = get_num (&opP->disp, tmpreg); + if (isvar (&opP->disp)) +- add_fix (s[1], &opP->disp, 0, 0); ++ add_fix (s[1], &opP->disp, 0, 0, opP->disp.baserel); + switch (s[1]) + { + case 'b': /* Danger: These do no check for + certain types of overflow. + user beware! */ + if (!isbyte (tmpreg)) +@@ -3133,22 +3199,22 @@ m68k_ip (char *instring) + case 'B': + tmpreg = get_num (&opP->disp, 90); + + switch (s[1]) + { + case 'B': +- add_fix ('B', &opP->disp, 1, -1); ++ add_fix ('B', &opP->disp, 1, -1, opP->disp.baserel); + break; + case 'W': +- add_fix ('w', &opP->disp, 1, 0); ++ add_fix ('w', &opP->disp, 1, 0, opP->disp.baserel); + addword (0); + break; + case 'L': + long_branch: + the_ins.opcode[0] |= 0xff; +- add_fix ('l', &opP->disp, 1, 0); ++ add_fix ('l', &opP->disp, 1, 0, opP->disp.baserel); + addword (0); + addword (0); + break; + case 'g': /* Conditional branch */ + have_disp = HAVE_LONG_CALL (current_architecture); + goto var_branch; +@@ -3188,13 +3254,13 @@ m68k_ip (char *instring) + else /* jCC */ + { + the_ins.opcode[0] ^= 0x0100; + the_ins.opcode[0] |= 0x0006; + addword (0x4EF9); + } +- add_fix ('l', &opP->disp, 0, 0); ++ add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel); + addword (0); + addword (0); + break; + } + + /* Now we know it's going into the relaxer. Now figure +@@ -3239,26 +3305,26 @@ m68k_ip (char *instring) + else + add_frag (adds (&opP->disp), + SEXT (offs (&opP->disp)), + TAB (DBCCABSJ, SZ_UNDEF)); + break; + } +- add_fix ('w', &opP->disp, 1, 0); ++ add_fix ('w', &opP->disp, 1, 0, opP->disp.baserel); + } + addword (0); + break; + case 'C': /* Fixed size LONG coproc branches. */ +- add_fix ('l', &opP->disp, 1, 0); ++ add_fix ('l', &opP->disp, 1, 0, opP->disp.baserel); + addword (0); + addword (0); + break; + case 'c': /* Var size Coprocesssor branches. */ + if (subs (&opP->disp) || (adds (&opP->disp) == 0)) + { + the_ins.opcode[the_ins.numo - 1] |= 0x40; +- add_fix ('l', &opP->disp, 1, 0); ++ add_fix ('l', &opP->disp, 1, 0, opP->disp.baserel); + addword (0); + addword (0); + } + else + add_frag (adds (&opP->disp), + SEXT (offs (&opP->disp)), +@@ -3706,13 +3772,13 @@ m68k_ip (char *instring) + case 't': + tmpreg = get_num (&opP->disp, 20); + install_operand (s[1], tmpreg); + break; + case '_': /* used only for move16 absolute 32-bit address. */ + if (isvar (&opP->disp)) +- add_fix ('l', &opP->disp, 0, 0); ++ add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel); + tmpreg = get_num (&opP->disp, 90); + addword (tmpreg >> 16); + addword (tmpreg & 0xFFFF); + break; + case 'u': + install_operand (s[1], opP->reg - DATA0L); +@@ -4055,12 +4121,18 @@ insert_reg (const char *regname, int regnum) + struct init_entry + { + const char *name; + int number; + }; + ++#if defined(TE_AMIGA) ++ #define FRAME ADDR5 ++#else ++ #define FRAME ADDR6 ++#endif ++ + static const struct init_entry init_table[] = + { + { "d0", DATA0 }, + { "d1", DATA1 }, + { "d2", DATA2 }, + { "d3", DATA3 }, +@@ -4072,13 +4144,13 @@ static const struct init_entry init_table[] = + { "a1", ADDR1 }, + { "a2", ADDR2 }, + { "a3", ADDR3 }, + { "a4", ADDR4 }, + { "a5", ADDR5 }, + { "a6", ADDR6 }, +- { "fp", ADDR6 }, ++ { "fp", FRAME }, + { "a7", ADDR7 }, + { "sp", ADDR7 }, + { "ssp", ADDR7 }, + { "fp0", FP0 }, + { "fp1", FP1 }, + { "fp2", FP2 }, +@@ -4443,13 +4515,14 @@ md_assemble (char *str) + ((toP - frag_now->fr_literal) + - the_ins.numo * 2 + the_ins.reloc[m].n), + n, + &the_ins.reloc[m].exp, + the_ins.reloc[m].pcrel, + get_reloc_code (n, the_ins.reloc[m].pcrel, +- the_ins.reloc[m].pic_reloc)); ++ the_ins.reloc[m].pic_reloc), ++ the_ins.reloc[m].baserel); + fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix; + if (the_ins.reloc[m].wid == 'B') + fixP->fx_signed = 1; + } + return; + } +@@ -4505,13 +4578,14 @@ md_assemble (char *str) + ((toP - frag_now->fr_literal) + - the_ins.numo * 2 + the_ins.reloc[m].n), + wid, + &the_ins.reloc[m].exp, + the_ins.reloc[m].pcrel, + get_reloc_code (wid, the_ins.reloc[m].pcrel, +- the_ins.reloc[m].pic_reloc)); ++ the_ins.reloc[m].pic_reloc), ++ the_ins.reloc[m].baserel); + fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix; + } + (void) frag_var (rs_machine_dependent, FRAG_VAR_SIZE, 0, + (relax_substateT) (the_ins.fragb[n].fragty), + the_ins.fragb[n].fadd, the_ins.fragb[n].foff, to_beg_P); + } +@@ -4542,13 +4616,14 @@ md_assemble (char *str) + ((the_ins.reloc[m].n + toP - frag_now->fr_literal) + - shorts_this_frag * 2), + wid, + &the_ins.reloc[m].exp, + the_ins.reloc[m].pcrel, + get_reloc_code (wid, the_ins.reloc[m].pcrel, +- the_ins.reloc[m].pic_reloc)); ++ the_ins.reloc[m].pic_reloc), ++ the_ins.reloc[m].baserel); + fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix; + } + } + + /* Comparison function used by qsort to rank the opcode entries by name. */ + +@@ -5058,29 +5133,29 @@ md_convert_frag_1 (fragS *fragP) + case TAB (BRANCHBWPL, BYTE): + know (issbyte (disp)); + if (disp == 0) + as_bad_where (fragP->fr_file, fragP->fr_line, + _("short branch with zero offset: use :w")); + fixP = fix_new (fragP, fragP->fr_fix - 1, 1, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC8); ++ fragP->fr_offset, 1, RELAX_RELOC_PC8, 0); + fixP->fx_pcrel_adjust = -1; + break; + case TAB (BRANCHBWL, SHORT): + case TAB (BRABSJUNC, SHORT): + case TAB (BRABSJCOND, SHORT): + case TAB (BRANCHBW, SHORT): + case TAB (BRANCHBWPL, SHORT): + fragP->fr_opcode[1] = 0x00; + fixP = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC16); ++ fragP->fr_offset, 1, RELAX_RELOC_PC16, 0); + fragP->fr_fix += 2; + break; + case TAB (BRANCHBWL, LONG): + fragP->fr_opcode[1] = (char) 0xFF; + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC32); ++ fragP->fr_offset, 1, RELAX_RELOC_PC32, 0); + fragP->fr_fix += 4; + break; + case TAB (BRANCHBWPL, LONG): + /* Here we are converting an unconditional branch into a pair of + conditional branches, in order to get the range. */ + fragP->fr_opcode[0] = 0x66; /* bne */ +@@ -5096,32 +5171,36 @@ md_convert_frag_1 (fragS *fragP) + fragP->fr_fix += 2; /* Skip second branch opcode */ + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, + fragP->fr_offset, 1, RELAX_RELOC_PC32); + fragP->fr_fix += 4; + break; + case TAB (BRABSJUNC, LONG): ++ if (flag_small_code) ++ { ++ as_bad (_("Long branch in small code model, not supported.")); ++ } else + if (fragP->fr_opcode[0] == 0x61) /* jbsr */ + { + if (flag_keep_pcrel) + as_bad_where (fragP->fr_file, fragP->fr_line, + _("Conversion of PC relative BSR to absolute JSR")); + fragP->fr_opcode[0] = 0x4E; + fragP->fr_opcode[1] = (char) 0xB9; /* JSR with ABSL LONG operand. */ + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, +- fragP->fr_offset, 0, RELAX_RELOC_ABS32); ++ fragP->fr_offset, 0, RELAX_RELOC_ABS32,0); + fragP->fr_fix += 4; + } + else if (fragP->fr_opcode[0] == 0x60) /* jbra */ + { + if (flag_keep_pcrel) + as_bad_where (fragP->fr_file, fragP->fr_line, + _("Conversion of PC relative branch to absolute jump")); + fragP->fr_opcode[0] = 0x4E; + fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG operand. */ + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, +- fragP->fr_offset, 0, RELAX_RELOC_ABS32); ++ fragP->fr_offset, 0, RELAX_RELOC_ABS32, 0); + fragP->fr_fix += 4; + } + else + { + /* This cannot happen, because jbsr and jbra are the only two + unconditional branches. */ +@@ -5142,31 +5221,31 @@ md_convert_frag_1 (fragS *fragP) + different frag, in which case referring to them is a no-no. + Only fr_opcode[0,1] are guaranteed to work. */ + *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */ + *buffer_address++ = (char) 0xf9; + fragP->fr_fix += 2; /* Account for jmp instruction. */ + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, +- fragP->fr_offset, 0, RELAX_RELOC_ABS32); ++ fragP->fr_offset, 0, RELAX_RELOC_ABS32,0); + fragP->fr_fix += 4; + break; + case TAB (FBRANCH, SHORT): + know ((fragP->fr_opcode[1] & 0x40) == 0); + fixP = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC16); ++ fragP->fr_offset, 1, RELAX_RELOC_PC16, 0); + fragP->fr_fix += 2; + break; + case TAB (FBRANCH, LONG): + fragP->fr_opcode[1] |= 0x40; /* Turn on LONG bit. */ + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC32); ++ fragP->fr_offset, 1, RELAX_RELOC_PC32, 0); + fragP->fr_fix += 4; + break; + case TAB (DBCCLBR, SHORT): + case TAB (DBCCABSJ, SHORT): + fixP = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC16); ++ fragP->fr_offset, 1, RELAX_RELOC_PC16,0); + fragP->fr_fix += 2; + break; + case TAB (DBCCLBR, LONG): + /* Only DBcc instructions can come here. + Change dbcc into dbcc/bral. + JF: these used to be fr_opcode[2-7], but that's wrong. */ +@@ -5180,13 +5259,13 @@ md_convert_frag_1 (fragS *fragP) + *buffer_address++ = 0x06; + *buffer_address++ = 0x60; /* Put in bral (0x60ff). */ + *buffer_address++ = (char) 0xff; + + fragP->fr_fix += 6; /* Account for bra/jmp instructions. */ + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC32); ++ fragP->fr_offset, 1, RELAX_RELOC_PC32,0); + fragP->fr_fix += 4; + break; + case TAB (DBCCABSJ, LONG): + /* Only DBcc instructions can come here. + Change dbcc into dbcc/jmp. + JF: these used to be fr_opcode[2-7], but that's wrong. */ +@@ -5200,61 +5279,61 @@ md_convert_frag_1 (fragS *fragP) + *buffer_address++ = 0x06; + *buffer_address++ = 0x4e; /* Put in jmp long (0x4ef9). */ + *buffer_address++ = (char) 0xf9; + + fragP->fr_fix += 6; /* Account for bra/jmp instructions. */ + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, +- fragP->fr_offset, 0, RELAX_RELOC_ABS32); ++ fragP->fr_offset, 0, RELAX_RELOC_ABS32, 0); + fragP->fr_fix += 4; + break; + case TAB (PCREL1632, SHORT): + fragP->fr_opcode[1] &= ~0x3F; + fragP->fr_opcode[1] |= 0x3A; /* 072 - mode 7.2 */ + fixP = fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC16); ++ fragP->fr_offset, 1, RELAX_RELOC_PC16, 0); + fragP->fr_fix += 2; + break; + case TAB (PCREL1632, LONG): + /* Already set to mode 7.3; this indicates: PC indirect with + suppressed index, 32-bit displacement. */ + *buffer_address++ = 0x01; + *buffer_address++ = 0x70; + fragP->fr_fix += 2; + fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC32); ++ fragP->fr_offset, 1, RELAX_RELOC_PC32, 0); + fixP->fx_pcrel_adjust = 2; + fragP->fr_fix += 4; + break; + case TAB (PCINDEX, BYTE): + gas_assert (fragP->fr_fix >= 2); + buffer_address[-2] &= ~1; + fixP = fix_new (fragP, fragP->fr_fix - 1, 1, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC8); ++ fragP->fr_offset, 1, RELAX_RELOC_PC8, 0); + fixP->fx_pcrel_adjust = 1; + break; + case TAB (PCINDEX, SHORT): + gas_assert (fragP->fr_fix >= 2); + buffer_address[-2] |= 0x1; + buffer_address[-1] = 0x20; + fixP = fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC16); ++ fragP->fr_offset, 1, RELAX_RELOC_PC16, 0); + fixP->fx_pcrel_adjust = 2; + fragP->fr_fix += 2; + break; + case TAB (PCINDEX, LONG): + gas_assert (fragP->fr_fix >= 2); + buffer_address[-2] |= 0x1; + buffer_address[-1] = 0x30; + fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC32); ++ fragP->fr_offset, 1, RELAX_RELOC_PC32, 0); + fixP->fx_pcrel_adjust = 2; + fragP->fr_fix += 4; + break; + case TAB (ABSTOPCREL, SHORT): + fixP = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC16); ++ fragP->fr_offset, 1, RELAX_RELOC_PC16,0); + fragP->fr_fix += 2; + break; + case TAB (ABSTOPCREL, LONG): + if (flag_keep_pcrel) + as_bad_where (fragP->fr_file, fragP->fr_line, + _("Conversion of PC relative displacement to absolute")); +@@ -5262,15 +5341,87 @@ md_convert_frag_1 (fragS *fragP) + ABSTOPCREL is really trying to shorten an ABSOLUTE address anyway. */ + if ((fragP->fr_opcode[1] & 0x3F) != 0x3A) + abort (); + fragP->fr_opcode[1] &= ~0x3F; + fragP->fr_opcode[1] |= 0x39; /* Mode 7.1 */ + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, +- fragP->fr_offset, 0, RELAX_RELOC_ABS32); ++ fragP->fr_offset, 0, RELAX_RELOC_ABS32, 0); + fragP->fr_fix += 4; + break; ++ case TAB (ABSREL, BYTE): ++ as_bad (_("ABSREL_BYTE: how the ** does this look??")); ++ break; ++ case TAB (ABSREL, SHORT): ++ fragP->fr_opcode[1] &= ~0x3f; ++ fragP->fr_fix += 2; ++ if (S_GET_TYPE (fragP->fr_symbol) == N_TEXT) ++ { ++ /* so this is really a pc-relative address */ ++ fragP->fr_opcode[1] |= 0x3a; ++ fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, 1, NO_RELOC, 0); ++ break; ++ } ++ /* in that case we have to generate base-relative code ++ * (note: if we're in N_UNDF, this could as well be pc-relative, but the linker ++ * will have to do the final patch in that case) */ ++ fragP->fr_opcode[1] |= 0x2c; /* (a4) */ ++ fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 1); ++ break; ++ case TAB (ABSREL, LONG): ++ as_bad (_("ABSREL_LONG: sorry, not supported.")); ++ break; ++ case TAB (IMMREL, BYTE): ++ as_bad (_("IMMREL_BYTE: how the ** does this look??")); ++ break; ++ case TAB (IMMREL, SHORT): ++ if (S_GET_TYPE (fragP->fr_symbol) == N_TEXT) ++ { ++ /* we can only fix operations on data registers, not on <ea> */ ++ if ((fragP->fr_opcode[1] & 0x38) != 0) ++ { ++ /* use the normal reloc32, sigh... */ ++ fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 0); ++ fragP->fr_fix += 4; ++ break; ++ } ++ ++ /* so this is really a pc-relative address ++ * What we have to do now is a VERY UGLY AND BIG KLUDGE. Basically do the ++ * following thing: ++ * turn ++ * addl #foo,d0 (foo is N_TEXT) ++ * into ++ * pea foo(pc) ++ * addl (sp)+,d0 ++ */ ++ *buffer_address++ = fragP->fr_opcode[0]; /* save the original command */ ++ *buffer_address++ = fragP->fr_opcode[1]; ++ fragP->fr_opcode[0] = 0x48; /* PEA */ ++ fragP->fr_opcode[1] = 0x7a; ++ fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, 1, NO_RELOC, 0); ++ ++ *buffer_address++ = 0x9f; /* sp@+ */ ++ fragP->fr_fix += 4; /* two byte fix, two byte code extension */ ++ break; ++ } ++ /* in that case we have to generate base-relative code ++ * (note: if we're in N_UNDF, this could as well be pc-relative, but the linker ++ * will have to do the final patch in that case) */ ++ ++ /* analogous (more or less;-)) to above, the following conversion is done ++ * turn ++ * addl #bar,d0 (bar is N_DATA) ++ * into ++ * addl #<bar>,d0 where <bar> is a baserel-reloc ++ * addl a4,d0 ++ */ ++ ++ fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 1); ++ *buffer_address++ = 0xd0; ++ *buffer_address++ = 0x8c; ++ break; + } + if (fixP) + { + fixP->fx_file = fragP->fr_file; + fixP->fx_line = fragP->fr_line; + } +@@ -5300,13 +5451,13 @@ md_estimate_size_before_relax (fragS *fragP, segT segment) + { + if (S_GET_SEGMENT (fragP->fr_symbol) == segment + && relaxable_symbol (fragP->fr_symbol)) + { + fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE); + } +- else if (flag_short_refs) ++ else if (flag_short_refs || (0 && flag_small_code)) + { + /* Symbol is undefined and we want short ref. */ + fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT); + } + else + { +@@ -5372,12 +5523,27 @@ md_estimate_size_before_relax (fragS *fragP, segT segment) + { + fragP->fr_subtype = TAB (ABSTOPCREL, LONG); + } + break; + } + ++ case TAB (ABSREL, SZ_UNDEF): ++ { ++ if ((S_GET_SEGMENT (fragP->fr_symbol) == segment ++ && relaxable_symbol (fragP->fr_symbol)) ++ || flag_short_refs || (0 && flag_small_code)) ++ { ++ fragP->fr_subtype = TAB (ABSREL, SHORT); ++ } ++ else ++ { ++ fragP->fr_subtype = TAB (ABSREL, LONG); ++ } ++ break; ++ } ++ + default: + break; + } + + /* Now that SZ_UNDEF are taken care of, check others. */ + switch (fragP->fr_subtype) +@@ -5434,16 +5600,52 @@ md_ri_to_chars (char *the_bytes, struct reloc_info_generic *ri) + /* Now the fun stuff. */ + the_bytes[4] = (ri->r_symbolnum >> 16) & 0x0ff; + the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff; + the_bytes[6] = ri->r_symbolnum & 0x0ff; + the_bytes[7] = (((ri->r_pcrel << 7) & 0x80) + | ((ri->r_length << 5) & 0x60) +- | ((ri->r_extern << 4) & 0x10)); ++ | ((ri->r_extern << 4) & 0x10) ++ | ((ri->r_baserel << 3) & 0x08)); + } + ++#endif /* comment */ ++ ++#if 0 /* FIXME: sba */ ++#ifndef BFD_ASSEMBLER ++void ++tc_aout_fix_to_chars (where, fixP, segment_address_in_file) ++ char *where; ++ fixS *fixP; ++ relax_addressT segment_address_in_file; ++{ ++ /* ++ * In: length of relocation (or of address) in chars: 1, 2 or 4. ++ * Out: GNU LD relocation length code: 0, 1, or 2. ++ */ ++ ++ static const unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2}; ++ long r_symbolnum; ++ ++ know (fixP->fx_addsy != NULL); ++ ++ md_number_to_chars (where, ++ fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, ++ 4); ++ ++ r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy) ++ ? S_GET_TYPE (fixP->fx_addsy) ++ : fixP->fx_addsy->sy_number); ++ ++ where[4] = (r_symbolnum >> 16) & 0x0ff; ++ where[5] = (r_symbolnum >> 8) & 0x0ff; ++ where[6] = r_symbolnum & 0x0ff; ++ where[7] = (((fixP->fx_pcrel << 7) & 0x80) | ((nbytes_r_length[fixP->fx_size] << 5) & 0x60) | ++ (((!S_IS_DEFINED (fixP->fx_addsy)) << 4) & 0x10) | ((fixP->tc_fix_data << 3) & 0x08)); ++} + #endif ++#endif /* 0 */ + + #endif /* OBJ_AOUT or OBJ_BOUT */ + + #ifndef WORKING_DOT_WORD + int md_short_jump_size = 4; + int md_long_jump_size = 6; +@@ -5472,13 +5674,13 @@ md_create_long_jump (char *ptr, addressT from_addr, addressT to_addr, + if (flag_keep_pcrel) + as_fatal (_("Tried to convert PC relative branch to absolute jump")); + offset = to_addr - S_GET_VALUE (to_symbol); + md_number_to_chars (ptr, (valueT) 0x4EF9, 2); + md_number_to_chars (ptr + 2, (valueT) offset, 4); + fix_new (frag, (ptr + 2) - frag->fr_literal, 4, to_symbol, (offsetT) 0, +- 0, NO_RELOC); ++ 0, NO_RELOC, 0); + } + else + { + offset = to_addr - (from_addr + 2); + md_number_to_chars (ptr, (valueT) 0x60ff, 2); + md_number_to_chars (ptr + 2, (valueT) offset, 4); +@@ -7519,13 +7721,13 @@ m68k_set_extension (char const *name, int allow_m, int silent) + Invocation line includes a switch not recognized by the base assembler. + */ + + #ifdef OBJ_ELF + const char *md_shortopts = "lSA:m:kQ:V"; + #else +-const char *md_shortopts = "lSA:m:k"; ++const char *md_shortopts = "lSA:m:s:k"; + #endif + + struct option md_longopts[] = { + #define OPTION_PIC (OPTION_MD_BASE) + {"pic", no_argument, NULL, OPTION_PIC}, + #define OPTION_REGISTER_PREFIX_OPTIONAL (OPTION_MD_BASE + 1) +@@ -7564,12 +7766,19 @@ md_parse_option (int c, char *arg) + + case OPTION_PCREL: /* --pcrel means never turn PC-relative + branches into absolute jumps. */ + flag_keep_pcrel = 1; + break; + ++ case 's': ++ if (!strcmp(arg, "c") || !strcmp(arg, "mallcode")) ++ flag_small_code = 1; ++ else ++ return 0; ++ break; ++ + case OPTION_PIC: + case 'k': + flag_want_pic = 1; + break; /* -pic, Position Independent Code. */ + + case OPTION_REGISTER_PREFIX_OPTIONAL: +@@ -7747,12 +7956,13 @@ md_show_usage (FILE *stream) + : m68k_extensions[i].alias < 0 ? " m68k" : ""); + + fprintf (stream, _("\ + -l use 1 word for refs to undefined symbols [default 2]\n\ + -pic, -k generate position independent code\n\ + -S turn jbsr into jsr\n\ ++-smallcode, -sc small code model\n\ + --pcrel never turn PC-relative branches into absolute jumps\n\ + --register-prefix-optional\n\ + recognize register names without prefix character\n\ + --bitwise-or do not treat `|' as a comment character\n\ + --base-size-default-16 base reg without size is 16 bits\n\ + --base-size-default-32 base reg without size is 32 bits (default)\n\ +@@ -7913,12 +8123,14 @@ md_pcrel_from (fixS *fixP) + + /* Because fx_pcrel_adjust is a char, and may be unsigned, we explicitly + sign extend the value here. */ + adjust = ((fixP->fx_pcrel_adjust & 0xff) ^ 0x80) - 0x80; + if (adjust == 64) + adjust = -1; ++ if (OBJ_AMIGAHUNK) ++ return -adjust; + return fixP->fx_where + fixP->fx_frag->fr_address - adjust; + } + + #ifdef OBJ_ELF + void + m68k_elf_final_processing (void) +diff --git a/gas/config/tc-m68k.h b/gas/config/tc-m68k.h +index bcf4607ebebe16d575166d666a536fb1fbdfeaee..144b7c7d783bab80bd84fa0e57cfce9f349a528f 100644 +--- gas/config/tc-m68k.h ++++ gas/config/tc-m68k.h +@@ -30,20 +30,27 @@ struct fix; + #ifdef TE_SUN3 + #define TARGET_FORMAT "a.out-sunos-big" + #endif + #ifdef TE_NetBSD + #define TARGET_FORMAT "a.out-m68k-netbsd" + #endif ++#ifdef TE_AMIGA ++#define TARGET_FORMAT "a.out-amiga" ++#endif + #ifdef TE_LINUX + #define TARGET_FORMAT "a.out-m68k-linux" + #endif + #ifndef TARGET_FORMAT + #define TARGET_FORMAT "a.out-zero-big" + #endif + #endif + ++#ifdef OBJ_AMIGAHUNK ++#define TARGET_FORMAT "amiga" ++#endif ++ + #ifdef OBJ_ELF + #define TARGET_FORMAT "elf32-m68k" + #endif + + #ifdef TE_APOLLO + #define COFF_MAGIC APOLLOM68KMAGIC +@@ -60,12 +67,17 @@ struct fix; + + #ifndef COFF_MAGIC + #define COFF_MAGIC MC68MAGIC + #endif + #define TARGET_ARCH bfd_arch_m68k + ++// FIXME: This was in binutils 2.14 ++//#ifdef TE_AMIGA ++//#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (OMAGIC); /* Magic byte for file header */ ++//#endif ++ + #define tc_comment_chars m68k_comment_chars + extern const char *m68k_comment_chars; + + #define LISTING_WORD_SIZE 2 /* A word is 2 bytes */ + #define LISTING_LHS_WIDTH 2 /* One word on the first line */ + #define LISTING_LHS_WIDTH_SECOND 2 /* One word on the second line */ +@@ -152,12 +164,15 @@ extern int m68k_parse_long_option (char *); + + #define TARGET_ARCH bfd_arch_m68k + + extern struct relax_type md_relax_table[]; + #define TC_GENERIC_RELAX_TABLE md_relax_table + ++#define TC_FIX_TYPE char ++#define TC_INIT_FIX_DATA(p) ++ + /* We can't do a byte jump to the next instruction, so in that case + force word mode by faking AIM. */ + #define md_prepare_relax_scan(fragP, address, aim, this_state, this_type) \ + do \ + { \ + if (aim == 0 && this_type->rlx_forward == 127) \ +diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c +index 208d76d847128c833f73713eff2b78deb610a764..11949323d80802138ec23fb8174727c0a7c4fd45 100644 +--- gas/config/tc-ppc.c ++++ gas/config/tc-ppc.c +@@ -1421,22 +1421,28 @@ ppc_target_format (void) + # else + return (ppc_obj64 ? "aixcoff64-rs6000" : "aixcoff-rs6000"); + # endif + #endif + #endif + #ifdef OBJ_ELF ++#ifdef TE_MORPHOS ++ return "elf32-morphos"; ++#elif TE_AMIGAOS ++ return "elf32-amigaos"; ++#else + # ifdef TE_FreeBSD + return (ppc_obj64 ? "elf64-powerpc-freebsd" : "elf32-powerpc-freebsd"); + # elif defined (TE_VXWORKS) + return "elf32-powerpc-vxworks"; + # else + return (target_big_endian + ? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc") + : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle")); + # endif + #endif ++#endif + } + + /* Validate one entry in powerpc_opcodes[] or vle_opcodes[]. + Return TRUE if there's a problem, otherwise FALSE. */ + + static bfd_boolean +@@ -1872,12 +1878,24 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p) + + #define MAP(str, reloc) { str, sizeof (str) - 1, 1, 1, reloc } + #define MAP32(str, reloc) { str, sizeof (str) - 1, 1, 0, reloc } + #define MAP64(str, reloc) { str, sizeof (str) - 1, 0, 1, reloc } + + static const struct map_bfd mapping[] = { ++ /* MorphOS specifc relocs */ ++ MAP ("drel", BFD_RELOC_PPC_MORPHOS_DREL), ++ MAP ("drell", BFD_RELOC_PPC_MORPHOS_DREL_LO), ++ MAP ("drelh", BFD_RELOC_PPC_MORPHOS_DREL_HI), ++ MAP ("drelha", BFD_RELOC_PPC_MORPHOS_DREL_HA), ++ ++ /* AmigaOS4 specific relocs */ ++ MAP ("brel", BFD_RELOC_PPC_AMIGAOS_BREL), ++ MAP ("brel@l", BFD_RELOC_PPC_AMIGAOS_BREL_LO), ++ MAP ("brel@h", BFD_RELOC_PPC_AMIGAOS_BREL_HI), ++ MAP ("brel@ha", BFD_RELOC_PPC_AMIGAOS_BREL_HA), ++ + MAP ("l", BFD_RELOC_LO16), + MAP ("h", BFD_RELOC_HI16), + MAP ("ha", BFD_RELOC_HI16_S), + MAP ("brtaken", BFD_RELOC_PPC_B16_BRTAKEN), + MAP ("brntaken", BFD_RELOC_PPC_B16_BRNTAKEN), + MAP ("got", BFD_RELOC_16_GOTOFF), +@@ -2098,13 +2116,13 @@ ppc_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long, 8=.llong */) + p = frag_more (nbytes); + memset (p, 0, nbytes); + offset = 0; + if (target_big_endian) + offset = nbytes - size; + fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, +- &exp, 0, reloc); ++ &exp, 0, reloc, 0); + } + } + else + emit_expr (&exp, (unsigned int) nbytes); + } + while (*input_line_pointer++ == ','); +@@ -3307,25 +3325,25 @@ md_assemble (char *str) + + fixP = fix_new_exp (frag_now, + f - frag_now->fr_literal + offset, + size, + &fixups[i].exp, + reloc_howto->pc_relative, +- fixups[i].reloc); ++ fixups[i].reloc, 0); + } + else + { + const struct powerpc_operand *operand; + + operand = &powerpc_operands[fixups[i].opindex]; + fixP = fix_new_exp (frag_now, + f - frag_now->fr_literal, + insn_length, + &fixups[i].exp, + (operand->flags & PPC_OPERAND_RELATIVE) != 0, +- BFD_RELOC_UNUSED); ++ BFD_RELOC_UNUSED, 0); + } + fixP->fx_pcrel_adjust = fixups[i].opindex; + } + } + + /* Handle a macro. Gather all the operands, transform them as +@@ -6650,12 +6668,16 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) + size = 2; + break; + + case BFD_RELOC_8: + if (fixP->fx_pcrel) + { ++ case BFD_RELOC_PPC_MORPHOS_DREL: ++ case BFD_RELOC_PPC_MORPHOS_DREL_LO: ++ case BFD_RELOC_PPC_MORPHOS_DREL_HI: ++ case BFD_RELOC_PPC_MORPHOS_DREL_HA: + #ifdef OBJ_ELF + bad_pcrel: + #endif + if (fixP->fx_addsy) + { + char *sfile; +@@ -6692,12 +6714,20 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) + + case BFD_RELOC_VTABLE_ENTRY: + fixP->fx_done = 0; + break; + + #ifdef OBJ_ELF ++ case BFD_RELOC_PPC_AMIGAOS_BREL: ++ case BFD_RELOC_PPC_AMIGAOS_BREL_HI: ++ case BFD_RELOC_PPC_AMIGAOS_BREL_LO: ++ case BFD_RELOC_PPC_AMIGAOS_BREL_HA: ++ md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, ++ value, 2); ++ break; ++ + /* These can appear with @l etc. in data. */ + case BFD_RELOC_LO16: + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_LO16_PCREL; + case BFD_RELOC_LO16_PCREL: + size = 2; +diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c +index 4db1a0913602aaf18d1390cc315f6db0fbdef649..ba0ed8e89e44a9ab8411662047e6f85b4f28d5d9 100644 +--- gas/config/tc-sh.c ++++ gas/config/tc-sh.c +@@ -800,13 +800,13 @@ sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp) + { + error: + as_bad (_("unsupported BFD relocation size %u"), size); + r_type = BFD_RELOC_UNUSED; + } + +- fix_new_exp (frag, off, size, exp, 0, r_type); ++ fix_new_exp (frag, off, size, exp, 0, r_type, 0); + } + + /* The regular cons() function, that reads constants, doesn't support + suffixes such as @GOT, @GOTOFF and @PLT, that generate + machine-specific relocation types. So we must define it here. */ + /* Clobbers input_line_pointer, checks end-of-line. */ +@@ -2239,24 +2239,24 @@ insert (char *where, int how, int pcrel, sh_operand_info *op) + { + fix_new_exp (frag_now, + where - frag_now->fr_literal, + 2, + &op->immediate, + pcrel, +- how); ++ how, 0); + } + + static void + insert4 (char * where, int how, int pcrel, sh_operand_info * op) + { + fix_new_exp (frag_now, + where - frag_now->fr_literal, + 4, + & op->immediate, + pcrel, +- how); ++ how, 0); + } + static void + build_relax (sh_opcode_info *opcode, sh_operand_info *op) + { + int high_byte = target_big_endian ? 0 : 1; + char *p; +@@ -2320,13 +2320,13 @@ insert_loop_bounds (char *output, sh_operand_info *operand) + #ifdef OBJ_COFF + SF_SET_LOCAL (end_sym); + #endif /* OBJ_COFF */ + symbol_table_insert (end_sym); + end_sym->sy_value = operand[1].immediate; + end_sym->sy_value.X_add_number += 2; +- fix_new (frag_now, frag_now_fix (), 2, end_sym, 0, 1, BFD_RELOC_SH_LABEL); ++ fix_new (frag_now, frag_now_fix (), 2, end_sym, 0, 1, BFD_RELOC_SH_LABEL, 0); + } + + output = frag_more (2); + output[0] = 0x8e; + output[1] = 0x8e; + insert (output, BFD_RELOC_SH_LOOP_START, 1, operand); +@@ -2974,13 +2974,13 @@ md_assemble (char *str) + if (sh_relax + && ! seg_info (now_seg)->tc_segment_info_data.in_code) + { + /* Output a CODE reloc to tell the linker that the following + bytes are instructions, not data. */ + fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, +- BFD_RELOC_SH_CODE); ++ BFD_RELOC_SH_CODE, 0); + seg_info (now_seg)->tc_segment_info_data.in_code = 1; + } + + if (opcode->nibbles[0] == PPI) + { + size = assemble_ppi (op_end, opcode); +@@ -3055,13 +3055,13 @@ sh_frob_label (symbolS *sym) + int offset; + + offset = frag_now_fix (); + if (frag_now != last_label_frag + || offset != last_label_offset) + { +- fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL); ++ fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL, 0); + last_label_frag = frag_now; + last_label_offset = offset; + } + } + + dwarf2_emit_label (sym); +@@ -3074,13 +3074,13 @@ void + sh_flush_pending_output (void) + { + if (sh_relax + && seg_info (now_seg)->tc_segment_info_data.in_code) + { + fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, +- BFD_RELOC_SH_DATA); ++ BFD_RELOC_SH_DATA, 0); + seg_info (now_seg)->tc_segment_info_data.in_code = 0; + } + } + + symbolS * + md_undefined_symbol (char *name ATTRIBUTE_UNUSED) +@@ -3115,13 +3115,13 @@ s_uses (int ignore ATTRIBUTE_UNUSED) + { + as_bad (_("bad .uses format")); + ignore_rest_of_line (); + return; + } + +- fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES); ++ fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES, 0); + + demand_empty_rest_of_line (); + } + + enum options + { +@@ -3514,13 +3514,13 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec, + /* Generate a BFD_RELOC_SH_COUNT fixup at the location of sym. + We have already adjusted the value of sym to include the + fragment address, so we undo that adjustment here. */ + subseg_change (sec, 0); + fix_new (fscan->fx_frag, + S_GET_VALUE (sym) - fscan->fx_frag->fr_address, +- 4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT); ++ 4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT, 0); + } + } + + /* This function is called after the symbol table has been completed, + but before the relocs or section contents have been written out. + If we have seen any .uses pseudo-ops, they point to an instruction +@@ -3555,21 +3555,21 @@ md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP) + switch (fragP->fr_subtype) + { + case C (COND_JUMP, COND8): + case C (COND_JUMP_DELAY, COND8): + subseg_change (seg, 0); + fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, +- 1, BFD_RELOC_SH_PCDISP8BY2); ++ 1, BFD_RELOC_SH_PCDISP8BY2, 0); + fragP->fr_fix += 2; + fragP->fr_var = 0; + break; + + case C (UNCOND_JUMP, UNCOND12): + subseg_change (seg, 0); + fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, +- 1, BFD_RELOC_SH_PCDISP12BY2); ++ 1, BFD_RELOC_SH_PCDISP12BY2, 0); + fragP->fr_fix += 2; + fragP->fr_var = 0; + break; + + case C (UNCOND_JUMP, UNCOND32): + case C (UNCOND_JUMP, UNDEF_WORD_DISP): +@@ -3620,19 +3620,19 @@ md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP) + its delay-slot insn already makes the branch reach. */ + + /* Build a relocation to six / four bytes farther on. */ + subseg_change (seg, 0); + fix_new (fragP, fragP->fr_fix, 2, section_symbol (seg), + fragP->fr_address + fragP->fr_fix + (delay ? 4 : 6), +- 1, BFD_RELOC_SH_PCDISP8BY2); ++ 1, BFD_RELOC_SH_PCDISP8BY2, 0); + + /* Set up a jump instruction. */ + buffer[highbyte + 2] = 0xa0; + buffer[lowbyte + 2] = 0; + fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol, +- fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2); ++ fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2, 0); + + if (delay) + { + buffer[highbyte] &= ~0x4; /* Removes delay slot from branch. */ + fragP->fr_fix += 4; + } +@@ -3798,13 +3798,13 @@ sh_handle_align (fragS *frag) + && (frag->fr_type == rs_align + || frag->fr_type == rs_align_code) + && frag->fr_address + frag->fr_fix > 0 + && frag->fr_offset > 1 + && now_seg != bss_section) + fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0, +- BFD_RELOC_SH_ALIGN); ++ BFD_RELOC_SH_ALIGN, 0); + } + + /* See whether the relocation should be resolved locally. */ + + static bfd_boolean + sh_local_pcrel (fixS *fix) +diff --git a/gas/config/te-amiga.h b/gas/config/te-amiga.h +new file mode 100644 +index 0000000000000000000000000000000000000000..a7b93727031092cdeb4bf66e3813663d66d79c3b +--- /dev/null ++++ gas/config/te-amiga.h +@@ -0,0 +1,24 @@ ++/* ++ * te-amiga.h -- Amiga target environment declarations. ++ */ ++ ++#define TE_AMIGA 1 ++ ++#define LOCAL_LABELS_DOLLAR 1 ++#define LOCAL_LABELS_FB 1 ++ ++#ifdef OBJ_HEADER ++#include OBJ_HEADER ++#else ++#include "obj-format.h" ++#endif ++ ++#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) \ ++ do { \ ++ if ((SIZE) >= 4) \ ++ (P2VAR) = 2; \ ++ else if ((SIZE) >= 2) \ ++ (P2VAR) = 1; \ ++ else \ ++ (P2VAR) = 0; \ ++ } while (0) +diff --git a/gas/config/te-amigaos.h b/gas/config/te-amigaos.h +new file mode 100644 +index 0000000000000000000000000000000000000000..8bd15a3d19b3f383e6756d6e307bd10dc4dcfb6f +--- /dev/null ++++ gas/config/te-amigaos.h +@@ -0,0 +1,14 @@ ++/* ++ * te-amigaos.h -- Amiga target environment declarations. ++ */ ++ ++#define TE_AMIGAOS 1 ++ ++#define LOCAL_LABELS_DOLLAR 1 ++#define LOCAL_LABELS_FB 1 ++ ++#ifdef OBJ_HEADER ++#include OBJ_HEADER ++#else ++#include "obj-format.h" ++#endif +diff --git a/gas/config/te-nbsd.h b/gas/config/te-amithlon.h +similarity index 65% +copy from gas/config/te-nbsd.h +copy to gas/config/te-amithlon.h +index ce291014824771b2081438766002c479eeb60d9b..2fbd88551330d46e5cd585d142d67e6b7efe1624 100644 +--- gas/config/te-nbsd.h ++++ gas/config/te-amithlon.h +@@ -1,24 +1,26 @@ +-/* te-nbsd.h -- NetBSD target environment declarations. +- Copyright 1987, 1990, 1991, 1992, 1994, 1998, 2000, 2005, 2007 +- Free Software Foundation, Inc. ++/* te-amithlon.h -- Amithlon target environment declarations. ++ Copyright 2000 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by +- the Free Software Foundation; either version 3, or (at your option) ++ the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free +- Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA +- 02110-1301, USA. */ ++ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ++ 02111-1307, USA. */ + +-#define TE_NetBSD 1 ++#define TE_Amithlon 1 ++ ++#define LOCAL_LABELS_DOLLAR 1 + #define LOCAL_LABELS_FB 1 ++ + #include "obj-format.h" +diff --git a/gas/config/te-morphos.h b/gas/config/te-morphos.h +new file mode 100644 +index 0000000000000000000000000000000000000000..43b0826fa79d9e9c97485cc6dd7d919771defbf9 +--- /dev/null ++++ gas/config/te-morphos.h +@@ -0,0 +1,14 @@ ++/* ++ * te-amiga.h -- Amiga target environment declarations. ++ */ ++ ++#define TE_MORPHOS 1 ++ ++#define LOCAL_LABELS_DOLLAR 1 ++#define LOCAL_LABELS_FB 1 ++ ++#ifdef OBJ_HEADER ++#include OBJ_HEADER ++#else ++#include "obj-format.h" ++#endif +diff --git a/gas/configure b/gas/configure +index 2e674491f392b756186c52f7b0d28de8a20398c5..6eabef030df837c80ab009e12ad99a3086df5e43 100755 +--- gas/configure ++++ gas/configure +@@ -12500,12 +12500,19 @@ _ACEOF + + cat >>confdefs.h <<_ACEOF + #define DEFAULT_EMULATION "$DEFAULT_EMULATION" + _ACEOF + + ++# FIXME: As of version 2.18 of binutils, MANY_SEGMENTS no longer exists ++#case ${primary_bfd_gas}-${target_cpu_type}-${obj_format} in ++# yes-*-coff) need_bfd=yes ;; ++# no-*-coff | yes-m68k-amigahunk | no-m68k-amigahunk) need_bfd=yes ++# AC_DEFINE(MANY_SEGMENTS, 1, [old COFF support?]) ;; ++#esac ++ + reject_dev_configs=yes + + case ${reject_dev_configs}-${dev} in + yes-yes) # Oops. + as_fn_error "GAS does not support the ${generic_target} configuration." "$LINENO" 5 + ;; +@@ -12549,12 +12556,25 @@ _ACEOF + + cat >>confdefs.h <<_ACEOF + #define TARGET_OS "${target_os}" + _ACEOF + + ++### begin-GG-local ++# Check for additional host specific CFLAGS. ++echo "$as_me:$LINENO: checking for host dependent CFLAGS" >&5 ++echo $ECHO_N "checking for host dependent CFLAGS... $ECHO_C" >&6 ++other_host_cflags="" ++case "${host}" in ++ m68k-*-amigaos*) other_host_cflags="-mstackextend" ;; ++esac ++test -n "$other_host_cflags" && CFLAGS="$CFLAGS $other_host_cflags" ++echo "$as_me:$LINENO: result: $other_host_cflags" >&5 ++echo "${ECHO_T}$other_host_cflags" >&6 ++### end-GG-local ++ + for ac_prog in 'bison -y' byacc + do + # Extract the first word of "$ac_prog", so it can be a program name with args. + set dummy $ac_prog; ac_word=$2 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 + $as_echo_n "checking for $ac_word... " >&6; } +diff --git a/gas/configure.in b/gas/configure.in +index 14f6edfe5deb041e968454931c451e1da226e0d1..183d98e8a4ac56e2e8a7a87f7b824f302bbb04f4 100644 +--- gas/configure.in ++++ gas/configure.in +@@ -598,12 +598,19 @@ if test `set . $emfiles ; shift ; echo $#` -gt 0 ; then + fi + AC_SUBST(extra_objects) + AC_DEFINE_UNQUOTED(EMULATIONS, $EMULATIONS, [Supported emulations.]) + AC_DEFINE_UNQUOTED(DEFAULT_EMULATION, "$DEFAULT_EMULATION", + [Default emulation.]) + ++# FIXME: As of version 2.18 of binutils, MANY_SEGMENTS no longer exists ++#case ${primary_bfd_gas}-${target_cpu_type}-${obj_format} in ++# yes-*-coff) need_bfd=yes ;; ++# no-*-coff | yes-m68k-amigahunk | no-m68k-amigahunk) need_bfd=yes ++# AC_DEFINE(MANY_SEGMENTS, 1, [old COFF support?]) ;; ++#esac ++ + reject_dev_configs=yes + + case ${reject_dev_configs}-${dev} in + yes-yes) # Oops. + AC_MSG_ERROR(GAS does not support the ${generic_target} configuration.) + ;; +@@ -628,12 +635,23 @@ AC_SUBST(OPCODES_LIB) + AC_DEFINE_UNQUOTED(TARGET_ALIAS, "${target_alias}", [Target alias.]) + AC_DEFINE_UNQUOTED(TARGET_CANONICAL, "${target}", [Canonical target.]) + AC_DEFINE_UNQUOTED(TARGET_CPU, "${target_cpu}", [Target CPU.]) + AC_DEFINE_UNQUOTED(TARGET_VENDOR, "${target_vendor}", [Target vendor.]) + AC_DEFINE_UNQUOTED(TARGET_OS, "${target_os}", [Target OS.]) + ++### begin-GG-local ++# Check for additional host specific CFLAGS. ++AC_MSG_CHECKING(for host dependent CFLAGS) ++other_host_cflags="" ++case "${host}" in ++ m68k-*-amigaos*) other_host_cflags="-mstackextend" ;; ++esac ++test -n "$other_host_cflags" && CFLAGS="$CFLAGS $other_host_cflags" ++AC_MSG_RESULT($other_host_cflags) ++### end-GG-local ++ + AC_PROG_YACC + AM_PROG_LEX + + ALL_LINGUAS="fr tr es rw id ru fi ja" + ZW_GNU_GETTEXT_SISTER_DIR + AM_PO_SUBDIRS +diff --git a/gas/configure.tgt b/gas/configure.tgt +index 9e44de000145c39abfd3ea325656a4d4bc066198..61f24acdb98484f43ac0c08d3cacfd38b1c1fb8b 100644 +--- gas/configure.tgt ++++ gas/configure.tgt +@@ -40,13 +40,14 @@ case ${cpu} in + cr16*) cpu_type=cr16 endian=little ;; + crisv32) cpu_type=cris arch=crisv32 ;; + crx*) cpu_type=crx endian=little ;; + epiphany*) cpu_type=epiphany endian=little ;; + fido) cpu_type=m68k ;; + hppa*) cpu_type=hppa ;; +- i[3-7]86) cpu_type=i386 arch=i386;; ++ i[3-7]86) cpu_type=i386 arch=i386 endian=little ;; ++ i[3-7]86) cpu_type=i386 arch=i386 endian=big ;; + ia64) cpu_type=ia64 ;; + ip2k) cpu_type=ip2k endian=big ;; + iq2000) cpu_type=iq2000 endian=big ;; + lm32) cpu_type=lm32 ;; + m32c) cpu_type=m32c endian=little ;; + m32r) cpu_type=m32r endian=big ;; +@@ -181,12 +182,13 @@ case ${generic_target} in + h8300-*-elf | h8300-*-rtems*) fmt=elf ;; + + i370-*-elf* | i370-*-linux*) fmt=elf ;; + + i386-ibm-aix*) fmt=coff em=i386aix ;; + i386-sequent-bsd*) fmt=aout em=dynix ;; ++ i386-*-amithlon*) fmt=elf em=amithlon ;; + i386-*-beospe*) fmt=coff em=pe ;; + i386-*-beos*) fmt=elf ;; + i386-*-coff) fmt=coff ;; + i386-*-elf) fmt=elf ;; + i386-*-kaos*) fmt=elf ;; + i386-*-bsd*) fmt=aout em=386bsd ;; +@@ -271,12 +273,14 @@ case ${generic_target} in + m32r-*-elf* | m32r-*-rtems*) fmt=elf ;; + m32r-*-linux*) fmt=elf em=linux;; + + m68hc11-*-* | m6811-*-*) fmt=elf ;; + m68hc12-*-* | m6812-*-*) fmt=elf ;; + ++ m68k-*-amigaoshunk) fmt=amigahunk em=amiga bfd_gas=yes ;; ++ m68k-*-amigaos*) fmt=aout em=amiga ;; + m68k-*-aout) fmt=aout bfd_gas=yes ;; + m68k-*-elf*) fmt=elf ;; + m68k-*-sysv4*) fmt=elf em=svr4 ;; + m68k-*-rtems*) fmt=elf ;; + m68k-*-linux-*) fmt=elf em=linux ;; + m68k-*-uclinux*) fmt=elf em=uclinux ;; +@@ -338,12 +342,14 @@ case ${generic_target} in + + or32-*-rtems*) fmt=elf ;; + or32-*-elf) fmt=elf ;; + + pj*) fmt=elf ;; + ++ ppc-*-amigaos*) fmt=elf em=amigaos ;; ++ ppc-*-morphos*) fmt=elf em=morphos ;; + ppc-*-pe | ppc-*-cygwin*) fmt=coff em=pe ;; + ppc-*-winnt*) fmt=coff em=pe ;; + ppc-*-aix5.[01]) fmt=coff em=aix5 ;; + ppc-*-aix[5-9].*) fmt=coff em=aix5 ;; + ppc-*-aix*) fmt=coff ;; + ppc-*-beos*) fmt=coff ;; +diff --git a/gas/read.c b/gas/read.c +index 21c42b27342fb8e2c687417bcdacc4c16e3905b7..9de62b9c512025212d52a19833ffe28004944dd1 100644 +--- gas/read.c ++++ gas/read.c +@@ -43,12 +43,16 @@ + #include "wchar.h" + + #ifndef TC_START_LABEL + #define TC_START_LABEL(x,y,z) (x == ':') + #endif + ++#ifdef OBJ_AMIGAHUNK ++extern segT data_chip_section, bss_chip_section; ++#endif ++ + /* Set by the object-format or the target. */ + #ifndef TC_IMPLICIT_LCOMM_ALIGNMENT + #define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) \ + do \ + { \ + if ((SIZE) >= 8) \ +@@ -314,12 +318,15 @@ static const pseudo_typeS potable[] = { + #endif + {"byte", cons, 1}, + {"comm", s_comm, 0}, + {"common", s_mri_common, 0}, + {"common.s", s_mri_common, 1}, + {"data", s_data, 0}, ++#ifdef OBJ_AMIGAHUNK ++ {"datachip", s_data_chip, 0}, ++#endif + {"dc", cons, 2}, + #ifdef TC_ADDRESS_BYTES + {"dc.a", cons, 0}, + #endif + {"dc.b", cons, 1}, + {"dc.d", float_cons, 'd'}, +@@ -1895,12 +1902,22 @@ s_data (int ignore ATTRIBUTE_UNUSED) + + subseg_set (section, (subsegT) temp); + + demand_empty_rest_of_line (); + } + ++#ifdef OBJ_AMIGAHUNK ++void ++s_data_chip (int ignore ATTRIBUTE_UNUSED) ++{ ++ int temp = get_absolute_expression (); ++ subseg_set (data_chip_section, (subsegT) temp); ++ demand_empty_rest_of_line (); ++} ++#endif ++ + /* Handle the .appfile pseudo-op. This is automatically generated by + do_scrub_chars when a preprocessor # line comment is seen with a + file name. This default definition may be overridden by the object + or CPU specific pseudo-ops. This function is also the default + definition for .file; the APPFILE argument is 1 for .appfile, 0 for + .file. */ +@@ -4526,13 +4543,13 @@ emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p) + { + memset (p, 0, nbytes); + + /* Generate a fixS to record the symbol value. */ + + #ifdef TC_CONS_FIX_NEW +- TC_CONS_FIX_NEW (frag, p - frag->fr_literal, nbytes, exp); ++ TC_CONS_FIX_NEW (frag, p - frag->fr_literal, nbytes, exp, 0); + #else + { + bfd_reloc_code_real_type r; + + switch (nbytes) + { +@@ -4554,13 +4571,13 @@ emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p) + default: + as_bad (_("unsupported BFD relocation size %u"), nbytes); + r = BFD_RELOC_32; + break; + } + fix_new_exp (frag, p - frag->fr_literal, (int) nbytes, exp, +- 0, r); ++ 0, r, 0); + } + #endif + } + + #ifdef BITFIELD_CONS_EXPRESSIONS + +diff --git a/gas/read.h b/gas/read.h +index 4e5d1bbd2dc7b0724a2fc047db01f97aec8a4bac..59e787e754a14e11195607d382f81992423584cb 100644 +--- gas/read.h ++++ gas/read.h +@@ -130,12 +130,16 @@ extern void do_repeat (int,const char *,const char *); + extern void do_repeat_with_expander (int, const char *, const char *, const char *); + extern void end_repeat (int); + extern void do_parse_cons_expression (expressionS *, int); + + extern void generate_lineno_debug (void); + ++#ifdef OBJ_AMIGAHUNK ++extern void s_data_chip (int); ++#endif ++ + extern void s_abort (int) ATTRIBUTE_NORETURN; + extern void s_align_bytes (int arg); + extern void s_align_ptwo (int); + extern void bss_alloc (symbolS *, addressT, int); + extern offsetT parse_align (int); + extern symbolS *s_comm_internal (int, symbolS *(*) (int, symbolS *, addressT)); +diff --git a/gas/write.c b/gas/write.c +index 56ebb6c565bea35df43565b53206156270a41b66..8a9746c927a3e8b7007cdec9c7f16e47509b5f45 100644 +--- gas/write.c ++++ gas/write.c +@@ -149,13 +149,14 @@ fix_new_internal (fragS *frag, /* Which frag? */ + int size, /* 1, 2, or 4 usually. */ + symbolS *add_symbol, /* X_add_symbol. */ + symbolS *sub_symbol, /* X_op_symbol. */ + offsetT offset, /* X_add_number. */ + int pcrel, /* TRUE if PC-relative relocation. */ + RELOC_ENUM r_type /* Relocation type. */, +- int at_beginning) /* Add to the start of the list? */ ++ int at_beginning, /* Add to the start of the list? */ ++ int baserel ATTRIBUTE_UNUSED) /* TRUE if base-relative data */ + { + fixS *fixP; + + n_fixups++; + + fixP = (fixS *) obstack_alloc (¬es, sizeof (fixS)); +@@ -188,14 +189,17 @@ fix_new_internal (fragS *frag, /* Which frag? */ + #ifdef USING_CGEN + fixP->fx_cgen.insn = NULL; + fixP->fx_cgen.opinfo = 0; + #endif + + #ifdef TC_FIX_TYPE ++#ifndef TC_PPC ++ fixP->tc_fix_data = baserel; + TC_INIT_FIX_DATA (fixP); + #endif ++#endif + + as_where (&fixP->fx_file, &fixP->fx_line); + + { + + fixS **seg_fix_rootP = (frags_chained +@@ -232,29 +236,31 @@ fixS * + fix_new (fragS *frag, /* Which frag? */ + int where, /* Where in that frag? */ + int size, /* 1, 2, or 4 usually. */ + symbolS *add_symbol, /* X_add_symbol. */ + offsetT offset, /* X_add_number. */ + int pcrel, /* TRUE if PC-relative relocation. */ +- RELOC_ENUM r_type /* Relocation type. */) ++ RELOC_ENUM r_type, /* Relocation type. */ ++ int baserel) /* TRUE if base-relative data */ + { + return fix_new_internal (frag, where, size, add_symbol, +- (symbolS *) NULL, offset, pcrel, r_type, FALSE); ++ (symbolS *) NULL, offset, pcrel, r_type, FALSE, baserel); + } + + /* Create a fixup for an expression. Currently we only support fixups + for difference expressions. That is itself more than most object + file formats support anyhow. */ + + fixS * + fix_new_exp (fragS *frag, /* Which frag? */ + int where, /* Where in that frag? */ + int size, /* 1, 2, or 4 usually. */ + expressionS *exp, /* Expression. */ + int pcrel, /* TRUE if PC-relative relocation. */ +- RELOC_ENUM r_type /* Relocation type. */) ++ RELOC_ENUM r_type, /* Relocation type. */ ++ int baserel) /* TRUE if base-relative data */ + { + symbolS *add = NULL; + symbolS *sub = NULL; + offsetT off = 0; + + switch (exp->X_op) +@@ -274,13 +280,13 @@ fix_new_exp (fragS *frag, /* Which frag? */ + + exp->X_op = O_symbol; + exp->X_op_symbol = 0; + exp->X_add_symbol = stmp; + exp->X_add_number = 0; + +- return fix_new_exp (frag, where, size, exp, pcrel, r_type); ++ return fix_new_exp (frag, where, size, exp, pcrel, r_type, baserel); + } + + case O_symbol_rva: + add = exp->X_add_symbol; + off = exp->X_add_number; + r_type = BFD_RELOC_RVA; +@@ -304,24 +310,24 @@ fix_new_exp (fragS *frag, /* Which frag? */ + default: + add = make_expr_symbol (exp); + break; + } + + return fix_new_internal (frag, where, size, add, sub, off, pcrel, +- r_type, FALSE); ++ r_type, FALSE, baserel); + } + + /* Create a fixup at the beginning of FRAG. The arguments are the same + as for fix_new, except that WHERE is implicitly 0. */ + + fixS * + fix_at_start (fragS *frag, int size, symbolS *add_symbol, + offsetT offset, int pcrel, RELOC_ENUM r_type) + { + return fix_new_internal (frag, 0, size, add_symbol, +- (symbolS *) NULL, offset, pcrel, r_type, TRUE); ++ (symbolS *) NULL, offset, pcrel, r_type, TRUE, 0); + } + + /* Generic function to determine whether a fixup requires a relocation. */ + int + generic_force_reloc (fixS *fix) + { +@@ -892,12 +898,19 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED, + For each one, call md_apply_fix to put the fix into the frag data. + + Result is a count of how many relocation structs will be needed to + handle the remaining fixS's that we couldn't completely handle here. + These will be output later by emit_relocations(). */ + ++/* FIXME: There was following code here ++#if !defined(BFD_ASSEMBLER) && !defined(MANY_SEGMENTS) ++ if (fixP->tc_fix_data && add_number != fixP->fx_offset) ++ add_number -= text_last_frag->fr_address; ++#endif ++*/ ++ + static long + fixup_segment (fixS *fixP, segT this_segment) + { + long seg_reloc_count = 0; + valueT add_number; + fragS *fragP; +@@ -1890,17 +1903,17 @@ write_object_file (void) + exp.X_add_symbol = lie->add; + exp.X_op_symbol = lie->sub; + exp.X_add_number = lie->addnum; + #ifdef TC_CONS_FIX_NEW + TC_CONS_FIX_NEW (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, +- 2, &exp); ++ 2, &exp, 0); + #else + fix_new_exp (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, +- 2, &exp, 0, BFD_RELOC_16); ++ 2, &exp, 0, BFD_RELOC_16, 0); + #endif + *prevP = lie->next_broken_word; + } + else + prevP = &(lie->next_broken_word); + +diff --git a/gas/write.h b/gas/write.h +index 8303f1be98b6548e4e30a326f042f78e07aed7f5..5f3598655b2665fa86d7b5291643f563536e2f31 100644 +--- gas/write.h ++++ gas/write.h +@@ -172,16 +172,16 @@ extern void write_object_file (void); + extern long relax_frag (segT, fragS *, long); + extern int relax_segment (struct frag *, segT, int); + extern void number_to_chars_littleendian (char *, valueT, int); + extern void number_to_chars_bigendian (char *, valueT, int); + extern fixS *fix_new + (fragS * frag, int where, int size, symbolS * add_symbol, +- offsetT offset, int pcrel, bfd_reloc_code_real_type r_type); ++ offsetT offset, int pcrel, bfd_reloc_code_real_type r_type, int baserel); + extern fixS *fix_at_start + (fragS * frag, int size, symbolS * add_symbol, + offsetT offset, int pcrel, bfd_reloc_code_real_type r_type); + extern fixS *fix_new_exp + (fragS * frag, int where, int size, expressionS *exp, int pcrel, +- bfd_reloc_code_real_type r_type); ++ bfd_reloc_code_real_type r_type, int baserel); + extern void write_print_statistics (FILE *); + + #endif /* __write_h__ */ +diff --git a/gprof/Makefile.am b/gprof/Makefile.am +index edd100ac924458a1e69da65cab55ddb6a3b61555..286d29546ecdfa6cfafbfc7f7fb83a0fdeadfb83 100644 +--- gprof/Makefile.am ++++ gprof/Makefile.am +@@ -36,13 +36,13 @@ noinst_HEADERS = \ + corefile.h gmon.h gmon_io.h gmon_out.h gprof.h hertz.h hist.h \ + search_list.h source.h sym_ids.h symtab.h utils.h + + BUILT_SOURCES = flat_bl.c bsd_callg_bl.c fsf_callg_bl.c + EXTRA_DIST = $(BUILT_SOURCES) bbconv.pl $(man_MANS) + +-diststuff: $(BUILT_SOURCES) info $(man_MANS) ++diststuff: $(BUILT_SOURCES) info guide $(man_MANS) + + # We extract version from bfd/configure.in, make sure to rerun configure + # when BFD's version changes. + CONFIG_STATUS_DEPENDENCIES = $(BFDDIR)/configure.in + + # This empty rule is a hack against gmake patched by Apple. +diff --git a/gprof/Makefile.in b/gprof/Makefile.in +index a9d7073c799863dc3b39124f83dbcba73bf8bf85..4d487c22a56406d567643a6bd53310e501fa99aa 100644 +--- gprof/Makefile.in ++++ gprof/Makefile.in +@@ -1013,13 +1013,13 @@ uninstall-man: uninstall-man1 + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-binPROGRAMS uninstall-dvi-am \ + uninstall-html-am uninstall-info-am uninstall-man \ + uninstall-man1 uninstall-pdf-am uninstall-ps-am + + +-diststuff: $(BUILT_SOURCES) info $(man_MANS) ++diststuff: $(BUILT_SOURCES) info guide $(man_MANS) + + # This empty rule is a hack against gmake patched by Apple. + %.o:%.m + + .m.c: + awk -f $(srcdir)/gen-c-prog.awk > ./$*.c \ +diff --git a/gprof/configure b/gprof/configure +index 6ffdbe30cef942eb7e28f26674b03c8ff5907711..665d5009457e7e17d7acc0c8bfb81301cd546b32 100755 +--- gprof/configure ++++ gprof/configure +@@ -11850,12 +11850,25 @@ $as_echo "found xgettext program is not GNU xgettext; ignore it" >&6; } + fi + + ac_config_commands="$ac_config_commands default-1" + + + ++### begin-GG-local ++# Check for additional host specific CFLAGS. ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for host dependent CFLAGS" >&5 ++$as_echo_n "checking for host dependent CFLAGS... " >&6; } ++other_host_cflags="" ++case "${host}" in ++ m68*-*-amigaos*) other_host_cflags="-mstackextend" ;; ++esac ++test -n "$other_host_cflags" && CFLAGS="$CFLAGS $other_host_cflags" ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $other_host_cflags" >&5 ++$as_echo "$other_host_cflags" >&6; } ++### end-GG-local ++ + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 + $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. + if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +diff --git a/gprof/configure.in b/gprof/configure.in +index 631e3e467314f3740c737f1534537c7532a00d08..7b4586b0aeee56169f321af15214054feec0c349 100644 +--- gprof/configure.in ++++ gprof/configure.in +@@ -28,12 +28,23 @@ LT_INIT + AC_CHECK_FUNCS(setmode) + + ALL_LINGUAS="fr tr sv es id da pt_BR de vi rw ga ms fi nl bg eo ja sr" + ZW_GNU_GETTEXT_SISTER_DIR + AM_PO_SUBDIRS + ++### begin-GG-local ++# Check for additional host specific CFLAGS. ++AC_MSG_CHECKING(for host dependent CFLAGS) ++other_host_cflags="" ++case "${host}" in ++ m68*-*-amigaos*) other_host_cflags="-mstackextend" ;; ++esac ++test -n "$other_host_cflags" && CFLAGS="$CFLAGS $other_host_cflags" ++AC_MSG_RESULT($other_host_cflags) ++### end-GG-local ++ + AM_MAINTAINER_MODE + AM_CONDITIONAL(GENINSRC_NEVER, false) + AC_EXEEXT + + AC_CHECK_HEADERS(sys/gmon_out.h) + +diff --git a/gprof/gconfig.in b/gprof/gconfig.in +index 25679910ee73fb2ae8f1c3f7b1cb2951166da71f..4ad8775fd559a1c06b6f572b4af24ca46f7f7f3e 100644 +--- gprof/gconfig.in ++++ gprof/gconfig.in +@@ -1,12 +1,8 @@ + /* gconfig.in. Generated from configure.in by autoheader. */ + +-/* Define to 1 if translation of program messages to the user's native +- language is requested. */ +-#undef ENABLE_NLS +- + /* Is the prototype for getopt in <unistd.h> in the expected format? */ + #undef HAVE_DECL_GETOPT + + /* Define to 1 if you have the <dlfcn.h> header file. */ + #undef HAVE_DLFCN_H + +diff --git a/include/elf/amigaos.h b/include/elf/amigaos.h +new file mode 100644 +index 0000000000000000000000000000000000000000..2cbcd490a300f0248aecf2ca6d50865181a3c1f0 +--- /dev/null ++++ include/elf/amigaos.h +@@ -0,0 +1,27 @@ ++/* AmigaOS ELF support for BFD. ++ Copyright 2001 Free Software Foundation, Inc. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software Foundation, Inc., ++51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++#ifndef _ELF_AMIGAOS_H ++#define _ELF_AMIGAOS_H ++ ++#include "elf/common.h" ++ ++#define DT_AMIGAOS_DYNVERSION (DT_LOOS + 1) ++ ++#endif /* _ELF_AMIGAOS_H */ +diff --git a/include/elf/ppc.h b/include/elf/ppc.h +index f80a1e8a3e9c5852902beaafbb6a2a9e36d815c3..9893a88d96a77d730d91ef2bfe89a18d75029dd1 100644 +--- include/elf/ppc.h ++++ include/elf/ppc.h +@@ -128,12 +128,18 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type) + RELOC_NUMBER (R_PPC_EMB_RELST_LO, 112) + RELOC_NUMBER (R_PPC_EMB_RELST_HI, 113) + RELOC_NUMBER (R_PPC_EMB_RELST_HA, 114) + RELOC_NUMBER (R_PPC_EMB_BIT_FLD, 115) + RELOC_NUMBER (R_PPC_EMB_RELSDA, 116) + ++/* AmigaOS4 relocs */ ++ RELOC_NUMBER (R_PPC_AMIGAOS_BREL, 210) ++ RELOC_NUMBER (R_PPC_AMIGAOS_BREL_LO, 211) ++ RELOC_NUMBER (R_PPC_AMIGAOS_BREL_HI, 212) ++ RELOC_NUMBER (R_PPC_AMIGAOS_BREL_HA, 213) ++ + /* PowerPC VLE relocations. */ + RELOC_NUMBER (R_PPC_VLE_REL8, 216) + RELOC_NUMBER (R_PPC_VLE_REL15, 217) + RELOC_NUMBER (R_PPC_VLE_REL24, 218) + RELOC_NUMBER (R_PPC_VLE_LO16A, 219) + RELOC_NUMBER (R_PPC_VLE_LO16D, 220) +diff --git a/include/libiberty.h b/include/libiberty.h +index cacde800ea3dda438ea8292ab4b9354a63ad048b..595ecf48242a2067dd71c4dda07a57994bdb4981 100644 +--- include/libiberty.h ++++ include/libiberty.h +@@ -103,13 +103,13 @@ extern int countargv (char**); + /* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is + undefined, we haven't run the autoconf check so provide the + declaration without arguments. If it is 0, we checked and failed + to find the declaration so provide a fully prototyped one. If it + is 1, we found it so don't provide any declaration at all. */ + #if !HAVE_DECL_BASENAME +-#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__) || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) || defined (HAVE_DECL_BASENAME) ++#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__) || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) || defined(AMIGA) || defined (HAVE_DECL_BASENAME) + extern char *basename (const char *); + #else + /* Do not allow basename to be used if there is no prototype seen. We + either need to use the above prototype or have one from + autoconf which would result in HAVE_DECL_BASENAME being set. */ + #define basename basename_cannot_be_used_without_a_prototype +diff --git a/ld/ChangeLog-9197 b/ld/ChangeLog-9197 +index 9307f333e3b156758598c19ff0873c21fc1dad29..0f0e189765f0438cd3bbd7a04f36c8e006cef91c 100644 +--- ld/ChangeLog-9197 ++++ ld/ChangeLog-9197 +@@ -144,12 +144,17 @@ Wed Oct 22 11:29:25 1997 Ian Lance Taylor <ian@cygnus.com> + Fri Oct 17 00:00:13 1997 Richard Henderson <rth@cygnus.com> + + * ldlang.c (lang_register_vers_node): Only check globals<=>locals, + since we need to be able to export different versions of the same + symbol. + ++Thu Oct 16 13:21:14 1997 Fred Fish <fnf@ninemoons.com> ++ ++ * ldlang.c (new_afile): Only reference amiga_attribute when ++ the target is AmigaOS. ++ + Wed Oct 15 14:52:36 1997 Ian Lance Taylor <ian@cygnus.com> + + * scripttempl/pe.sc: Put .stab and .stabstr sections at end. + + Wed Oct 8 12:37:05 1997 Richard Henderson <rth@cygnus.com> + +@@ -1280,12 +1285,18 @@ Mon Aug 5 16:26:14 1996 Ian Lance Taylor <ian@cygnus.com> + + * ldgram.y (SIZEOF, ADDR): Do not specify type. + + * ldcref.c (check_nocrossref): Skip symbols with no output + sections. + ++Sun Aug 4 22:15:56 1996 Fred Fish <fnf@ninemoons.com> ++ ++ * ldfile.c (ldfile_open_file_search): Use alloca to allocate ++ dynamically sized array, rather than using a GNU C extension that ++ is not portable. ++ + Fri Aug 2 14:57:49 1996 Ian Lance Taylor <ian@cygnus.com> + + * ldgram.y (LOADADDR): New terminal. + (exp): Handle LOADADDR. + * ldlex.l: Recognize LOADADDR. + * ldexp.c (exp_print_token): Add LOADADDR. +@@ -1506,12 +1517,16 @@ Mon Jun 24 12:00:32 1996 Ian Lance Taylor <ian@cygnus.com> + at 0. + + * configure.in: On alpha*-*-osf*, link against libbfd.a if not + using shared libraries. + * configure: Rebuild with autoconf 2.10. + ++Sat Jun 22 21:41:37 1996 Daniel Verite <daniel@brainstorm.eu.org> ++ ++ * ldfile.c, lexsup.c: Sort the flavors. ++ + Fri Jun 21 17:40:56 1996 Joel Sherrill <joel@merlin.gcs.redstone.army.mil> + + * configure.tgt: Add support for *-*-rtems* configurations. + + Fri Jun 21 13:05:51 1996 Richard Henderson <rth@tamu.edu> + +diff --git a/ld/ChangeLog-9899 b/ld/ChangeLog-9899 +index 866e4a0cfbb8a086ae01716e4a806e3386914cab..de288123cb7b80422bfc2973640bbdd16c6af900 100644 +--- ld/ChangeLog-9899 ++++ ld/ChangeLog-9899 +@@ -1881,12 +1881,17 @@ Wed Mar 18 09:42:24 1998 Nick Clifton <nickc@cygnus.com> + * configure.tgt (targ_extra_emuls): Add thumb-pe target. + + Sun Mar 8 23:34:14 1998 Stan Cox <scox@equinox.cygnus.com> + + * configure.tgt (sparclite*-*-elf): Added. + ++Sun Mar 8 20:25:09 1998 Daniel Verite <daniel@brainstorm.fr> ++ ++ * ldlang.c (new_afile): Remove obsolete references to ++ amiga_attribute. ++ + Mon Mar 2 19:24:08 1998 Michael Meissner <meissner@cygnus.com> + + * ldlang.c (lang_size_sections): If the default memory region is + *default*, see if there is a memory region that could be used. + + Thu Feb 26 17:09:53 1998 Michael Meissner <meissner@cygnus.com> +diff --git a/ld/Makefile.am b/ld/Makefile.am +index e343ab06531054392ae09d67ecb2dc3022053c07..cbaa4c736f8e87f05a60d8580174e207069872fd 100644 +--- ld/Makefile.am ++++ ld/Makefile.am +@@ -128,12 +128,16 @@ LIBIBERTY = ../libiberty/libiberty.a + + ALL_EMULATION_SOURCES = \ + eaix5ppc.c \ + eaix5rs6.c \ + eaixppc.c \ + eaixrs6.c \ ++ eamiga.c \ ++ eamiga_bss.c \ ++ eamigaos.c \ ++ eamithlon.c \ + ealpha.c \ + ealphavms.c \ + earcelf.c \ + earm_epoc_pe.c \ + earm_wince_pe.c \ + earmaoutb.c \ +@@ -336,12 +340,14 @@ ALL_EMULATION_SOURCES = \ + emipsbsd.c \ + emipsidt.c \ + emipsidtl.c \ + emipslit.c \ + emipslnews.c \ + emipspe.c \ ++ emorphos.c \ ++ emorphos_baserel.c \ + emn10200.c \ + emn10300.c \ + emsp430x110.c \ + emsp430x1101.c \ + emsp430x1111.c \ + emsp430x112.c \ +@@ -403,12 +409,14 @@ ALL_EMULATION_SOURCES = \ + enews.c \ + ens32knbsd.c \ + eor32.c \ + eor32elf.c \ + epc532macha.c \ + epdp11.c \ ++ eppcamiga.c \ ++ eppcamiga_bss.c \ + epjelf.c \ + epjlelf.c \ + eppclynx.c \ + eppcmacos.c \ + eppcnw.c \ + eppcpe.c \ +@@ -661,12 +669,26 @@ GENSCRIPTS = LIB_PATH='${LIB_PATH}' $(SHELL) $(srcdir)/genscripts.sh "${srcdir}" + GEN_DEPENDS = $(srcdir)/genscripts.sh stringify.sed + ELF_DEPS = $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/elf-generic.em + ELF_GEN_DEPS = $(srcdir)/emultempl/generic.em $(srcdir)/emultempl/elf-generic.em $(srcdir)/emultempl/genelf.em + + @TDIRS@ + ++eamiga.c: $(srcdir)/emulparams/amiga.sh\ ++ $(srcdir)/emultempl/amiga.em $(srcdir)/scripttempl/amiga.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} amiga "$(tdir_amiga)" ++eamiga_bss.c: $(srcdir)/emulparams/amiga_bss.sh\ ++ $(srcdir)/emultempl/amiga.em $(srcdir)/scripttempl/amiga_bss.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} amiga_bss "$(tdir_amiga_bss)" ++eamigaos.c: $(srcdir)/emulparams/amigaos.sh \ ++ $(srcdir)/emulparams/amigaos.sh $(srcdir)/emultempl/amigaos.em \ ++ ldemul-list.h \ ++ $(ELF_DEPS) $(srcdir)/scripttempl/amigaos.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} amigaos "$(tdir_amigaos)" ++eamithlon.c: $(srcdir)/emulparams/amithlon.sh \ ++ $(srcdir)/emultempl/amithlon.em $(srcdir)/scripttempl/amithlon.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} amithlon "$(tdir_amithlon)" + eaix5ppc.c: $(srcdir)/emulparams/aix5ppc.sh \ + $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS} + ${GENSCRIPTS} aix5ppc "$(tdir_aixppc)" + eaix5rs6.c: $(srcdir)/emulparams/aix5rs6.sh \ + $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS} + ${GENSCRIPTS} aix5rs6 "$(tdir_aixrs6)" +@@ -1472,12 +1494,18 @@ emipslit.c: $(srcdir)/emulparams/mipslit.sh $(srcdir)/emultempl/generic.em \ + emipslnews.c: $(srcdir)/emulparams/mipslnews.sh \ + $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/mips.sc ${GEN_DEPENDS} + ${GENSCRIPTS} mipslnews "$(tdir_mipslnews)" + emipspe.c: $(srcdir)/emulparams/mipspe.sh $(srcdir)/emultempl/pe.em \ + $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS} + ${GENSCRIPTS} mipspe "$(tdir_mipspe)" ++emorphos.c: $(srcdir)/emulparams/morphos.sh \ ++ $(srcdir)/emultempl/morphos.em $(srcdir)/scripttempl/morphos.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} morphos "$(tdir_morphos)" ++emorphos_baserel.c: $(srcdir)/emulparams/morphos_baserel.sh \ ++ $(srcdir)/emultempl/morphos.em $(srcdir)/scripttempl/morphos_baserel.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} morphos_baserel "$(tdir_morphos)" + emn10200.c: $(srcdir)/emulparams/mn10200.sh \ + $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} mn10200 "$(tdir_mn10200)" + emn10300.c: $(srcdir)/emulparams/mn10300.sh \ + $(srcdir)/emulparams/mn10200.sh \ + $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} +@@ -1756,12 +1784,22 @@ epdp11.c: $(srcdir)/emulparams/pdp11.sh \ + epjelf.c: $(srcdir)/emulparams/pjelf.sh \ + $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} pjelf "$(tdir_pjelf)" + epjlelf.c: $(srcdir)/emulparams/pjlelf.sh $(srcdir)/emulparams/pjelf.sh \ + $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} pjlelf "$(tdir_pjlelf)" ++eppcamiga.c: $(srcdir)/emulparams/ppcamiga.sh \ ++ $(srcdir)/emulparams/ppcamiga.sh $(srcdir)/emultempl/ppcamiga.em \ ++ ldemul-list.h \ ++ $(ELF_DEPS) $(srcdir)/scripttempl/ppcamiga.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} ppcamiga "$(tdir_ppcamiga)" ++eppcamiga_bss.c: $(srcdir)/emulparams/ppcamiga_bss.sh \ ++ $(srcdir)/emulparams/ppcamiga_bss.sh $(srcdir)/emultempl/ppcamiga_bss.em \ ++ ldemul-list.h \ ++ $(ELF_DEPS) $(srcdir)/scripttempl/ppcamiga_bss.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} ppcamiga_bss "$(tdir_ppcamiga_bss)" + eppclynx.c: $(srcdir)/emulparams/ppclynx.sh \ + $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} ppclynx "$(tdir_ppclynx)" + eppcmacos.c: $(srcdir)/emulparams/ppcmacos.sh \ + $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS} + ${GENSCRIPTS} ppcmacos "$(tdir_ppcmacos)" +diff --git a/ld/Makefile.in b/ld/Makefile.in +index 7da93b46501b8f8aa076134b903e1cdf34025941..43947832717c60ff3a89a8fcea838f5151afd56e 100644 +--- ld/Makefile.in ++++ ld/Makefile.in +@@ -435,12 +435,16 @@ BFDLIB = ../bfd/libbfd.la + LIBIBERTY = ../libiberty/libiberty.a + ALL_EMULATION_SOURCES = \ + eaix5ppc.c \ + eaix5rs6.c \ + eaixppc.c \ + eaixrs6.c \ ++ eamiga.c \ ++ eamiga_bss.c \ ++ eamigaos.c \ ++ eamithlon.c \ + ealpha.c \ + ealphavms.c \ + earcelf.c \ + earm_epoc_pe.c \ + earm_wince_pe.c \ + earmaoutb.c \ +@@ -643,12 +647,14 @@ ALL_EMULATION_SOURCES = \ + emipsbsd.c \ + emipsidt.c \ + emipsidtl.c \ + emipslit.c \ + emipslnews.c \ + emipspe.c \ ++ emorphos.c \ ++ emorphos_baserel.c \ + emn10200.c \ + emn10300.c \ + emsp430x110.c \ + emsp430x1101.c \ + emsp430x1111.c \ + emsp430x112.c \ +@@ -710,12 +716,14 @@ ALL_EMULATION_SOURCES = \ + enews.c \ + ens32knbsd.c \ + eor32.c \ + eor32elf.c \ + epc532macha.c \ + epdp11.c \ ++ eppcamiga.c \ ++ eppcamiga_bss.c \ + epjelf.c \ + epjlelf.c \ + eppclynx.c \ + eppcmacos.c \ + eppcnw.c \ + eppcpe.c \ +@@ -1063,12 +1071,16 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eaix5ppc.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eaix5rs6.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eaixppc.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eaixrs6.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ealpha.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ealphavms.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eamiga.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eamiga_bss.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eamigaos.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eamithlon.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earcelf.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earm_epoc_pe.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earm_wince_pe.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earmaoutb.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earmaoutl.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/earmcoff.Po@am__quote@ +@@ -1299,12 +1311,14 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emipslit.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emipslnews.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emipspe.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emmo.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emn10200.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emn10300.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emorphos.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emorphos_baserel.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x110.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1101.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1111.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x112.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1121.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1122.Po@am__quote@ +@@ -1366,12 +1380,14 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eor32.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eor32elf.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epc532macha.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epdp11.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epjelf.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epjlelf.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppcamiga.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppcamiga_bss.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppclynx.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppcmacos.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppcnw.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eppcpe.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eriscix.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/escore3_elf.Po@am__quote@ +@@ -2131,12 +2147,26 @@ ldemul-list.h: Makefile + + stringify.sed: ${srcdir}/emultempl/$(STRINGIFY) + cp ${srcdir}/emultempl/$(STRINGIFY) stringify.sed + + @TDIRS@ + ++eamiga.c: $(srcdir)/emulparams/amiga.sh\ ++ $(srcdir)/emultempl/amiga.em $(srcdir)/scripttempl/amiga.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} amiga "$(tdir_amiga)" ++eamiga_bss.c: $(srcdir)/emulparams/amiga_bss.sh\ ++ $(srcdir)/emultempl/amiga.em $(srcdir)/scripttempl/amiga_bss.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} amiga_bss "$(tdir_amiga_bss)" ++eamigaos.c: $(srcdir)/emulparams/amigaos.sh \ ++ $(srcdir)/emulparams/amigaos.sh $(srcdir)/emultempl/amigaos.em \ ++ ldemul-list.h \ ++ $(ELF_DEPS) $(srcdir)/scripttempl/amigaos.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} amigaos "$(tdir_amigaos)" ++eamithlon.c: $(srcdir)/emulparams/amithlon.sh \ ++ $(srcdir)/emultempl/amithlon.em $(srcdir)/scripttempl/amithlon.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} amithlon "$(tdir_amithlon)" + eaix5ppc.c: $(srcdir)/emulparams/aix5ppc.sh \ + $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS} + ${GENSCRIPTS} aix5ppc "$(tdir_aixppc)" + eaix5rs6.c: $(srcdir)/emulparams/aix5rs6.sh \ + $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS} + ${GENSCRIPTS} aix5rs6 "$(tdir_aixrs6)" +@@ -2942,12 +2972,18 @@ emipslit.c: $(srcdir)/emulparams/mipslit.sh $(srcdir)/emultempl/generic.em \ + emipslnews.c: $(srcdir)/emulparams/mipslnews.sh \ + $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/mips.sc ${GEN_DEPENDS} + ${GENSCRIPTS} mipslnews "$(tdir_mipslnews)" + emipspe.c: $(srcdir)/emulparams/mipspe.sh $(srcdir)/emultempl/pe.em \ + $(srcdir)/scripttempl/pe.sc ${GEN_DEPENDS} + ${GENSCRIPTS} mipspe "$(tdir_mipspe)" ++emorphos.c: $(srcdir)/emulparams/morphos.sh \ ++ $(srcdir)/emultempl/morphos.em $(srcdir)/scripttempl/morphos.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} morphos "$(tdir_morphos)" ++emorphos_baserel.c: $(srcdir)/emulparams/morphos_baserel.sh \ ++ $(srcdir)/emultempl/morphos.em $(srcdir)/scripttempl/morphos_baserel.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} morphos_baserel "$(tdir_morphos)" + emn10200.c: $(srcdir)/emulparams/mn10200.sh \ + $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} mn10200 "$(tdir_mn10200)" + emn10300.c: $(srcdir)/emulparams/mn10300.sh \ + $(srcdir)/emulparams/mn10200.sh \ + $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} +@@ -3226,12 +3262,22 @@ epdp11.c: $(srcdir)/emulparams/pdp11.sh \ + epjelf.c: $(srcdir)/emulparams/pjelf.sh \ + $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} pjelf "$(tdir_pjelf)" + epjlelf.c: $(srcdir)/emulparams/pjlelf.sh $(srcdir)/emulparams/pjelf.sh \ + $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} pjlelf "$(tdir_pjlelf)" ++eppcamiga.c: $(srcdir)/emulparams/ppcamiga.sh \ ++ $(srcdir)/emulparams/ppcamiga.sh $(srcdir)/emultempl/ppcamiga.em \ ++ ldemul-list.h \ ++ $(ELF_DEPS) $(srcdir)/scripttempl/ppcamiga.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} ppcamiga "$(tdir_ppcamiga)" ++eppcamiga_bss.c: $(srcdir)/emulparams/ppcamiga_bss.sh \ ++ $(srcdir)/emulparams/ppcamiga_bss.sh $(srcdir)/emultempl/ppcamiga_bss.em \ ++ ldemul-list.h \ ++ $(ELF_DEPS) $(srcdir)/scripttempl/ppcamiga_bss.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} ppcamiga_bss "$(tdir_ppcamiga_bss)" + eppclynx.c: $(srcdir)/emulparams/ppclynx.sh \ + $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} ppclynx "$(tdir_ppclynx)" + eppcmacos.c: $(srcdir)/emulparams/ppcmacos.sh \ + $(srcdir)/emultempl/aix.em $(srcdir)/scripttempl/aix.sc ${GEN_DEPENDS} + ${GENSCRIPTS} ppcmacos "$(tdir_ppcmacos)" +diff --git a/ld/configure.host b/ld/configure.host +index f47b961176fa37c2786aa9ff322b21b06081cdfd..c7e1e700c24e48e783d07023b678dbd59bee0b11 100644 +--- ld/configure.host ++++ ld/configure.host +@@ -170,12 +170,16 @@ mips*-sgi-irix4* | mips*-sgi-irix5*) + + mips*-sgi-irix6*) + HOSTING_CRT0='/usr/lib32/crt1.o `if [ -f ../gcc/crtbegin.o ]; then echo ../gcc/crtbegin.o ; else ${CC} -print-file-name=crtbegin.o; fi`' + HOSTING_LIBS='-L/usr/lib32 '"$HOSTING_LIBS"' `if [ -f ../gcc/crtend.o ]; then echo ../gcc/crtend.o ; else ${CC} -print-file-name=crtend.o; fi` /usr/lib32/crtn.o -init __do_global_ctors -fini __do_global_dtors' + ;; + ++m68*-*-amigaos*) ++ HDEFINES=-mstackextend ++ ;; ++ + m68*-motorola-sysv) + HOSTING_CRT0='`if [ -f ../gcc/crt0.o ]; then echo ../gcc/crt0.o; elif [ -f \`${CC} -print-file-name=\`crt0.o ]; then echo \`${CC} -print-file-name=\`crt0.o; else echo /lib/crt0.o; fi`' + HOSTING_LIBS=`sed -e 's,-lc,-lc881,' <<EOF + $HOSTING_LIBS + EOF` + ;; +diff --git a/ld/configure.tgt b/ld/configure.tgt +index 72bc5bca48d7c93f838de826a0685c13ef1db3c2..ddba96d6da87eb2f033eae77509639b6a630ec2a 100644 +--- ld/configure.tgt ++++ ld/configure.tgt +@@ -298,12 +298,13 @@ x86_64-*-pe | x86_64-*-pep) targ_emul=i386pep ; + targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" ;; + x86_64-*-mingw*) targ_emul=i386pep ; + targ_extra_emuls=i386pe + targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o" ;; + i[3-7]86-*-interix*) targ_emul=i386pe_posix; + targ_extra_ofiles="deffilep.o pe-dll.o" ;; ++i[3-7]86be-*-amithlon*) targ_emul=amithlon;; + i[3-7]86-*-beospe*) targ_emul=i386beos ;; + i[3-7]86-*-beos*) targ_emul=elf_i386_be ;; + i[3-7]86-*-vxworks*) targ_emul=elf_i386_vxworks ;; + i[3-7]86-*-chaos) targ_emul=elf_i386_chaos + ;; + i[3-7]86-*-nacl*) targ_emul=elf_i386_nacl +@@ -362,12 +363,13 @@ m68*-sun-sunos[34]*) targ_emul=sun3 ;; + m68*-wrs-vxworks*) targ_emul=sun3 ;; + m68*-ericsson-ose) targ_emul=sun3 ;; + m68*-apple-aux*) targ_emul=m68kaux ;; + m68k-sony-*) targ_emul=news ;; + m68k-hp-bsd*) targ_emul=hp300bsd ;; + m68*-motorola-sysv*) targ_emul=delta68 ;; ++m68*-*-amigaos*) targ_emul=amiga ; targ_extra_emuls=amiga_bss;; + m68*-*-aout) targ_emul=m68kaout ;; + m68*-*-coff) targ_emul=m68kcoff ;; + m68*-*-elf) targ_emul=m68kelf ;; + m68*-*-hpux*) targ_emul=hp3hpux ;; + m68k-*-linux*aout*) targ_emul=m68klinux + targ_extra_emuls=m68kelf +@@ -488,12 +490,15 @@ or32-*-rtems*) targ_emul=or32elf + ;; + pdp11-*-*) targ_emul=pdp11 + ;; + pjl*-*-*) targ_emul=pjlelf ; targ_extra_emuls="elf_i386" ;; + pj*-*-*) targ_emul=pjelf + ;; ++powerpc-*-amigaos*) targ_emul=amigaos; targ_extra_emuls=elf32ppc ;; ++powerpc-*-amigaoshunk*) targ_emul=ppcamiga ; targ_extra_emuls=ppcamiga_bss;; ++powerpc-*-morphos*) targ_emul=morphos ; targ_extra_emuls=morphos_baserel;; + powerpc-*-freebsd* | powerpc-*-kfreebsd*-gnu) + targ_emul=elf32ppc_fbsd + targ_extra_emuls="elf32ppc elf32ppcsim" + targ_extra_libpath=elf32ppc; + tdir_elf32ppcsim=`echo ${targ_alias} | sed -e 's/ppc/ppcsim/'` ;; + powerpc64-*-freebsd*) +@@ -780,11 +785,15 @@ i[03-9x]86-*-cygwin*) + *-*-linux*) + ;; + + *-*-netbsd*) + ;; + ++powerpc-*-amigaos*) ++ NATIVE_LIB_DIRS='/gcc/local/lib /gcc/lib' ++ ;; ++ + alpha*-*-*) + NATIVE_LIB_DIRS='/usr/local/lib /usr/ccs/lib /lib /usr/lib' + ;; + + esac +diff --git a/ld/emulparams/amiga.sh b/ld/emulparams/amiga.sh +new file mode 100644 +index 0000000000000000000000000000000000000000..c2915d47d7964c6406eae9079ce90d695ecdbfda +--- /dev/null ++++ ld/emulparams/amiga.sh +@@ -0,0 +1,6 @@ ++SCRIPT_NAME=amiga ++OUTPUT_FORMAT="amiga" ++TEXT_START_ADDR=0x0 ++SEGMENT_SIZE=0x0 ++TEMPLATE_NAME=amiga ++ARCH=m68k +diff --git a/ld/emulparams/amiga_bss.sh b/ld/emulparams/amiga_bss.sh +new file mode 100644 +index 0000000000000000000000000000000000000000..5405d737448875ea39e5d9c4edfd59ee32c8a7b4 +--- /dev/null ++++ ld/emulparams/amiga_bss.sh +@@ -0,0 +1,6 @@ ++SCRIPT_NAME=amiga_bss ++OUTPUT_FORMAT="amiga" ++TEXT_START_ADDR=0x0 ++SEGMENT_SIZE=0x0 ++TEMPLATE_NAME=amiga ++ARCH=m68k +diff --git a/ld/emulparams/amigaos.sh b/ld/emulparams/amigaos.sh +new file mode 100644 +index 0000000000000000000000000000000000000000..605b81e76bcbbd2322561d7d9502190dc7c00674 +--- /dev/null ++++ ld/emulparams/amigaos.sh +@@ -0,0 +1,26 @@ ++#. ${srcdir}/emulparams/elf32ppccommon.sh ++TEMPLATE_NAME=amigaos ++SCRIPT_NAME=amigaos ++OUTPUT_FORMAT="elf32-amigaos" ++MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" ++COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" ++ALIGNMENT=16 ++ARCH=powerpc ++MACHINE= ++GENERATE_SHLIB_SCRIPT=yes ++TEXT_START_ADDR=0x01000000 ++SHLIB_TEXT_START_ADDR=0x10000000 ++unset WRITABLE_RODATA ++DATA_START_SYMBOLS="_DATA_BASE_ = .;" ++SDATA_START_SYMBOLS="_SDA_BASE_ = . + 0x8000;" ++DATA_GOT= ++SDATA_GOT= ++TEXT_PLT=yes ++SEPARATE_GOTPLT=0 ++unset BSS_PLT ++unset DATA_PLT ++GOT=".got ${RELOCATING-0} : SPECIAL { *(.got) }" ++PLT=".plt ${RELOCATING-0} : { *(.plt) }" ++# GOTPLT="${PLT}" ++OTHER_TEXT_SECTIONS="*(.glink)" ++EXTRA_EM_FILE=ppc32elf +diff --git a/ld/emulparams/amithlon.sh b/ld/emulparams/amithlon.sh +new file mode 100644 +index 0000000000000000000000000000000000000000..14b1c776396e2424af51c9b409e2d05f2881a84d +--- /dev/null ++++ ld/emulparams/amithlon.sh +@@ -0,0 +1,11 @@ ++SCRIPT_NAME=amithlon ++OUTPUT_FORMAT="elf32-i386be-amithlon" ++#TEXT_START_ADDR=0x08048000 ++#MAXPAGESIZE=0x1000 ++MAXPAGESIZE=32 ++#NONPAGED_TEXT_START_ADDR=0x08048000 ++ARCH=i386 ++MACHINE= ++NOP=0x9090 ++TEMPLATE_NAME=amithlon ++GENERATE_SHLIB_SCRIPT=yes +diff --git a/ld/emulparams/morphos.sh b/ld/emulparams/morphos.sh +new file mode 100644 +index 0000000000000000000000000000000000000000..45908c662f9b6085877dd39621e813da45a9f5f7 +--- /dev/null ++++ ld/emulparams/morphos.sh +@@ -0,0 +1,6 @@ ++TEMPLATE_NAME=morphos ++SCRIPT_NAME=morphos ++OUTPUT_FORMAT="elf32-morphos" ++MAXPAGESIZE=0x40000 ++ARCH=powerpc ++MACHINE= +diff --git a/ld/emulparams/morphos_baserel.sh b/ld/emulparams/morphos_baserel.sh +new file mode 100644 +index 0000000000000000000000000000000000000000..46c483484813395904772673d1ae1eed0bc9109f +--- /dev/null ++++ ld/emulparams/morphos_baserel.sh +@@ -0,0 +1,6 @@ ++TEMPLATE_NAME=morphos ++SCRIPT_NAME=morphos_baserel ++OUTPUT_FORMAT="elf32-morphos" ++MAXPAGESIZE=0x40000 ++ARCH=powerpc ++MACHINE= +diff --git a/ld/emulparams/ppcamiga.sh b/ld/emulparams/ppcamiga.sh +new file mode 100644 +index 0000000000000000000000000000000000000000..3f266cf5265f13748eeb78f67dd93227ade92de5 +--- /dev/null ++++ ld/emulparams/ppcamiga.sh +@@ -0,0 +1,8 @@ ++SCRIPT_NAME=amiga ++OUTPUT_FORMAT="amiga" ++TEXT_START_ADDR=0x400 ++PAGE_SIZE=0x400 ++SEGMENT_SIZE=0x400 ++NONPAGED_TEXT_START_ADDR=0x400 ++TEMPLATE_NAME=amiga ++ARCH=powerpc +diff --git a/ld/emulparams/ppcamiga_bss.sh b/ld/emulparams/ppcamiga_bss.sh +new file mode 100644 +index 0000000000000000000000000000000000000000..8d1720fb17c876d55b75f0885eb9f6eb0c7e9f1e +--- /dev/null ++++ ld/emulparams/ppcamiga_bss.sh +@@ -0,0 +1,8 @@ ++SCRIPT_NAME=amiga_bss ++OUTPUT_FORMAT="amiga" ++TEXT_START_ADDR=0x400 ++PAGE_SIZE=0x400 ++SEGMENT_SIZE=0x400 ++NONPAGED_TEXT_START_ADDR=0x400 ++TEMPLATE_NAME=amiga ++ARCH=powerpc +diff --git a/ld/emultempl/amiga.em b/ld/emultempl/amiga.em +new file mode 100644 +index 0000000000000000000000000000000000000000..c6abc5c644d3d93609d66972752e6cd3d474d70e +--- /dev/null ++++ ld/emultempl/amiga.em +@@ -0,0 +1,288 @@ ++# This shell script emits a C file. -*- C -*- ++# It does some substitutions. ++cat >e${EMULATION_NAME}.c <<EOF ++/* This file is is generated by a shell script. DO NOT EDIT! */ ++ ++/* emulate the original gld for the given ${EMULATION_NAME} ++ Copyright (C) 1991, 1993 Free Software Foundation, Inc. ++ Written by Steve Chamberlain steve@cygnus.com ++ ++This file is part of GLD, the Gnu Linker. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++ ++#define TARGET_IS_${EMULATION_NAME} ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "bfdlink.h" ++#include "getopt.h" ++ ++#include "ld.h" ++#include "ldmain.h" ++#include "ldmisc.h" ++#include "ldexp.h" ++#include "ldlang.h" ++#include "ldfile.h" ++#include "ldemul.h" ++#include "ldctor.h" ++ ++#include "libamiga.h" ++ ++/* shared functions */ ++void amiga_add_options PARAMS ((int, char **, int, struct option **, int, struct option **)); ++bfd_boolean amiga_handle_option PARAMS ((int)); ++void amiga_after_parse PARAMS ((void)); ++void amiga_after_open PARAMS ((void)); ++void amiga_after_allocation PARAMS ((void)); ++ ++/* amigaoslink.c variables */ ++ ++/* 1 means, write out debug hunk, when producing a load file */ ++extern int write_debug_hunk; ++ ++/* This is the attribute to use for the next file */ ++extern int amiga_attribute; ++ ++/* generate a combined data+bss hunk */ ++extern int amiga_base_relative; ++ ++/* generate a resident executable */ ++extern int amiga_resident; ++ ++static void gld${EMULATION_NAME}_before_parse PARAMS ((void)); ++static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile)); ++ ++#if defined(TARGET_IS_amiga) ++ ++/* Handle amiga specific options */ ++ ++enum { ++ OPTION_IGNORE = 300, ++ OPTION_AMIGA_CHIP, ++ OPTION_AMIGA_FAST, ++ OPTION_AMIGA_ATTRIBUTE, ++ OPTION_AMIGA_DEBUG, ++ OPTION_AMIGA_DATABSS_TOGETHER, ++ OPTION_AMIGA_DATADATA_RELOC, ++ OPTION_FLAVOR ++}; ++ ++void ++amiga_add_options (ns, shortopts, nl, longopts, nrl, really_longopts) ++ int ns ATTRIBUTE_UNUSED; ++ char **shortopts ATTRIBUTE_UNUSED; ++ int nl; ++ struct option **longopts; ++ int nrl ATTRIBUTE_UNUSED; ++ struct option **really_longopts ATTRIBUTE_UNUSED; ++{ ++ static const struct option xtra_long[] = { ++ {"flavor", required_argument, NULL, OPTION_FLAVOR}, ++ {"amiga-datadata-reloc", no_argument, NULL, OPTION_AMIGA_DATADATA_RELOC}, ++ {"amiga-databss-together", no_argument, NULL, OPTION_AMIGA_DATABSS_TOGETHER}, ++ {"amiga-debug-hunk", no_argument, NULL, OPTION_AMIGA_DEBUG}, ++ {"attribute", required_argument, NULL, OPTION_AMIGA_ATTRIBUTE}, ++ {"fast", no_argument, NULL, OPTION_AMIGA_FAST}, ++ {"chip", no_argument, NULL, OPTION_AMIGA_CHIP}, ++ {NULL, no_argument, NULL, 0} ++ }; ++ ++ *longopts = (struct option *) ++ xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long)); ++ memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long)); ++} ++ ++bfd_boolean ++amiga_handle_option (optc) ++ int optc; ++{ ++ switch (optc) ++ { ++ default: ++ return FALSE; ++ ++ case 0: ++ /* Long option which just sets a flag. */ ++ break; ++ ++ case OPTION_AMIGA_CHIP: ++ amiga_attribute = MEMF_CHIP; ++ break; ++ ++ case OPTION_AMIGA_FAST: ++ amiga_attribute = MEMF_FAST; ++ break; ++ ++ case OPTION_AMIGA_ATTRIBUTE: ++ { ++ char *end; ++ amiga_attribute = strtoul (optarg, &end, 0); ++ if (*end) ++ einfo ("%P%F: invalid number \`%s\'\n", optarg); ++ } ++ break; ++ ++ case OPTION_AMIGA_DEBUG: ++ write_debug_hunk = 1; /* Write out debug hunk */ ++ break; ++ ++ case OPTION_AMIGA_DATABSS_TOGETHER: ++ amiga_base_relative = 1; /* Combine data and bss */ ++ break; ++ ++ case OPTION_AMIGA_DATADATA_RELOC: ++ amiga_resident = 1; /* Write out datadata_reloc array */ ++ break; ++ ++ case OPTION_FLAVOR: ++ ldfile_add_flavor (optarg); ++ break; ++ } ++ ++ return TRUE; ++} ++ ++void ++amiga_after_parse () ++{ ++ ldfile_sort_flavors(); ++} ++ ++void ++amiga_after_open () ++{ ++ ldctor_build_sets (); ++} ++ ++static void ++amiga_assign_attribute (inp) ++ lang_input_statement_type *inp; ++{ ++ asection *s; ++ ++ if (bfd_get_flavour(inp->the_bfd)==bfd_target_amiga_flavour) ++ { ++ for (s=inp->the_bfd->sections;s!=NULL;s=s->next) ++ amiga_per_section(s)->attribute=inp->amiga_attribute; ++ } ++} ++ ++void ++amiga_after_allocation () ++{ ++ if (0) /* Does not work at the moment */ ++ lang_for_each_input_file (amiga_assign_attribute); ++} ++ ++#endif ++ ++static void ++gld${EMULATION_NAME}_before_parse () ++{ ++ write_debug_hunk = 0; ++ ++#if defined(TARGET_IS_amiga_bss) ++ amiga_base_relative = 1; ++#endif ++ ++#ifndef TARGET_ /* I.e., if not generic. */ ++ ldfile_output_architecture = bfd_arch_${ARCH}; ++#endif /* not TARGET_ */ ++} ++ ++static char * ++gld${EMULATION_NAME}_get_script (isfile) ++ int *isfile; ++EOF ++ ++if test -n "$COMPILE_IN" ++then ++# Scripts compiled in. ++ ++# sed commands to quote an ld script as a C string. ++sc="-f stringify.sed" ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++{ ++ *isfile = 0; ++ ++ if (link_info.relocateable == TRUE && config.build_constructors == TRUE) ++ return ++EOF ++sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.relocateable == TRUE) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c ++echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c ++echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c ++echo ' ; else return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c ++echo '; }' >> e${EMULATION_NAME}.c ++ ++else ++# Scripts read from the filesystem. ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++{ ++ *isfile = 1; ++ ++ if (link_info.relocateable == TRUE && config.build_constructors == TRUE) ++ return "ldscripts/${EMULATION_NAME}.xu"; ++ else if (link_info.relocateable == TRUE) ++ return "ldscripts/${EMULATION_NAME}.xr"; ++ else if (!config.text_read_only) ++ return "ldscripts/${EMULATION_NAME}.xbn"; ++ else if (!config.magic_demand_paged) ++ return "ldscripts/${EMULATION_NAME}.xn"; ++ else ++ return "ldscripts/${EMULATION_NAME}.x"; ++} ++EOF ++ ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = ++{ ++ gld${EMULATION_NAME}_before_parse, /* before_parse */ ++ syslib_default, /* syslib */ ++ hll_default, /* hll */ ++ amiga_after_parse, /* after_parse */ ++ amiga_after_open, /* after_open */ ++ amiga_after_allocation, /* after_allocation */ ++ set_output_arch_default, /* set_output_arch */ ++ ldemul_default_target, /* choose_target */ ++ before_allocation_default, /* before_allocation */ ++ gld${EMULATION_NAME}_get_script, /* get_script */ ++ "${EMULATION_NAME}", /* emulation_name */ ++ "${OUTPUT_FORMAT}", /* target_name */ ++ NULL, /* finish */ ++ NULL, /* create_output_section_statements */ ++ NULL, /* open_dynamic_library */ ++ NULL, /* place_orphan */ ++ NULL, /* set_symbols */ ++ NULL, /* parse_args */ ++ amiga_add_options, /* add_options */ ++ amiga_handle_option, /* handle_option */ ++ NULL, /* unrecognized file */ ++ NULL, /* list_options */ ++ NULL, /* recognized_file */ ++ NULL, /* find potential_libraries */ ++ NULL /* new_vers_pattern */ ++}; ++EOF +diff --git a/ld/emultempl/elf32.em b/ld/emultempl/amigaos.em +similarity index 100% +copy from ld/emultempl/elf32.em +copy to ld/emultempl/amigaos.em +diff --git a/ld/emultempl/amithlon.em b/ld/emultempl/amithlon.em +new file mode 100644 +index 0000000000000000000000000000000000000000..5e453a72f8c01e621d110d505b83d1abbcd19831 +--- /dev/null ++++ ld/emultempl/amithlon.em +@@ -0,0 +1,1698 @@ ++# This shell script emits a C file. -*- C -*- ++# It does some substitutions. ++# This file is now misnamed, because it supports both 32 bit and 64 bit ++# ELF emulations. ++test -z "${ELFSIZE}" && ELFSIZE=32 ++if [ -z "$MACHINE" ]; then ++ OUTPUT_ARCH=${ARCH} ++else ++ OUTPUT_ARCH=${ARCH}:${MACHINE} ++fi ++cat >e${EMULATION_NAME}.c <<EOF ++/* This file is is generated by a shell script. DO NOT EDIT! */ ++ ++/* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME} ++ Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, ++ 2002 Free Software Foundation, Inc. ++ Written by Steve Chamberlain <sac@cygnus.com> ++ ELF support by Ian Lance Taylor <ian@cygnus.com> ++ ++This file is part of GLD, the Gnu Linker. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++#define TARGET_IS_${EMULATION_NAME} ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "libiberty.h" ++#include "safe-ctype.h" ++ ++#include "bfdlink.h" ++ ++#include "ld.h" ++#include "ldmain.h" ++#include "ldmisc.h" ++#include "ldexp.h" ++#include "ldlang.h" ++#include "ldfile.h" ++#include "ldemul.h" ++#include <ldgram.h> ++#include "elf/common.h" ++ ++static void gld${EMULATION_NAME}_before_parse ++ PARAMS ((void)); ++static void gld${EMULATION_NAME}_vercheck ++ PARAMS ((lang_input_statement_type *)); ++static void gld${EMULATION_NAME}_stat_needed ++ PARAMS ((lang_input_statement_type *)); ++static boolean gld${EMULATION_NAME}_try_needed ++ PARAMS ((const char *, int)); ++static boolean gld${EMULATION_NAME}_search_needed ++ PARAMS ((const char *, const char *, int)); ++static void gld${EMULATION_NAME}_check_needed ++ PARAMS ((lang_input_statement_type *)); ++static void gld${EMULATION_NAME}_after_open ++ PARAMS ((void)); ++static void gld${EMULATION_NAME}_find_exp_assignment ++ PARAMS ((etree_type *)); ++static void gld${EMULATION_NAME}_find_statement_assignment ++ PARAMS ((lang_statement_union_type *)); ++static void gld${EMULATION_NAME}_before_allocation ++ PARAMS ((void)); ++static boolean gld${EMULATION_NAME}_open_dynamic_archive ++ PARAMS ((const char *, search_dirs_type *, lang_input_statement_type *)); ++static lang_output_section_statement_type *output_rel_find ++ PARAMS ((asection *)); ++static asection *output_prev_sec_find ++ PARAMS ((lang_output_section_statement_type *)); ++static boolean gld${EMULATION_NAME}_place_orphan ++ PARAMS ((lang_input_statement_type *, asection *)); ++static void gld${EMULATION_NAME}_finish ++ PARAMS ((void)); ++static char *gld${EMULATION_NAME}_get_script ++ PARAMS ((int *isfile)); ++ ++extern void ldfile_add_flavor (char*); ++ ++EOF ++ ++# Import any needed special functions and/or overrides. ++# ++if test -n "$EXTRA_EM_FILE" ; then ++. ${srcdir}/emultempl/${EXTRA_EM_FILE}.em ++fi ++ ++# Functions in this file can be overridden by setting the LDEMUL_* shell ++# variables. If the name of the overriding function is the same as is ++# defined in this file, then don't output this file's version. ++# If a different overriding name is given then output the standard function ++# as presumably it is called from the overriding function. ++# ++if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++static void ++gld${EMULATION_NAME}_before_parse () ++{ ++ const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}"); ++ if (arch) ++ { ++ ldfile_output_architecture = arch->arch; ++ ldfile_output_machine = arch->mach; ++ ldfile_output_machine_name = arch->printable_name; ++ } ++ else ++ ldfile_output_architecture = bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`; ++ config.dynamic_link = ${DYNAMIC_LINK-true}; ++ config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`; ++ sort_flavors(); ++} ++ ++EOF ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* These variables are required to pass information back and forth ++ between after_open and check_needed and stat_needed and vercheck. */ ++ ++static struct bfd_link_needed_list *global_needed; ++static struct stat global_stat; ++static boolean global_found; ++static struct bfd_link_needed_list *global_vercheck_needed; ++static boolean global_vercheck_failed; ++ ++ ++/* On Linux, it's possible to have different versions of the same ++ shared library linked against different versions of libc. The ++ dynamic linker somehow tags which libc version to use in ++ /etc/ld.so.cache, and, based on the libc that it sees in the ++ executable, chooses which version of the shared library to use. ++ ++ We try to do a similar check here by checking whether this shared ++ library needs any other shared libraries which may conflict with ++ libraries we have already included in the link. If it does, we ++ skip it, and try to find another shared library farther on down the ++ link path. ++ ++ This is called via lang_for_each_input_file. ++ GLOBAL_VERCHECK_NEEDED is the list of objects needed by the object ++ which we are checking. This sets GLOBAL_VERCHECK_FAILED if we find ++ a conflicting version. */ ++ ++static void ++gld${EMULATION_NAME}_vercheck (s) ++ lang_input_statement_type *s; ++{ ++ const char *soname; ++ struct bfd_link_needed_list *l; ++ ++ if (global_vercheck_failed) ++ return; ++ if (s->the_bfd == NULL ++ || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0) ++ return; ++ ++ soname = bfd_elf_get_dt_soname (s->the_bfd); ++ if (soname == NULL) ++ soname = lbasename (bfd_get_filename (s->the_bfd)); ++ ++ for (l = global_vercheck_needed; l != NULL; l = l->next) ++ { ++ const char *suffix; ++ ++ if (strcmp (soname, l->name) == 0) ++ { ++ /* Probably can't happen, but it's an easy check. */ ++ continue; ++ } ++ ++ if (strchr (l->name, '/') != NULL) ++ continue; ++ ++ suffix = strstr (l->name, ".so."); ++ if (suffix == NULL) ++ continue; ++ ++ suffix += sizeof ".so." - 1; ++ ++ if (strncmp (soname, l->name, suffix - l->name) == 0) ++ { ++ /* Here we know that S is a dynamic object FOO.SO.VER1, and ++ the object we are considering needs a dynamic object ++ FOO.SO.VER2, and VER1 and VER2 are different. This ++ appears to be a version mismatch, so we tell the caller ++ to try a different version of this library. */ ++ global_vercheck_failed = true; ++ return; ++ } ++ } ++} ++ ++ ++/* See if an input file matches a DT_NEEDED entry by running stat on ++ the file. */ ++ ++static void ++gld${EMULATION_NAME}_stat_needed (s) ++ lang_input_statement_type *s; ++{ ++ struct stat st; ++ const char *suffix; ++ const char *soname; ++ ++ if (global_found) ++ return; ++ if (s->the_bfd == NULL) ++ return; ++ ++ if (bfd_stat (s->the_bfd, &st) != 0) ++ { ++ einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd); ++ return; ++ } ++ ++ if (st.st_dev == global_stat.st_dev ++ && st.st_ino == global_stat.st_ino) ++ { ++ global_found = true; ++ return; ++ } ++ ++ /* We issue a warning if it looks like we are including two ++ different versions of the same shared library. For example, ++ there may be a problem if -lc picks up libc.so.6 but some other ++ shared library has a DT_NEEDED entry of libc.so.5. This is a ++ heuristic test, and it will only work if the name looks like ++ NAME.so.VERSION. FIXME: Depending on file names is error-prone. ++ If we really want to issue warnings about mixing version numbers ++ of shared libraries, we need to find a better way. */ ++ ++ if (strchr (global_needed->name, '/') != NULL) ++ return; ++ suffix = strstr (global_needed->name, ".so."); ++ if (suffix == NULL) ++ return; ++ suffix += sizeof ".so." - 1; ++ ++ soname = bfd_elf_get_dt_soname (s->the_bfd); ++ if (soname == NULL) ++ soname = lbasename (s->filename); ++ ++ if (strncmp (soname, global_needed->name, suffix - global_needed->name) == 0) ++ einfo ("%P: warning: %s, needed by %B, may conflict with %s\n", ++ global_needed->name, global_needed->by, soname); ++} ++ ++ ++/* This function is called for each possible name for a dynamic object ++ named by a DT_NEEDED entry. The FORCE parameter indicates whether ++ to skip the check for a conflicting version. */ ++ ++static boolean ++gld${EMULATION_NAME}_try_needed (name, force) ++ const char *name; ++ int force; ++{ ++ bfd *abfd; ++ const char *soname; ++ ++ abfd = bfd_openr (name, bfd_get_target (output_bfd)); ++ if (abfd == NULL) ++ return false; ++ if (! bfd_check_format (abfd, bfd_object)) ++ { ++ bfd_close (abfd); ++ return false; ++ } ++ if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0) ++ { ++ bfd_close (abfd); ++ return false; ++ } ++ ++ /* For DT_NEEDED, they have to match. */ ++ if (abfd->xvec != output_bfd->xvec) ++ { ++ bfd_close (abfd); ++ return false; ++ } ++ ++ /* Check whether this object would include any conflicting library ++ versions. If FORCE is set, then we skip this check; we use this ++ the second time around, if we couldn't find any compatible ++ instance of the shared library. */ ++ ++ if (! force) ++ { ++ struct bfd_link_needed_list *needed; ++ ++ if (! bfd_elf_get_bfd_needed_list (abfd, &needed)) ++ einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd); ++ ++ if (needed != NULL) ++ { ++ global_vercheck_needed = needed; ++ global_vercheck_failed = false; ++ lang_for_each_input_file (gld${EMULATION_NAME}_vercheck); ++ if (global_vercheck_failed) ++ { ++ bfd_close (abfd); ++ /* Return false to force the caller to move on to try ++ another file on the search path. */ ++ return false; ++ } ++ ++ /* But wait! It gets much worse. On Linux, if a shared ++ library does not use libc at all, we are supposed to skip ++ it the first time around in case we encounter a shared ++ library later on with the same name which does use the ++ version of libc that we want. This is much too horrible ++ to use on any system other than Linux. */ ++ ++EOF ++case ${target} in ++ *-*-linux-gnu*) ++ cat >>e${EMULATION_NAME}.c <<EOF ++ { ++ struct bfd_link_needed_list *l; ++ ++ for (l = needed; l != NULL; l = l->next) ++ if (strncmp (l->name, "libc.so", 7) == 0) ++ break; ++ if (l == NULL) ++ { ++ bfd_close (abfd); ++ return false; ++ } ++ } ++ ++EOF ++ ;; ++esac ++cat >>e${EMULATION_NAME}.c <<EOF ++ } ++ } ++ ++ /* We've found a dynamic object matching the DT_NEEDED entry. */ ++ ++ /* We have already checked that there is no other input file of the ++ same name. We must now check again that we are not including the ++ same file twice. We need to do this because on many systems ++ libc.so is a symlink to, e.g., libc.so.1. The SONAME entry will ++ reference libc.so.1. If we have already included libc.so, we ++ don't want to include libc.so.1 if they are the same file, and we ++ can only check that using stat. */ ++ ++ if (bfd_stat (abfd, &global_stat) != 0) ++ einfo ("%F%P:%B: bfd_stat failed: %E\n", abfd); ++ ++ /* First strip off everything before the last '/'. */ ++ soname = lbasename (abfd->filename); ++ ++ if (trace_file_tries) ++ info_msg (_("found %s at %s\n"), soname, name); ++ ++ global_found = false; ++ lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed); ++ if (global_found) ++ { ++ /* Return true to indicate that we found the file, even though ++ we aren't going to do anything with it. */ ++ return true; ++ } ++ ++ /* Tell the ELF backend that we don't want the output file to have a ++ DT_NEEDED entry for this file. */ ++ bfd_elf_set_dt_needed_name (abfd, ""); ++ ++ /* Tell the ELF backend that the output file needs a DT_NEEDED ++ entry for this file if it is used to resolve the reference in ++ a regular object. */ ++ bfd_elf_set_dt_needed_soname (abfd, soname); ++ ++ /* Add this file into the symbol table. */ ++ if (! bfd_link_add_symbols (abfd, &link_info)) ++ einfo ("%F%B: could not read symbols: %E\n", abfd); ++ ++ return true; ++} ++ ++ ++/* Search for a needed file in a path. */ ++ ++static boolean ++gld${EMULATION_NAME}_search_needed (path, name, force) ++ const char *path; ++ const char *name; ++ int force; ++{ ++ const char *s; ++ size_t len; ++ ++ if (name[0] == '/') ++ return gld${EMULATION_NAME}_try_needed (name, force); ++ ++ if (path == NULL || *path == '\0') ++ return false; ++ len = strlen (name); ++ while (1) ++ { ++ char *filename, *sset; ++ ++ s = strchr (path, ':'); ++ if (s == NULL) ++ s = path + strlen (path); ++ ++ filename = (char *) xmalloc (s - path + len + 2); ++ if (s == path) ++ sset = filename; ++ else ++ { ++ memcpy (filename, path, s - path); ++ filename[s - path] = '/'; ++ sset = filename + (s - path) + 1; ++ } ++ strcpy (sset, name); ++ ++ if (gld${EMULATION_NAME}_try_needed (filename, force)) ++ return true; ++ ++ free (filename); ++ ++ if (*s == '\0') ++ break; ++ path = s + 1; ++ } ++ ++ return false; ++} ++ ++EOF ++if [ "x${host}" = "x${target}" ] ; then ++ case " ${EMULATION_LIBPATH} " in ++ *" ${EMULATION_NAME} "*) ++ case ${target} in ++ *-*-linux-gnu*) ++ cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* For a native linker, check the file /etc/ld.so.conf for directories ++ in which we may find shared libraries. /etc/ld.so.conf is really ++ only meaningful on Linux. */ ++ ++static boolean gld${EMULATION_NAME}_check_ld_so_conf ++ PARAMS ((const char *, int)); ++ ++static boolean ++gld${EMULATION_NAME}_check_ld_so_conf (name, force) ++ const char *name; ++ int force; ++{ ++ static boolean initialized; ++ static char *ld_so_conf; ++ ++ if (! initialized) ++ { ++ FILE *f; ++ ++ f = fopen ("/etc/ld.so.conf", FOPEN_RT); ++ if (f != NULL) ++ { ++ char *b; ++ size_t len, alloc; ++ int c; ++ ++ len = 0; ++ alloc = 100; ++ b = (char *) xmalloc (alloc); ++ ++ while ((c = getc (f)) != EOF) ++ { ++ if (len + 1 >= alloc) ++ { ++ alloc *= 2; ++ b = (char *) xrealloc (b, alloc); ++ } ++ if (c != ':' ++ && c != ' ' ++ && c != '\t' ++ && c != '\n' ++ && c != ',') ++ { ++ b[len] = c; ++ ++len; ++ } ++ else ++ { ++ if (len > 0 && b[len - 1] != ':') ++ { ++ b[len] = ':'; ++ ++len; ++ } ++ } ++ } ++ ++ if (len > 0 && b[len - 1] == ':') ++ --len; ++ ++ if (len > 0) ++ b[len] = '\0'; ++ else ++ { ++ free (b); ++ b = NULL; ++ } ++ ++ fclose (f); ++ ++ ld_so_conf = b; ++ } ++ ++ initialized = true; ++ } ++ ++ if (ld_so_conf == NULL) ++ return false; ++ ++ return gld${EMULATION_NAME}_search_needed (ld_so_conf, name, force); ++} ++ ++EOF ++ # Linux ++ ;; ++ esac ++ esac ++fi ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* See if an input file matches a DT_NEEDED entry by name. */ ++ ++static void ++gld${EMULATION_NAME}_check_needed (s) ++ lang_input_statement_type *s; ++{ ++ if (global_found) ++ return; ++ ++ if (s->filename != NULL) ++ { ++ const char *f; ++ ++ if (strcmp (s->filename, global_needed->name) == 0) ++ { ++ global_found = true; ++ return; ++ } ++ ++ if (s->search_dirs_flag) ++ { ++ f = strrchr (s->filename, '/'); ++ if (f != NULL ++ && strcmp (f + 1, global_needed->name) == 0) ++ { ++ global_found = true; ++ return; ++ } ++ } ++ } ++ ++ if (s->the_bfd != NULL) ++ { ++ const char *soname; ++ ++ soname = bfd_elf_get_dt_soname (s->the_bfd); ++ if (soname != NULL ++ && strcmp (soname, global_needed->name) == 0) ++ { ++ global_found = true; ++ return; ++ } ++ } ++} ++ ++EOF ++ ++if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* This is called after all the input files have been opened. */ ++ ++static void ++gld${EMULATION_NAME}_after_open () ++{ ++ struct bfd_link_needed_list *needed, *l; ++ ++ /* We only need to worry about this when doing a final link. */ ++ if (link_info.relocateable || link_info.shared) ++ return; ++ ++ /* Get the list of files which appear in DT_NEEDED entries in ++ dynamic objects included in the link (often there will be none). ++ For each such file, we want to track down the corresponding ++ library, and include the symbol table in the link. This is what ++ the runtime dynamic linker will do. Tracking the files down here ++ permits one dynamic object to include another without requiring ++ special action by the person doing the link. Note that the ++ needed list can actually grow while we are stepping through this ++ loop. */ ++ needed = bfd_elf_get_needed_list (output_bfd, &link_info); ++ for (l = needed; l != NULL; l = l->next) ++ { ++ struct bfd_link_needed_list *ll; ++ int force; ++ ++ /* If we've already seen this file, skip it. */ ++ for (ll = needed; ll != l; ll = ll->next) ++ if (strcmp (ll->name, l->name) == 0) ++ break; ++ if (ll != l) ++ continue; ++ ++ /* See if this file was included in the link explicitly. */ ++ global_needed = l; ++ global_found = false; ++ lang_for_each_input_file (gld${EMULATION_NAME}_check_needed); ++ if (global_found) ++ continue; ++ ++ if (trace_file_tries) ++ info_msg (_("%s needed by %B\n"), l->name, l->by); ++ ++ /* We need to find this file and include the symbol table. We ++ want to search for the file in the same way that the dynamic ++ linker will search. That means that we want to use ++ rpath_link, rpath, then the environment variable ++ LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH ++ entries (native only), then the linker script LIB_SEARCH_DIRS. ++ We do not search using the -L arguments. ++ ++ We search twice. The first time, we skip objects which may ++ introduce version mismatches. The second time, we force ++ their use. See gld${EMULATION_NAME}_vercheck comment. */ ++ for (force = 0; force < 2; force++) ++ { ++ size_t len; ++ search_dirs_type *search; ++EOF ++if [ "x${host}" = "x${target}" ] ; then ++ case " ${EMULATION_LIBPATH} " in ++ *" ${EMULATION_NAME} "*) ++cat >>e${EMULATION_NAME}.c <<EOF ++ const char *lib_path; ++ struct bfd_link_needed_list *rp; ++ int found; ++EOF ++ ;; ++ esac ++fi ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++ if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link, ++ l->name, force)) ++ break; ++EOF ++if [ "x${host}" = "x${target}" ] ; then ++ case " ${EMULATION_LIBPATH} " in ++ *" ${EMULATION_NAME} "*) ++cat >>e${EMULATION_NAME}.c <<EOF ++ if (gld${EMULATION_NAME}_search_needed (command_line.rpath, ++ l->name, force)) ++ break; ++ if (command_line.rpath_link == NULL ++ && command_line.rpath == NULL) ++ { ++ lib_path = (const char *) getenv ("LD_RUN_PATH"); ++ if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, ++ force)) ++ break; ++ } ++ lib_path = (const char *) getenv ("LD_LIBRARY_PATH"); ++ if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force)) ++ break; ++ ++ found = 0; ++ rp = bfd_elf_get_runpath_list (output_bfd, &link_info); ++ for (; !found && rp != NULL; rp = rp->next) ++ { ++ found = (rp->by == l->by ++ && gld${EMULATION_NAME}_search_needed (rp->name, ++ l->name, ++ force)); ++ } ++ if (found) ++ break; ++ ++EOF ++ ;; ++ esac ++fi ++cat >>e${EMULATION_NAME}.c <<EOF ++ len = strlen (l->name); ++ for (search = search_head; search != NULL; search = search->next) ++ { ++ char *filename; ++ ++ if (search->cmdline) ++ continue; ++ filename = (char *) xmalloc (strlen (search->name) + len + 2); ++ sprintf (filename, "%s/%s", search->name, l->name); ++ if (gld${EMULATION_NAME}_try_needed (filename, force)) ++ break; ++ free (filename); ++ } ++ if (search != NULL) ++ break; ++EOF ++if [ "x${host}" = "x${target}" ] ; then ++ case " ${EMULATION_LIBPATH} " in ++ *" ${EMULATION_NAME} "*) ++ case ${target} in ++ *-*-linux-gnu*) ++ cat >>e${EMULATION_NAME}.c <<EOF ++ if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force)) ++ break; ++EOF ++ # Linux ++ ;; ++ esac ++ ;; ++ esac ++fi ++cat >>e${EMULATION_NAME}.c <<EOF ++ } ++ ++ if (force < 2) ++ continue; ++ ++ einfo ("%P: warning: %s, needed by %B, not found (try using -rpath or -rpath-link)\n", ++ l->name, l->by); ++ } ++} ++ ++EOF ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* Look through an expression for an assignment statement. */ ++ ++static void ++gld${EMULATION_NAME}_find_exp_assignment (exp) ++ etree_type *exp; ++{ ++ struct bfd_link_hash_entry *h; ++ ++ switch (exp->type.node_class) ++ { ++ case etree_provide: ++ h = bfd_link_hash_lookup (link_info.hash, exp->assign.dst, ++ false, false, false); ++ if (h == NULL) ++ break; ++ ++ /* We call record_link_assignment even if the symbol is defined. ++ This is because if it is defined by a dynamic object, we ++ actually want to use the value defined by the linker script, ++ not the value from the dynamic object (because we are setting ++ symbols like etext). If the symbol is defined by a regular ++ object, then, as it happens, calling record_link_assignment ++ will do no harm. */ ++ ++ /* Fall through. */ ++ case etree_assign: ++ if (strcmp (exp->assign.dst, ".") != 0) ++ { ++ if (! (bfd_elf${ELFSIZE}_record_link_assignment ++ (output_bfd, &link_info, exp->assign.dst, ++ exp->type.node_class == etree_provide ? true : false))) ++ einfo ("%P%F: failed to record assignment to %s: %E\n", ++ exp->assign.dst); ++ } ++ gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src); ++ break; ++ ++ case etree_binary: ++ gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs); ++ gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs); ++ break; ++ ++ case etree_trinary: ++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond); ++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); ++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs); ++ break; ++ ++ case etree_unary: ++ gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++ ++/* This is called by the before_allocation routine via ++ lang_for_each_statement. It locates any assignment statements, and ++ tells the ELF backend about them, in case they are assignments to ++ symbols which are referred to by dynamic objects. */ ++ ++static void ++gld${EMULATION_NAME}_find_statement_assignment (s) ++ lang_statement_union_type *s; ++{ ++ if (s->header.type == lang_assignment_statement_enum) ++ gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp); ++} ++ ++EOF ++ ++if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then ++ if test x"${ELF_INTERPRETER_NAME+set}" = xset; then ++ ELF_INTERPRETER_SET_DEFAULT=" ++ if (sinterp != NULL) ++ { ++ sinterp->contents = ${ELF_INTERPRETER_NAME}; ++ sinterp->_raw_size = strlen (sinterp->contents) + 1; ++ } ++ ++" ++ else ++ ELF_INTERPRETER_SET_DEFAULT= ++ fi ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* This is called after the sections have been attached to output ++ sections, but before any sizes or addresses have been set. */ ++ ++static void ++gld${EMULATION_NAME}_before_allocation () ++{ ++ const char *rpath; ++ asection *sinterp; ++ ++ /* If we are going to make any variable assignments, we need to let ++ the ELF backend know about them in case the variables are ++ referred to by dynamic objects. */ ++ lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment); ++ ++ /* Let the ELF backend work out the sizes of any sections required ++ by dynamic linking. */ ++ rpath = command_line.rpath; ++ if (rpath == NULL) ++ rpath = (const char *) getenv ("LD_RUN_PATH"); ++ if (! (bfd_elf${ELFSIZE}_size_dynamic_sections ++ (output_bfd, command_line.soname, rpath, ++ command_line.filter_shlib, ++ (const char * const *) command_line.auxiliary_filters, ++ &link_info, &sinterp, lang_elf_version_info))) ++ einfo ("%P%F: failed to set dynamic section sizes: %E\n"); ++${ELF_INTERPRETER_SET_DEFAULT} ++ /* Let the user override the dynamic linker we are using. */ ++ if (command_line.interpreter != NULL ++ && sinterp != NULL) ++ { ++ sinterp->contents = (bfd_byte *) command_line.interpreter; ++ sinterp->_raw_size = strlen (command_line.interpreter) + 1; ++ } ++ ++ /* Look for any sections named .gnu.warning. As a GNU extensions, ++ we treat such sections as containing warning messages. We print ++ out the warning message, and then zero out the section size so ++ that it does not get copied into the output file. */ ++ ++ { ++ LANG_FOR_EACH_INPUT_STATEMENT (is) ++ { ++ asection *s; ++ bfd_size_type sz; ++ char *msg; ++ boolean ret; ++ ++ if (is->just_syms_flag) ++ continue; ++ ++ s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning"); ++ if (s == NULL) ++ continue; ++ ++ sz = bfd_section_size (is->the_bfd, s); ++ msg = xmalloc ((size_t) sz + 1); ++ if (! bfd_get_section_contents (is->the_bfd, s, msg, (file_ptr) 0, sz)) ++ einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n", ++ is->the_bfd); ++ msg[sz] = '\0'; ++ ret = link_info.callbacks->warning (&link_info, msg, ++ (const char *) NULL, ++ is->the_bfd, (asection *) NULL, ++ (bfd_vma) 0); ++ ASSERT (ret); ++ free (msg); ++ ++ /* Clobber the section size, so that we don't waste copying the ++ warning into the output file. */ ++ s->_raw_size = 0; ++ } ++ } ++} ++ ++EOF ++fi ++ ++if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* Try to open a dynamic archive. This is where we know that ELF ++ dynamic libraries have an extension of .so (or .sl on oddball systems ++ like hpux). */ ++ ++static boolean ++gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry) ++ const char *arch; ++ search_dirs_type *search; ++ lang_input_statement_type *entry; ++{ ++ const char *filename; ++ char *string; ++ ++ if (! entry->is_archive) ++ return false; ++ ++ filename = entry->filename; ++ ++ /* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION ++ is defined, but it does not seem worth the headache to optimize ++ away those two bytes of space. */ ++ string = (char *) xmalloc (strlen (search->name) ++ + strlen (filename) ++ + strlen (arch) ++#ifdef EXTRA_SHLIB_EXTENSION ++ + strlen (EXTRA_SHLIB_EXTENSION) ++#endif ++ + sizeof "/lib.so"); ++ ++ sprintf (string, "%s/lib%s%s.so", search->name, filename, arch); ++ ++#ifdef EXTRA_SHLIB_EXTENSION ++ /* Try the .so extension first. If that fails build a new filename ++ using EXTRA_SHLIB_EXTENSION. */ ++ if (! ldfile_try_open_bfd (string, entry)) ++ sprintf (string, "%s/lib%s%s%s", search->name, ++ filename, arch, EXTRA_SHLIB_EXTENSION); ++#endif ++ ++ if (! ldfile_try_open_bfd (string, entry)) ++ { ++ free (string); ++ return false; ++ } ++ ++ entry->filename = string; ++ ++ /* We have found a dynamic object to include in the link. The ELF ++ backend linker will create a DT_NEEDED entry in the .dynamic ++ section naming this file. If this file includes a DT_SONAME ++ entry, it will be used. Otherwise, the ELF linker will just use ++ the name of the file. For an archive found by searching, like ++ this one, the DT_NEEDED entry should consist of just the name of ++ the file, without the path information used to find it. Note ++ that we only need to do this if we have a dynamic object; an ++ archive will never be referenced by a DT_NEEDED entry. ++ ++ FIXME: This approach--using bfd_elf_set_dt_needed_name--is not ++ very pretty. I haven't been able to think of anything that is ++ pretty, though. */ ++ if (bfd_check_format (entry->the_bfd, bfd_object) ++ && (entry->the_bfd->flags & DYNAMIC) != 0) ++ { ++ ASSERT (entry->is_archive && entry->search_dirs_flag); ++ ++ /* Rather than duplicating the logic above. Just use the ++ filename we recorded earlier. */ ++ ++ filename = lbasename (entry->filename); ++ bfd_elf_set_dt_needed_name (entry->the_bfd, filename); ++ } ++ ++ return true; ++} ++ ++EOF ++fi ++ ++if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* A variant of lang_output_section_find. Used by place_orphan. */ ++ ++static lang_output_section_statement_type * ++output_rel_find (sec) ++ asection *sec; ++{ ++ lang_statement_union_type *u; ++ lang_output_section_statement_type *lookup; ++ lang_output_section_statement_type *last = NULL; ++ lang_output_section_statement_type *last_rel = NULL; ++ lang_output_section_statement_type *last_rel_alloc = NULL; ++ int rela = sec->name[4] == 'a'; ++ ++ for (u = lang_output_section_statement.head; u; u = lookup->next) ++ { ++ lookup = &u->output_section_statement; ++ if (strncmp (".rel", lookup->name, 4) == 0) ++ { ++ /* Don't place after .rel.plt as doing so results in wrong ++ dynamic tags. Also, place allocated reloc sections before ++ non-allocated. */ ++ int lookrela = lookup->name[4] == 'a'; ++ ++ if (strcmp (".plt", lookup->name + 4 + lookrela) == 0 ++ || (lookup->bfd_section != NULL ++ && (lookup->bfd_section->flags & SEC_ALLOC) == 0)) ++ break; ++ last = lookup; ++ if (rela == lookrela) ++ last_rel = lookup; ++ if (lookup->bfd_section != NULL ++ && (lookup->bfd_section->flags & SEC_ALLOC) != 0) ++ last_rel_alloc = lookup; ++ } ++ } ++ ++ if (last_rel_alloc) ++ return last_rel_alloc; ++ ++ if (last_rel) ++ return last_rel; ++ ++ return last; ++} ++ ++/* Find the last output section before given output statement. ++ Used by place_orphan. */ ++ ++static asection * ++output_prev_sec_find (os) ++ lang_output_section_statement_type *os; ++{ ++ asection *s = (asection *) NULL; ++ lang_statement_union_type *u; ++ lang_output_section_statement_type *lookup; ++ ++ for (u = lang_output_section_statement.head; ++ u != (lang_statement_union_type *) NULL; ++ u = lookup->next) ++ { ++ lookup = &u->output_section_statement; ++ if (lookup == os) ++ return s; ++ ++ if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL) ++ s = lookup->bfd_section; ++ } ++ ++ return NULL; ++} ++ ++/* Place an orphan section. We use this to put random SHF_ALLOC ++ sections in the right segment. */ ++ ++struct orphan_save { ++ lang_output_section_statement_type *os; ++ asection **section; ++ lang_statement_union_type **stmt; ++}; ++ ++static boolean ++gld${EMULATION_NAME}_place_orphan (file, s) ++ lang_input_statement_type *file; ++ asection *s; ++{ ++ static struct orphan_save hold_text; ++ static struct orphan_save hold_rodata; ++ static struct orphan_save hold_data; ++ static struct orphan_save hold_bss; ++ static struct orphan_save hold_rel; ++ static struct orphan_save hold_interp; ++ static struct orphan_save hold_sdata; ++ static int count = 1; ++ struct orphan_save *place; ++ lang_statement_list_type *old; ++ lang_statement_list_type add; ++ etree_type *address; ++ const char *secname; ++ const char *ps = NULL; ++ lang_output_section_statement_type *os; ++ int isdyn = 0; ++ ++ secname = bfd_get_section_name (s->owner, s); ++ if (! link_info.relocateable ++ && link_info.combreloc ++ && (s->flags & SEC_ALLOC) ++ && strncmp (secname, ".rel", 4) == 0) ++ { ++ if (secname[4] == 'a') ++ secname = ".rela.dyn"; ++ else ++ secname = ".rel.dyn"; ++ isdyn = 1; ++ } ++ ++ if (isdyn || (!config.unique_orphan_sections && !unique_section_p (secname))) ++ { ++ /* Look through the script to see where to place this section. */ ++ os = lang_output_section_find (secname); ++ ++ if (os != NULL ++ && (os->bfd_section == NULL ++ || ((s->flags ^ os->bfd_section->flags) ++ & (SEC_LOAD | SEC_ALLOC)) == 0)) ++ { ++ /* We already have an output section statement with this ++ name, and its bfd section, if any, has compatible flags. */ ++ lang_add_section (&os->children, s, os, file); ++ return true; ++ } ++ } ++ ++ if (hold_text.os == NULL) ++ hold_text.os = lang_output_section_find (".text"); ++ ++ /* If this is a final link, then always put .gnu.warning.SYMBOL ++ sections into the .text section to get them out of the way. */ ++ if (! link_info.shared ++ && ! link_info.relocateable ++ && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0 ++ && hold_text.os != NULL) ++ { ++ lang_add_section (&hold_text.os->children, s, hold_text.os, file); ++ return true; ++ } ++ ++ /* Decide which segment the section should go in based on the ++ section name and section flags. We put loadable .note sections ++ right after the .interp section, so that the PT_NOTE segment is ++ stored right after the program headers where the OS can read it ++ in the first page. */ ++#define HAVE_SECTION(hold, name) \ ++(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL) ++ ++ if ((s->flags & SEC_EXCLUDE) != 0 && !link_info.relocateable) ++ { ++ if (s->output_section == NULL) ++ s->output_section = bfd_abs_section_ptr; ++ return true; ++ } ++ ++ place = NULL; ++ if ((s->flags & SEC_ALLOC) == 0) ++ ; ++ else if ((s->flags & SEC_LOAD) != 0 ++ && strncmp (secname, ".note", 5) == 0 ++ && HAVE_SECTION (hold_interp, ".interp")) ++ place = &hold_interp; ++ else if ((s->flags & SEC_HAS_CONTENTS) == 0 ++ && HAVE_SECTION (hold_bss, ".bss")) ++ place = &hold_bss; ++ else if ((s->flags & SEC_SMALL_DATA) != 0 ++ && HAVE_SECTION (hold_sdata, ".sdata")) ++ place = &hold_sdata; ++ else if ((s->flags & SEC_READONLY) == 0 ++ && HAVE_SECTION (hold_data, ".data")) ++ place = &hold_data; ++ else if (strncmp (secname, ".rel", 4) == 0 ++ && (s->flags & SEC_LOAD) != 0 ++ && (hold_rel.os != NULL ++ || (hold_rel.os = output_rel_find (s)) != NULL)) ++ place = &hold_rel; ++ else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY ++ && HAVE_SECTION (hold_rodata, ".rodata")) ++ place = &hold_rodata; ++ else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY) ++ && hold_text.os != NULL) ++ place = &hold_text; ++ ++#undef HAVE_SECTION ++ ++ /* Choose a unique name for the section. This will be needed if the ++ same section name appears in the input file with different ++ loadable or allocatable characteristics. */ ++ if (bfd_get_section_by_name (output_bfd, secname) != NULL) ++ { ++ secname = bfd_get_unique_section_name (output_bfd, secname, &count); ++ if (secname == NULL) ++ einfo ("%F%P: place_orphan failed: %E\n"); ++ } ++ ++ /* Start building a list of statements for this section. ++ First save the current statement pointer. */ ++ old = stat_ptr; ++ ++ /* If we have found an appropriate place for the output section ++ statements for this orphan, add them to our own private list, ++ inserting them later into the global statement list. */ ++ if (place != NULL) ++ { ++ stat_ptr = &add; ++ lang_list_init (stat_ptr); ++ } ++ ++ if (config.build_constructors) ++ { ++ /* If the name of the section is representable in C, then create ++ symbols to mark the start and the end of the section. */ ++ for (ps = secname; *ps != '\0'; ps++) ++ if (! ISALNUM (*ps) && *ps != '_') ++ break; ++ if (*ps == '\0') ++ { ++ char *symname; ++ etree_type *e_align; ++ ++ symname = (char *) xmalloc (ps - secname + sizeof "__start_"); ++ sprintf (symname, "__start_%s", secname); ++ e_align = exp_unop (ALIGN_K, ++ exp_intop ((bfd_vma) 1 << s->alignment_power)); ++ lang_add_assignment (exp_assop ('=', symname, e_align)); ++ } ++ } ++ ++ if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) ++ address = exp_intop ((bfd_vma) 0); ++ else ++ address = NULL; ++ ++ os = lang_enter_output_section_statement (secname, address, 0, ++ (bfd_vma) 0, ++ (etree_type *) NULL, ++ (etree_type *) NULL, ++ (etree_type *) NULL); ++ ++ lang_add_section (&os->children, s, os, file); ++ ++ lang_leave_output_section_statement ++ ((bfd_vma) 0, "*default*", ++ (struct lang_output_section_phdr_list *) NULL, NULL); ++ ++ if (config.build_constructors && *ps == '\0') ++ { ++ char *symname; ++ ++ /* lang_leave_ouput_section_statement resets stat_ptr. Put ++ stat_ptr back where we want it. */ ++ if (place != NULL) ++ stat_ptr = &add; ++ ++ symname = (char *) xmalloc (ps - secname + sizeof "__stop_"); ++ sprintf (symname, "__stop_%s", secname); ++ lang_add_assignment (exp_assop ('=', symname, ++ exp_nameop (NAME, "."))); ++ } ++ ++ /* Restore the global list pointer. */ ++ stat_ptr = old; ++ ++ if (place != NULL && os->bfd_section != NULL) ++ { ++ asection *snew, **pps; ++ ++ snew = os->bfd_section; ++ ++ /* Shuffle the bfd section list to make the output file look ++ neater. This is really only cosmetic. */ ++ if (place->section == NULL) ++ { ++ asection *bfd_section = place->os->bfd_section; ++ ++ /* If the output statement hasn't been used to place ++ any input sections (and thus doesn't have an output ++ bfd_section), look for the closest prior output statement ++ having an output section. */ ++ if (bfd_section == NULL) ++ bfd_section = output_prev_sec_find (place->os); ++ ++ if (bfd_section != NULL && bfd_section != snew) ++ place->section = &bfd_section->next; ++ } ++ ++ if (place->section != NULL) ++ { ++ /* Unlink the section. */ ++ for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) ++ ; ++ bfd_section_list_remove (output_bfd, pps); ++ ++ /* Now tack it on to the "place->os" section list. */ ++ bfd_section_list_insert (output_bfd, place->section, snew); ++ } ++ ++ /* Save the end of this list. Further ophans of this type will ++ follow the one we've just added. */ ++ place->section = &snew->next; ++ ++ /* The following is non-cosmetic. We try to put the output ++ statements in some sort of reasonable order here, because ++ they determine the final load addresses of the orphan ++ sections. In addition, placing output statements in the ++ wrong order may require extra segments. For instance, ++ given a typical situation of all read-only sections placed ++ in one segment and following that a segment containing all ++ the read-write sections, we wouldn't want to place an orphan ++ read/write section before or amongst the read-only ones. */ ++ if (add.head != NULL) ++ { ++ if (place->stmt == NULL) ++ { ++ /* Put the new statement list right at the head. */ ++ *add.tail = place->os->header.next; ++ place->os->header.next = add.head; ++ } ++ else ++ { ++ /* Put it after the last orphan statement we added. */ ++ *add.tail = *place->stmt; ++ *place->stmt = add.head; ++ } ++ ++ /* Fix the global list pointer if we happened to tack our ++ new list at the tail. */ ++ if (*old->tail == add.head) ++ old->tail = add.tail; ++ ++ /* Save the end of this list. */ ++ place->stmt = add.tail; ++ } ++ } ++ ++ return true; ++} ++EOF ++fi ++ ++if test x"$LDEMUL_FINISH" != xgld"$EMULATION_NAME"_finish; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++static void ++gld${EMULATION_NAME}_finish () ++{ ++ if (bfd_elf${ELFSIZE}_discard_info (output_bfd, &link_info)) ++ { ++ lang_reset_memory_regions (); ++ ++ /* Resize the sections. */ ++ lang_size_sections (stat_ptr->head, abs_output_section, ++ &stat_ptr->head, 0, (bfd_vma) 0, NULL); ++ ++ /* Redo special stuff. */ ++ ldemul_after_allocation (); ++ ++ /* Do the assignments again. */ ++ lang_do_assignments (stat_ptr->head, abs_output_section, ++ (fill_type *) 0, (bfd_vma) 0); ++ } ++} ++EOF ++fi ++ ++if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++static char * ++gld${EMULATION_NAME}_get_script (isfile) ++ int *isfile; ++EOF ++ ++if test -n "$COMPILE_IN" ++then ++# Scripts compiled in. ++ ++# sed commands to quote an ld script as a C string. ++sc="-f stringify.sed" ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++{ ++ *isfile = 0; ++ ++ if (link_info.relocateable == true && config.build_constructors == true) ++ return ++EOF ++sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.relocateable == true) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c ++echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c ++if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else ++echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c ++fi ++if test -n "$GENERATE_SHLIB_SCRIPT" ; then ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c ++fi ++echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c ++fi ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c ++fi ++echo ' ; else return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c ++echo '; }' >> e${EMULATION_NAME}.c ++ ++else ++# Scripts read from the filesystem. ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++{ ++ *isfile = 1; ++ ++ if (link_info.relocateable == true && config.build_constructors == true) ++ return "ldscripts/${EMULATION_NAME}.xu"; ++ else if (link_info.relocateable == true) ++ return "ldscripts/${EMULATION_NAME}.xr"; ++ else if (!config.text_read_only) ++ return "ldscripts/${EMULATION_NAME}.xbn"; ++ else if (!config.magic_demand_paged) ++ return "ldscripts/${EMULATION_NAME}.xn"; ++ else if (link_info.shared) ++ return "ldscripts/${EMULATION_NAME}.xs"; ++ else ++ return "ldscripts/${EMULATION_NAME}.x"; ++} ++ ++EOF ++fi ++fi ++ ++if test -n "$PARSE_AND_LIST_ARGS_CASES" -o x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++ ++if test x"$LDEMUL_PARSE_ARGS" != xgld"$EMULATION_NAME"_parse_args; then ++ ++if test -n "$PARSE_AND_LIST_PROLOGUE" ; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ $PARSE_AND_LIST_PROLOGUE ++EOF ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++#include "getopt.h" ++ ++#define OPTION_IGNORE (300) ++#define OPTION_FLAVOR (OPTION_IGNORE + 1) ++ ++#define OPTION_DISABLE_NEW_DTAGS (400) ++#define OPTION_ENABLE_NEW_DTAGS (OPTION_DISABLE_NEW_DTAGS + 1) ++#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1) ++#define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1) ++ ++static struct option longopts[] = ++{ ++ {"flavor", required_argument, NULL, OPTION_FLAVOR}, ++EOF ++ ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ /* getopt allows abbreviations, so we do this to stop it from ++ treating -d/-e as abbreviations for these options. */ ++ {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS}, ++ {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS}, ++ {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS}, ++ {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS}, ++ {"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR}, ++ {"Bgroup", no_argument, NULL, OPTION_GROUP}, ++ {"Bgroup", no_argument, NULL, OPTION_GROUP}, ++EOF ++fi ++ ++if test -n "$PARSE_AND_LIST_LONGOPTS" ; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ $PARSE_AND_LIST_LONGOPTS ++EOF ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ {NULL, no_argument, NULL, 0} ++}; ++ ++ ++static int gld${EMULATION_NAME}_parse_args PARAMS ((int, char **)); ++ ++static int ++gld${EMULATION_NAME}_parse_args (argc, argv) ++ int argc; ++ char ** argv; ++{ ++ int longind; ++ int optc; ++ static int prevoptind = -1; ++ int prevopterr = opterr; ++ int wanterror; ++ ++ if (prevoptind != optind) ++ opterr = 0; ++ ++ wanterror = opterr; ++ prevoptind = optind; ++ ++ optc = getopt_long_only (argc, argv, ++ "-${PARSE_AND_LIST_SHORTOPTS}z:", longopts, ++ &longind); ++ opterr = prevopterr; ++ ++ switch (optc) ++ { ++ default: ++ if (wanterror) ++ xexit (1); ++ optind = prevoptind; ++ return 0; ++ ++ case OPTION_FLAVOR: ++ ldfile_add_flavor (optarg); ++ break; ++EOF ++ ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ case OPTION_DISABLE_NEW_DTAGS: ++ link_info.new_dtags = false; ++ break; ++ ++ case OPTION_ENABLE_NEW_DTAGS: ++ link_info.new_dtags = true; ++ break; ++ ++ case OPTION_EH_FRAME_HDR: ++ link_info.eh_frame_hdr = true; ++ break; ++ ++ case OPTION_GROUP: ++ link_info.flags_1 |= (bfd_vma) DF_1_GROUP; ++ /* Groups must be self-contained. */ ++ link_info.no_undefined = true; ++ break; ++ ++ case 'z': ++ if (strcmp (optarg, "initfirst") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST; ++ else if (strcmp (optarg, "interpose") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_INTERPOSE; ++ else if (strcmp (optarg, "loadfltr") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_LOADFLTR; ++ else if (strcmp (optarg, "nodefaultlib") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NODEFLIB; ++ else if (strcmp (optarg, "nodelete") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NODELETE; ++ else if (strcmp (optarg, "nodlopen") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NOOPEN; ++ else if (strcmp (optarg, "nodump") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NODUMP; ++ else if (strcmp (optarg, "now") == 0) ++ { ++ link_info.flags |= (bfd_vma) DF_BIND_NOW; ++ link_info.flags_1 |= (bfd_vma) DF_1_NOW; ++ } ++ else if (strcmp (optarg, "origin") == 0) ++ { ++ link_info.flags |= (bfd_vma) DF_ORIGIN; ++ link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN; ++ } ++ else if (strcmp (optarg, "defs") == 0) ++ link_info.no_undefined = true; ++ else if (strcmp (optarg, "muldefs") == 0) ++ link_info.allow_multiple_definition = true; ++ else if (strcmp (optarg, "combreloc") == 0) ++ link_info.combreloc = true; ++ else if (strcmp (optarg, "nocombreloc") == 0) ++ link_info.combreloc = false; ++ else if (strcmp (optarg, "nocopyreloc") == 0) ++ link_info.nocopyreloc = true; ++ /* What about the other Solaris -z options? FIXME. */ ++ break; ++EOF ++fi ++ ++if test -n "$PARSE_AND_LIST_ARGS_CASES" ; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ $PARSE_AND_LIST_ARGS_CASES ++EOF ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ } ++ ++ return 1; ++} ++ ++EOF ++fi ++ ++if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++static void gld${EMULATION_NAME}_list_options PARAMS ((FILE * file)); ++ ++static void ++gld${EMULATION_NAME}_list_options (file) ++ FILE * file; ++{ ++EOF ++ ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ fprintf (file, _(" -Bgroup\t\tSelects group name lookup rules for DSO\n")); ++ fprintf (file, _(" --disable-new-dtags\tDisable new dynamic tags\n")); ++ fprintf (file, _(" --enable-new-dtags\tEnable new dynamic tags\n")); ++ fprintf (file, _(" --eh-frame-hdr\tCreate .eh_frame_hdr section\n")); ++ fprintf (file, _(" -z combreloc\t\tMerge dynamic relocs into one section and sort\n")); ++ fprintf (file, _(" -z defs\t\tDisallows undefined symbols\n")); ++ fprintf (file, _(" -z initfirst\t\tMark DSO to be initialized first at runtime\n")); ++ fprintf (file, _(" -z interpose\t\tMark object to interpose all DSOs but executable\n")); ++ fprintf (file, _(" -z loadfltr\t\tMark object requiring immediate process\n")); ++ fprintf (file, _(" -z muldefs\t\tAllow multiple definitions\n")); ++ fprintf (file, _(" -z nocombreloc\tDon't merge dynamic relocs into one section\n")); ++ fprintf (file, _(" -z nocopyreloc\tDon't create copy relocs\n")); ++ fprintf (file, _(" -z nodefaultlib\tMark object not to use default search paths\n")); ++ fprintf (file, _(" -z nodelete\t\tMark DSO non-deletable at runtime\n")); ++ fprintf (file, _(" -z nodlopen\t\tMark DSO not available to dlopen\n")); ++ fprintf (file, _(" -z nodump\t\tMark DSO not available to dldump\n")); ++ fprintf (file, _(" -z now\t\tMark object non-lazy runtime binding\n")); ++ fprintf (file, _(" -z origin\t\tMark object requiring immediate \$ORIGIN processing\n\t\t\t at runtime\n")); ++ fprintf (file, _(" -z KEYWORD\t\tIgnored for Solaris compatibility\n")); ++EOF ++fi ++ ++if test -n "$PARSE_AND_LIST_OPTIONS" ; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ $PARSE_AND_LIST_OPTIONS ++EOF ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++} ++EOF ++ ++if test -n "$PARSE_AND_LIST_EPILOGUE" ; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ $PARSE_AND_LIST_EPILOGUE ++EOF ++fi ++fi ++else ++if test x"$LDEMUL_PARSE_ARGS" != xgld"$EMULATION_NAME"_parse_args; then ++cat >>e${EMULATION_NAME}.c <<EOF ++#define gld${EMULATION_NAME}_parse_args NULL ++EOF ++fi ++if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then ++cat >>e${EMULATION_NAME}.c <<EOF ++#define gld${EMULATION_NAME}_list_options NULL ++EOF ++fi ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = ++{ ++ ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse}, ++ ${LDEMUL_SYSLIB-syslib_default}, ++ ${LDEMUL_HLL-hll_default}, ++ ${LDEMUL_AFTER_PARSE-after_parse_default}, ++ ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open}, ++ ${LDEMUL_AFTER_ALLOCATION-after_allocation_default}, ++ ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default}, ++ ${LDEMUL_CHOOSE_TARGET-ldemul_default_target}, ++ ${LDEMUL_BEFORE_ALLOCATION-gld${EMULATION_NAME}_before_allocation}, ++ ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script}, ++ "${EMULATION_NAME}", ++ "${OUTPUT_FORMAT}", ++ ${LDEMUL_FINISH-gld${EMULATION_NAME}_finish}, ++ ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL}, ++ ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-gld${EMULATION_NAME}_open_dynamic_archive}, ++ ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan}, ++ ${LDEMUL_SET_SYMBOLS-NULL}, ++ ${LDEMUL_PARSE_ARGS-gld${EMULATION_NAME}_parse_args}, ++ ${LDEMUL_UNRECOGNIZED_FILE-NULL}, ++ ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options}, ++ ${LDEMUL_RECOGNIZED_FILE-NULL}, ++ ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL}, ++ ${LDEMUL_NEW_VERS_PATTERN-NULL} ++}; ++EOF +diff --git a/ld/emultempl/morphos.em b/ld/emultempl/morphos.em +new file mode 100644 +index 0000000000000000000000000000000000000000..cd3b9a790fb286187d8fa3e11af9382f1603d16b +--- /dev/null ++++ ld/emultempl/morphos.em +@@ -0,0 +1,1104 @@ ++# This shell script emits a C file. -*- C -*- ++# It does some substitutions. ++# This file is now misnamed, because it supports both 32 bit and 64 bit ++# ELF emulations. ++test -z "${ELFSIZE}" && ELFSIZE=32 ++if [ -z "$MACHINE" ]; then ++ OUTPUT_ARCH=${ARCH} ++else ++ OUTPUT_ARCH=${ARCH}:${MACHINE} ++fi ++cat >e${EMULATION_NAME}.c <<EOF ++/* This file is is generated by a shell script. DO NOT EDIT! */ ++ ++/* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME} ++ Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, ++ 2002 Free Software Foundation, Inc. ++ Written by Steve Chamberlain <sac@cygnus.com> ++ ELF support by Ian Lance Taylor <ian@cygnus.com> ++ MorphOS support by Emmanuel Lesueur <lesueur@club-internet.fr> ++ ++This file is part of GLD, the Gnu Linker. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++#define TARGET_IS_${EMULATION_NAME} ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "libiberty.h" ++#include "safe-ctype.h" ++ ++#include "bfdlink.h" ++ ++#include "ld.h" ++#include "ldmain.h" ++#include "ldmisc.h" ++#include "ldexp.h" ++#include "ldlang.h" ++#include "ldfile.h" ++#include "ldemul.h" ++#include <ldgram.h> ++#include "elf/common.h" ++ ++static void gld${EMULATION_NAME}_before_parse ++ PARAMS ((void)); ++static void gld${EMULATION_NAME}_set_symbols ++ PARAMS ((void)); ++static lang_output_section_statement_type *output_rel_find ++ PARAMS ((asection *)); ++static asection *output_prev_sec_find ++ PARAMS ((lang_output_section_statement_type *)); ++static boolean gld${EMULATION_NAME}_place_orphan ++ PARAMS ((lang_input_statement_type *, asection *)); ++static void gld${EMULATION_NAME}_finish ++ PARAMS ((void)); ++static char *gld${EMULATION_NAME}_get_script ++ PARAMS ((int *isfile)); ++ ++extern void ldfile_add_flavor (char*); ++static int morphos_resident; ++ ++EOF ++ ++# Import any needed special functions and/or overrides. ++# ++if test -n "$EXTRA_EM_FILE" ; then ++. ${srcdir}/emultempl/${EXTRA_EM_FILE}.em ++fi ++ ++# Functions in this file can be overridden by setting the LDEMUL_* shell ++# variables. If the name of the overriding function is the same as is ++# defined in this file, then don't output this file's version. ++# If a different overriding name is given then output the standard function ++# as presumably it is called from the overriding function. ++# ++if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++static void ++gld${EMULATION_NAME}_before_parse () ++{ ++ const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}"); ++ if (arch) ++ { ++ ldfile_output_architecture = arch->arch; ++ ldfile_output_machine = arch->mach; ++ ldfile_output_machine_name = arch->printable_name; ++ } ++ else ++ ldfile_output_architecture = bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`; ++ config.dynamic_link = ${DYNAMIC_LINK-true}; ++ config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`; ++ sort_flavors(); ++} ++ ++EOF ++fi ++ ++if test x"$LDEMUL_SET_SYMBOLS" != xgld"$EMULATION_NAME"_set_symbols; then ++cat >>e${EMULATION_NAME}.c <<EOF ++static void ++gld${EMULATION_NAME}_set_symbols() ++{ ++ if (link_info.strip == strip_all) ++ { ++ link_info.keep_hash = ((struct bfd_hash_table *) ++ xmalloc (sizeof (struct bfd_hash_table))); ++ ++ if (! bfd_hash_table_init (link_info.keep_hash, bfd_hash_newfunc)) ++ einfo ("%P%F: bfd_hash_table_init failed: %E\n"); ++ ++ if (bfd_hash_lookup (link_info.keep_hash, "__amigappc__", true, true) ++ == (struct bfd_hash_entry *) NULL) ++ einfo ("%P%F: bfd_hash_lookup for insertion failed: %E\n"); ++ ++ link_info.strip = strip_some; ++ } ++} ++EOF ++fi ++ ++if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* This is called after all the input files have been opened. */ ++ ++static void ++gld${EMULATION_NAME}_after_open () ++{ ++ struct bfd_link_needed_list *needed, *l; ++ ++ /* We only need to worry about this when doing a final link. */ ++ if (link_info.relocateable || link_info.shared) ++ return; ++ ++ /* Get the list of files which appear in DT_NEEDED entries in ++ dynamic objects included in the link (often there will be none). ++ For each such file, we want to track down the corresponding ++ library, and include the symbol table in the link. This is what ++ the runtime dynamic linker will do. Tracking the files down here ++ permits one dynamic object to include another without requiring ++ special action by the person doing the link. Note that the ++ needed list can actually grow while we are stepping through this ++ loop. */ ++ needed = bfd_elf_get_needed_list (output_bfd, &link_info); ++ for (l = needed; l != NULL; l = l->next) ++ { ++ struct bfd_link_needed_list *ll; ++ int force = 0; ++ ++ /* If we've already seen this file, skip it. */ ++ for (ll = needed; ll != l; ll = ll->next) ++ if (strcmp (ll->name, l->name) == 0) ++ break; ++ if (ll != l) ++ continue; ++ ++#if 0 ++ /* See if this file was included in the link explicitly. */ ++ global_needed = l; ++ global_found = false; ++ lang_for_each_input_file (gld${EMULATION_NAME}_check_needed); ++ if (global_found) ++ continue; ++ ++ if (trace_file_tries) ++ info_msg (_("%s needed by %B\n"), l->name, l->by); ++ ++ /* We need to find this file and include the symbol table. We ++ want to search for the file in the same way that the dynamic ++ linker will search. That means that we want to use ++ rpath_link, rpath, then the environment variable ++ LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH ++ entries (native only), then the linker script LIB_SEARCH_DIRS. ++ We do not search using the -L arguments. ++ ++ We search twice. The first time, we skip objects which may ++ introduce version mismatches. The second time, we force ++ their use. See gld${EMULATION_NAME}_vercheck comment. */ ++ for (force = 0; force < 2; force++) ++ { ++ size_t len; ++ search_dirs_type *search; ++EOF ++if [ "x${host}" = "x${target}" ] ; then ++ case " ${EMULATION_LIBPATH} " in ++ *" ${EMULATION_NAME} "*) ++cat >>e${EMULATION_NAME}.c <<EOF ++ const char *lib_path; ++ struct bfd_link_needed_list *rp; ++ int found; ++EOF ++ ;; ++ esac ++fi ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++ if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link, ++ l->name, force)) ++ break; ++EOF ++if [ "x${host}" = "x${target}" ] ; then ++ case " ${EMULATION_LIBPATH} " in ++ *" ${EMULATION_NAME} "*) ++cat >>e${EMULATION_NAME}.c <<EOF ++ if (gld${EMULATION_NAME}_search_needed (command_line.rpath, ++ l->name, force)) ++ break; ++ if (command_line.rpath_link == NULL ++ && command_line.rpath == NULL) ++ { ++ lib_path = (const char *) getenv ("LD_RUN_PATH"); ++ if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, ++ force)) ++ break; ++ } ++ lib_path = (const char *) getenv ("LD_LIBRARY_PATH"); ++ if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force)) ++ break; ++ ++ found = 0; ++ rp = bfd_elf_get_runpath_list (output_bfd, &link_info); ++ for (; !found && rp != NULL; rp = rp->next) ++ { ++ found = (rp->by == l->by ++ && gld${EMULATION_NAME}_search_needed (rp->name, ++ l->name, ++ force)); ++ } ++ if (found) ++ break; ++ ++EOF ++ ;; ++ esac ++fi ++cat >>e${EMULATION_NAME}.c <<EOF ++ len = strlen (l->name); ++ for (search = search_head; search != NULL; search = search->next) ++ { ++ char *filename; ++ ++ if (search->cmdline) ++ continue; ++ filename = (char *) xmalloc (strlen (search->name) + len + 2); ++ sprintf (filename, "%s/%s", search->name, l->name); ++ if (gld${EMULATION_NAME}_try_needed (filename, force)) ++ break; ++ free (filename); ++ } ++ if (search != NULL) ++ break; ++EOF ++if [ "x${host}" = "x${target}" ] ; then ++ case " ${EMULATION_LIBPATH} " in ++ *" ${EMULATION_NAME} "*) ++ case ${target} in ++ *-*-linux-gnu*) ++ cat >>e${EMULATION_NAME}.c <<EOF ++ if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force)) ++ break; ++EOF ++ # Linux ++ ;; ++ esac ++ ;; ++ esac ++fi ++cat >>e${EMULATION_NAME}.c <<EOF ++ } ++#endif ++ if (force < 2) ++ continue; ++ ++ einfo ("%P: warning: %s, needed by %B, not found (try using -rpath or -rpath-link)\n", ++ l->name, l->by); ++ } ++} ++ ++EOF ++fi ++ ++ ++if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then ++ if test x"${ELF_INTERPRETER_NAME+set}" = xset; then ++ ELF_INTERPRETER_SET_DEFAULT=" ++ if (sinterp != NULL) ++ { ++ sinterp->contents = ${ELF_INTERPRETER_NAME}; ++ sinterp->_raw_size = strlen (sinterp->contents) + 1; ++ } ++ ++" ++ else ++ ELF_INTERPRETER_SET_DEFAULT= ++ fi ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* This is called after the sections have been attached to output ++ sections, but before any sizes or addresses have been set. */ ++ ++static void ++gld${EMULATION_NAME}_before_allocation () ++{ ++ const char *rpath; ++ asection *sinterp; ++ ++ /* If we are going to make any variable assignments, we need to let ++ the ELF backend know about them in case the variables are ++ referred to by dynamic objects. */ ++ /*lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment);*/ ++ ++ /* Add the data->data relocation table... */ ++ if (morphos_resident) ++ { ++ asection *sec = bfd_make_section(output_bfd, "ddrelocs"); ++ struct bfd_link_hash_entry *sym; ++ ++ if (sec) ++ { ++ bfd_set_section_flags(output_bfd, sec, SEC_ALLOC | SEC_LOAD | SEC_READONLY | ++ SEC_DATA | SEC_HAS_CONTENTS); ++ sec->output_section = sec; ++ sec->output_offset = 0; ++ sym = bfd_link_hash_lookup(link_info.hash, "__datadata_relocs", true, false, false); ++ if (sym) ++ { ++ sym->type = bfd_link_hash_defined; ++ sym->u.def.value = 0; ++ sym->u.def.section = sec; ++ } ++ } ++ } ++ ++ /* Let the ELF backend work out the sizes of any sections required ++ by dynamic linking. */ ++ rpath = command_line.rpath; ++ /*if (rpath == NULL) ++ rpath = (const char *) getenv ("LD_RUN_PATH");*/ ++ if (! (bfd_elf${ELFSIZE}_size_dynamic_sections ++ (output_bfd, command_line.soname, rpath, ++ command_line.filter_shlib, ++ (const char * const *) command_line.auxiliary_filters, ++ &link_info, &sinterp, lang_elf_version_info))) ++ einfo ("%P%F: failed to set dynamic section sizes: %E\n"); ++${ELF_INTERPRETER_SET_DEFAULT} ++ /* Let the user override the dynamic linker we are using. */ ++ if (command_line.interpreter != NULL ++ && sinterp != NULL) ++ { ++ sinterp->contents = (bfd_byte *) command_line.interpreter; ++ sinterp->_raw_size = strlen (command_line.interpreter) + 1; ++ } ++ ++ /* Look for any sections named .gnu.warning. As a GNU extensions, ++ we treat such sections as containing warning messages. We print ++ out the warning message, and then zero out the section size so ++ that it does not get copied into the output file. */ ++ ++ { ++ LANG_FOR_EACH_INPUT_STATEMENT (is) ++ { ++ asection *s; ++ bfd_size_type sz; ++ char *msg; ++ boolean ret; ++ ++ if (is->just_syms_flag) ++ continue; ++ ++ s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning"); ++ if (s == NULL) ++ continue; ++ ++ sz = bfd_section_size (is->the_bfd, s); ++ msg = xmalloc ((size_t) sz + 1); ++ if (! bfd_get_section_contents (is->the_bfd, s, msg, (file_ptr) 0, sz)) ++ einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n", ++ is->the_bfd); ++ msg[sz] = '\0'; ++ ret = link_info.callbacks->warning (&link_info, msg, ++ (const char *) NULL, ++ is->the_bfd, (asection *) NULL, ++ (bfd_vma) 0); ++ ASSERT (ret); ++ free (msg); ++ ++ /* Clobber the section size, so that we don't waste copying the ++ warning into the output file. */ ++ s->_raw_size = 0; ++ } ++ } ++} ++ ++EOF ++fi ++ ++ ++if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++/* A variant of lang_output_section_find. Used by place_orphan. */ ++ ++static lang_output_section_statement_type * ++output_rel_find (sec) ++ asection *sec; ++{ ++ lang_statement_union_type *u; ++ lang_output_section_statement_type *lookup; ++ lang_output_section_statement_type *last = NULL; ++ lang_output_section_statement_type *last_rel = NULL; ++ lang_output_section_statement_type *last_rel_alloc = NULL; ++ int rela = sec->name[4] == 'a'; ++ ++ for (u = lang_output_section_statement.head; u; u = lookup->next) ++ { ++ lookup = &u->output_section_statement; ++ if (strncmp (".rel", lookup->name, 4) == 0) ++ { ++ /* Don't place after .rel.plt as doing so results in wrong ++ dynamic tags. Also, place allocated reloc sections before ++ non-allocated. */ ++ int lookrela = lookup->name[4] == 'a'; ++ ++ if (strcmp (".plt", lookup->name + 4 + lookrela) == 0 ++ || (lookup->bfd_section != NULL ++ && (lookup->bfd_section->flags & SEC_ALLOC) == 0)) ++ break; ++ last = lookup; ++ if (rela == lookrela) ++ last_rel = lookup; ++ if (lookup->bfd_section != NULL ++ && (lookup->bfd_section->flags & SEC_ALLOC) != 0) ++ last_rel_alloc = lookup; ++ } ++ } ++ ++ if (last_rel_alloc) ++ return last_rel_alloc; ++ ++ if (last_rel) ++ return last_rel; ++ ++ return last; ++} ++ ++/* Find the last output section before given output statement. ++ Used by place_orphan. */ ++ ++static asection * ++output_prev_sec_find (os) ++ lang_output_section_statement_type *os; ++{ ++ asection *s = (asection *) NULL; ++ lang_statement_union_type *u; ++ lang_output_section_statement_type *lookup; ++ ++ for (u = lang_output_section_statement.head; ++ u != (lang_statement_union_type *) NULL; ++ u = lookup->next) ++ { ++ lookup = &u->output_section_statement; ++ if (lookup == os) ++ return s; ++ ++ if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL) ++ s = lookup->bfd_section; ++ } ++ ++ return NULL; ++} ++ ++/* Place an orphan section. We use this to put random SHF_ALLOC ++ sections in the right segment. */ ++ ++struct orphan_save { ++ lang_output_section_statement_type *os; ++ asection **section; ++ lang_statement_union_type **stmt; ++}; ++ ++static boolean ++gld${EMULATION_NAME}_place_orphan (file, s) ++ lang_input_statement_type *file; ++ asection *s; ++{ ++ static struct orphan_save hold_text; ++ static struct orphan_save hold_rodata; ++ static struct orphan_save hold_data; ++ static struct orphan_save hold_bss; ++ static struct orphan_save hold_rel; ++ static struct orphan_save hold_interp; ++ static struct orphan_save hold_sdata; ++ static int count = 1; ++ struct orphan_save *place; ++ lang_statement_list_type *old; ++ lang_statement_list_type add; ++ etree_type *address; ++ const char *secname; ++ const char *ps = NULL; ++ lang_output_section_statement_type *os; ++ int isdyn = 0; ++ ++ secname = bfd_get_section_name (s->owner, s); ++ if (! link_info.relocateable ++ && link_info.combreloc ++ && (s->flags & SEC_ALLOC) ++ && strncmp (secname, ".rel", 4) == 0) ++ { ++ if (secname[4] == 'a') ++ secname = ".rela.dyn"; ++ else ++ secname = ".rel.dyn"; ++ isdyn = 1; ++ } ++ ++ if (isdyn || (!config.unique_orphan_sections && !unique_section_p (secname))) ++ { ++ /* Look through the script to see where to place this section. */ ++ os = lang_output_section_find (secname); ++ ++ if (os != NULL ++ && (os->bfd_section == NULL ++ || ((s->flags ^ os->bfd_section->flags) ++ & (SEC_LOAD | SEC_ALLOC)) == 0)) ++ { ++ /* We already have an output section statement with this ++ name, and its bfd section, if any, has compatible flags. */ ++ lang_add_section (&os->children, s, os, file); ++ return true; ++ } ++ } ++ ++ if (hold_text.os == NULL) ++ hold_text.os = lang_output_section_find (".text"); ++ ++ /* If this is a final link, then always put .gnu.warning.SYMBOL ++ sections into the .text section to get them out of the way. */ ++ if (! link_info.shared ++ && ! link_info.relocateable ++ && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0 ++ && hold_text.os != NULL) ++ { ++ lang_add_section (&hold_text.os->children, s, hold_text.os, file); ++ return true; ++ } ++ ++ /* Decide which segment the section should go in based on the ++ section name and section flags. We put loadable .note sections ++ right after the .interp section, so that the PT_NOTE segment is ++ stored right after the program headers where the OS can read it ++ in the first page. */ ++#define HAVE_SECTION(hold, name) \ ++(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL) ++ ++ if ((s->flags & SEC_EXCLUDE) != 0 && !link_info.relocateable) ++ { ++ if (s->output_section == NULL) ++ s->output_section = bfd_abs_section_ptr; ++ return true; ++ } ++ ++ place = NULL; ++ if ((s->flags & SEC_ALLOC) == 0) ++ ; ++ else if ((s->flags & SEC_LOAD) != 0 ++ && strncmp (secname, ".note", 5) == 0 ++ && HAVE_SECTION (hold_interp, ".interp")) ++ place = &hold_interp; ++ else if ((s->flags & SEC_HAS_CONTENTS) == 0 ++ && HAVE_SECTION (hold_bss, ".bss")) ++ place = &hold_bss; ++ else if ((s->flags & SEC_SMALL_DATA) != 0 ++ && HAVE_SECTION (hold_sdata, ".sdata")) ++ place = &hold_sdata; ++ else if ((s->flags & SEC_READONLY) == 0 ++ && HAVE_SECTION (hold_data, ".data")) ++ place = &hold_data; ++ else if (strncmp (secname, ".rel", 4) == 0 ++ && (s->flags & SEC_LOAD) != 0 ++ && (hold_rel.os != NULL ++ || (hold_rel.os = output_rel_find (s)) != NULL)) ++ place = &hold_rel; ++ else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY ++ && HAVE_SECTION (hold_rodata, ".rodata")) ++ place = &hold_rodata; ++ else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY) ++ && hold_text.os != NULL) ++ place = &hold_text; ++ ++#undef HAVE_SECTION ++ ++ /* Choose a unique name for the section. This will be needed if the ++ same section name appears in the input file with different ++ loadable or allocatable characteristics. */ ++ if (bfd_get_section_by_name (output_bfd, secname) != NULL) ++ { ++ secname = bfd_get_unique_section_name (output_bfd, secname, &count); ++ if (secname == NULL) ++ einfo ("%F%P: place_orphan failed: %E\n"); ++ } ++ ++ /* Start building a list of statements for this section. ++ First save the current statement pointer. */ ++ old = stat_ptr; ++ ++ /* If we have found an appropriate place for the output section ++ statements for this orphan, add them to our own private list, ++ inserting them later into the global statement list. */ ++ if (place != NULL) ++ { ++ stat_ptr = &add; ++ lang_list_init (stat_ptr); ++ } ++ ++ if (config.build_constructors) ++ { ++ /* If the name of the section is representable in C, then create ++ symbols to mark the start and the end of the section. */ ++ for (ps = secname; *ps != '\0'; ps++) ++ if (! ISALNUM (*ps) && *ps != '_') ++ break; ++ if (*ps == '\0') ++ { ++ char *symname; ++ etree_type *e_align; ++ ++ symname = (char *) xmalloc (ps - secname + sizeof "__start_"); ++ sprintf (symname, "__start_%s", secname); ++ e_align = exp_unop (ALIGN_K, ++ exp_intop ((bfd_vma) 1 << s->alignment_power)); ++ lang_add_assignment (exp_assop ('=', symname, e_align)); ++ } ++ } ++ ++ if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) ++ address = exp_intop ((bfd_vma) 0); ++ else ++ address = NULL; ++ ++ os = lang_enter_output_section_statement (secname, address, 0, ++ (bfd_vma) 0, ++ (etree_type *) NULL, ++ (etree_type *) NULL, ++ (etree_type *) NULL); ++ ++ lang_add_section (&os->children, s, os, file); ++ ++ lang_leave_output_section_statement ++ ((bfd_vma) 0, "*default*", ++ (struct lang_output_section_phdr_list *) NULL, NULL); ++ ++ if (config.build_constructors && *ps == '\0') ++ { ++ char *symname; ++ ++ /* lang_leave_ouput_section_statement resets stat_ptr. Put ++ stat_ptr back where we want it. */ ++ if (place != NULL) ++ stat_ptr = &add; ++ ++ symname = (char *) xmalloc (ps - secname + sizeof "__stop_"); ++ sprintf (symname, "__stop_%s", secname); ++ lang_add_assignment (exp_assop ('=', symname, ++ exp_nameop (NAME, "."))); ++ } ++ ++ /* Restore the global list pointer. */ ++ stat_ptr = old; ++ ++ if (place != NULL && os->bfd_section != NULL) ++ { ++ asection *snew, **pps; ++ ++ snew = os->bfd_section; ++ ++ /* Shuffle the bfd section list to make the output file look ++ neater. This is really only cosmetic. */ ++ if (place->section == NULL) ++ { ++ asection *bfd_section = place->os->bfd_section; ++ ++ /* If the output statement hasn't been used to place ++ any input sections (and thus doesn't have an output ++ bfd_section), look for the closest prior output statement ++ having an output section. */ ++ if (bfd_section == NULL) ++ bfd_section = output_prev_sec_find (place->os); ++ ++ if (bfd_section != NULL && bfd_section != snew) ++ place->section = &bfd_section->next; ++ } ++ ++ if (place->section != NULL) ++ { ++ /* Unlink the section. */ ++ for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) ++ ; ++ bfd_section_list_remove (output_bfd, pps); ++ ++ /* Now tack it on to the "place->os" section list. */ ++ bfd_section_list_insert (output_bfd, place->section, snew); ++ } ++ ++ /* Save the end of this list. Further ophans of this type will ++ follow the one we've just added. */ ++ place->section = &snew->next; ++ ++ /* The following is non-cosmetic. We try to put the output ++ statements in some sort of reasonable order here, because ++ they determine the final load addresses of the orphan ++ sections. In addition, placing output statements in the ++ wrong order may require extra segments. For instance, ++ given a typical situation of all read-only sections placed ++ in one segment and following that a segment containing all ++ the read-write sections, we wouldn't want to place an orphan ++ read/write section before or amongst the read-only ones. */ ++ if (add.head != NULL) ++ { ++ if (place->stmt == NULL) ++ { ++ /* Put the new statement list right at the head. */ ++ *add.tail = place->os->header.next; ++ place->os->header.next = add.head; ++ } ++ else ++ { ++ /* Put it after the last orphan statement we added. */ ++ *add.tail = *place->stmt; ++ *place->stmt = add.head; ++ } ++ ++ /* Fix the global list pointer if we happened to tack our ++ new list at the tail. */ ++ if (*old->tail == add.head) ++ old->tail = add.tail; ++ ++ /* Save the end of this list. */ ++ place->stmt = add.tail; ++ } ++ } ++ ++ return true; ++} ++EOF ++fi ++ ++if test x"$LDEMUL_FINISH" != xgld"$EMULATION_NAME"_finish; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++static void ++gld${EMULATION_NAME}_finish () ++{ ++ if (bfd_elf${ELFSIZE}_discard_info (output_bfd, &link_info)) ++ { ++ lang_reset_memory_regions (); ++ ++ /* Resize the sections. */ ++ lang_size_sections (stat_ptr->head, abs_output_section, ++ &stat_ptr->head, 0, (bfd_vma) 0, NULL); ++ ++ /* Redo special stuff. */ ++ ldemul_after_allocation (); ++ ++ /* Do the assignments again. */ ++ lang_do_assignments (stat_ptr->head, abs_output_section, ++ (fill_type *) 0, (bfd_vma) 0); ++ } ++} ++EOF ++fi ++ ++if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++static char * ++gld${EMULATION_NAME}_get_script (isfile) ++ int *isfile; ++EOF ++ ++if test -n "$COMPILE_IN" ++then ++# Scripts compiled in. ++ ++# sed commands to quote an ld script as a C string. ++sc="-f stringify.sed" ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++{ ++ *isfile = 0; ++ ++ if (link_info.relocateable == true && config.build_constructors == true) ++ return ++EOF ++sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.relocateable == true) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c ++echo ' ; else return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c ++echo '; }' >> e${EMULATION_NAME}.c ++ ++else ++# Scripts read from the filesystem. ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++{ ++ *isfile = 1; ++ ++ if (link_info.relocateable == true && config.build_constructors == true) ++ return "ldscripts/${EMULATION_NAME}.xu"; ++ else if (link_info.relocateable == true) ++ return "ldscripts/${EMULATION_NAME}.xr"; ++ else ++ return "ldscripts/${EMULATION_NAME}.x"; ++} ++ ++EOF ++fi ++fi ++ ++if test -n "$PARSE_AND_LIST_ARGS_CASES" -o x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++ ++if test x"$LDEMUL_PARSE_ARGS" != xgld"$EMULATION_NAME"_parse_args; then ++ ++if test -n "$PARSE_AND_LIST_PROLOGUE" ; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ $PARSE_AND_LIST_PROLOGUE ++EOF ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++#include "getopt.h" ++ ++#define OPTION_IGNORE (300) ++#define OPTION_MORPHOS_DATADATA_RELOC (OPTION_IGNORE + 1) ++#define OPTION_MORPHOS_BASEREL32 (OPTION_IGNORE + 2) ++#define OPTION_FLAVOR (OPTION_IGNORE + 3) ++ ++#define OPTION_DISABLE_NEW_DTAGS (400) ++#define OPTION_ENABLE_NEW_DTAGS (OPTION_DISABLE_NEW_DTAGS + 1) ++#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1) ++#define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1) ++ ++static struct option longopts[] = ++{ ++ {"datadata-reloc", no_argument, NULL, OPTION_MORPHOS_DATADATA_RELOC}, ++ /* '\0', NULL, "Relocate for resident program", ONE_DASH },*/ ++ {"flavor", required_argument, NULL, OPTION_FLAVOR}, ++ /*'\0', NULL, "Select a library flavor", ONE_DASH },*/ ++ /*{"baserel32", no_argument, NULL, OPTION_MORPHOS_BASEREL32},*/ ++ /* '\0', NULL, "Build a large-data base relative executable", ONE_DASH },*/ ++EOF ++ ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ /* getopt allows abbreviations, so we do this to stop it from ++ treating -d/-e as abbreviations for these options. */ ++ {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS}, ++ {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS}, ++ {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS}, ++ {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS}, ++ {"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR}, ++ {"Bgroup", no_argument, NULL, OPTION_GROUP}, ++ {"Bgroup", no_argument, NULL, OPTION_GROUP}, ++EOF ++fi ++ ++if test -n "$PARSE_AND_LIST_LONGOPTS" ; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ $PARSE_AND_LIST_LONGOPTS ++EOF ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ {NULL, no_argument, NULL, 0} ++}; ++ ++ ++static int gld${EMULATION_NAME}_parse_args PARAMS ((int, char **)); ++ ++static int ++gld${EMULATION_NAME}_parse_args (argc, argv) ++ int argc; ++ char ** argv; ++{ ++ int longind; ++ int optc; ++ static int prevoptind = -1; ++ int prevopterr = opterr; ++ int wanterror; ++ ++ if (prevoptind != optind) ++ opterr = 0; ++ ++ wanterror = opterr; ++ prevoptind = optind; ++ ++ optc = getopt_long_only (argc, argv, ++ "-${PARSE_AND_LIST_SHORTOPTS}z:", longopts, ++ &longind); ++ opterr = prevopterr; ++ ++ switch (optc) ++ { ++ default: ++ if (wanterror) ++ xexit (1); ++ optind = prevoptind; ++ return 0; ++ ++ case OPTION_MORPHOS_DATADATA_RELOC: ++ morphos_resident=1; /* Write out datadata_reloc array */ ++ break; ++ ++ /*case OPTION_MORPHOS_BASEREL32: ++ morphos_baserel32=1; ++ break;*/ ++ ++ case OPTION_FLAVOR: ++ ldfile_add_flavor (optarg); ++ break; ++EOF ++ ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ case OPTION_DISABLE_NEW_DTAGS: ++ link_info.new_dtags = false; ++ break; ++ ++ case OPTION_ENABLE_NEW_DTAGS: ++ link_info.new_dtags = true; ++ break; ++ ++ case OPTION_EH_FRAME_HDR: ++ link_info.eh_frame_hdr = true; ++ break; ++ ++ case OPTION_GROUP: ++ link_info.flags_1 |= (bfd_vma) DF_1_GROUP; ++ /* Groups must be self-contained. */ ++ link_info.no_undefined = true; ++ break; ++ ++ case 'z': ++ if (strcmp (optarg, "initfirst") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST; ++ else if (strcmp (optarg, "interpose") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_INTERPOSE; ++ else if (strcmp (optarg, "loadfltr") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_LOADFLTR; ++ else if (strcmp (optarg, "nodefaultlib") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NODEFLIB; ++ else if (strcmp (optarg, "nodelete") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NODELETE; ++ else if (strcmp (optarg, "nodlopen") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NOOPEN; ++ else if (strcmp (optarg, "nodump") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NODUMP; ++ else if (strcmp (optarg, "now") == 0) ++ { ++ link_info.flags |= (bfd_vma) DF_BIND_NOW; ++ link_info.flags_1 |= (bfd_vma) DF_1_NOW; ++ } ++ else if (strcmp (optarg, "origin") == 0) ++ { ++ link_info.flags |= (bfd_vma) DF_ORIGIN; ++ link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN; ++ } ++ else if (strcmp (optarg, "defs") == 0) ++ link_info.no_undefined = true; ++ else if (strcmp (optarg, "muldefs") == 0) ++ link_info.allow_multiple_definition = true; ++ else if (strcmp (optarg, "combreloc") == 0) ++ link_info.combreloc = true; ++ else if (strcmp (optarg, "nocombreloc") == 0) ++ link_info.combreloc = false; ++ else if (strcmp (optarg, "nocopyreloc") == 0) ++ link_info.nocopyreloc = true; ++ /* What about the other Solaris -z options? FIXME. */ ++ break; ++EOF ++fi ++ ++if test -n "$PARSE_AND_LIST_ARGS_CASES" ; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ $PARSE_AND_LIST_ARGS_CASES ++EOF ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ } ++ ++ return 1; ++} ++ ++EOF ++fi ++ ++if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++static void gld${EMULATION_NAME}_list_options PARAMS ((FILE * file)); ++ ++static void ++gld${EMULATION_NAME}_list_options (file) ++ FILE * file; ++{ ++EOF ++ ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ fprintf (file, _(" -Bgroup\t\tSelects group name lookup rules for DSO\n")); ++ fprintf (file, _(" --disable-new-dtags\tDisable new dynamic tags\n")); ++ fprintf (file, _(" --enable-new-dtags\tEnable new dynamic tags\n")); ++ fprintf (file, _(" --eh-frame-hdr\tCreate .eh_frame_hdr section\n")); ++ fprintf (file, _(" -z combreloc\t\tMerge dynamic relocs into one section and sort\n")); ++ fprintf (file, _(" -z defs\t\tDisallows undefined symbols\n")); ++ fprintf (file, _(" -z initfirst\t\tMark DSO to be initialized first at runtime\n")); ++ fprintf (file, _(" -z interpose\t\tMark object to interpose all DSOs but executable\n")); ++ fprintf (file, _(" -z loadfltr\t\tMark object requiring immediate process\n")); ++ fprintf (file, _(" -z muldefs\t\tAllow multiple definitions\n")); ++ fprintf (file, _(" -z nocombreloc\tDon't merge dynamic relocs into one section\n")); ++ fprintf (file, _(" -z nocopyreloc\tDon't create copy relocs\n")); ++ fprintf (file, _(" -z nodefaultlib\tMark object not to use default search paths\n")); ++ fprintf (file, _(" -z nodelete\t\tMark DSO non-deletable at runtime\n")); ++ fprintf (file, _(" -z nodlopen\t\tMark DSO not available to dlopen\n")); ++ fprintf (file, _(" -z nodump\t\tMark DSO not available to dldump\n")); ++ fprintf (file, _(" -z now\t\tMark object non-lazy runtime binding\n")); ++ fprintf (file, _(" -z origin\t\tMark object requiring immediate \$ORIGIN processing\n\t\t\t at runtime\n")); ++ fprintf (file, _(" -z KEYWORD\t\tIgnored for Solaris compatibility\n")); ++EOF ++fi ++ ++if test -n "$PARSE_AND_LIST_OPTIONS" ; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ $PARSE_AND_LIST_OPTIONS ++EOF ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++} ++EOF ++ ++if test -n "$PARSE_AND_LIST_EPILOGUE" ; then ++cat >>e${EMULATION_NAME}.c <<EOF ++ $PARSE_AND_LIST_EPILOGUE ++EOF ++fi ++fi ++else ++if test x"$LDEMUL_PARSE_ARGS" != xgld"$EMULATION_NAME"_parse_args; then ++cat >>e${EMULATION_NAME}.c <<EOF ++#define gld${EMULATION_NAME}_parse_args NULL ++EOF ++fi ++if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then ++cat >>e${EMULATION_NAME}.c <<EOF ++#define gld${EMULATION_NAME}_list_options NULL ++EOF ++fi ++fi ++ ++cat >>e${EMULATION_NAME}.c <<EOF ++ ++struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = ++{ ++ ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse}, ++ ${LDEMUL_SYSLIB-syslib_default}, ++ ${LDEMUL_HLL-hll_default}, ++ ${LDEMUL_AFTER_PARSE-after_parse_default}, ++ ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open}, ++ ${LDEMUL_AFTER_ALLOCATION-after_allocation_default}, ++ ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default}, ++ ${LDEMUL_CHOOSE_TARGET-ldemul_default_target}, ++ ${LDEMUL_BEFORE_ALLOCATION-gld${EMULATION_NAME}_before_allocation}, ++ ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script}, ++ "${EMULATION_NAME}", ++ "${OUTPUT_FORMAT}", ++ ${LDEMUL_FINISH-gld${EMULATION_NAME}_finish}, ++ ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL}, ++ ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-NULL}, ++ ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan}, ++ ${LDEMUL_SET_SYMBOLS-gld${EMULATION_NAME}_set_symbols}, ++ ${LDEMUL_PARSE_ARGS-gld${EMULATION_NAME}_parse_args}, ++ ${LDEMUL_UNRECOGNIZED_FILE-NULL}, ++ ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options}, ++ ${LDEMUL_RECOGNIZED_FILE-NULL}, ++ ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL}, ++ ${LDEMUL_NEW_VERS_PATTERN-NULL} ++}; ++EOF +diff --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em +index 6843770ca9431d7a4b698bfda7060082b215c41f..801d1d6424bc1f61bb0e7171de9f9b5178bc8100 100644 +--- ld/emultempl/ppc32elf.em ++++ ld/emultempl/ppc32elf.em +@@ -26,12 +26,15 @@ + fragment <<EOF + + #include "libbfd.h" + #include "elf32-ppc.h" + #include "ldlex.h" + ++extern int ppc_elf_amigaos_select_plt_layout (bfd *, struct bfd_link_info *, ++ enum ppc_elf_plt_type, int); ++ + #define is_ppc_elf(bfd) \ + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ + && elf_object_id (bfd) == PPC32_ELF_DATA) + + /* Whether to run tls optimization. */ + static int notlsopt = 0; +@@ -56,14 +59,19 @@ ppc_after_open (void) + lang_output_section_statement_type *os; + lang_output_section_statement_type *plt_os[2]; + lang_output_section_statement_type *got_os[2]; + + if (emit_stub_syms < 0) + emit_stub_syms = link_info.emitrelocations || link_info.shared; ++#ifdef TARGET_IS_amigaos ++ new_plt = ppc_elf_amigaos_select_plt_layout (link_info.output_bfd, &link_info, ++ plt_style, emit_stub_syms); ++#else + new_plt = ppc_elf_select_plt_layout (link_info.output_bfd, &link_info, + plt_style, emit_stub_syms); ++#endif + if (new_plt < 0) + einfo ("%X%P: select_plt_layout problem %E\n"); + + num_got = 0; + num_plt = 0; + for (os = &lang_output_section_statement.head->output_section_statement; +@@ -185,12 +193,16 @@ PARSE_AND_LIST_PROLOGUE=${PARSE_AND_LIST_PROLOGUE}' + #define OPTION_OLD_PLT (OPTION_NEW_PLT + 1) + #define OPTION_OLD_GOT (OPTION_OLD_PLT + 1) + #define OPTION_STUBSYMS (OPTION_OLD_GOT + 1) + #define OPTION_NO_STUBSYMS (OPTION_STUBSYMS + 1) + ' + ++# ++# CHECK: There was more here about use-dynld option. ++# ++ + PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}' + { "emit-stub-syms", no_argument, NULL, OPTION_STUBSYMS }, + { "no-emit-stub-syms", no_argument, NULL, OPTION_NO_STUBSYMS }, + { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT }, + { "no-tls-get-addr-optimize", no_argument, NULL, OPTION_NO_TLS_GET_ADDR_OPT }, + { "secure-plt", no_argument, NULL, OPTION_NEW_PLT }, +diff --git a/ld/ldctor.c b/ld/ldctor.c +index b29c1e0cbb13463f58989042722775698365cf9a..18d5f9370c7a0e9b009c74fdff48a4c45659245f 100644 +--- ld/ldctor.c ++++ ld/ldctor.c +@@ -256,14 +256,18 @@ ldctor_build_sets (void) + reloc_howto_type *howto; + int reloc_size, size; + + /* If the symbol is defined, we may have been invoked from + collect, and the sets may already have been built, so we do + not do anything. */ +- if (p->h->type == bfd_link_hash_defined +- || p->h->type == bfd_link_hash_defweak) ++ /* dgv -- libnix v1.1 uses absolute sets that are also explicitly ++ defined in the library so that the sets need to be build even ++ if the symbol is defined */ ++ if ((bfd_get_flavour (link_info.output_bfd) != bfd_target_amiga_flavour) && ++ (p->h->type == bfd_link_hash_defined ++ || p->h->type == bfd_link_hash_defweak)) + continue; + + /* For each set we build: + set: + .long number_of_elements + .long element0 +@@ -353,21 +357,27 @@ ldctor_build_sets (void) + print_space (); + ++len; + } + + if (e->name != NULL) + minfo ("%T\n", e->name); +- else ++ else if (e->section->owner) + minfo ("%G\n", e->section->owner, e->section, e->value); ++ else ++ minfo ("%s\n", "** ABS **"); + } + + /* Need SEC_KEEP for --gc-sections. */ + if (! bfd_is_abs_section (e->section)) + e->section->flags |= SEC_KEEP; + +- if (link_info.relocatable) ++ /* dgv -- on the amiga, we want the constructors to be relocateable ++ objects. However, this should be arranged somewhere else (FIXME) */ ++ if (link_info.relocatable || ++ (bfd_get_flavour (link_info.output_bfd) == bfd_target_amiga_flavour && ++ e->section != bfd_abs_section_ptr)) + lang_add_reloc (p->reloc, howto, e->section, e->name, + exp_intop (e->value)); + else + lang_add_data (size, exp_relop (e->section, e->value)); + } + +diff --git a/ld/ldfile.c b/ld/ldfile.c +index e9091e9fa9ab0cb1182a102de48096ac13215a39..034eb2a7e452623f8c2571f4d6186b981c10c11d 100644 +--- ld/ldfile.c ++++ ld/ldfile.c +@@ -63,12 +63,46 @@ typedef struct search_arch + } search_arch_type; + + static search_dirs_type **search_tail_ptr = &search_head; + static search_arch_type *search_arch_head; + static search_arch_type **search_arch_tail_ptr = &search_arch_head; + ++/* Flavour support. */ ++ ++static int flavors_cmp PARAMS ((const void *f1, const void *f2)); ++ ++static int n_flavors, flavors_len; ++static char **flavors; ++ ++static int ++flavors_cmp (f1, f2) ++ const void *f1, *f2; ++{ ++ return strcmp (*(char **)f1, *(char **)f2); ++} ++ ++void ++ldfile_sort_flavors () ++{ ++ if (n_flavors > 1) ++ qsort ((void *) flavors, n_flavors, sizeof (char **), flavors_cmp); ++} ++ ++void ++ldfile_add_flavor (name) ++ const char *name; ++{ ++ n_flavors++; ++ if (flavors) ++ flavors = (char **) xrealloc ((PTR)flavors, n_flavors * sizeof (char *)); ++ else ++ flavors = (char **) xmalloc (sizeof (char *)); ++ flavors [n_flavors-1] = (char *) name; ++ flavors_len += strlen (name); ++} ++ + /* Test whether a pathname, after canonicalization, is the same or a + sub-directory of the sysroot directory. */ + + static bfd_boolean + is_sysrooted_pathname (const char *name) + { +@@ -332,12 +366,13 @@ success: + bfd_boolean + ldfile_open_file_search (const char *arch, + lang_input_statement_type *entry, + const char *lib, + const char *suffix) + { ++ char *flavor_dir = (char *) alloca (flavors_len + n_flavors + 1); + search_dirs_type *search; + + /* If this is not an archive, try to open it in the current + directory first. */ + if (! entry->flags.maybe_archive) + { +@@ -359,35 +394,50 @@ ldfile_open_file_search (const char *arch, + return FALSE; + } + + for (search = search_head; search != NULL; search = search->next) + { + char *string; ++ int i, count; + + if (entry->flags.dynamic && ! link_info.relocatable) + { + if (ldemul_open_dynamic_archive (arch, search, entry)) + return TRUE; + } + ++ /* This is intentionally indented so strange to aid merging */ ++ for (count=n_flavors; count>=0; count--) ++ { ++ *flavor_dir = '\0'; ++ for (i=0; i<count; i++) ++ { ++ strcat (flavor_dir, flavors[i]); ++ strcat (flavor_dir, slash); ++ } ++ + if (entry->flags.maybe_archive) +- string = concat (search->name, slash, lib, entry->filename, ++ string = concat (search->name, slash, flavor_dir, lib, entry->filename, + arch, suffix, (const char *) NULL); ++ else if (entry->filename[0] == '/' || entry->filename[0] == '.') ++ string = concat(entry->filename, NULL); + else +- string = concat (search->name, slash, entry->filename, ++ string = concat (search->name, slash, flavor_dir, entry->filename, + (const char *) 0); + + if (ldfile_try_open_bfd (string, entry)) + { + entry->filename = string; + return TRUE; + } + + free (string); + } + ++ } ++ + return FALSE; + } + + /* Open the input file specified by ENTRY. + PR 4437: Do not stop on the first missing file, but + continue processing other input files in case there +diff --git a/ld/ldfile.h b/ld/ldfile.h +index 945609250afc6fede2985dbdd59bf035cb835843..530fb0f3b78f7ce54421b074bea4fcd5ae28022d 100644 +--- ld/ldfile.h ++++ ld/ldfile.h +@@ -56,7 +56,12 @@ extern bfd_boolean ldfile_try_open_bfd + extern void ldfile_set_output_arch + (const char *, enum bfd_architecture); + extern bfd_boolean ldfile_open_file_search + (const char *arch, struct lang_input_statement_struct *, + const char *lib, const char *suffix); + ++extern void ldfile_sort_flavors ++ PARAMS ((void)); ++extern void ldfile_add_flavor ++ PARAMS ((const char *)); ++ + #endif +diff --git a/ld/ldlang.c b/ld/ldlang.c +index 459f277a3ea5baa2f38e7b95db0ac9ef67d648b8..d199cda1fd9bd4d8bfa12fe72a44501861ffe1ff 100644 +--- ld/ldlang.c ++++ ld/ldlang.c +@@ -3389,12 +3389,19 @@ typedef struct bfd_sym_chain ldlang_undef_chain_list_type; + + #define ldlang_undef_chain_list_head entry_symbol.next + + void + ldlang_add_undef (const char *const name, bfd_boolean cmdline) + { ++#if 1 ++ /* This is a quick ugly hak of getting around the problem ++ * with -use-dynld being passed to the linker ++ */ ++ if (strcmp(name, "se-dynld") == 0) ++ return; ++#endif + ldlang_undef_chain_list_type *new_undef; + + undef_from_cmdline = undef_from_cmdline || cmdline; + new_undef = (ldlang_undef_chain_list_type *) stat_alloc (sizeof (*new_undef)); + new_undef->next = ldlang_undef_chain_list_head; + ldlang_undef_chain_list_head = new_undef; +diff --git a/ld/ldlang.h b/ld/ldlang.h +index d5ea8d20e34c9c4697d0aa14b4af09d2df8f0d20..f6f061dfe6e92cdb3a5097baf644773cc402ad3f 100644 +--- ld/ldlang.h ++++ ld/ldlang.h +@@ -302,12 +302,14 @@ typedef struct lang_input_statement_struct + /* Point to the next file, but skips archive contents. */ + union lang_statement_union *next_real_file; + + const char *target; + + struct lang_input_statement_flags flags; ++ /* Added for AMIGA support of section attributes */ ++ int amiga_attribute; + } lang_input_statement_type; + + typedef struct + { + lang_statement_header_type header; + asection *section; +diff --git a/ld/ldlex.c b/ld/ldlex.c +index 50bb3b1e14133555e524ad059d7b578cfaac6b24..eb7e21a7741a0fc82b72f2c7e3d88d1888998db8 100644 +--- ld/ldlex.c ++++ ld/ldlex.c +@@ -1,17 +1,17 @@ + +-#line 3 "ldlex.c" ++#line 3 "/home/sba/amiga/adtools/branches/binutils/2.23.2/ld/ldlex.c" + + #define YY_INT_ALIGNED short int + + /* A lexical scanner generated by flex */ + + #define FLEX_SCANNER + #define YY_FLEX_MAJOR_VERSION 2 + #define YY_FLEX_MINOR_VERSION 5 +-#define YY_FLEX_SUBMINOR_VERSION 35 ++#define YY_FLEX_SUBMINOR_VERSION 39 + #if YY_FLEX_SUBMINOR_VERSION > 0 + #define FLEX_BETA + #endif + + /* First, we deal with platform-specific or compiler-specific issues. */ + +@@ -50,13 +50,12 @@ typedef uint32_t flex_uint32_t; + typedef signed char flex_int8_t; + typedef short int flex_int16_t; + typedef int flex_int32_t; + typedef unsigned char flex_uint8_t; + typedef unsigned short int flex_uint16_t; + typedef unsigned int flex_uint32_t; +-#endif /* ! C99 */ + + /* Limits of integral types. */ + #ifndef INT8_MIN + #define INT8_MIN (-128) + #endif + #ifndef INT16_MIN +@@ -81,12 +80,14 @@ typedef unsigned int flex_uint32_t; + #define UINT16_MAX (65535U) + #endif + #ifndef UINT32_MAX + #define UINT32_MAX (4294967295U) + #endif + ++#endif /* ! C99 */ ++ + #endif /* ! FLEXINT_H */ + + #ifdef __cplusplus + + /* The "const" storage-class-modifier is valid. */ + #define YY_USE_CONST +@@ -137,33 +138,47 @@ typedef unsigned int flex_uint32_t; + #define YY_NEW_FILE yyrestart(yyin ) + + #define YY_END_OF_BUFFER_CHAR 0 + + /* Size of default input buffer. */ + #ifndef YY_BUF_SIZE ++#ifdef __ia64__ ++/* On IA-64, the buffer size is 16k, not 8k. ++ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. ++ * Ditto for the __ia64__ case accordingly. ++ */ ++#define YY_BUF_SIZE 32768 ++#else + #define YY_BUF_SIZE 16384 ++#endif /* __ia64__ */ + #endif + + /* The state buf must be large enough to hold one state per character in the main buffer. + */ + #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + + #ifndef YY_TYPEDEF_YY_BUFFER_STATE + #define YY_TYPEDEF_YY_BUFFER_STATE + typedef struct yy_buffer_state *YY_BUFFER_STATE; + #endif + +-extern int yyleng; ++#ifndef YY_TYPEDEF_YY_SIZE_T ++#define YY_TYPEDEF_YY_SIZE_T ++typedef size_t yy_size_t; ++#endif ++ ++extern yy_size_t yyleng; + + extern FILE *yyin, *yyout; + + #define EOB_ACT_CONTINUE_SCAN 0 + #define EOB_ACT_END_OF_FILE 1 + #define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) ++ #define YY_LINENO_REWIND_TO(ptr) + + /* Return all but the first "n" matched characters back to the input stream. */ + #define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ +@@ -175,17 +190,12 @@ extern FILE *yyin, *yyout; + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + + #define unput(c) yyunput( c, (yytext_ptr) ) + +-#ifndef YY_TYPEDEF_YY_SIZE_T +-#define YY_TYPEDEF_YY_SIZE_T +-typedef size_t yy_size_t; +-#endif +- + #ifndef YY_STRUCT_YY_BUFFER_STATE + #define YY_STRUCT_YY_BUFFER_STATE + struct yy_buffer_state + { + FILE *yy_input_file; + +@@ -197,13 +207,13 @@ struct yy_buffer_state + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ +- int yy_n_chars; ++ yy_size_t yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; +@@ -267,14 +277,14 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + * NULL or when we need an lvalue. For internal use only. + */ + #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + + /* yy_hold_char holds the character lost when yytext is formed. */ + static char yy_hold_char; +-static int yy_n_chars; /* number of characters read into yy_ch_buf */ +-int yyleng; ++static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ ++yy_size_t yyleng; + + /* Points to current character in buffer. */ + static char *yy_c_buf_p = (char *) 0; + static int yy_init = 0; /* whether we need to initialize */ + static int yy_start = 0; /* start state number */ + +@@ -296,13 +306,13 @@ static void yy_load_buffer_state (void ); + static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); + + #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + + YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); + YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); ++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); + + void *yyalloc (yy_size_t ); + void *yyrealloc (void *,yy_size_t ); + void yyfree (void * ); + + #define yy_new_buffer yy_create_buffer +@@ -1711,13 +1721,13 @@ int yywrap (void) { return 1; } + + + + + + +-#line 1718 "ldlex.c" ++#line 1728 "/home/sba/amiga/adtools/branches/binutils/2.23.2/ld/ldlex.c" + + #define INITIAL 0 + #define SCRIPT 1 + #define EXPRESSION 2 + #define BOTH 3 + #define DEFSYMEXP 4 +@@ -1758,13 +1768,13 @@ FILE *yyget_in (void ); + void yyset_in (FILE * in_str ); + + FILE *yyget_out (void ); + + void yyset_out (FILE * out_str ); + +-int yyget_leng (void ); ++yy_size_t yyget_leng (void ); + + char *yyget_text (void ); + + int yyget_lineno (void ); + + void yyset_lineno (int line_number ); +@@ -1798,32 +1808,37 @@ static int input (void ); + #endif + + #endif + + /* Amount of stuff to slurp up with each read. */ + #ifndef YY_READ_BUF_SIZE ++#ifdef __ia64__ ++/* On IA-64, the buffer size is 16k, not 8k */ ++#define YY_READ_BUF_SIZE 16384 ++#else + #define YY_READ_BUF_SIZE 8192 ++#endif /* __ia64__ */ + #endif + + /* Copy whatever the last rule matched to the standard output. */ + #ifndef ECHO + /* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +-#define ECHO fwrite( yytext, yyleng, 1, yyout ) ++#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) + #endif + + /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ + #ifndef YY_INPUT + #define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ +- yy_size_t n; \ ++ size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ +@@ -1899,33 +1914,12 @@ extern int yylex (void); + YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +-#line 121 "ldlex.l" +- +- +- if (parser_input != input_selected) +- { +- /* The first token of the input determines the initial parser state. */ +- input_type t = parser_input; +- parser_input = input_selected; +- switch (t) +- { +- case input_script: return INPUT_SCRIPT; break; +- case input_mri_script: return INPUT_MRI_SCRIPT; break; +- case input_version_script: return INPUT_VERSION_SCRIPT; break; +- case input_dynamic_list: return INPUT_DYNAMIC_LIST; break; +- case input_defsym: return INPUT_DEFSYM; break; +- default: abort (); +- } +- } +- +-#line 1925 "ldlex.c" +- + if ( !(yy_init) ) + { + (yy_init) = 1; + + #ifdef YY_USER_INIT + YY_USER_INIT; +@@ -1946,12 +1940,34 @@ YY_DECL + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + ++ { ++#line 121 "ldlex.l" ++ ++ ++ if (parser_input != input_selected) ++ { ++ /* The first token of the input determines the initial parser state. */ ++ input_type t = parser_input; ++ parser_input = input_selected; ++ switch (t) ++ { ++ case input_script: return INPUT_SCRIPT; break; ++ case input_mri_script: return INPUT_MRI_SCRIPT; break; ++ case input_version_script: return INPUT_VERSION_SCRIPT; break; ++ case input_dynamic_list: return INPUT_DYNAMIC_LIST; break; ++ case input_defsym: return INPUT_DEFSYM; break; ++ default: abort (); ++ } ++ } ++ ++#line 1967 "/home/sba/amiga/adtools/branches/binutils/2.23.2/ld/ldlex.c" ++ + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); +@@ -1962,13 +1978,13 @@ YY_DECL + yy_bp = yy_cp; + + yy_current_state = (yy_start); + yy_match: + do + { +- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; ++ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) +@@ -3105,13 +3121,13 @@ lex_warn_invalid (" in expression", yytext); + YY_BREAK + case 195: + YY_RULE_SETUP + #line 468 "ldlex.l" + ECHO; + YY_BREAK +-#line 3112 "ldlex.c" ++#line 3128 "/home/sba/amiga/adtools/branches/binutils/2.23.2/ld/ldlex.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + +@@ -3234,12 +3250,13 @@ ECHO; + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ ++ } /* end of user's declarations */ + } /* end of yylex */ + + /* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - +@@ -3289,27 +3306,27 @@ static int yy_get_next_buffer (void) + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { +- int num_to_read = ++ yy_size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ +- YY_BUFFER_STATE b = YY_CURRENT_BUFFER; ++ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { +- int new_size = b->yy_buf_size * 2; ++ yy_size_t new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + +@@ -3334,13 +3351,13 @@ static int yy_get_next_buffer (void) + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), +- (yy_n_chars), (size_t) num_to_read ); ++ (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { +@@ -3429,13 +3446,13 @@ static int yy_get_next_buffer (void) + if ( yy_current_state >= 1706 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 1705); + +- return yy_is_jam ? 0 : yy_current_state; ++ return yy_is_jam ? 0 : yy_current_state; + } + + #ifndef YY_NO_INPUT + #ifdef __cplusplus + static int yyinput (void) + #else +@@ -3456,13 +3473,13 @@ static int yy_get_next_buffer (void) + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ +- int offset = (yy_c_buf_p) - (yytext_ptr); ++ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() +@@ -3616,16 +3633,12 @@ static void yy_load_buffer_state (void) + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ); + + yyfree((void *) b ); + } + +-#ifndef __cplusplus +-extern int isatty (int ); +-#endif /* __cplusplus */ +- + /* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +@@ -3732,13 +3745,13 @@ void yypop_buffer_state (void) + + /* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ + static void yyensure_buffer_stack (void) + { +- int num_to_alloc; ++ yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. +@@ -3824,23 +3837,23 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) + + return yy_scan_bytes(yystr,strlen(yystr) ); + } + + /** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. +- * @param bytes the byte buffer to scan +- * @param len the number of bytes in the buffer pointed to by @a bytes. ++ * @param yybytes the byte buffer to scan ++ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) ++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; +- int i; ++ yy_size_t i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); +@@ -3916,13 +3929,13 @@ FILE *yyget_out (void) + return yyout; + } + + /** Get the length of the current token. + * + */ +-int yyget_leng (void) ++yy_size_t yyget_leng (void) + { + return yyleng; + } + + /** Get the current token. + * +@@ -4064,13 +4077,13 @@ void yyfree (void * ptr ) + { + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ + } + + #define YYTABLES_NAME "yytables" + +-#line 468 "ldlex.l" ++#line 467 "ldlex.l" + + + + + /* Switch flex to reading script file NAME, open on FILE, + saving the current input info on the include stack. */ +diff --git a/ld/ldmain.c b/ld/ldmain.c +index 73353309c3595a2e53e160cbf2bcfd215a92aab2..8b7513d8e83264c0cb236781cdb753181612fb14 100644 +--- ld/ldmain.c ++++ ld/ldmain.c +@@ -408,16 +408,23 @@ main (int argc, char **argv) + } + + lang_process (); + + /* Print error messages for any missing symbols, for any warning + symbols, and possibly multiple definitions. */ ++#ifdef __amigaos4__ ++ /* Make all files executable, even relocatable files */ ++ link_info.output_bfd->flags |= EXEC_P; ++#else ++ /* Print error messages for any missing symbols, for any warning ++ symbols, and possibly multiple definitions. */ + if (link_info.relocatable) + link_info.output_bfd->flags &= ~EXEC_P; + else + link_info.output_bfd->flags |= EXEC_P; ++#endif + + ldwrite (); + + if (config.map_file != NULL) + lang_map (); + if (command_line.cref) +diff --git a/ld/scripttempl/amiga.sc b/ld/scripttempl/amiga.sc +new file mode 100644 +index 0000000000000000000000000000000000000000..f5c9d694742ecabb3a2a9c6b85e8f2aaf23e78f1 +--- /dev/null ++++ ld/scripttempl/amiga.sc +@@ -0,0 +1,49 @@ ++cat <<EOF ++OUTPUT_FORMAT("${OUTPUT_FORMAT}") ++OUTPUT_ARCH(${ARCH}) ++ ++${RELOCATING+${LIB_SEARCH_DIRS}} ++${STACKZERO+${RELOCATING+${STACKZERO}}} ++${SHLIB_PATH+${RELOCATING+${SHLIB_PATH}}} ++ ++SECTIONS ++{ ++ ${RELOCATING+PROVIDE(___machtype = 0x0);} ++ ${RELOCATING+. = ${TEXT_START_ADDR};} ++ .text : ++ { ++ ${RELOCATING+__stext = .;} ++ *(.text) ++ ${RELOCATING+___datadata_relocs = .;} ++ ${RELOCATING+__etext = .;} ++ ${PAD_TEXT+${RELOCATING+. = ${DATA_ALIGNMENT};}} ++ } ++ ${RELOCATING+___text_size = SIZEOF(.text);} ++ ${RELOCATING+. = ${DATA_ALIGNMENT};} ++ .data : ++ { ++ ${RELOCATING+__sdata = .;} ++ ${CONSTRUCTING+CONSTRUCTORS} ++ *(.data) ++ ${RELOCATING+___a4_init = 0x7ffe;} ++ ${RELOCATING+__edata = .;} ++ } ++ ${RELOCATING+___data_size = SIZEOF(.data);} ++ .bss : ++ { ++ ${RELOCATING+__bss_start = .;} ++ *(.bss) ++ *(COMMON) ++ ${RELOCATING+__end = .;} ++ } ++ ${RELOCATING+___bss_size = SIZEOF(.bss);} ++ .data_chip : ++ { ++ *(.data_chip) ++ } ++ .bss_chip : ++ { ++ *(.bss_chip) ++ } ++} ++EOF +diff --git a/ld/scripttempl/amiga_bss.sc b/ld/scripttempl/amiga_bss.sc +new file mode 100644 +index 0000000000000000000000000000000000000000..668ce7c0dee923dd0d4643a379bf24f4b352cef0 +--- /dev/null ++++ ld/scripttempl/amiga_bss.sc +@@ -0,0 +1,41 @@ ++cat <<EOF ++OUTPUT_FORMAT("${OUTPUT_FORMAT}") ++OUTPUT_ARCH(${ARCH}) ++ ++${RELOCATING+${LIB_SEARCH_DIRS}} ++${STACKZERO+${RELOCATING+${STACKZERO}}} ++${SHLIB_PATH+${RELOCATING+${SHLIB_PATH}}} ++ ++SECTIONS ++{ ++ ${RELOCATING+PROVIDE(___machtype = 0x0);} ++ ${RELOCATING+. = ${TEXT_START_ADDR};} ++ .text : ++ { ++ ${RELOCATING+__stext = .;} ++ *(.text) ++ ${RELOCATING+___datadata_relocs = .;} ++ ${RELOCATING+__etext = .;} ++ ${PAD_TEXT+${RELOCATING+. = ${DATA_ALIGNMENT};}} ++ } ++ ${RELOCATING+___text_size = SIZEOF(.text);} ++ ${RELOCATING+. = ${DATA_ALIGNMENT};} ++ .data : ++ { ++ ${RELOCATING+__sdata = .;} ++ ${CONSTRUCTING+CONSTRUCTORS} ++ *(.data) ++ ${RELOCATING+___a4_init = 0x7ffe;} ++ ${RELOCATING+__edata = .;} ++ } ++ .bss : ++ { ++ ${RELOCATING+__bss_start = .;} ++ *(.bss) ++ *(COMMON) ++ ${RELOCATING+__end = .;} ++ } ++ ${RELOCATING+___data_size = SIZEOF(.data) + SIZEOF(.bss);} ++ ${RELOCATING+___bss_size = 0x0;} ++} ++EOF +diff --git a/ld/scripttempl/elf64hppa.sc b/ld/scripttempl/amigaos.sc +similarity index 88% +copy from ld/scripttempl/elf64hppa.sc +copy to ld/scripttempl/amigaos.sc +index 18090e6b9b73969ba6c33ccb272d88fc125be19d..865c9ba63ca1746c6bc6b66153557a10da677e58 100644 +--- ld/scripttempl/elf64hppa.sc ++++ ld/scripttempl/amigaos.sc +@@ -33,17 +33,14 @@ + # OTHER_SDATA_SECTIONS - sections just after .sdata. + # OTHER_BSS_SYMBOLS - symbols that appear at the start of the + # .bss section besides __bss_start. + # DATA_PLT - .plt should be in data segment, not text segment. + # PLT_BEFORE_GOT - .plt just before .got when .plt is in data segement. + # BSS_PLT - .plt should be in bss segment +-# NO_REL_RELOCS - Don't include .rel.* sections in script +-# NO_RELA_RELOCS - Don't include .rela.* sections in script +-# NON_ALLOC_DYN - Place dynamic sections after data segment. + # TEXT_DYNAMIC - .dynamic in text segment, not data segment. +-# EMBEDDED - whether this is for an embedded system. ++# EMBEDDED - whether this is for an embedded system. + # SHLIB_TEXT_START_ADDR - if set, add to SIZEOF_HEADERS to set + # start address of shared library. + # INPUT_FILES - INPUT command of files to always include + # WRITABLE_RODATA - if set, the .rodata section should be writable + # INIT_START, INIT_END - statements just before and just after + # combination of .init sections. +@@ -98,13 +95,14 @@ test -z "${ALIGNMENT}" && ALIGNMENT="${ELFSIZE} / 8" + test "$LD_FLAG" = "N" && DATA_ADDR=. + test -z "${ETEXT_NAME}" && ETEXT_NAME=etext + test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE="" + test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE="" + test -n "$RELRO_NOW" && unset SEPARATE_GOTPLT + test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }" +-DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))" ++DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE})" ++#DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))" + DATA_SEGMENT_RELRO_END="" + DATA_SEGMENT_END="" + if test -n "${COMMONPAGESIZE}"; then + DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})" + DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);" + DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT-0}, .);" +@@ -123,14 +121,14 @@ if test -z "$GOT"; then + GOT=".got ${RELOCATING-0} : { *(.got) }" + GOTPLT=".got.plt ${RELOCATING-0} : { *(.got.plt) }" + fi + fi + DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }" + RODATA=".rodata ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }" +-DATARELRO=".data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }" +-DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }" ++DATARELRO=".data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }" ++DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) }" + if test -z "${NO_SMALL_DATA}"; then + SBSS=".sbss ${RELOCATING-0} : + { + ${RELOCATING+${SBSS_START_SYMBOLS}} + ${CREATE_SHLIB+*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)} + *(.dynsbss) +@@ -139,13 +137,13 @@ if test -z "${NO_SMALL_DATA}"; then + ${RELOCATING+${SBSS_END_SYMBOLS}} + }" + SBSS2=".sbss2 ${RELOCATING-0} : { *(.sbss2${RELOCATING+ .sbss2.* .gnu.linkonce.sb2.*}) }" + SDATA="/* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ +- .sdata ${RELOCATING-0} : ++ .sdata ${RELOCATING-0} : + { + ${RELOCATING+${SDATA_START_SYMBOLS}} + ${CREATE_SHLIB+*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)} + *(.sdata${RELOCATING+ .sdata.* .gnu.linkonce.s.*}) + }" + SDATA2=".sdata2 ${RELOCATING-0} : +@@ -197,27 +195,13 @@ test "${LARGE_SECTIONS}" = "yes" && LARGE_SECTIONS=" + } + .ldata ${RELOCATING-0} ${RELOCATING+ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))} : + { + *(.ldata${RELOCATING+ .ldata.* .gnu.linkonce.l.*}) + ${RELOCATING+. = ALIGN(. != 0 ? ${ALIGNMENT} : 1);} + }" +-INIT_ARRAY=".init_array ${RELOCATING-0} : +- { +- ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__init_array_start = .);}} +- KEEP (*(SORT(.init_array.*))) +- KEEP (*(.init_array)) +- ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__init_array_end = .);}} +- }" +-FINI_ARRAY=".fini_array ${RELOCATING-0} : +- { +- ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_start = .);}} +- KEEP (*(SORT(.fini_array.*))) +- KEEP (*(.fini_array)) +- ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_end = .);}} +- }" +-CTOR=".ctors ${CONSTRUCTING-0} : ++CTOR=".ctors ${CONSTRUCTING-0} : + { + ${CONSTRUCTING+${CTOR_START}} + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not +@@ -253,27 +237,24 @@ DTOR=".dtors ${CONSTRUCTING-0} : + STACK=" .stack ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} : + { + ${RELOCATING+_stack = .;} + *(.stack) + }" + +-TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${TEXT_START_ADDR})" +-SHLIB_TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${SHLIB_TEXT_START_ADDR:-0})" +- + # if this is for an embedded system, don't add SIZEOF_HEADERS. + if [ -z "$EMBEDDED" ]; then + test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR} + SIZEOF_HEADERS" + else + test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR}" + fi + + cat <<EOF + OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}", + "${LITTLE_OUTPUT_FORMAT}") + OUTPUT_ARCH(${OUTPUT_ARCH}) +-${RELOCATING+ENTRY(${ENTRY})} ++ENTRY(${ENTRY}) + + ${RELOCATING+${LIB_SEARCH_DIRS}} + ${RELOCATING+${EXECUTABLE_SYMBOLS}} + ${RELOCATING+${INPUT_FILES}} + ${RELOCATING- /* For some reason, the Solaris linker makes bad executables + if gld -r is used and the intermediate file has sections starting +@@ -281,33 +262,28 @@ ${RELOCATING- /* For some reason, the Solaris linker makes bad executables + bug. But for now assigning the zero vmas works. */} + + SECTIONS + { + /* Read-only sections, merged into text segment: */ + ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+PROVIDE (__executable_start = ${TEXT_START_ADDR}); . = ${TEXT_BASE_ADDRESS};}}} +- ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR} + SIZEOF_HEADERS;}} +- ${CREATE_PIE+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR} + SIZEOF_HEADERS;}} ++ ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}} ++ ${CREATE_PIE+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}} + ${INITIAL_READONLY_SECTIONS} + .note.gnu.build-id : { *(.note.gnu.build-id) } +-EOF +- +-test -n "${RELOCATING+0}" || unset NON_ALLOC_DYN +-test -z "${NON_ALLOC_DYN}" || TEXT_DYNAMIC= +-cat > ldscripts/dyntmp.$$ <<EOF + ${TEXT_DYNAMIC+${DYNAMIC}} + .hash ${RELOCATING-0} : { *(.hash) } + .gnu.hash ${RELOCATING-0} : { *(.gnu.hash) } + .dynsym ${RELOCATING-0} : { *(.dynsym) } + .dynstr ${RELOCATING-0} : { *(.dynstr) } + .gnu.version ${RELOCATING-0} : { *(.gnu.version) } + .gnu.version_d ${RELOCATING-0}: { *(.gnu.version_d) } + .gnu.version_r ${RELOCATING-0}: { *(.gnu.version_r) } +-EOF + ++EOF + if [ "x$COMBRELOC" = x ]; then +- COMBRELOCCAT="cat >> ldscripts/dyntmp.$$" ++ COMBRELOCCAT=cat + else + COMBRELOCCAT="cat > $COMBRELOC" + fi + eval $COMBRELOCCAT <<EOF + .rel.init ${RELOCATING-0} : { *(.rel.init) } + .rela.init ${RELOCATING-0} : { *(.rela.init) } +@@ -315,14 +291,14 @@ eval $COMBRELOCCAT <<EOF + .rela.text ${RELOCATING-0} : { *(.rela.text${RELOCATING+ .rela.text.* .rela.gnu.linkonce.t.*}) } + .rel.fini ${RELOCATING-0} : { *(.rel.fini) } + .rela.fini ${RELOCATING-0} : { *(.rela.fini) } + .rel.rodata ${RELOCATING-0} : { *(.rel.rodata${RELOCATING+ .rel.rodata.* .rel.gnu.linkonce.r.*}) } + .rela.rodata ${RELOCATING-0} : { *(.rela.rodata${RELOCATING+ .rela.rodata.* .rela.gnu.linkonce.r.*}) } + ${OTHER_READONLY_RELOC_SECTIONS} +- .rel.data.rel.ro ${RELOCATING-0} : { *(.rel.data.rel.ro${RELOCATING+ .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*}) } +- .rela.data.rel.ro ${RELOCATING-0} : { *(.rela.data.rel.ro${RELOCATING+ .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*}) } ++ .rel.data.rel.ro ${RELOCATING-0} : { *(.rel.data.rel.ro${RELOCATING+* .rel.gnu.linkonce.d.rel.ro.*}) } ++ .rela.data.rel.ro ${RELOCATING-0} : { *(.rela.data.rel.ro${RELOCATING+* .rela.gnu.linkonce.d.rel.ro.*}) } + .rel.data ${RELOCATING-0} : { *(.rel.data${RELOCATING+ .rel.data.* .rel.gnu.linkonce.d.*}) } + .rela.data ${RELOCATING-0} : { *(.rela.data${RELOCATING+ .rela.data.* .rela.gnu.linkonce.d.*}) } + .rel.tdata ${RELOCATING-0} : { *(.rel.tdata${RELOCATING+ .rel.tdata.* .rel.gnu.linkonce.td.*}) } + .rela.tdata ${RELOCATING-0} : { *(.rela.tdata${RELOCATING+ .rela.tdata.* .rela.gnu.linkonce.td.*}) } + .rel.tbss ${RELOCATING-0} : { *(.rel.tbss${RELOCATING+ .rel.tbss.* .rel.gnu.linkonce.tb.*}) } + .rela.tbss ${RELOCATING-0} : { *(.rela.tbss${RELOCATING+ .rela.tbss.* .rela.gnu.linkonce.tb.*}) } +@@ -338,76 +314,53 @@ eval $COMBRELOCCAT <<EOF + ${REL_SDATA2} + ${REL_SBSS2} + .rel.bss ${RELOCATING-0} : { *(.rel.bss${RELOCATING+ .rel.bss.* .rel.gnu.linkonce.b.*}) } + .rela.bss ${RELOCATING-0} : { *(.rela.bss${RELOCATING+ .rela.bss.* .rela.gnu.linkonce.b.*}) } + ${REL_LARGE} + EOF +- + if [ -n "$COMBRELOC" ]; then +-cat >> ldscripts/dyntmp.$$ <<EOF ++cat <<EOF + .rel.dyn ${RELOCATING-0} : + { + EOF +-sed -e '/^[ ]*[{}][ ]*$/d;/:[ ]*$/d;/\.rela\./d;s/^.*: { *\(.*\)}$/ \1/' $COMBRELOC >> ldscripts/dyntmp.$$ +-cat >> ldscripts/dyntmp.$$ <<EOF +- } +- .rel.ifunc.dyn ${RELOCATING-0} : +- { +- *(.rel.ifunc.*) ++sed -e '/^[ ]*[{}][ ]*$/d;/:[ ]*$/d;/\.rela\./d;s/^.*: { *\(.*\)}$/ \1/' $COMBRELOC ++cat <<EOF + } + .rela.dyn ${RELOCATING-0} : + { + EOF +-sed -e '/^[ ]*[{}][ ]*$/d;/:[ ]*$/d;/\.rel\./d;s/^.*: { *\(.*\)}/ \1/' $COMBRELOC >> ldscripts/dyntmp.$$ +-cat >> ldscripts/dyntmp.$$ <<EOF +- } +- .rela.ifunc.dyn ${RELOCATING-0} : +- { +- *(.rela.ifunc.*) ++sed -e '/^[ ]*[{}][ ]*$/d;/:[ ]*$/d;/\.rel\./d;s/^.*: { *\(.*\)}/ \1/' $COMBRELOC ++cat <<EOF + } + EOF + fi +- +-cat >> ldscripts/dyntmp.$$ <<EOF ++cat <<EOF + .rel.plt ${RELOCATING-0} : { *(.rel.plt) } + .rela.plt ${RELOCATING-0} : { *(.rela.plt) } + ${OTHER_PLT_RELOC_SECTIONS} +-EOF + +-if test -z "${NON_ALLOC_DYN}"; then +- if test -z "${NO_REL_RELOCS}${NO_RELA_RELOCS}"; then +- cat ldscripts/dyntmp.$$ +- else +- if test -z "${NO_REL_RELOCS}"; then +- sed -e '/^[ ]*\.rela\.[^}]*$/,/}/d' -e '/^[ ]*\.rela\./d' ldscripts/dyntmp.$$ +- fi +- if test -z "${NO_RELA_RELOCS}"; then +- sed -e '/^[ ]*\.rel\.[^}]*$/,/}/d' -e '/^[ ]*\.rel\./d' ldscripts/dyntmp.$$ +- fi +- fi +- rm -f ldscripts/dyntmp.$$ +-fi +- +-cat <<EOF + .init ${RELOCATING-0} : + { + ${RELOCATING+${INIT_START}} + KEEP (*(.init)) + ${RELOCATING+${INIT_END}} + } =${NOP-0} + +- ${TEXT_PLT+${PLT}} + ${TINY_READONLY_SECTION} + .text ${RELOCATING-0} : + { + ${RELOCATING+${TEXT_START_SYMBOLS}} + *(.text .stub${RELOCATING+ .text.* .gnu.linkonce.t.*}) ++ KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + ${RELOCATING+${OTHER_TEXT_SECTIONS}} + } =${NOP-0} ++ . = ALIGN(4096); ++ ${TEXT_PLT+${PLT}} ++ . = ALIGN(4096); + .fini ${RELOCATING-0} : + { + ${RELOCATING+${FINI_START}} + KEEP (*(.fini)) + ${RELOCATING+${FINI_END}} + } =${NOP-0} +@@ -432,21 +385,34 @@ cat <<EOF + /* Exception handling */ + .eh_frame ${RELOCATING-0} : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table ${RELOCATING-0} : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + + /* Thread Local Storage sections */ + .tdata ${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) } ++ .tbss ${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} } + + .preinit_array ${RELOCATING-0} : + { + ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__preinit_array_start = .);}} + KEEP (*(.preinit_array)) + ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__preinit_array_end = .);}} + } +- ${RELOCATING+${INIT_ARRAY}} +- ${RELOCATING+${FINI_ARRAY}} ++ .init_array ${RELOCATING-0} : ++ { ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__init_array_start = .);}} ++ KEEP (*(SORT(.init_array.*))) ++ KEEP (*(.init_array)) ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__init_array_end = .);}} ++ } ++ .fini_array ${RELOCATING-0} : ++ { ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_start = .);}} ++ KEEP (*(.fini_array)) ++ KEEP (*(SORT(.fini_array.*))) ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_end = .);}} ++ } + ${SMALL_DATA_CTOR-${RELOCATING+${CTOR}}} + ${SMALL_DATA_DTOR-${RELOCATING+${DTOR}}} + .jcr ${RELOCATING-0} : { KEEP (*(.jcr)) } + + ${RELOCATING+${DATARELRO}} + ${OTHER_RELRO_SECTIONS} +@@ -461,12 +427,13 @@ cat <<EOF + ${DATA_PLT+${PLT_BEFORE_GOT-${PLT}}} + + .data ${RELOCATING-0} : + { + ${RELOCATING+${DATA_START_SYMBOLS}} + *(.data${RELOCATING+ .data.* .gnu.linkonce.d.*}) ++ ${RELOCATING+KEEP (*(.gnu.linkonce.d.*personality*))} + ${CONSTRUCTING+SORT(CONSTRUCTORS)} + } + .data1 ${RELOCATING-0} : { *(.data1) } + ${WRITABLE_RODATA+${RODATA}} + ${OTHER_READWRITE_SECTIONS} + ${SMALL_DATA_CTOR+${RELOCATING+${CTOR}}} +@@ -499,29 +466,13 @@ cat <<EOF + ${RELOCATING+. = ALIGN(${ALIGNMENT});} + ${LARGE_SECTIONS} + ${RELOCATING+. = ALIGN(${ALIGNMENT});} + ${RELOCATING+${OTHER_END_SYMBOLS}} + ${RELOCATING+${END_SYMBOLS-${USER_LABEL_PREFIX}_end = .; PROVIDE (${USER_LABEL_PREFIX}end = .);}} + ${RELOCATING+${DATA_SEGMENT_END}} +-EOF +- +-if test -n "${NON_ALLOC_DYN}"; then +- if test -z "${NO_REL_RELOCS}${NO_RELA_RELOCS}"; then +- cat ldscripts/dyntmp.$$ +- else +- if test -z "${NO_REL_RELOCS}"; then +- sed -e '/^[ ]*\.rela\.[^}]*$/,/}/d' -e '/^[ ]*\.rela\./d' ldscripts/dyntmp.$$ +- fi +- if test -z "${NO_RELA_RELOCS}"; then +- sed -e '/^[ ]*\.rel\.[^}]*$/,/}/d' -e '/^[ ]*\.rel\./d' ldscripts/dyntmp.$$ +- fi +- fi +- rm -f ldscripts/dyntmp.$$ +-fi + +-cat <<EOF + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } +@@ -561,15 +512,12 @@ cat <<EOF + .debug_varnames 0 : { *(.debug_varnames) } + + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + +- /* DWARF Extension. */ +- .debug_macro 0 : { *(.debug_macro) } +- + ${TINY_DATA_SECTION} + ${TINY_BSS_SECTION} + + ${STACK_ADDR+${STACK}} + ${ATTRS_SECTIONS} + ${OTHER_SECTIONS} +diff --git a/ld/scripttempl/mep.sc b/ld/scripttempl/amithlon.sc +similarity index 76% +copy from ld/scripttempl/mep.sc +copy to ld/scripttempl/amithlon.sc +index 3fc1352e19184c0319302e809cccf7cc861ec8d7..b8248cd4966e34e95c8b262e515ace1802c6db35 100644 +--- ld/scripttempl/mep.sc ++++ ld/scripttempl/amithlon.sc +@@ -1,57 +1,45 @@ + # + # Unusual variables checked by this code: + # NOP - four byte opcode for no-op (defaults to 0) + # NO_SMALL_DATA - no .sbss/.sbss2/.sdata/.sdata2 sections if not + # empty. +-# SMALL_DATA_CTOR - .ctors contains small data. +-# SMALL_DATA_DTOR - .dtors contains small data. + # DATA_ADDR - if end-of-text-plus-one-page isn't right for data start + # INITIAL_READONLY_SECTIONS - at start of text segment + # OTHER_READONLY_SECTIONS - other than .text .init .rodata ... + # (e.g., .PARISC.milli) + # OTHER_TEXT_SECTIONS - these get put in .text when relocating + # OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ... + # (e.g., .PARISC.global) +-# OTHER_RELRO_SECTIONS - other than .data.rel.ro ... +-# (e.g. PPC32 .fixup, .got[12]) + # OTHER_BSS_SECTIONS - other than .bss .sbss ... + # OTHER_SECTIONS - at the end + # EXECUTABLE_SYMBOLS - symbols that must be defined for an + # executable (e.g., _DYNAMIC_LINK) +-# TEXT_START_ADDR - the first byte of the text segment, after any +-# headers. +-# TEXT_BASE_ADDRESS - the first byte of the text segment. + # TEXT_START_SYMBOLS - symbols that appear at the start of the + # .text section. + # DATA_START_SYMBOLS - symbols that appear at the start of the + # .data section. + # OTHER_GOT_SYMBOLS - symbols defined just before .got. + # OTHER_GOT_SECTIONS - sections just after .got. + # OTHER_SDATA_SECTIONS - sections just after .sdata. + # OTHER_BSS_SYMBOLS - symbols that appear at the start of the + # .bss section besides __bss_start. + # DATA_PLT - .plt should be in data segment, not text segment. +-# PLT_BEFORE_GOT - .plt just before .got when .plt is in data segement. + # BSS_PLT - .plt should be in bss segment + # TEXT_DYNAMIC - .dynamic in text segment, not data segment. +-# EMBEDDED - whether this is for an embedded system. ++# EMBEDDED - whether this is for an embedded system. + # SHLIB_TEXT_START_ADDR - if set, add to SIZEOF_HEADERS to set + # start address of shared library. + # INPUT_FILES - INPUT command of files to always include + # WRITABLE_RODATA - if set, the .rodata section should be writable + # INIT_START, INIT_END - statements just before and just after + # combination of .init sections. + # FINI_START, FINI_END - statements just before and just after + # combination of .fini sections. + # STACK_ADDR - start of a .stack section. + # OTHER_END_SYMBOLS - symbols to place right at the end of the script. +-# SEPARATE_GOTPLT - if set, .got.plt should be separate output section, +-# so that .got can be in the RELRO area. It should be set to +-# the number of bytes in the beginning of .got.plt which can be +-# in the RELRO area as well. + # + # When adding sections, do note that the names of some sections are used + # when specifying the start address of the next. + # + + # Many sections come in three flavours. There is the 'real' section, +@@ -81,108 +69,85 @@ test -z "$ENTRY" && ENTRY=_start + test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT} + test -z "${LITTLE_OUTPUT_FORMAT}" && LITTLE_OUTPUT_FORMAT=${OUTPUT_FORMAT} + if [ -z "$MACHINE" ]; then OUTPUT_ARCH=${ARCH}; else OUTPUT_ARCH=${ARCH}:${MACHINE}; fi + test -z "${ELFSIZE}" && ELFSIZE=32 + test -z "${ALIGNMENT}" && ALIGNMENT="${ELFSIZE} / 8" + test "$LD_FLAG" = "N" && DATA_ADDR=. +-test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE="" +-test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE="" +-test -n "$RELRO_NOW" && unset SEPARATE_GOTPLT +-DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))" +-DATA_SEGMENT_RELRO_END="" +-DATA_SEGMENT_RELRO_GOTPLT_END="" ++test -n "$CREATE_SHLIB" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE="" ++test -z "$CREATE_SHLIB" && test -n "$DATA_ADDR" && COMMONPAGESIZE="" ++#DATA_SEGMENT_ALIGN="ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))" ++DATA_SEGMENT_ALIGN="ALIGN(${MAXPAGESIZE}) + ${MAXPAGESIZE}" + DATA_SEGMENT_END="" + if test -n "${COMMONPAGESIZE}"; then +- DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})" ++ DATA_SEGMENT_ALIGN="DATA_SEGMENT_ALIGN(${MAXPAGESIZE}, ${COMMONPAGESIZE})" + DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);" +- if test -n "${SEPARATE_GOTPLT}"; then +- DATA_SEGMENT_RELRO_GOTPLT_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT}, .);" +- else +- DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (0, .);" +- fi + fi + INTERP=".interp ${RELOCATING-0} : { *(.interp) }" + PLT=".plt ${RELOCATING-0} : { *(.plt) }" +-if test -z "$GOT"; then +- if test -z "$SEPARATE_GOTPLT"; then +- GOT=".got ${RELOCATING-0} : { *(.got.plt) *(.got) }" +- else +- GOT=".got ${RELOCATING-0} : { *(.got) }" +- GOTPLT="${RELOCATING+${DATA_SEGMENT_RELRO_GOTPLT_END}} +- .got.plt ${RELOCATING-0} : { *(.got.plt) }" +- fi +-fi + DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }" + RODATA=".rodata ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }" +-DATARELRO=".data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro .data.rel.ro.*) }" +-DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }" + if test -z "${NO_SMALL_DATA}"; then + SBSS=".sbss ${RELOCATING-0} : + { + ${RELOCATING+PROVIDE (__sbss_start = .);} + ${RELOCATING+PROVIDE (___sbss_start = .);} +- ${CREATE_SHLIB+*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)} + *(.dynsbss) + *(.sbss${RELOCATING+ .sbss.* .gnu.linkonce.sb.*}) + *(.scommon) + ${RELOCATING+PROVIDE (__sbss_end = .);} + ${RELOCATING+PROVIDE (___sbss_end = .);} + }" + SBSS2=".sbss2 ${RELOCATING-0} : { *(.sbss2${RELOCATING+ .sbss2.* .gnu.linkonce.sb2.*}) }" + SDATA="/* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ +- .sdata ${RELOCATING-0} : ++ .sdata ${RELOCATING-0} : + { + ${RELOCATING+${SDATA_START_SYMBOLS}} +- ${CREATE_SHLIB+*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)} + *(.sdata${RELOCATING+ .sdata.* .gnu.linkonce.s.*}) + }" + SDATA2=".sdata2 ${RELOCATING-0} : { *(.sdata2${RELOCATING+ .sdata2.* .gnu.linkonce.s2.*}) }" + REL_SDATA=".rel.sdata ${RELOCATING-0} : { *(.rel.sdata${RELOCATING+ .rel.sdata.* .rel.gnu.linkonce.s.*}) } + .rela.sdata ${RELOCATING-0} : { *(.rela.sdata${RELOCATING+ .rela.sdata.* .rela.gnu.linkonce.s.*}) }" + REL_SBSS=".rel.sbss ${RELOCATING-0} : { *(.rel.sbss${RELOCATING+ .rel.sbss.* .rel.gnu.linkonce.sb.*}) } + .rela.sbss ${RELOCATING-0} : { *(.rela.sbss${RELOCATING+ .rela.sbss.* .rela.gnu.linkonce.sb.*}) }" + REL_SDATA2=".rel.sdata2 ${RELOCATING-0} : { *(.rel.sdata2${RELOCATING+ .rel.sdata2.* .rel.gnu.linkonce.s2.*}) } + .rela.sdata2 ${RELOCATING-0} : { *(.rela.sdata2${RELOCATING+ .rela.sdata2.* .rela.gnu.linkonce.s2.*}) }" + REL_SBSS2=".rel.sbss2 ${RELOCATING-0} : { *(.rel.sbss2${RELOCATING+ .rel.sbss2.* .rel.gnu.linkonce.sb2.*}) } + .rela.sbss2 ${RELOCATING-0} : { *(.rela.sbss2${RELOCATING+ .rela.sbss2.* .rela.gnu.linkonce.sb2.*}) }" +-else +- NO_SMALL_DATA=" " + fi +-test -n "$SEPARATE_GOTPLT" && SEPARATE_GOTPLT=" " +-CTOR=".ctors ${CONSTRUCTING-0} : ++CTOR=".ctors ${CONSTRUCTING-0} : + { + ${CONSTRUCTING+${CTOR_START}} + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + +- KEEP (*crtbegin*.o(.ctors)) ++ KEEP (*crtbegin.o(.ctors)) + + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + +- KEEP (*(EXCLUDE_FILE (*crtend*.o $OTHER_EXCLUDE_FILES) .ctors)) ++ KEEP (*(EXCLUDE_FILE (*crtend.o $OTHER_EXCLUDE_FILES) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + ${CONSTRUCTING+${CTOR_END}} + }" + DTOR=".dtors ${CONSTRUCTING-0} : + { + ${CONSTRUCTING+${DTOR_START}} +- KEEP (*crtbegin*.o(.dtors)) +- KEEP (*(EXCLUDE_FILE (*crtend*.o $OTHER_EXCLUDE_FILES) .dtors)) ++ KEEP (*crtbegin.o(.dtors)) ++ KEEP (*(EXCLUDE_FILE (*crtend.o $OTHER_EXCLUDE_FILES) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + ${CONSTRUCTING+${DTOR_END}} + }" + STACK=" .stack ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} : + { +@@ -198,13 +163,13 @@ else + fi + + cat <<EOF + OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}", + "${LITTLE_OUTPUT_FORMAT}") + OUTPUT_ARCH(${OUTPUT_ARCH}) +-${RELOCATING+ENTRY(${ENTRY})} ++ENTRY(${ENTRY}) + + ${RELOCATING+${LIB_SEARCH_DIRS}} + ${RELOCATING+/* Do we need any of these for elf? + __DYNAMIC = 0; ${STACKZERO+${STACKZERO}} ${SHLIB_PATH+${SHLIB_PATH}} */} + ${RELOCATING+${EXECUTABLE_SYMBOLS}} + ${RELOCATING+${INPUT_FILES}} +@@ -213,15 +178,14 @@ ${RELOCATING- /* For some reason, the Solaris linker makes bad executables + at non-zero addresses. Could be a Solaris ld bug, could be a GNU ld + bug. But for now assigning the zero vmas works. */} + + SECTIONS + { + /* Read-only sections, merged into text segment: */ +- ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+PROVIDE (__executable_start = ${TEXT_START_ADDR}); . = ${TEXT_BASE_ADDRESS};}}} ++ ${CREATE_SHLIB-${RELOCATING+. = ${TEXT_BASE_ADDRESS};}} + ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}} +- ${CREATE_PIE+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}} + ${CREATE_SHLIB-${INTERP}} + ${INITIAL_READONLY_SECTIONS} + ${TEXT_DYNAMIC+${DYNAMIC}} + .hash ${RELOCATING-0} : { *(.hash) } + .dynsym ${RELOCATING-0} : { *(.dynsym) } + .dynstr ${RELOCATING-0} : { *(.dynstr) } +@@ -242,14 +206,12 @@ eval $COMBRELOCCAT <<EOF + .rela.text ${RELOCATING-0} : { *(.rela.text${RELOCATING+ .rela.text.* .rela.gnu.linkonce.t.*}) } + .rel.fini ${RELOCATING-0} : { *(.rel.fini) } + .rela.fini ${RELOCATING-0} : { *(.rela.fini) } + .rel.rodata ${RELOCATING-0} : { *(.rel.rodata${RELOCATING+ .rel.rodata.* .rel.gnu.linkonce.r.*}) } + .rela.rodata ${RELOCATING-0} : { *(.rela.rodata${RELOCATING+ .rela.rodata.* .rela.gnu.linkonce.r.*}) } + ${OTHER_READONLY_RELOC_SECTIONS} +- .rel.data.rel.ro ${RELOCATING-0} : { *(.rel.data.rel.ro${RELOCATING+ .rel.data.rel.ro.*}) } +- .rela.data.rel.ro ${RELOCATING-0} : { *(.rela.data.rel.ro${RELOCATING+ .rela.data.rel.ro.*}) } + .rel.data ${RELOCATING-0} : { *(.rel.data${RELOCATING+ .rel.data.* .rel.gnu.linkonce.d.*}) } + .rela.data ${RELOCATING-0} : { *(.rela.data${RELOCATING+ .rela.data.* .rela.gnu.linkonce.d.*}) } + .rel.tdata ${RELOCATING-0} : { *(.rel.tdata${RELOCATING+ .rel.tdata.* .rel.gnu.linkonce.td.*}) } + .rela.tdata ${RELOCATING-0} : { *(.rela.tdata${RELOCATING+ .rela.tdata.* .rela.gnu.linkonce.td.*}) } + .rel.tbss ${RELOCATING-0} : { *(.rel.tbss${RELOCATING+ .rel.tbss.* .rel.gnu.linkonce.tb.*}) } + .rela.tbss ${RELOCATING-0} : { *(.rela.tbss${RELOCATING+ .rela.tbss.* .rela.gnu.linkonce.tb.*}) } +@@ -285,12 +247,15 @@ EOF + fi + cat <<EOF + .rel.plt ${RELOCATING-0} : { *(.rel.plt) } + .rela.plt ${RELOCATING-0} : { *(.rela.plt) } + ${OTHER_PLT_RELOC_SECTIONS} + ++ /* Force a new section by skipping a page */ ++ . = ALIGN(${MAXPAGESIZE}) + ${MAXPAGESIZE}; ++ + .init ${RELOCATING-0} : + { + ${RELOCATING+${INIT_START}} + KEEP (*(.init)) + ${RELOCATING+${INIT_END}} + } =${NOP-0} +@@ -310,69 +275,68 @@ cat <<EOF + KEEP (*(.fini)) + ${RELOCATING+${FINI_END}} + } =${NOP-0} + ${RELOCATING+PROVIDE (__etext = .);} + ${RELOCATING+PROVIDE (_etext = .);} + ${RELOCATING+PROVIDE (etext = .);} ++ ++ /* Force a new section by skipping a page */ ++ . = ALIGN(${MAXPAGESIZE}) + ${MAXPAGESIZE}; ++ + ${WRITABLE_RODATA-${RODATA}} + .rodata1 ${RELOCATING-0} : { *(.rodata1) } + ${CREATE_SHLIB-${SDATA2}} + ${CREATE_SHLIB-${SBSS2}} + ${OTHER_READONLY_SECTIONS} + .eh_frame_hdr : { *(.eh_frame_hdr) } +- .eh_frame ${RELOCATING-0} : ONLY_IF_RO { KEEP (*(.eh_frame)) } +- .gcc_except_table ${RELOCATING-0} : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } + + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ +- ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+. = ${DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}} ++ ${CREATE_SHLIB-${RELOCATING+. = ${DATA_ADDR-${DATA_SEGMENT_ALIGN}};}} + ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}} +- ${CREATE_PIE+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}} +- +- /* Exception handling */ +- .eh_frame ${RELOCATING-0} : ONLY_IF_RW { KEEP (*(.eh_frame)) } +- .gcc_except_table ${RELOCATING-0} : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } +- +- /* Thread Local Storage sections */ +- .tdata ${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) } +- .tbss ${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} } +- +- .preinit_array ${RELOCATING-0} : { KEEP (*(.preinit_array)) } +- .init_array ${RELOCATING-0} : { KEEP (*(.init_array)) } +- .fini_array ${RELOCATING-0} : { KEEP (*(.fini_array)) } + +- ${SMALL_DATA_CTOR-${RELOCATING+${CTOR}}} +- ${SMALL_DATA_DTOR-${RELOCATING+${DTOR}}} +- .jcr ${RELOCATING-0} : { KEEP (*(.jcr)) } ++ /* Ensure the __preinit_array_start label is properly aligned. We ++ could instead move the label definition inside the section, but ++ the linker would then create the section even if it turns out to ++ be empty, which isn't pretty. */ ++ ${RELOCATING+. = ALIGN(${ALIGNMENT});} ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE (__preinit_array_start = .);}} ++ .preinit_array ${RELOCATING-0} : { *(.preinit_array) } ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE (__preinit_array_end = .);}} + +- ${RELOCATING+${DATARELRO}} +- ${OTHER_RELRO_SECTIONS} +- ${TEXT_DYNAMIC-${DYNAMIC}} +- ${NO_SMALL_DATA+${RELRO_NOW+${GOT}}} +- ${NO_SMALL_DATA+${RELRO_NOW-${SEPARATE_GOTPLT+${GOT}}}} +- ${NO_SMALL_DATA+${RELRO_NOW-${SEPARATE_GOTPLT+${GOTPLT}}}} +- ${RELOCATING+${DATA_SEGMENT_RELRO_END}} +- ${NO_SMALL_DATA+${RELRO_NOW-${SEPARATE_GOTPLT-${GOT}}}} ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE (__init_array_start = .);}} ++ .init_array ${RELOCATING-0} : { *(.init_array) } ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE (__init_array_end = .);}} + +- ${DATA_PLT+${PLT_BEFORE_GOT-${PLT}}} ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE (__fini_array_start = .);}} ++ .fini_array ${RELOCATING-0} : { *(.fini_array) } ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE (__fini_array_end = .);}} + + .data ${RELOCATING-0} : + { + ${RELOCATING+${DATA_START_SYMBOLS}} + *(.data${RELOCATING+ .data.* .gnu.linkonce.d.*}) + ${CONSTRUCTING+SORT(CONSTRUCTORS)} + } + .data1 ${RELOCATING-0} : { *(.data1) } ++ .tdata ${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) } ++ .tbss ${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} } ++ .eh_frame ${RELOCATING-0} : { KEEP (*(.eh_frame)) } ++ .gcc_except_table ${RELOCATING-0} : { *(.gcc_except_table) } + ${WRITABLE_RODATA+${RODATA}} + ${OTHER_READWRITE_SECTIONS} +- ${SMALL_DATA_CTOR+${RELOCATING+${CTOR}}} +- ${SMALL_DATA_DTOR+${RELOCATING+${DTOR}}} +- ${DATA_PLT+${PLT_BEFORE_GOT+${PLT}}} ++ ${TEXT_DYNAMIC-${DYNAMIC}} ++ ${RELOCATING+${CTOR}} ++ ${RELOCATING+${DTOR}} ++ .jcr ${RELOCATING-0} : { KEEP (*(.jcr)) } ++ ${DATA_PLT+${PLT}} + ${RELOCATING+${OTHER_GOT_SYMBOLS}} +- ${NO_SMALL_DATA-${GOT}} ++ .got ${RELOCATING-0} : { *(.got.plt) *(.got) } + ${OTHER_GOT_SECTIONS} ++ ${CREATE_SHLIB+${SDATA2}} ++ ${CREATE_SHLIB+${SBSS2}} + ${SDATA} + ${OTHER_SDATA_SECTIONS} + ${RELOCATING+_edata = .;} + ${RELOCATING+PROVIDE (edata = .);} + ${RELOCATING+__bss_start = .;} + ${RELOCATING+${OTHER_BSS_SYMBOLS}} +@@ -433,19 +397,16 @@ cat <<EOF + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + +- /* DWARF 3 */ +- .debug_pubtypes 0 : { *(.debug_pubtypes) } +- .debug_ranges 0 : { *(.debug_ranges) } +- +- /* DWARF Extension. */ +- .debug_macro 0 : { *(.debug_macro) } +- + ${STACK_ADDR+${STACK}} + ${OTHER_SECTIONS} + ${RELOCATING+${OTHER_END_SYMBOLS}} +- ${RELOCATING+${DISCARDED}} ++ ++ /* Libnix sections */ ++ .libnix___INIT_LIST__ ${RELOCATING-0} : { *(.libnix___INIT_LIST__) } ++ .libnix___EXIT_LIST__ ${RELOCATING-0} : { *(.libnix___EXIT_LIST__) } ++ .libnix___LIB_LIST__ ${RELOCATING-0} : { *(.libnix___LIB_LIST__) } + } + EOF +diff --git a/libiberty/config/mh-amigaos b/libiberty/config/mh-amigaos +new file mode 100644 +index 0000000000000000000000000000000000000000..495fa7e35897000efe600c9f1dd844b086731fcd +--- /dev/null ++++ libiberty/config/mh-amigaos +@@ -0,0 +1,12 @@ ++# Host makefile fragment for Commodore Amiga running AmigaOS. ++ ++# We don't actually use libmmalloc.a, since there is no sbrk(), ++# but this allows us to compile it (and then ignore it). ++MMALLOC= ++MMALLOC_DISABLE = -DNO_MMALLOC ++ ++# There is no standard system compiler. Assume using GNU C. ++#CC = gcc ++ ++# Compile for automatic stack extension. ++#HDEFINES = -mstackextend +diff --git a/libiberty/config/mh-morphos b/libiberty/config/mh-morphos +new file mode 100644 +index 0000000000000000000000000000000000000000..064647ab3397b088317905a47cce0171e25a4bae +--- /dev/null ++++ libiberty/config/mh-morphos +@@ -0,0 +1,12 @@ ++# Host makefile fragment for Commodore Amiga running AmigaOS. ++ ++# We don't actually use libmmalloc.a, since there is no sbrk(), ++# but this allows us to compile it (and then ignore it). ++MMALLOC= ++MMALLOC_DISABLE = -DNO_MMALLOC ++ ++# There is no standard system compiler. Assume using GNU C. ++CC = gcc ++ ++# Compile for automatic stack extension. ++HDEFINES = +diff --git a/libiberty/lrealpath.c b/libiberty/lrealpath.c +index b27c8de990e974c7294dfc4024ef44fbd3844a52..e94add4802d830aa3e04c9a784a8d081938ae0d5 100644 +--- libiberty/lrealpath.c ++++ libiberty/lrealpath.c +@@ -69,12 +69,18 @@ extern char *canonicalize_file_name (const char *); + # if defined (_WIN32) + # define WIN32_LEAN_AND_MEAN + # include <windows.h> /* for GetFullPathName */ + # endif + #endif + ++/* OS4 does not have _PC_PATH_MAX so we use the ++ REALPATH_LIMIT method only */ ++#if defined(__amigaos4__) ++#undef HAVE_REALPATH ++#endif ++ + char * + lrealpath (const char *filename) + { + /* Method 1: The system has a compile time upper bound on a filename + path. Use that and realpath() to canonicalize the name. This is + the most common case. Note that, if there isn't a compile time +diff --git a/opcodes/m68k-dis.c b/opcodes/m68k-dis.c +index bc2dd491592e56fb664cdf96fc32491c08e1e075..bc40541b7c5aecc30a7a74fd61f29225acd21fcd 100644 +--- opcodes/m68k-dis.c ++++ opcodes/m68k-dis.c +@@ -36,13 +36,13 @@ const char * const fpcr_names[] = + "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr" + }; + + static char *const reg_names[] = + { + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", +- "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", ++ "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", + "%ps", "%pc" + }; + + /* Name of register halves for MAC/EMAC. + Seperate from reg_names since 'spu', 'fpl' look weird. */ + static char *const reg_half_names[] = +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/binutils/0002-Fixed-errors-occuring-with-more-recent-versions-of-t.p b/ppc-amigaos/recipes/patches/binutils/0002-Fixed-errors-occuring-with-more-recent-versions-of-t.p new file mode 100644 index 0000000..eb82ebf --- /dev/null +++ b/ppc-amigaos/recipes/patches/binutils/0002-Fixed-errors-occuring-with-more-recent-versions-of-t.p @@ -0,0 +1,436 @@ +From e5811195ee1007420de6150b593fd6b3654c4921 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Sat, 29 Nov 2014 11:32:22 +0100 +Subject: [PATCH 2/7] Fixed errors occuring with more recent versions of + texinfo. + +--- + bfd/doc/bfd.texinfo | 4 ++-- + binutils/doc/binutils.texi | 12 ++++++------ + gas/doc/c-arc.texi | 4 ++-- + gas/doc/c-arm.texi | 18 +++++++++--------- + gas/doc/c-cr16.texi | 47 ++++++++++++++++++++++++++-------------------- + gas/doc/c-mips.texi | 2 +- + gas/doc/c-score.texi | 8 ++++---- + gas/doc/c-tic54x.texi | 10 +++++----- + ld/ld.texinfo | 4 ++-- + 9 files changed, 58 insertions(+), 51 deletions(-) + +diff --git a/bfd/doc/bfd.texinfo b/bfd/doc/bfd.texinfo +index 7b9774b71a3cb9b3c154c8c75a41de29a6813146..d3b14c56449321b5dfe33206b2c5cfcd87eb0b91 100644 +--- bfd/doc/bfd.texinfo ++++ bfd/doc/bfd.texinfo +@@ -324,21 +324,21 @@ All of BFD lives in one directory. + + @node BFD Index, , GNU Free Documentation License, Top + @unnumbered BFD Index + @printindex cp + + @tex +-% I think something like @colophon should be in texinfo. In the ++% I think something like @ colophon should be in texinfo. In the + % meantime: + \long\def\colophon{\hbox to0pt{}\vfill + \centerline{The body of this manual is set in} + \centerline{\fontname\tenrm,} + \centerline{with headings in {\bf\fontname\tenbf}} + \centerline{and examples in {\tt\fontname\tentt}.} + \centerline{{\it\fontname\tenit\/} and} + \centerline{{\sl\fontname\tensl\/}} + \centerline{are used for emphasis.}\vfill} + \page\colophon +-% Blame: doc@cygnus.com, 28mar91. ++% Blame: doc at cygnus.com, 28mar91. + @end tex + + @bye +diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi +index 45174b739e568d8f7f01fc373035e010ffeced3d..ce7746c103d9f6a5770b43a850a2e26b68b4b58d 100644 +--- binutils/doc/binutils.texi ++++ binutils/doc/binutils.texi +@@ -4410,45 +4410,45 @@ which fields in the ELF header should be updated. + The long and short forms of options, shown here as alternatives, are + equivalent. At least one of the @option{--output-mach}, + @option{--output-type} and @option{--output-osabi} options must be given. + + @table @env + +-@itemx --input-mach=@var{machine} ++@item --input-mach=@var{machine} + Set the matching input ELF machine type to @var{machine}. If + @option{--input-mach} isn't specified, it will match any ELF + machine types. + + The supported ELF machine types are, @var{L1OM}, @var{K1OM} and + @var{x86-64}. + +-@itemx --output-mach=@var{machine} ++@item --output-mach=@var{machine} + Change the ELF machine type in the ELF header to @var{machine}. The + supported ELF machine types are the same as @option{--input-mach}. + +-@itemx --input-type=@var{type} ++@item --input-type=@var{type} + Set the matching input ELF file type to @var{type}. If + @option{--input-type} isn't specified, it will match any ELF file types. + + The supported ELF file types are, @var{rel}, @var{exec} and @var{dyn}. + +-@itemx --output-type=@var{type} ++@item --output-type=@var{type} + Change the ELF file type in the ELF header to @var{type}. The + supported ELF types are the same as @option{--input-type}. + +-@itemx --input-osabi=@var{osabi} ++@item --input-osabi=@var{osabi} + Set the matching input ELF file OSABI to @var{osabi}. If + @option{--input-osabi} isn't specified, it will match any ELF OSABIs. + + The supported ELF OSABIs are, @var{none}, @var{HPUX}, @var{NetBSD}, + @var{GNU}, @var{Linux} (alias for @var{GNU}), + @var{Solaris}, @var{AIX}, @var{Irix}, + @var{FreeBSD}, @var{TRU64}, @var{Modesto}, @var{OpenBSD}, @var{OpenVMS}, + @var{NSK}, @var{AROS} and @var{FenixOS}. + +-@itemx --output-osabi=@var{osabi} ++@item --output-osabi=@var{osabi} + Change the ELF OSABI in the ELF header to @var{osabi}. The + supported ELF OSABI are the same as @option{--input-osabi}. + + @item -v + @itemx --version + Display the version number of @command{elfedit}. +diff --git a/gas/doc/c-arc.texi b/gas/doc/c-arc.texi +index ea0fa4eb522c265700bdc3b6712894ec2ad61d7c..f27b3270abce6c40a7ff1b068313a14572c79b56 100644 +--- gas/doc/c-arc.texi ++++ gas/doc/c-arc.texi +@@ -217,13 +217,13 @@ can shortcut the pipeline. + @item .extInstruction @var{name},@var{opcode},@var{subopcode},@var{suffixclass},@var{syntaxclass} + The ARCtangent A4 allows the user to specify extension instructions. + The extension instructions are not macros. The assembler creates + encodings for use of these instructions according to the specification + by the user. The parameters are: + +-@table @bullet ++@itemize @bullet + @item @var{name} + Name of the extension instruction + + @item @var{opcode} + Opcode to be used. (Bits 27:31 in the encoding). Valid values + 0x10-0x1f or 0x03 +@@ -276,13 +276,13 @@ inst r1,r2 + it really means that the first argument is an implied immediate (that + is, the result is discarded). This is the same as though the source + code were: inst 0,r1,r2. You use OP1_IMM_IMPLIED by bitwise ORing it + with SYNTAX_20P. + + @end itemize +-@end table ++@end itemize + + For example, defining 64-bit multiplier with immediate operands: + + @smallexample + .extInstruction mp64,0x14,0x0,SUFFIX_COND | SUFFIX_FLAG , + SYNTAX_3OP|OP1_MUST_BE_IMM +diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi +index a46e08f4400ef64851828be4ab4df1046678699e..1944862d1caeb8f2aca57902f4ec1be55b68eb7e 100644 +--- gas/doc/c-arm.texi ++++ gas/doc/c-arm.texi +@@ -387,13 +387,13 @@ features. The default is to warn. + Two slightly different syntaxes are support for ARM and THUMB + instructions. The default, @code{divided}, uses the old style where + ARM and THUMB instructions had their own, separate syntaxes. The new, + @code{unified} syntax, which can be selected via the @code{.syntax} + directive, and has the following main features: + +-@table @bullet ++@itemize @bullet + @item + Immediate operands do not require a @code{#} prefix. + + @item + The @code{IT} instruction may appear, and if it does it is validated + against subsequent conditional affixes. In ARM mode it does not +@@ -412,13 +412,13 @@ available. (Only a few such instructions can be written in the + @item + The @code{.N} and @code{.W} suffixes are recognized and honored. + + @item + All instructions set the flags if and only if they have an @code{s} + affix. +-@end table ++@end itemize + + @node ARM-Chars + @subsection Special Characters + + @cindex line comment character, ARM + @cindex ARM line comment character +@@ -463,19 +463,12 @@ the @samp{@@} character as a "line comment" start, + so @samp{: @var{align}} is used instead. For example: + + @smallexample + vld1.8 @{q0@}, [r0, :128] + @end smallexample + +-@node ARM Floating Point +-@section Floating Point +- +-@cindex floating point, ARM (@sc{ieee}) +-@cindex ARM floating point (@sc{ieee}) +-The ARM family uses @sc{ieee} floating-point numbers. +- + @node ARM-Relocations + @subsection ARM relocation generation + + @cindex data relocations, ARM + @cindex ARM data relocations + Specific data relocations can be generated by putting the relocation name +@@ -516,12 +509,19 @@ respectively. For example to load the 32-bit address of foo into r0: + + @smallexample + MOVW r0, #:lower16:foo + MOVT r0, #:upper16:foo + @end smallexample + ++@node ARM Floating Point ++@section Floating Point ++ ++@cindex floating point, ARM (@sc{ieee}) ++@cindex ARM floating point (@sc{ieee}) ++The ARM family uses @sc{ieee} floating-point numbers. ++ + @node ARM Directives + @section ARM Machine Directives + + @cindex machine directives, ARM + @cindex ARM machine directives + @table @code +diff --git a/gas/doc/c-cr16.texi b/gas/doc/c-cr16.texi +index 19f859f71d8f8712e8250fda07ee5b148d2d13ac..592dc5a5459d0e48ba1ca2e2846dc5e380f18e63 100644 +--- gas/doc/c-cr16.texi ++++ gas/doc/c-cr16.texi +@@ -41,32 +41,39 @@ Operand expression type qualifier is an optional field in the instruction operan + - @code{Specifies the CompactRISC Assembler generates a relocation entry for the operand, where pc has implied bit, the expression is adjusted accordingly. The linker uses the relocation entry to update the operand address at link time.} + @end table + + CR16 target operand qualifiers and its size (in bits): + + @table @samp +-@item Immediate Operand +-- s ---- 4 bits +-@item +-- m ---- 16 bits, for movb and movw instructions. +-@item +-- m ---- 20 bits, movd instructions. +-@item +-- l ---- 32 bits +- +-@item Absolute Operand +-- s ---- Illegal specifier for this operand. +-@item +-- m ---- 20 bits, movd instructions. +- +-@item Displacement Operand +-- s ---- 8 bits +-@item +-- m ---- 16 bits +-@item +-- l ---- 24 bits ++@item Immediate Operand: s ++4 bits. ++ ++@item Immediate Operand: m ++16 bits, for movb and movw instructions. ++ ++@item Immediate Operand: m ++20 bits, movd instructions. ++ ++@item Immediate Operand: l ++32 bits ++ ++@item Absolute Operand: s ++Illegal specifier for this operand. ++ ++@item Absolute Operand: m ++20 bits, movd instructions. ++ ++@item Displacement Operand: s ++8 bits ++ ++@item Displacement Operand: m ++16 bits ++ ++@item Displacement Operand: l ++24 bits ++ + @end table + + For example: + @example + 1 @code{movw $_myfun@@c,r1} + +diff --git a/gas/doc/c-mips.texi b/gas/doc/c-mips.texi +index 9ed0420549220079a9c44d2eed0b9daca7805af5..6054ab90442b3de4622743ef73720b5c891334e4 100644 +--- gas/doc/c-mips.texi ++++ gas/doc/c-mips.texi +@@ -231,13 +231,13 @@ option. + @itemx -no-m4650 + Generate code for the MIPS @sc{r4650} chip. This tells the assembler to accept + the @samp{mad} and @samp{madu} instruction, and to not schedule @samp{nop} + instructions around accesses to the @samp{HI} and @samp{LO} registers. + @samp{-no-m4650} turns off this option. + +-@itemx -m3900 ++@item -m3900 + @itemx -no-m3900 + @itemx -m4100 + @itemx -no-m4100 + For each option @samp{-m@var{nnnn}}, generate code for the MIPS + @sc{r@var{nnnn}} chip. This tells the assembler to accept instructions + specific to that chip, and to schedule for that chip's hazards. +diff --git a/gas/doc/c-score.texi b/gas/doc/c-score.texi +index 3af20a381dccc9738b4e6f5152a0f83edba9892e..40959f5b9cb2aef21b5e55289b6b9c981d57ce79 100644 +--- gas/doc/c-score.texi ++++ gas/doc/c-score.texi +@@ -34,31 +34,31 @@ The following table lists all available SCORE options. + This option sets the largest size of an object that can be referenced + implicitly with the @code{gp} register. The default value is 8. + + @item -EB + Assemble code for a big-endian cpu + +-@itemx -EL ++@item -EL + Assemble code for a little-endian cpu + + @item -FIXDD + Assemble code for fix data dependency + + @item -NWARN + Assemble code for no warning message for fix data dependency + + @item -SCORE5 + Assemble code for target is SCORE5 + +-@itemx -SCORE5U ++@item -SCORE5U + Assemble code for target is SCORE5U + +-@itemx -SCORE7 ++@item -SCORE7 + Assemble code for target is SCORE7, this is default setting + +-@itemx -SCORE3 ++@item -SCORE3 + Assemble code for target is SCORE3 + + @item -march=score7 + Assemble code for target is SCORE7, this is default setting + + @item -march=score3 +diff --git a/gas/doc/c-tic54x.texi b/gas/doc/c-tic54x.texi +index d61ec3af1a7de0b52e9a8230e65d8b55992c8540..2c3b0f2c111461debe9d4ea20d0219a04764c734 100644 +--- gas/doc/c-tic54x.texi ++++ gas/doc/c-tic54x.texi +@@ -106,13 +106,13 @@ Expansion is recursive until a previously encountered symbol is seen, at + which point substitution stops. + + In this example, x is replaced with SYM2; SYM2 is replaced with SYM1, and SYM1 + is replaced with x. At this point, x has already been encountered + and the substitution stops. + +-@smallexample @code ++@smallexample + .asg "x",SYM1 + .asg "SYM1",SYM2 + .asg "SYM2",x + add x,a ; final code assembled is "add x, a" + @end smallexample + +@@ -123,20 +123,20 @@ directive is used to identify the subsym as a local macro variable + @pxref{TIC54X-Directives,,@code{.var}}. + + Substitution may be forced in situations where replacement might be + ambiguous by placing colons on either side of the subsym. The following + code: + +-@smallexample @code ++@smallexample + .eval "10",x + LAB:X: add #x, a + @end smallexample + + When assembled becomes: + +-@smallexample @code ++@smallexample + LAB10 add #10, a + @end smallexample + + Smaller parts of the string assigned to a subsym may be accessed with + the following syntax: + +@@ -306,13 +306,13 @@ floating point. + @node TIC54X-Ext + @section Extended Addressing + The @code{LDX} pseudo-op is provided for loading the extended addressing bits + of a label or address. For example, if an address @code{_label} resides + in extended program memory, the value of @code{_label} may be loaded as + follows: +-@smallexample @code ++@smallexample + ldx #_label,16,a ; loads extended bits of _label + or #_label,a ; loads lower 16 bits of _label + bacc a ; full address is in accumulator A + @end smallexample + + @node TIC54X-Directives +@@ -342,13 +342,13 @@ Align SPC to page boundary + @cindex @code{asg} directive, TIC54X + @item .asg @var{string}, @var{name} + Assign @var{name} the string @var{string}. String replacement is + performed on @var{string} before assignment. + + @cindex @code{eval} directive, TIC54X +-@itemx .eval @var{string}, @var{name} ++@item .eval @var{string}, @var{name} + Evaluate the contents of string @var{string} and assign the result as a + string to the subsym @var{name}. String replacement is performed on + @var{string} before assignment. + + @cindex @code{bss} directive, TIC54X + @item .bss @var{symbol}, @var{size} [, [@var{blocking_flag}] [,@var{alignment_flag}]] +diff --git a/ld/ld.texinfo b/ld/ld.texinfo +index 71e909e4b61606d4ca8d1f855d9cd10a3ae1947b..81d538bad91eee08ae24dc88f589b6d07719fff0 100644 +--- ld/ld.texinfo ++++ ld/ld.texinfo +@@ -7860,21 +7860,21 @@ If you have more than one @code{SECT} statement for the same + @node LD Index + @unnumbered LD Index + + @printindex cp + + @tex +-% I think something like @colophon should be in texinfo. In the ++% I think something like @ colophon should be in texinfo. In the + % meantime: + \long\def\colophon{\hbox to0pt{}\vfill + \centerline{The body of this manual is set in} + \centerline{\fontname\tenrm,} + \centerline{with headings in {\bf\fontname\tenbf}} + \centerline{and examples in {\tt\fontname\tentt}.} + \centerline{{\it\fontname\tenit\/} and} + \centerline{{\sl\fontname\tensl\/}} + \centerline{are used for emphasis.}\vfill} + \page\colophon +-% Blame: doc@cygnus.com, 28mar91. ++% Blame: doc @ cygnus.com, 28mar91. + @end tex + + @bye +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/binutils/0003-Disabled-some-stuff-such-that-68k-vtarget-builds-aga.p b/ppc-amigaos/recipes/patches/binutils/0003-Disabled-some-stuff-such-that-68k-vtarget-builds-aga.p new file mode 100644 index 0000000..f3b89fd --- /dev/null +++ b/ppc-amigaos/recipes/patches/binutils/0003-Disabled-some-stuff-such-that-68k-vtarget-builds-aga.p @@ -0,0 +1,110 @@ +From be1c62376ea16552979036768972be85ca66c9ed Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Tue, 17 Mar 2015 19:30:24 +0100 +Subject: [PATCH 3/7] Disabled some stuff such that 68k vtarget builds again. + +This doesn't imply that it is working. +--- + gas/config/tc-m68k.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c +index 8b5f6c60f2141ee91d6e9d1d639815abdf4e5042..9070a862b9c1266e84a8cea8da697f333227fa98 100644 +--- gas/config/tc-m68k.c ++++ gas/config/tc-m68k.c +@@ -5158,22 +5158,22 @@ md_convert_frag_1 (fragS *fragP) + case TAB (BRANCHBWPL, LONG): + /* Here we are converting an unconditional branch into a pair of + conditional branches, in order to get the range. */ + fragP->fr_opcode[0] = 0x66; /* bne */ + fragP->fr_opcode[1] = 0xFF; + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC32); ++ fragP->fr_offset, 1, RELAX_RELOC_PC32, 0); + fixP->fx_file = fragP->fr_file; + fixP->fx_line = fragP->fr_line; + fragP->fr_fix += 4; /* Skip first offset */ + buffer_address += 4; + *buffer_address++ = 0x67; /* beq */ + *buffer_address++ = 0xff; + fragP->fr_fix += 2; /* Skip second branch opcode */ + fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, +- fragP->fr_offset, 1, RELAX_RELOC_PC32); ++ fragP->fr_offset, 1, RELAX_RELOC_PC32, 0); + fragP->fr_fix += 4; + break; + case TAB (BRABSJUNC, LONG): + if (flag_small_code) + { + as_bad (_("Long branch in small code model, not supported.")); +@@ -5348,12 +5348,14 @@ md_convert_frag_1 (fragS *fragP) + fragP->fr_fix += 4; + break; + case TAB (ABSREL, BYTE): + as_bad (_("ABSREL_BYTE: how the ** does this look??")); + break; + case TAB (ABSREL, SHORT): ++ as_bad (_("ABSREL_SHORT: sorry, not supported. See" __FILE__)); ++#if 0 + fragP->fr_opcode[1] &= ~0x3f; + fragP->fr_fix += 2; + if (S_GET_TYPE (fragP->fr_symbol) == N_TEXT) + { + /* so this is really a pc-relative address */ + fragP->fr_opcode[1] |= 0x3a; +@@ -5362,20 +5364,23 @@ md_convert_frag_1 (fragS *fragP) + } + /* in that case we have to generate base-relative code + * (note: if we're in N_UNDF, this could as well be pc-relative, but the linker + * will have to do the final patch in that case) */ + fragP->fr_opcode[1] |= 0x2c; /* (a4) */ + fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 1); ++#endif + break; + case TAB (ABSREL, LONG): + as_bad (_("ABSREL_LONG: sorry, not supported.")); + break; + case TAB (IMMREL, BYTE): + as_bad (_("IMMREL_BYTE: how the ** does this look??")); + break; + case TAB (IMMREL, SHORT): ++ as_bad (_("IMMREL_SHORT: sorry, not supported. See " __FILE__)); ++#if 0 + if (S_GET_TYPE (fragP->fr_symbol) == N_TEXT) + { + /* we can only fix operations on data registers, not on <ea> */ + if ((fragP->fr_opcode[1] & 0x38) != 0) + { + /* use the normal reloc32, sigh... */ +@@ -5415,12 +5420,13 @@ md_convert_frag_1 (fragS *fragP) + * addl a4,d0 + */ + + fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 1); + *buffer_address++ = 0xd0; + *buffer_address++ = 0x8c; ++#endif + break; + } + if (fixP) + { + fixP->fx_file = fragP->fr_file; + fixP->fx_line = fragP->fr_line; +@@ -8302,13 +8308,13 @@ m68k_elf_cons (int nbytes /* 4=.long */) + + p = frag_more (nbytes); + offset = 0; + if (target_big_endian) + offset = nbytes - size; + fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, +- &exp, 0, reloc); ++ &exp, 0, reloc, 0); + } + } + else + emit_expr (&exp, (unsigned int) nbytes); + } + while (*input_line_pointer++ == ','); +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/binutils/0004-Print-symbol-name-when-an-unexpected-type-was-encoun.p b/ppc-amigaos/recipes/patches/binutils/0004-Print-symbol-name-when-an-unexpected-type-was-encoun.p new file mode 100644 index 0000000..7c4f7a6 --- /dev/null +++ b/ppc-amigaos/recipes/patches/binutils/0004-Print-symbol-name-when-an-unexpected-type-was-encoun.p @@ -0,0 +1,31 @@ +From 5e5e0a5505d8e5fc67697f3ab397fa5a39e085cc Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Sat, 12 Sep 2015 11:29:01 +0200 +Subject: [PATCH 4/7] Print symbol name when an unexpected type was + encountered. + +--- + bfd/elflink.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/bfd/elflink.c b/bfd/elflink.c +index bcd3add478ab13addffee21b54919afd5cdcd7d6..f10801b99e366ad956faf039401cfcbf0c42aaa1 100644 +--- bfd/elflink.c ++++ bfd/elflink.c +@@ -8801,12 +8801,13 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + case bfd_link_hash_warning: ++ (*_bfd_error_handler)(_("Unexpected type (%d) of symbol %s"), h->root.type, h->root.root.string); + abort (); + return FALSE; + + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + input_sec = bfd_und_section_ptr; +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/binutils/0005-Bind-in-the-ld-unwind-options.p b/ppc-amigaos/recipes/patches/binutils/0005-Bind-in-the-ld-unwind-options.p new file mode 100644 index 0000000..f82d880 --- /dev/null +++ b/ppc-amigaos/recipes/patches/binutils/0005-Bind-in-the-ld-unwind-options.p @@ -0,0 +1,27 @@ +From ce074fe73deeb899bf1cd863092c174034f56e67 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Thu, 22 Oct 2015 09:48:26 +0200 +Subject: [PATCH 5/7] Bind in the ld unwind options. + +--- + ld/emulparams/amigaos.sh | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/ld/emulparams/amigaos.sh b/ld/emulparams/amigaos.sh +index 605b81e76bcbbd2322561d7d9502190dc7c00674..2661d4ddcd1c5ecab9adea84af7f7d0ba054aa95 100644 +--- ld/emulparams/amigaos.sh ++++ ld/emulparams/amigaos.sh +@@ -1,7 +1,9 @@ +-#. ${srcdir}/emulparams/elf32ppccommon.sh ++. ${srcdir}/emulparams/elf32ppccommon.sh ++. ${srcdir}/emulparams/plt_unwind.sh ++ + TEMPLATE_NAME=amigaos + SCRIPT_NAME=amigaos + OUTPUT_FORMAT="elf32-amigaos" + MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" + COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" + ALIGNMENT=16 +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/binutils/0006-Introduced-strip-unneeded-rel-relocs.p b/ppc-amigaos/recipes/patches/binutils/0006-Introduced-strip-unneeded-rel-relocs.p new file mode 100644 index 0000000..db15c54 --- /dev/null +++ b/ppc-amigaos/recipes/patches/binutils/0006-Introduced-strip-unneeded-rel-relocs.p @@ -0,0 +1,128 @@ +From 6b64c328f239a146c1ce5a85c27b0ff1636f3987 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Tue, 1 Dec 2015 13:51:20 +0100 +Subject: [PATCH 6/7] Introduced strip-unneeded-rel-relocs. + +Normally, on AmigaOS we keep all relocs for executables as we don't have +an isolated address space. However, not all relative relocs are necessary +to be kept, for instance if they are refering to the same program section. +With the newly introduced strip option --strip-unneeded-rel-relocs these +can be removed now. +--- + binutils/objcopy.c | 30 +++++++++++++++++++++++------- + 1 file changed, 23 insertions(+), 7 deletions(-) + +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index 88bd071eefa8b5426eaadfd6431e9de5d4a4591b..4beee77179b85479d5b43507d9eb2a6e0caf384e 100644 +--- binutils/objcopy.c ++++ binutils/objcopy.c +@@ -101,12 +101,15 @@ enum strip_action + STRIP_ALL /* Strip all symbols. */ + }; + + /* Which symbols to remove. */ + static enum strip_action strip_symbols; + ++/* Shall we strip unneeded relative relocs? */ ++static int strip_unneeded_rel_relocs; ++ + enum locals_action + { + LOCALS_UNDEF, + LOCALS_START_L, /* Discard locals starting with L. */ + LOCALS_ALL /* Discard all locals. */ + }; +@@ -315,13 +318,14 @@ enum command_line_switch + OPTION_IMAGE_BASE, + OPTION_SECTION_ALIGNMENT, + OPTION_STACK, + OPTION_INTERLEAVE_WIDTH, + OPTION_SUBSYSTEM, + OPTION_EXTRACT_DWO, +- OPTION_STRIP_DWO ++ OPTION_STRIP_DWO, ++ OPTION_STRIP_UNNEEED_REL_RELOCS + }; + + /* Options to handle if running as "strip". */ + + static struct option strip_options[] = + { +@@ -343,12 +347,13 @@ static struct option strip_options[] = + {"preserve-dates", no_argument, 0, 'p'}, + {"remove-section", required_argument, 0, 'R'}, + {"strip-all", no_argument, 0, 's'}, + {"strip-debug", no_argument, 0, 'S'}, + {"strip-dwo", no_argument, 0, OPTION_STRIP_DWO}, + {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED}, ++ {"strip-unneeded-rel-relocs", no_argument, 0, OPTION_STRIP_UNNEEED_REL_RELOCS}, + {"strip-symbol", required_argument, 0, 'N'}, + {"target", required_argument, 0, 'F'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {"wildcard", no_argument, 0, 'w'}, + {0, no_argument, 0, 0} +@@ -2771,30 +2776,38 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg) + temp_relpp = (arelent **) xmalloc (relsize); + for (i = 0; i < relcount; i++) + { + asection *sec; + sec = bfd_get_section(*relpp[i]->sym_ptr_ptr); + +-// printf("%d: %s (0x%lx + 0x%lx) value 0x%lx (in section %s)\n", ++// printf("%ld: %s (0x%lx + 0x%lx) value 0x%lx (in section %s)\n", + // i, bfd_asymbol_name (*relpp [i]->sym_ptr_ptr), relpp [i]->address, relpp [i]->addend, + // bfd_asymbol_value(*relpp [i]->sym_ptr_ptr), + // bfd_section_name(ibfd, sec)); + + /* Keep the symbol */ + if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr), + keep_specific_htab)) + temp_relpp [temp_relcount++] = relpp [i]; + else + { +- /* Don't keep the symbol, but keep the reloc */ +- temp_relpp [temp_relcount] = relpp[i]; +- temp_relpp [temp_relcount]->addend = bfd_asymbol_value(*relpp [i]->sym_ptr_ptr) ++ /* Don't keep the symbol, but keep the reloc unless it is a relative reloc that is ++ * requested by the user to be removed. For now, we also don't discard the reloc if ++ * its targeting a different section. This can happen for relocs in the .rodata ++ * segment that refering to the .text segment. AmigaOS will possibly split these ++ * up. ++ */ ++ if (!strip_unneeded_rel_relocs || !relpp [i]->howto->pc_relative || sec->index != osection->index) ++ { ++ temp_relpp [temp_relcount] = relpp[i]; ++ temp_relpp [temp_relcount]->addend = bfd_asymbol_value(*relpp [i]->sym_ptr_ptr) + - sec->vma + + relpp[i]->addend; +- temp_relpp [temp_relcount]->sym_ptr_ptr = sec->symbol_ptr_ptr; +- temp_relcount++; ++ temp_relpp [temp_relcount]->sym_ptr_ptr = sec->symbol_ptr_ptr; ++ temp_relcount++; ++ } + } + } + relcount = temp_relcount; + free (relpp); + relpp = temp_relpp; + } +@@ -3124,12 +3137,15 @@ strip_main (int argc, char *argv[]) + case OPTION_STRIP_DWO: + strip_symbols = STRIP_DWO; + break; + case OPTION_STRIP_UNNEEDED: + strip_symbols = STRIP_UNNEEDED; + break; ++ case OPTION_STRIP_UNNEEED_REL_RELOCS: ++ strip_unneeded_rel_relocs = 1; ++ break; + case 'K': + add_specific_symbol (optarg, keep_specific_htab); + break; + case 'N': + add_specific_symbol (optarg, strip_specific_htab); + break; +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/binutils/0007-Keep-symbols-for-stripped-sections.-This-is-importan.p b/ppc-amigaos/recipes/patches/binutils/0007-Keep-symbols-for-stripped-sections.-This-is-importan.p new file mode 100644 index 0000000..7681051 --- /dev/null +++ b/ppc-amigaos/recipes/patches/binutils/0007-Keep-symbols-for-stripped-sections.-This-is-importan.p @@ -0,0 +1,42 @@ +From 035f3afce47e01ee70c7972a71a9dccea2b61e6f Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Thu, 3 Dec 2015 23:48:21 +0100 +Subject: [PATCH 7/7] Keep symbols for stripped sections. This is important for + _SDA_BASE_, + +--- + binutils/objcopy.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index 4beee77179b85479d5b43507d9eb2a6e0caf384e..8750db51279ec56080aba114cd61780d061b168f 100644 +--- binutils/objcopy.c ++++ binutils/objcopy.c +@@ -1239,13 +1239,23 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, + if (!keep + && ((keep_file_symbols && (flags & BSF_FILE)) + || is_specified_symbol (name, keep_specific_htab))) + keep = TRUE; + + if (keep && is_strip_section (abfd, bfd_get_section (sym))) +- keep = FALSE; ++ { ++ /* If the symbol refers to a stripped section, we still want to ++ * keep it, e.g., _SDA_BASE_ TODO: We should perhaps output a ++ * warning or add another option to trigger this behaviour. ++ * FIXME: The section to which symbol refers must be adjusted ++ * as well */ ++ if (!is_specified_symbol (name, keep_specific_htab)) ++ { ++ keep = FALSE; ++ } ++ } + + if (keep) + { + if ((flags & BSF_GLOBAL) != 0 + && (weaken || is_specified_symbol (name, weaken_specific_htab))) + { +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/binutils/missing-files.p b/ppc-amigaos/recipes/patches/binutils/missing-files.p new file mode 100644 index 0000000..be93e0f --- /dev/null +++ b/ppc-amigaos/recipes/patches/binutils/missing-files.p @@ -0,0 +1,13021 @@ +--- /dev/null 2015-09-06 08:42:34.091999986 +0100 ++++ bfd/elf32-amigaos.c 2016-01-03 01:46:50.503001072 +0000 +@@ -0,0 +1,9972 @@ ++/* PowerPC-specific support for 32-bit ELF ++ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, ++ 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 ++ Free Software Foundation, Inc. ++ Written by Ian Lance Taylor, Cygnus Support. ++ ++ This file is part of BFD, the Binary File Descriptor library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the ++ Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, ++ Boston, MA 02110-1301, USA. */ ++ ++ ++/* This file is based on a preliminary PowerPC ELF ABI. The ++ information may not match the final PowerPC ELF ABI. It includes ++ suggestions from the in-progress Embedded PowerPC ABI, and that ++ information may also not match. */ ++ ++#include "sysdep.h" ++#include <stdarg.h> ++#include "bfd.h" ++#include "bfdlink.h" ++#include "libbfd.h" ++#include "elf-bfd.h" ++#include "elf/ppc.h" ++#include "elf/amigaos.h" ++#include "elf32-ppc.h" ++#include "elf-vxworks.h" ++#include "dwarf2.h" ++ ++#undef DEBUG ++ ++typedef enum split16_format_type ++{ ++ split16a_type = 0, ++ split16d_type ++} ++split16_format_type; ++ ++/* RELA relocations are used here. */ ++#define USE_RELA ++#define USE_REL 0 ++ ++static bfd_reloc_status_type ppc_elf_addr16_ha_reloc ++ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); ++static bfd_reloc_status_type ppc_elf_unhandled_reloc ++ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); ++static void ppc_elf_vle_split16 ++ (bfd *, bfd_byte *, bfd_vma, bfd_vma, split16_format_type); ++ ++int ppc_elf_amigaos_select_plt_layout (bfd *, struct bfd_link_info *, ++ enum ppc_elf_plt_type, int); ++ ++bfd_boolean ppc_elf_amigaos_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr); ++bfd_boolean ppc_elf_amigaos_modify_segment_map (bfd *abfd, ++ struct bfd_link_info *info ATTRIBUTE_UNUSED); ++asection *ppc_elf_amigaos_tls_setup (bfd *obfd, struct bfd_link_info *info, ++ int no_tls_get_addr_opt); ++bfd_boolean ppc_elf_amigaos_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *info); ++unsigned int _bfd_elf_amigaos_ppc_at_tls_transform (unsigned int insn, unsigned int reg); ++unsigned int _bfd_elf_amigaos_ppc_at_tprel_transform (unsigned int insn, unsigned int reg); ++ ++/* Branch prediction bit for branch taken relocs. */ ++#define BRANCH_PREDICT_BIT 0x200000 ++/* Mask to set RA in memory instructions. */ ++#define RA_REGISTER_MASK 0x001f0000 ++/* Value to shift register by to insert RA. */ ++#define RA_REGISTER_SHIFT 16 ++ ++/* The name of the dynamic interpreter. This is put in the .interp ++ section. */ ++#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" ++ ++/* For old-style PLT. */ ++/* The number of single-slot PLT entries (the rest use two slots). */ ++#define PLT_NUM_SINGLE_ENTRIES 8192 ++ ++/* For new-style .glink and .plt. */ ++#define GLINK_PLTRESOLVE 16*4 ++#define GLINK_ENTRY_SIZE 4*4 ++#define TLS_GET_ADDR_GLINK_SIZE 12*4 ++ ++/* VxWorks uses its own plt layout, filled in by the static linker. */ ++ ++/* The standard VxWorks PLT entry. */ ++#define VXWORKS_PLT_ENTRY_SIZE 32 ++static const bfd_vma ppc_elf_vxworks_plt_entry ++ [VXWORKS_PLT_ENTRY_SIZE / 4] = ++ { ++ 0x3d800000, /* lis r12,0 */ ++ 0x818c0000, /* lwz r12,0(r12) */ ++ 0x7d8903a6, /* mtctr r12 */ ++ 0x4e800420, /* bctr */ ++ 0x39600000, /* li r11,0 */ ++ 0x48000000, /* b 14 <.PLT0resolve+0x4> */ ++ 0x60000000, /* nop */ ++ 0x60000000, /* nop */ ++ }; ++static const bfd_vma ppc_elf_vxworks_pic_plt_entry ++ [VXWORKS_PLT_ENTRY_SIZE / 4] = ++ { ++ 0x3d9e0000, /* addis r12,r30,0 */ ++ 0x818c0000, /* lwz r12,0(r12) */ ++ 0x7d8903a6, /* mtctr r12 */ ++ 0x4e800420, /* bctr */ ++ 0x39600000, /* li r11,0 */ ++ 0x48000000, /* b 14 <.PLT0resolve+0x4> 14: R_PPC_REL24 .PLTresolve */ ++ 0x60000000, /* nop */ ++ 0x60000000, /* nop */ ++ }; ++ ++/* The initial VxWorks PLT entry. */ ++#define VXWORKS_PLT_INITIAL_ENTRY_SIZE 32 ++static const bfd_vma ppc_elf_vxworks_plt0_entry ++ [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] = ++ { ++ 0x3d800000, /* lis r12,0 */ ++ 0x398c0000, /* addi r12,r12,0 */ ++ 0x800c0008, /* lwz r0,8(r12) */ ++ 0x7c0903a6, /* mtctr r0 */ ++ 0x818c0004, /* lwz r12,4(r12) */ ++ 0x4e800420, /* bctr */ ++ 0x60000000, /* nop */ ++ 0x60000000, /* nop */ ++ }; ++static const bfd_vma ppc_elf_vxworks_pic_plt0_entry ++ [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] = ++ { ++ 0x819e0008, /* lwz r12,8(r30) */ ++ 0x7d8903a6, /* mtctr r12 */ ++ 0x819e0004, /* lwz r12,4(r30) */ ++ 0x4e800420, /* bctr */ ++ 0x60000000, /* nop */ ++ 0x60000000, /* nop */ ++ 0x60000000, /* nop */ ++ 0x60000000, /* nop */ ++ }; ++ ++/* For executables, we have some additional relocations in ++ .rela.plt.unloaded, for the kernel loader. */ ++ ++/* The number of non-JMP_SLOT relocations per PLT0 slot. */ ++#define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3 ++/* The number of relocations in the PLTResolve slot. */ ++#define VXWORKS_PLTRESOLVE_RELOCS 2 ++/* The number of relocations in the PLTResolve slot when when creating ++ a shared library. */ ++#define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0 ++ ++/* Some instructions. */ ++#define ADDIS_11_11 0x3d6b0000 ++#define ADDIS_11_30 0x3d7e0000 ++#define ADDIS_12_12 0x3d8c0000 ++#define ADDI_11_11 0x396b0000 ++#define ADD_0_11_11 0x7c0b5a14 ++#define ADD_3_12_2 0x7c6c1214 ++#define ADD_11_0_11 0x7d605a14 ++#define B 0x48000000 ++#define BCL_20_31 0x429f0005 ++#define BCTR 0x4e800420 ++#define BEQLR 0x4d820020 ++#define CMPWI_11_0 0x2c0b0000 ++#define LIS_11 0x3d600000 ++#define LIS_12 0x3d800000 ++#define LWZU_0_12 0x840c0000 ++#define LWZ_0_12 0x800c0000 ++#define LWZ_11_3 0x81630000 ++#define LWZ_11_11 0x816b0000 ++#define LWZ_11_30 0x817e0000 ++#define LWZ_12_3 0x81830000 ++#define LWZ_12_12 0x818c0000 ++#define MR_0_3 0x7c601b78 ++#define MR_3_0 0x7c030378 ++#define MFLR_0 0x7c0802a6 ++#define MFLR_12 0x7d8802a6 ++#define MTCTR_0 0x7c0903a6 ++#define MTCTR_11 0x7d6903a6 ++#define MTLR_0 0x7c0803a6 ++#define NOP 0x60000000 ++#define SUB_11_11_12 0x7d6c5850 ++ ++/* Offset of tp and dtp pointers from start of TLS block. */ ++#define TP_OFFSET 0x7000 ++#define DTP_OFFSET 0x8000 ++ ++/* The value of a defined global symbol. */ ++#define SYM_VAL(SYM) \ ++ ((SYM)->root.u.def.section->output_section->vma \ ++ + (SYM)->root.u.def.section->output_offset \ ++ + (SYM)->root.u.def.value) ++ ++static reloc_howto_type *ppc_elf_howto_table[R_PPC_max]; ++ ++static reloc_howto_type ppc_elf_howto_raw[] = { ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_NONE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_NONE", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A standard 32 bit relocation. */ ++ HOWTO (R_PPC_ADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* An absolute 26 bit branch; the lower two bits must be zero. ++ FIXME: we don't check that, we just clear them. */ ++ HOWTO (R_PPC_ADDR24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR24", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A standard 16 bit relocation. */ ++ HOWTO (R_PPC_ADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A 16 bit relocation without overflow. */ ++ HOWTO (R_PPC_ADDR16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of an address. */ ++ HOWTO (R_PPC_ADDR16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of an address, plus 1 if the contents of ++ the low 16 bits, treated as a signed number, is negative. */ ++ HOWTO (R_PPC_ADDR16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_ADDR16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch; the lower two bits must be zero. ++ FIXME: we don't check that, we just clear them. */ ++ HOWTO (R_PPC_ADDR14, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch, for which bit 10 should be set to ++ indicate that the branch is expected to be taken. The lower two ++ bits must be zero. */ ++ HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14_BRTAKEN",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch, for which bit 10 should be set to ++ indicate that the branch is not expected to be taken. The lower ++ two bits must be zero. */ ++ HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14_BRNTAKEN",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A relative 26 bit branch; the lower two bits must be zero. */ ++ HOWTO (R_PPC_REL24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL24", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch; the lower two bits must be zero. */ ++ HOWTO (R_PPC_REL14, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch. Bit 10 should be set to indicate that ++ the branch is expected to be taken. The lower two bits must be ++ zero. */ ++ HOWTO (R_PPC_REL14_BRTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14_BRTAKEN", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch. Bit 10 should be set to indicate that ++ the branch is not expected to be taken. The lower two bits must ++ be zero. */ ++ HOWTO (R_PPC_REL14_BRNTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14_BRNTAKEN",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16, but referring to the GOT table entry for the ++ symbol. */ ++ HOWTO (R_PPC_GOT16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_GOT16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like R_PPC_REL24, but referring to the procedure linkage table ++ entry for the symbol. */ ++ HOWTO (R_PPC_PLTREL24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL24", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* This is used only by the dynamic linker. The symbol should exist ++ both in the object being run and in some shared library. The ++ dynamic linker copies the data addressed by the symbol from the ++ shared library into the object, because the object being ++ run has to have the data at some particular address. */ ++ HOWTO (R_PPC_COPY, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_COPY", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR32, but used when setting global offset table ++ entries. */ ++ HOWTO (R_PPC_GLOB_DAT, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GLOB_DAT", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Marks a procedure linkage table entry for a symbol. */ ++ HOWTO (R_PPC_JMP_SLOT, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_JMP_SLOT", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Used only by the dynamic linker. When the object is run, this ++ longword is set to the load address of the object, plus the ++ addend. */ ++ HOWTO (R_PPC_RELATIVE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_RELATIVE", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like R_PPC_REL24, but uses the value of the symbol within the ++ object rather than the final value. Normally used for ++ _GLOBAL_OFFSET_TABLE_. */ ++ HOWTO (R_PPC_LOCAL24PC, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_LOCAL24PC", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR32, but may be unaligned. */ ++ HOWTO (R_PPC_UADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_UADDR32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16, but may be unaligned. */ ++ HOWTO (R_PPC_UADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_UADDR16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 32-bit PC relative */ ++ HOWTO (R_PPC_REL32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* 32-bit relocation to the symbol's procedure linkage table. ++ FIXME: not supported. */ ++ HOWTO (R_PPC_PLT32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 32-bit PC relative relocation to the symbol's procedure linkage table. ++ FIXME: not supported. */ ++ HOWTO (R_PPC_PLTREL32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_PLT16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A sign-extended 16 bit value relative to _SDA_BASE_, for use with ++ small data items. */ ++ HOWTO (R_PPC_SDAREL16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SDAREL16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 16-bit section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 16-bit lower half section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 16-bit upper half section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 16-bit upper half adjusted section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Marker relocs for TLS. */ ++ HOWTO (R_PPC_TLS, ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_TLS", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ HOWTO (R_PPC_TLSGD, ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_TLSGD", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ HOWTO (R_PPC_TLSLD, ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_TLSLD", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Computes the load module index of the load module that contains the ++ definition of its TLS sym. */ ++ HOWTO (R_PPC_DTPMOD32, ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_DTPMOD32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Computes a dtv-relative displacement, the difference between the value ++ of sym+add and the base address of the thread-local storage block that ++ contains the definition of sym, minus 0x8000. */ ++ HOWTO (R_PPC_DTPREL32, ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_DTPREL32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A 16 bit dtprel reloc. */ ++ HOWTO (R_PPC_DTPREL16, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_DTPREL16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like DTPREL16, but no overflow. */ ++ HOWTO (R_PPC_DTPREL16_LO, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_DTPREL16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like DTPREL16_LO, but next higher group of 16 bits. */ ++ HOWTO (R_PPC_DTPREL16_HI, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_DTPREL16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like DTPREL16_HI, but adjust for low 16 bits. */ ++ HOWTO (R_PPC_DTPREL16_HA, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_DTPREL16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Computes a tp-relative displacement, the difference between the value of ++ sym+add and the value of the thread pointer (r13). */ ++ HOWTO (R_PPC_TPREL32, ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_TPREL32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A 16 bit tprel reloc. */ ++ HOWTO (R_PPC_TPREL16, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_TPREL16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like TPREL16, but no overflow. */ ++ HOWTO (R_PPC_TPREL16_LO, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_TPREL16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like TPREL16_LO, but next higher group of 16 bits. */ ++ HOWTO (R_PPC_TPREL16_HI, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_TPREL16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like TPREL16_HI, but adjust for low 16 bits. */ ++ HOWTO (R_PPC_TPREL16_HA, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_TPREL16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Allocates two contiguous entries in the GOT to hold a tls_index structure, ++ with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset ++ to the first entry. */ ++ HOWTO (R_PPC_GOT_TLSGD16, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TLSGD16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_TLSGD16, but no overflow. */ ++ HOWTO (R_PPC_GOT_TLSGD16_LO, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TLSGD16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_TLSGD16_LO, but next higher group of 16 bits. */ ++ HOWTO (R_PPC_GOT_TLSGD16_HI, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TLSGD16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_TLSGD16_HI, but adjust for low 16 bits. */ ++ HOWTO (R_PPC_GOT_TLSGD16_HA, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TLSGD16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Allocates two contiguous entries in the GOT to hold a tls_index structure, ++ with values (sym+add)@dtpmod and zero, and computes the offset to the ++ first entry. */ ++ HOWTO (R_PPC_GOT_TLSLD16, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TLSLD16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_TLSLD16, but no overflow. */ ++ HOWTO (R_PPC_GOT_TLSLD16_LO, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TLSLD16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_TLSLD16_LO, but next higher group of 16 bits. */ ++ HOWTO (R_PPC_GOT_TLSLD16_HI, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TLSLD16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_TLSLD16_HI, but adjust for low 16 bits. */ ++ HOWTO (R_PPC_GOT_TLSLD16_HA, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TLSLD16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes ++ the offset to the entry. */ ++ HOWTO (R_PPC_GOT_DTPREL16, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_DTPREL16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_DTPREL16, but no overflow. */ ++ HOWTO (R_PPC_GOT_DTPREL16_LO, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_DTPREL16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_DTPREL16_LO, but next higher group of 16 bits. */ ++ HOWTO (R_PPC_GOT_DTPREL16_HI, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_DTPREL16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_DTPREL16_HI, but adjust for low 16 bits. */ ++ HOWTO (R_PPC_GOT_DTPREL16_HA, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_DTPREL16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the ++ offset to the entry. */ ++ HOWTO (R_PPC_GOT_TPREL16, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TPREL16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_TPREL16, but no overflow. */ ++ HOWTO (R_PPC_GOT_TPREL16_LO, ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TPREL16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_TPREL16_LO, but next higher group of 16 bits. */ ++ HOWTO (R_PPC_GOT_TPREL16_HI, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TPREL16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Like GOT_TPREL16_HI, but adjust for low 16 bits. */ ++ HOWTO (R_PPC_GOT_TPREL16_HA, ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_unhandled_reloc, /* special_function */ ++ "R_PPC_GOT_TPREL16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++ ++ /* 32 bit value resulting from the addend minus the symbol. */ ++ HOWTO (R_PPC_EMB_NADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR32", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from the addend minus the symbol. */ ++ HOWTO (R_PPC_EMB_NADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from the addend minus the symbol. */ ++ HOWTO (R_PPC_EMB_NADDR16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_ADDR16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of the addend minus the symbol. */ ++ HOWTO (R_PPC_EMB_NADDR16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of the result of the addend minus the address, ++ plus 1 if the contents of the low 16 bits, treated as a signed number, ++ is negative. */ ++ HOWTO (R_PPC_EMB_NADDR16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from allocating a 4 byte word to hold an ++ address in the .sdata section, and returning the offset from ++ _SDA_BASE_ for that relocation. */ ++ HOWTO (R_PPC_EMB_SDAI16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDAI16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from allocating a 4 byte word to hold an ++ address in the .sdata2 section, and returning the offset from ++ _SDA2_BASE_ for that relocation. */ ++ HOWTO (R_PPC_EMB_SDA2I16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2I16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with ++ small data items. */ ++ HOWTO (R_PPC_EMB_SDA2REL, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2REL", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit ++ signed offset from the appropriate base, and filling in the register ++ field with the appropriate register (0, 2, or 13). */ ++ HOWTO (R_PPC_EMB_SDA21, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA21", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Relocation not handled: R_PPC_EMB_MRKREF */ ++ /* Relocation not handled: R_PPC_EMB_RELSEC16 */ ++ /* Relocation not handled: R_PPC_EMB_RELST_LO */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HI */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HA */ ++ /* Relocation not handled: R_PPC_EMB_BIT_FLD */ ++ ++ ++ /* A standard 32 bit base relative relocation. */ ++ HOWTO (R_PPC_AMIGAOS_BREL, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_AMIGAOS_BREL", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A 16 bit base relative relocation without overflow. */ ++ HOWTO (R_PPC_AMIGAOS_BREL_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_AMIGAOS_BREL_LO",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of a base relative address. */ ++ HOWTO (R_PPC_AMIGAOS_BREL_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_AMIGAOS_BREL_HI",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of a base relative address, plus 1 if the contents ++ of the low 16 bits, treated as a signed number, is negative. */ ++ HOWTO (R_PPC_AMIGAOS_BREL_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_AMIGAOS_BREL_HA",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling ++ in the 16 bit signed offset from the appropriate base, and filling in the ++ register field with the appropriate register (0, 2, or 13). */ ++ HOWTO (R_PPC_EMB_RELSDA, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_RELSDA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A relative 8 bit branch. */ ++ HOWTO (R_PPC_VLE_REL8, /* type */ ++ 1, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 8, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_REL8", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xff, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* A relative 15 bit branch. */ ++ HOWTO (R_PPC_VLE_REL15, /* type */ ++ 1, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 15, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 1, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_REL15", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfe, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* A relative 24 bit branch. */ ++ HOWTO (R_PPC_VLE_REL24, /* type */ ++ 1, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 24, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 1, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_REL24", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1fffffe, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* The 16 LSBS in split16a format. */ ++ HOWTO (R_PPC_VLE_LO16A, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_LO16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The 16 LSBS in split16d format. */ ++ HOWTO (R_PPC_VLE_LO16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_LO16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 split16a format. */ ++ HOWTO (R_PPC_VLE_HI16A, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_HI16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 split16d format. */ ++ HOWTO (R_PPC_VLE_HI16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_HI16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 (High Adjusted) in split16a format. */ ++ HOWTO (R_PPC_VLE_HA16A, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_HA16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 (High Adjusted) in split16d format. */ ++ HOWTO (R_PPC_VLE_HA16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_HA16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_VLE_SDA21, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDA21", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_VLE_SDA21_LO, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDA21_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The 16 LSBS relative to _SDA_BASE_ in split16a format. */ ++ HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_LO16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The 16 LSBS relative to _SDA_BASE_ in split16d format. */ ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_LO16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 relative to _SDA_BASE_ in split16a format. */ ++ HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_HI16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 relative to _SDA_BASE_ in split16d format. */ ++ HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_HI16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */ ++ HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_HA16A", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f007ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */ ++ HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_VLE_SDAREL_HA16D", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x1f07ff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ HOWTO (R_PPC_IRELATIVE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_IRELATIVE", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A 16 bit relative relocation. */ ++ HOWTO (R_PPC_REL16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* A 16 bit relative relocation without overflow. */ ++ HOWTO (R_PPC_REL16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL16_LO", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of a relative address. */ ++ HOWTO (R_PPC_REL16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL16_HI", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of a relative address, plus 1 if the contents of ++ the low 16 bits, treated as a signed number, is negative. */ ++ HOWTO (R_PPC_REL16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ TRUE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_REL16_HA", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ TRUE), /* pcrel_offset */ ++ ++ /* GNU extension to record C++ vtable hierarchy. */ ++ HOWTO (R_PPC_GNU_VTINHERIT, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ NULL, /* special_function */ ++ "R_PPC_GNU_VTINHERIT", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* GNU extension to record C++ vtable member usage. */ ++ HOWTO (R_PPC_GNU_VTENTRY, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ NULL, /* special_function */ ++ "R_PPC_GNU_VTENTRY", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* Phony reloc to handle AIX style TOC entries. */ ++ HOWTO (R_PPC_TOC16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_TOC16", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++}; ++ ++/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ ++ ++static void ++ppc_elf_howto_init (void) ++{ ++ unsigned int i, type; ++ ++ for (i = 0; ++ i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); ++ i++) ++ { ++ type = ppc_elf_howto_raw[i].type; ++ if (type >= (sizeof (ppc_elf_howto_table) ++ / sizeof (ppc_elf_howto_table[0]))) ++ abort (); ++ ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i]; ++ } ++} ++ ++static reloc_howto_type * ++ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, ++ bfd_reloc_code_real_type code) ++{ ++ enum elf_ppc_reloc_type r; ++ ++ /* Initialize howto table if not already done. */ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ ppc_elf_howto_init (); ++ ++ switch (code) ++ { ++ default: ++ return NULL; ++ ++ case BFD_RELOC_NONE: r = R_PPC_NONE; break; ++ case BFD_RELOC_32: r = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC_BA26: r = R_PPC_ADDR24; break; ++ case BFD_RELOC_PPC64_ADDR16_DS: ++ case BFD_RELOC_16: r = R_PPC_ADDR16; break; ++ case BFD_RELOC_PPC64_ADDR16_LO_DS: ++ case BFD_RELOC_LO16: r = R_PPC_ADDR16_LO; break; ++ case BFD_RELOC_HI16: r = R_PPC_ADDR16_HI; break; ++ case BFD_RELOC_HI16_S: r = R_PPC_ADDR16_HA; break; ++ case BFD_RELOC_PPC_BA16: r = R_PPC_ADDR14; break; ++ case BFD_RELOC_PPC_BA16_BRTAKEN: r = R_PPC_ADDR14_BRTAKEN; break; ++ case BFD_RELOC_PPC_BA16_BRNTAKEN: r = R_PPC_ADDR14_BRNTAKEN; break; ++ case BFD_RELOC_PPC_B26: r = R_PPC_REL24; break; ++ case BFD_RELOC_PPC_B16: r = R_PPC_REL14; break; ++ case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC_REL14_BRTAKEN; break; ++ case BFD_RELOC_PPC_B16_BRNTAKEN: r = R_PPC_REL14_BRNTAKEN; break; ++ case BFD_RELOC_PPC64_GOT16_DS: ++ case BFD_RELOC_16_GOTOFF: r = R_PPC_GOT16; break; ++ case BFD_RELOC_PPC64_GOT16_LO_DS: ++ case BFD_RELOC_LO16_GOTOFF: r = R_PPC_GOT16_LO; break; ++ case BFD_RELOC_HI16_GOTOFF: r = R_PPC_GOT16_HI; break; ++ case BFD_RELOC_HI16_S_GOTOFF: r = R_PPC_GOT16_HA; break; ++ case BFD_RELOC_24_PLT_PCREL: r = R_PPC_PLTREL24; break; ++ case BFD_RELOC_PPC_COPY: r = R_PPC_COPY; break; ++ case BFD_RELOC_PPC_GLOB_DAT: r = R_PPC_GLOB_DAT; break; ++ case BFD_RELOC_PPC_LOCAL24PC: r = R_PPC_LOCAL24PC; break; ++ case BFD_RELOC_32_PCREL: r = R_PPC_REL32; break; ++ case BFD_RELOC_32_PLTOFF: r = R_PPC_PLT32; break; ++ case BFD_RELOC_32_PLT_PCREL: r = R_PPC_PLTREL32; break; ++ case BFD_RELOC_PPC64_PLT16_LO_DS: ++ case BFD_RELOC_LO16_PLTOFF: r = R_PPC_PLT16_LO; break; ++ case BFD_RELOC_HI16_PLTOFF: r = R_PPC_PLT16_HI; break; ++ case BFD_RELOC_HI16_S_PLTOFF: r = R_PPC_PLT16_HA; break; ++ case BFD_RELOC_GPREL16: r = R_PPC_SDAREL16; break; ++ case BFD_RELOC_PPC64_SECTOFF_DS: ++ case BFD_RELOC_16_BASEREL: r = R_PPC_SECTOFF; break; ++ case BFD_RELOC_PPC64_SECTOFF_LO_DS: ++ case BFD_RELOC_LO16_BASEREL: r = R_PPC_SECTOFF_LO; break; ++ case BFD_RELOC_HI16_BASEREL: r = R_PPC_SECTOFF_HI; break; ++ case BFD_RELOC_HI16_S_BASEREL: r = R_PPC_SECTOFF_HA; break; ++ case BFD_RELOC_CTOR: r = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC64_TOC16_DS: ++ case BFD_RELOC_PPC_TOC16: r = R_PPC_TOC16; break; ++ case BFD_RELOC_PPC_TLS: r = R_PPC_TLS; break; ++ case BFD_RELOC_PPC_TLSGD: r = R_PPC_TLSGD; break; ++ case BFD_RELOC_PPC_TLSLD: r = R_PPC_TLSLD; break; ++ case BFD_RELOC_PPC_DTPMOD: r = R_PPC_DTPMOD32; break; ++ case BFD_RELOC_PPC64_TPREL16_DS: ++ case BFD_RELOC_PPC_TPREL16: r = R_PPC_TPREL16; break; ++ case BFD_RELOC_PPC64_TPREL16_LO_DS: ++ case BFD_RELOC_PPC_TPREL16_LO: r = R_PPC_TPREL16_LO; break; ++ case BFD_RELOC_PPC_TPREL16_HI: r = R_PPC_TPREL16_HI; break; ++ case BFD_RELOC_PPC_TPREL16_HA: r = R_PPC_TPREL16_HA; break; ++ case BFD_RELOC_PPC_TPREL: r = R_PPC_TPREL32; break; ++ case BFD_RELOC_PPC64_DTPREL16_DS: ++ case BFD_RELOC_PPC_DTPREL16: r = R_PPC_DTPREL16; break; ++ case BFD_RELOC_PPC64_DTPREL16_LO_DS: ++ case BFD_RELOC_PPC_DTPREL16_LO: r = R_PPC_DTPREL16_LO; break; ++ case BFD_RELOC_PPC_DTPREL16_HI: r = R_PPC_DTPREL16_HI; break; ++ case BFD_RELOC_PPC_DTPREL16_HA: r = R_PPC_DTPREL16_HA; break; ++ case BFD_RELOC_PPC_DTPREL: r = R_PPC_DTPREL32; break; ++ case BFD_RELOC_PPC_GOT_TLSGD16: r = R_PPC_GOT_TLSGD16; break; ++ case BFD_RELOC_PPC_GOT_TLSGD16_LO: r = R_PPC_GOT_TLSGD16_LO; break; ++ case BFD_RELOC_PPC_GOT_TLSGD16_HI: r = R_PPC_GOT_TLSGD16_HI; break; ++ case BFD_RELOC_PPC_GOT_TLSGD16_HA: r = R_PPC_GOT_TLSGD16_HA; break; ++ case BFD_RELOC_PPC_GOT_TLSLD16: r = R_PPC_GOT_TLSLD16; break; ++ case BFD_RELOC_PPC_GOT_TLSLD16_LO: r = R_PPC_GOT_TLSLD16_LO; break; ++ case BFD_RELOC_PPC_GOT_TLSLD16_HI: r = R_PPC_GOT_TLSLD16_HI; break; ++ case BFD_RELOC_PPC_GOT_TLSLD16_HA: r = R_PPC_GOT_TLSLD16_HA; break; ++ case BFD_RELOC_PPC_GOT_TPREL16: r = R_PPC_GOT_TPREL16; break; ++ case BFD_RELOC_PPC_GOT_TPREL16_LO: r = R_PPC_GOT_TPREL16_LO; break; ++ case BFD_RELOC_PPC_GOT_TPREL16_HI: r = R_PPC_GOT_TPREL16_HI; break; ++ case BFD_RELOC_PPC_GOT_TPREL16_HA: r = R_PPC_GOT_TPREL16_HA; break; ++ case BFD_RELOC_PPC_GOT_DTPREL16: r = R_PPC_GOT_DTPREL16; break; ++ case BFD_RELOC_PPC_GOT_DTPREL16_LO: r = R_PPC_GOT_DTPREL16_LO; break; ++ case BFD_RELOC_PPC_GOT_DTPREL16_HI: r = R_PPC_GOT_DTPREL16_HI; break; ++ case BFD_RELOC_PPC_GOT_DTPREL16_HA: r = R_PPC_GOT_DTPREL16_HA; break; ++ case BFD_RELOC_PPC_EMB_NADDR32: r = R_PPC_EMB_NADDR32; break; ++ case BFD_RELOC_PPC_EMB_NADDR16: r = R_PPC_EMB_NADDR16; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_LO: r = R_PPC_EMB_NADDR16_LO; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HI: r = R_PPC_EMB_NADDR16_HI; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HA: r = R_PPC_EMB_NADDR16_HA; break; ++ case BFD_RELOC_PPC_EMB_SDAI16: r = R_PPC_EMB_SDAI16; break; ++ case BFD_RELOC_PPC_EMB_SDA2I16: r = R_PPC_EMB_SDA2I16; break; ++ case BFD_RELOC_PPC_EMB_SDA2REL: r = R_PPC_EMB_SDA2REL; break; ++ case BFD_RELOC_PPC_EMB_SDA21: r = R_PPC_EMB_SDA21; break; ++ case BFD_RELOC_PPC_EMB_MRKREF: r = R_PPC_EMB_MRKREF; break; ++ case BFD_RELOC_PPC_EMB_RELSEC16: r = R_PPC_EMB_RELSEC16; break; ++ case BFD_RELOC_PPC_EMB_RELST_LO: r = R_PPC_EMB_RELST_LO; break; ++ case BFD_RELOC_PPC_EMB_RELST_HI: r = R_PPC_EMB_RELST_HI; break; ++ case BFD_RELOC_PPC_EMB_RELST_HA: r = R_PPC_EMB_RELST_HA; break; ++ case BFD_RELOC_PPC_EMB_BIT_FLD: r = R_PPC_EMB_BIT_FLD; break; ++ case BFD_RELOC_PPC_EMB_RELSDA: r = R_PPC_EMB_RELSDA; break; ++ case BFD_RELOC_PPC_VLE_REL8: r = R_PPC_VLE_REL8; break; ++ case BFD_RELOC_PPC_VLE_REL15: r = R_PPC_VLE_REL15; break; ++ case BFD_RELOC_PPC_VLE_REL24: r = R_PPC_VLE_REL24; break; ++ case BFD_RELOC_PPC_VLE_LO16A: r = R_PPC_VLE_LO16A; break; ++ case BFD_RELOC_PPC_VLE_LO16D: r = R_PPC_VLE_LO16D; break; ++ case BFD_RELOC_PPC_VLE_HI16A: r = R_PPC_VLE_HI16A; break; ++ case BFD_RELOC_PPC_VLE_HI16D: r = R_PPC_VLE_HI16D; break; ++ case BFD_RELOC_PPC_VLE_HA16A: r = R_PPC_VLE_HA16A; break; ++ case BFD_RELOC_PPC_VLE_HA16D: r = R_PPC_VLE_HA16D; break; ++ case BFD_RELOC_PPC_VLE_SDA21: r = R_PPC_VLE_SDA21; break; ++ case BFD_RELOC_PPC_VLE_SDA21_LO: r = R_PPC_VLE_SDA21_LO; break; ++ case BFD_RELOC_PPC_VLE_SDAREL_LO16A: ++ r = R_PPC_VLE_SDAREL_LO16A; ++ break; ++ case BFD_RELOC_PPC_VLE_SDAREL_LO16D: ++ r = R_PPC_VLE_SDAREL_LO16D; ++ break; ++ case BFD_RELOC_PPC_VLE_SDAREL_HI16A: ++ r = R_PPC_VLE_SDAREL_HI16A; ++ break; ++ case BFD_RELOC_PPC_VLE_SDAREL_HI16D: ++ r = R_PPC_VLE_SDAREL_HI16D; ++ break; ++ case BFD_RELOC_PPC_VLE_SDAREL_HA16A: ++ r = R_PPC_VLE_SDAREL_HA16A; ++ break; ++ case BFD_RELOC_PPC_VLE_SDAREL_HA16D: ++ r = R_PPC_VLE_SDAREL_HA16D; ++ break; ++ case BFD_RELOC_16_PCREL: r = R_PPC_REL16; break; ++ case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break; ++ case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break; ++ case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL: r = R_PPC_AMIGAOS_BREL; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL_LO: r = R_PPC_AMIGAOS_BREL_LO; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL_HI: r = R_PPC_AMIGAOS_BREL_HI; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL_HA: r = R_PPC_AMIGAOS_BREL_HA; break; ++ case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break; ++ case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break; ++ } ++ ++ return ppc_elf_howto_table[r]; ++}; ++ ++static reloc_howto_type * ++ppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, ++ const char *r_name) ++{ ++ unsigned int i; ++ ++ for (i = 0; ++ i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); ++ i++) ++ if (ppc_elf_howto_raw[i].name != NULL ++ && strcasecmp (ppc_elf_howto_raw[i].name, r_name) == 0) ++ return &ppc_elf_howto_raw[i]; ++ ++ return NULL; ++} ++ ++/* Set the howto pointer for a PowerPC ELF reloc. */ ++ ++static void ++ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, ++ arelent *cache_ptr, ++ Elf_Internal_Rela *dst) ++{ ++ /* Initialize howto table if not already done. */ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ ppc_elf_howto_init (); ++ ++ BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); ++ cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; ++ ++ /* Just because the above assert didn't trigger doesn't mean that ++ ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation. */ ++ if (!cache_ptr->howto) ++ { ++ (*_bfd_error_handler) (_("%B: invalid relocation type %d"), ++ abfd, ELF32_R_TYPE (dst->r_info)); ++ bfd_set_error (bfd_error_bad_value); ++ ++ cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE]; ++ } ++} ++ ++/* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs. */ ++ ++static bfd_reloc_status_type ++ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED, ++ arelent *reloc_entry, ++ asymbol *symbol, ++ void *data ATTRIBUTE_UNUSED, ++ asection *input_section, ++ bfd *output_bfd, ++ char **error_message ATTRIBUTE_UNUSED) ++{ ++ bfd_vma relocation; ++ ++ if (output_bfd != NULL) ++ { ++ reloc_entry->address += input_section->output_offset; ++ return bfd_reloc_ok; ++ } ++ ++ if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) ++ return bfd_reloc_outofrange; ++ ++ if (bfd_is_com_section (symbol->section)) ++ relocation = 0; ++ else ++ relocation = symbol->value; ++ ++ relocation += symbol->section->output_section->vma; ++ relocation += symbol->section->output_offset; ++ relocation += reloc_entry->addend; ++ if (reloc_entry->howto->pc_relative) ++ relocation -= reloc_entry->address; ++ ++ reloc_entry->addend += (relocation & 0x8000) << 1; ++ ++ return bfd_reloc_continue; ++} ++ ++static bfd_reloc_status_type ++ppc_elf_unhandled_reloc (bfd *abfd, ++ arelent *reloc_entry, ++ asymbol *symbol, ++ void *data, ++ asection *input_section, ++ bfd *output_bfd, ++ char **error_message) ++{ ++ /* If this is a relocatable link (output_bfd test tells us), just ++ call the generic function. Any adjustment will be done at final ++ link time. */ ++ if (output_bfd != NULL) ++ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, ++ input_section, output_bfd, error_message); ++ ++ if (error_message != NULL) ++ { ++ static char buf[60]; ++ sprintf (buf, _("generic linker can't handle %s"), ++ reloc_entry->howto->name); ++ *error_message = buf; ++ } ++ return bfd_reloc_dangerous; ++} ++ ++/* Sections created by the linker. */ ++ ++typedef struct elf_linker_section ++{ ++ /* Pointer to the bfd section. */ ++ asection *section; ++ /* Section name. */ ++ const char *name; ++ /* Associated bss section name. */ ++ const char *bss_name; ++ /* Associated symbol name. */ ++ const char *sym_name; ++ /* Associated symbol. */ ++ struct elf_link_hash_entry *sym; ++} elf_linker_section_t; ++ ++/* Linked list of allocated pointer entries. This hangs off of the ++ symbol lists, and provides allows us to return different pointers, ++ based on different addend's. */ ++ ++typedef struct elf_linker_section_pointers ++{ ++ /* next allocated pointer for this symbol */ ++ struct elf_linker_section_pointers *next; ++ /* offset of pointer from beginning of section */ ++ bfd_vma offset; ++ /* addend used */ ++ bfd_vma addend; ++ /* which linker section this is */ ++ elf_linker_section_t *lsect; ++} elf_linker_section_pointers_t; ++ ++struct ppc_elf_obj_tdata ++{ ++ struct elf_obj_tdata elf; ++ ++ /* A mapping from local symbols to offsets into the various linker ++ sections added. This is index by the symbol index. */ ++ elf_linker_section_pointers_t **linker_section_pointers; ++ ++ /* Flags used to auto-detect plt type. */ ++ unsigned int makes_plt_call : 1; ++ unsigned int has_rel16 : 1; ++}; ++ ++#define ppc_elf_tdata(bfd) \ ++ ((struct ppc_elf_obj_tdata *) (bfd)->tdata.any) ++ ++#define elf_local_ptr_offsets(bfd) \ ++ (ppc_elf_tdata (bfd)->linker_section_pointers) ++ ++#define is_ppc_elf(bfd) \ ++ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ ++ && elf_object_id (bfd) == PPC32_ELF_DATA) ++ ++/* Override the generic function because we store some extras. */ ++ ++static bfd_boolean ++ppc_elf_mkobject (bfd *abfd) ++{ ++ return bfd_elf_allocate_object (abfd, sizeof (struct ppc_elf_obj_tdata), ++ PPC32_ELF_DATA); ++} ++ ++/* Fix bad default arch selected for a 32 bit input bfd when the ++ default is 64 bit. */ ++ ++static bfd_boolean ++ppc_elf_object_p (bfd *abfd) ++{ ++ if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64) ++ { ++ Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); ++ ++ if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32) ++ { ++ /* Relies on arch after 64 bit default being 32 bit default. */ ++ abfd->arch_info = abfd->arch_info->next; ++ BFD_ASSERT (abfd->arch_info->bits_per_word == 32); ++ } ++ } ++ return TRUE; ++} ++ ++/* Function to set whether a module needs the -mrelocatable bit set. */ ++ ++static bfd_boolean ++ppc_elf_set_private_flags (bfd *abfd, flagword flags) ++{ ++ BFD_ASSERT (!elf_flags_init (abfd) ++ || elf_elfheader (abfd)->e_flags == flags); ++ ++ elf_elfheader (abfd)->e_flags = flags; ++ elf_flags_init (abfd) = TRUE; ++ return TRUE; ++} ++ ++/* Support for core dump NOTE sections. */ ++ ++static bfd_boolean ++ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) ++{ ++ int offset; ++ unsigned int size; ++ ++ switch (note->descsz) ++ { ++ default: ++ return FALSE; ++ ++ case 268: /* Linux/PPC. */ ++ /* pr_cursig */ ++ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); ++ ++ /* pr_pid */ ++ elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); ++ ++ /* pr_reg */ ++ offset = 72; ++ size = 192; ++ ++ break; ++ } ++ ++ /* Make a ".reg/999" section. */ ++ return _bfd_elfcore_make_pseudosection (abfd, ".reg", ++ size, note->descpos + offset); ++} ++ ++static bfd_boolean ++ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) ++{ ++ switch (note->descsz) ++ { ++ default: ++ return FALSE; ++ ++ case 128: /* Linux/PPC elf_prpsinfo. */ ++ elf_tdata (abfd)->core_pid ++ = bfd_get_32 (abfd, note->descdata + 16); ++ elf_tdata (abfd)->core_program ++ = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); ++ elf_tdata (abfd)->core_command ++ = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); ++ } ++ ++ /* Note that for some reason, a spurious space is tacked ++ onto the end of the args in some (at least one anyway) ++ implementations, so strip it off if it exists. */ ++ ++ { ++ char *command = elf_tdata (abfd)->core_command; ++ int n = strlen (command); ++ ++ if (0 < n && command[n - 1] == ' ') ++ command[n - 1] = '\0'; ++ } ++ ++ return TRUE; ++} ++ ++static char * ++ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...) ++{ ++ switch (note_type) ++ { ++ default: ++ return NULL; ++ ++ case NT_PRPSINFO: ++ { ++ char data[128]; ++ va_list ap; ++ ++ va_start (ap, note_type); ++ memset (data, 0, sizeof (data)); ++ strncpy (data + 32, va_arg (ap, const char *), 16); ++ strncpy (data + 48, va_arg (ap, const char *), 80); ++ va_end (ap); ++ return elfcore_write_note (abfd, buf, bufsiz, ++ "CORE", note_type, data, sizeof (data)); ++ } ++ ++ case NT_PRSTATUS: ++ { ++ char data[268]; ++ va_list ap; ++ long pid; ++ int cursig; ++ const void *greg; ++ ++ va_start (ap, note_type); ++ memset (data, 0, 72); ++ pid = va_arg (ap, long); ++ bfd_put_32 (abfd, pid, data + 24); ++ cursig = va_arg (ap, int); ++ bfd_put_16 (abfd, cursig, data + 12); ++ greg = va_arg (ap, const void *); ++ memcpy (data + 72, greg, 192); ++ memset (data + 264, 0, 4); ++ va_end (ap); ++ return elfcore_write_note (abfd, buf, bufsiz, ++ "CORE", note_type, data, sizeof (data)); ++ } ++ } ++} ++ ++static flagword ++ppc_elf_lookup_section_flags (char *flag_name) ++{ ++ ++ if (!strcmp (flag_name, "SHF_PPC_VLE")) ++ return SHF_PPC_VLE; ++ ++ return 0; ++} ++ ++/* Add the VLE flag if required. */ ++ ++bfd_boolean ++ppc_elf_amigaos_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr) ++{ ++ if (bfd_get_mach (abfd) == bfd_mach_ppc_vle ++ && (shdr->sh_flags & SHF_EXECINSTR) != 0) ++ shdr->sh_flags |= SHF_PPC_VLE; ++ ++ return TRUE; ++} ++ ++/* Return address for Ith PLT stub in section PLT, for relocation REL ++ or (bfd_vma) -1 if it should not be included. */ ++ ++static bfd_vma ++ppc_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED, ++ const asection *plt ATTRIBUTE_UNUSED, ++ const arelent *rel) ++{ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_plt_sym_cal (0x%08x)\n", (unsigned int)rel->address); ++#endif ++ return rel->address; ++} ++ ++/* Handle a PowerPC specific section when reading an object file. This ++ is called when bfd_section_from_shdr finds a section with an unknown ++ type. */ ++ ++static bfd_boolean ++ppc_elf_section_from_shdr (bfd *abfd, ++ Elf_Internal_Shdr *hdr, ++ const char *name, ++ int shindex) ++{ ++ asection *newsect; ++ flagword flags; ++ ++ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) ++ return FALSE; ++ ++ newsect = hdr->bfd_section; ++ flags = bfd_get_section_flags (abfd, newsect); ++ if (hdr->sh_flags & SHF_EXCLUDE) ++ flags |= SEC_EXCLUDE; ++ ++ if (hdr->sh_type == SHT_ORDERED) ++ flags |= SEC_SORT_ENTRIES; ++ ++ bfd_set_section_flags (abfd, newsect, flags); ++ return TRUE; ++} ++ ++/* Set up any other section flags and such that may be necessary. */ ++ ++static bfd_boolean ++ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, ++ Elf_Internal_Shdr *shdr, ++ asection *asect) ++{ ++ if ((asect->flags & SEC_SORT_ENTRIES) != 0) ++ shdr->sh_type = SHT_ORDERED; ++ ++ return TRUE; ++} ++ ++/* If we have .sbss2 or .PPC.EMB.sbss0 output sections, we ++ need to bump up the number of section headers. */ ++ ++static int ++ppc_elf_additional_program_headers (bfd *abfd, ++ struct bfd_link_info *info ATTRIBUTE_UNUSED) ++{ ++ asection *s; ++// int ret = 0; ++ int ret = 1; ++ ++ s = bfd_get_section_by_name (abfd, ".sbss2"); ++ if (s != NULL && (s->flags & SEC_ALLOC) != 0) ++ ++ret; ++ ++ s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0"); ++ if (s != NULL && (s->flags & SEC_ALLOC) != 0) ++ ++ret; ++ ++ return ret; ++} ++ ++/* Modify the segment map for VLE executables. */ ++ ++bfd_boolean ++ppc_elf_amigaos_modify_segment_map (bfd *abfd, ++ struct bfd_link_info *info ATTRIBUTE_UNUSED) ++{ ++ struct elf_segment_map *m, *n; ++ bfd_size_type amt; ++ unsigned int j, k; ++ bfd_boolean sect0_vle, sectj_vle; ++ ++ /* At this point in the link, output sections have already been sorted by ++ LMA and assigned to segments. All that is left to do is to ensure ++ there is no mixing of VLE & non-VLE sections in a text segment. ++ If we find that case, we split the segment. ++ We maintain the original output section order. */ ++ ++ for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) ++ { ++ if (m->count == 0) ++ continue; ++ ++ sect0_vle = (elf_section_flags (m->sections[0]) & SHF_PPC_VLE) != 0; ++ for (j = 1; j < m->count; ++j) ++ { ++ sectj_vle = (elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0; ++ ++ if (sectj_vle != sect0_vle) ++ break; ++ } ++ if (j >= m->count) ++ continue; ++ ++ /* sections 0..j-1 stay in this (current) segment, ++ the remainder are put in a new segment. ++ The scan resumes with the new segment. */ ++ ++ /* Fix the new segment. */ ++ amt = sizeof (struct elf_segment_map); ++ amt += (m->count - j - 1) * sizeof (asection *); ++ n = (struct elf_segment_map *) bfd_zalloc (abfd, amt); ++ if (n == NULL) ++ return FALSE; ++ ++ n->p_type = PT_LOAD; ++ n->p_flags = PF_X | PF_R; ++ if (sectj_vle) ++ n->p_flags |= PF_PPC_VLE; ++ n->count = m->count - j; ++ for (k = 0; k < n->count; ++k) ++ { ++ n->sections[k] = m->sections[j+k]; ++ m->sections[j+k] = NULL; ++ } ++ n->next = m->next; ++ m->next = n; ++ ++ /* Fix the current segment */ ++ m->count = j; ++ } ++ ++ return TRUE; ++} ++ ++/* Add extra PPC sections -- Note, for now, make .sbss2 and ++ .PPC.EMB.sbss0 a normal section, and not a bss section so ++ that the linker doesn't crater when trying to make more than ++ 2 sections. */ ++ ++static const struct bfd_elf_special_section ppc_elf_special_sections[] = ++{ ++ { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR }, ++ { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, ++ { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC }, ++ { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, ++ { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC }, ++ { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC }, ++ { STRING_COMMA_LEN (".PPC.EMB.apuinfo"), 0, SHT_NOTE, 0 }, ++ { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC }, ++ { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC }, ++ { NULL, 0, 0, 0, 0 } ++}; ++ ++/* This is what we want for new plt/got. */ ++static struct bfd_elf_special_section ppc_alt_plt = ++ { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC }; ++ ++static const struct bfd_elf_special_section * ++ppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) ++{ ++ const struct bfd_elf_special_section *ssect; ++ ++ /* See if this is one of the special sections. */ ++ if (sec->name == NULL) ++ return NULL; ++ ++ ssect = _bfd_elf_get_special_section (sec->name, ppc_elf_special_sections, ++ sec->use_rela_p); ++ if (ssect != NULL) ++ { ++ if (ssect == ppc_elf_special_sections && (sec->flags & SEC_LOAD) != 0) ++ ssect = &ppc_alt_plt; ++ return ssect; ++ } ++ ++ return _bfd_elf_get_sec_type_attr (abfd, sec); ++} ++ ++/* Very simple linked list structure for recording apuinfo values. */ ++typedef struct apuinfo_list ++{ ++ struct apuinfo_list *next; ++ unsigned long value; ++} ++apuinfo_list; ++ ++static apuinfo_list *head; ++static bfd_boolean apuinfo_set; ++ ++static void ++apuinfo_list_init (void) ++{ ++ head = NULL; ++ apuinfo_set = FALSE; ++} ++ ++static void ++apuinfo_list_add (unsigned long value) ++{ ++ apuinfo_list *entry = head; ++ ++ while (entry != NULL) ++ { ++ if (entry->value == value) ++ return; ++ entry = entry->next; ++ } ++ ++ entry = bfd_malloc (sizeof (* entry)); ++ if (entry == NULL) ++ return; ++ ++ entry->value = value; ++ entry->next = head; ++ head = entry; ++} ++ ++static unsigned ++apuinfo_list_length (void) ++{ ++ apuinfo_list *entry; ++ unsigned long count; ++ ++ for (entry = head, count = 0; ++ entry; ++ entry = entry->next) ++ ++ count; ++ ++ return count; ++} ++ ++static inline unsigned long ++apuinfo_list_element (unsigned long number) ++{ ++ apuinfo_list * entry; ++ ++ for (entry = head; ++ entry && number --; ++ entry = entry->next) ++ ; ++ ++ return entry ? entry->value : 0; ++} ++ ++static void ++apuinfo_list_finish (void) ++{ ++ apuinfo_list *entry; ++ ++ for (entry = head; entry;) ++ { ++ apuinfo_list *next = entry->next; ++ free (entry); ++ entry = next; ++ } ++ ++ head = NULL; ++} ++ ++#define APUINFO_SECTION_NAME ".PPC.EMB.apuinfo" ++#define APUINFO_LABEL "APUinfo" ++ ++/* Scan the input BFDs and create a linked list of ++ the APUinfo values that will need to be emitted. */ ++ ++static void ++ppc_elf_amigaos_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info) ++{ ++ bfd *ibfd; ++ asection *asec; ++ char *buffer = NULL; ++ bfd_size_type largest_input_size = 0; ++ unsigned i; ++ unsigned long length; ++ const char *error_message = NULL; ++ ++ if (link_info == NULL) ++ return; ++ ++ apuinfo_list_init (); ++ ++ /* Read in the input sections contents. */ ++ for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next) ++ { ++ unsigned long datum; ++ ++ asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME); ++ if (asec == NULL) ++ continue; ++ ++ error_message = _("corrupt %s section in %B"); ++ length = asec->size; ++ if (length < 20) ++ goto fail; ++ ++ apuinfo_set = TRUE; ++ if (largest_input_size < asec->size) ++ { ++ if (buffer) ++ free (buffer); ++ largest_input_size = asec->size; ++ buffer = bfd_malloc (largest_input_size); ++ if (!buffer) ++ return; ++ } ++ ++ if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0 ++ || (bfd_bread (buffer, length, ibfd) != length)) ++ { ++ error_message = _("unable to read in %s section from %B"); ++ goto fail; ++ } ++ ++ /* Verify the contents of the header. Note - we have to ++ extract the values this way in order to allow for a ++ host whose endian-ness is different from the target. */ ++ datum = bfd_get_32 (ibfd, buffer); ++ if (datum != sizeof APUINFO_LABEL) ++ goto fail; ++ ++ datum = bfd_get_32 (ibfd, buffer + 8); ++ if (datum != 0x2) ++ goto fail; ++ ++ if (strcmp (buffer + 12, APUINFO_LABEL) != 0) ++ goto fail; ++ ++ /* Get the number of bytes used for apuinfo entries. */ ++ datum = bfd_get_32 (ibfd, buffer + 4); ++ if (datum + 20 != length) ++ goto fail; ++ ++ /* Scan the apuinfo section, building a list of apuinfo numbers. */ ++ for (i = 0; i < datum; i += 4) ++ apuinfo_list_add (bfd_get_32 (ibfd, buffer + 20 + i)); ++ } ++ ++ error_message = NULL; ++ ++ if (apuinfo_set) ++ { ++ /* Compute the size of the output section. */ ++ unsigned num_entries = apuinfo_list_length (); ++ ++ /* Set the output section size, if it exists. */ ++ asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); ++ ++ if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4)) ++ { ++ ibfd = abfd; ++ error_message = _("warning: unable to set size of %s section in %B"); ++ } ++ } ++ ++ fail: ++ if (buffer) ++ free (buffer); ++ ++ if (error_message) ++ (*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME); ++} ++ ++/* Prevent the output section from accumulating the input sections' ++ contents. We have already stored this in our linked list structure. */ ++ ++static bfd_boolean ++ppc_elf_amigaos_write_section (bfd *abfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *link_info ATTRIBUTE_UNUSED, ++ asection *asec, ++ bfd_byte *contents ATTRIBUTE_UNUSED) ++{ ++ return apuinfo_set && strcmp (asec->name, APUINFO_SECTION_NAME) == 0; ++} ++ ++/* Finally we can generate the output section. */ ++ ++static void ++ppc_elf_amigaos_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) ++{ ++ bfd_byte *buffer; ++ asection *asec; ++ unsigned i; ++ unsigned num_entries; ++ bfd_size_type length; ++ ++ asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); ++ if (asec == NULL) ++ return; ++ ++ if (!apuinfo_set) ++ return; ++ ++ length = asec->size; ++ if (length < 20) ++ return; ++ ++ buffer = bfd_malloc (length); ++ if (buffer == NULL) ++ { ++ (*_bfd_error_handler) ++ (_("failed to allocate space for new APUinfo section.")); ++ return; ++ } ++ ++ /* Create the apuinfo header. */ ++ num_entries = apuinfo_list_length (); ++ bfd_put_32 (abfd, sizeof APUINFO_LABEL, buffer); ++ bfd_put_32 (abfd, num_entries * 4, buffer + 4); ++ bfd_put_32 (abfd, 0x2, buffer + 8); ++ strcpy ((char *) buffer + 12, APUINFO_LABEL); ++ ++ length = 20; ++ for (i = 0; i < num_entries; i++) ++ { ++ bfd_put_32 (abfd, apuinfo_list_element (i), buffer + length); ++ length += 4; ++ } ++ ++ if (length != asec->size) ++ (*_bfd_error_handler) (_("failed to compute new APUinfo section.")); ++ ++ if (! bfd_set_section_contents (abfd, asec, buffer, (file_ptr) 0, length)) ++ (*_bfd_error_handler) (_("failed to install new APUinfo section.")); ++ ++ free (buffer); ++ ++ apuinfo_list_finish (); ++} ++ ++static bfd_boolean ++is_nonpic_glink_stub (bfd *abfd, asection *glink, bfd_vma off) ++{ ++ bfd_byte buf[GLINK_ENTRY_SIZE]; ++ ++ if (!bfd_get_section_contents (abfd, glink, buf, off, GLINK_ENTRY_SIZE)) ++ return FALSE; ++ ++ return ((bfd_get_32 (abfd, buf + 0) & 0xffff0000) == LIS_11 ++ && (bfd_get_32 (abfd, buf + 4) & 0xffff0000) == LWZ_11_11 ++ && bfd_get_32 (abfd, buf + 8) == MTCTR_11 ++ && bfd_get_32 (abfd, buf + 12) == BCTR); ++} ++ ++static bfd_boolean ++section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr) ++{ ++ bfd_vma vma = *(bfd_vma *) ptr; ++ return ((section->flags & SEC_ALLOC) != 0 ++ && section->vma <= vma ++ && vma < section->vma + section->size); ++} ++ ++static long ++ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, ++ long dynsymcount, asymbol **dynsyms, ++ asymbol **ret) ++{ ++ bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); ++ asection *plt, *relplt, *dynamic, *glink; ++ bfd_vma glink_vma = 0; ++ bfd_vma resolv_vma = 0; ++ bfd_vma stub_vma; ++ asymbol *s; ++ arelent *p; ++ long count, i; ++ size_t size; ++ char *names; ++ bfd_byte buf[4]; ++ ++ *ret = NULL; ++ ++ if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) ++ return 0; ++ ++ if (dynsymcount <= 0) ++ return 0; ++ ++ relplt = bfd_get_section_by_name (abfd, ".rela.plt"); ++ if (relplt == NULL) ++ return 0; ++ ++ plt = bfd_get_section_by_name (abfd, ".plt"); ++ if (plt == NULL) ++ return 0; ++ ++ /* Call common code to handle old-style executable PLTs. */ ++ if (elf_section_flags (plt) & SHF_EXECINSTR) ++ return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms, ++ dynsymcount, dynsyms, ret); ++ ++ /* If this object was prelinked, the prelinker stored the address ++ of .glink at got[1]. If it wasn't prelinked, got[1] will be zero. */ ++ dynamic = bfd_get_section_by_name (abfd, ".dynamic"); ++ if (dynamic != NULL) ++ { ++ bfd_byte *dynbuf, *extdyn, *extdynend; ++ size_t extdynsize; ++ void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); ++ ++ if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf)) ++ return -1; ++ ++ extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; ++ swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; ++ ++ extdyn = dynbuf; ++ extdynend = extdyn + dynamic->size; ++ for (; extdyn < extdynend; extdyn += extdynsize) ++ { ++ Elf_Internal_Dyn dyn; ++ (*swap_dyn_in) (abfd, extdyn, &dyn); ++ ++ if (dyn.d_tag == DT_NULL) ++ break; ++ ++ if (dyn.d_tag == DT_PPC_GOT) ++ { ++ unsigned int g_o_t = dyn.d_un.d_val; ++ asection *got = bfd_get_section_by_name (abfd, ".got"); ++ if (got != NULL ++ && bfd_get_section_contents (abfd, got, buf, ++ g_o_t - got->vma + 4, 4)) ++ glink_vma = bfd_get_32 (abfd, buf); ++ break; ++ } ++ } ++ free (dynbuf); ++ } ++ ++ /* Otherwise we read the first plt entry. */ ++ if (glink_vma == 0) ++ { ++ if (bfd_get_section_contents (abfd, plt, buf, 0, 4)) ++ glink_vma = bfd_get_32 (abfd, buf); ++ } ++ ++ if (glink_vma == 0) ++ return 0; ++ ++ /* The .glink section usually does not survive the final ++ link; search for the section (usually .text) where the ++ glink stubs now reside. */ ++ glink = bfd_sections_find_if (abfd, section_covers_vma, &glink_vma); ++ if (glink == NULL) ++ return 0; ++ ++ /* Determine glink PLT resolver by reading the relative branch ++ from the first glink stub. */ ++ if (bfd_get_section_contents (abfd, glink, buf, ++ glink_vma - glink->vma, 4)) ++ { ++ unsigned int insn = bfd_get_32 (abfd, buf); ++ ++ /* The first glink stub may either branch to the resolver ... */ ++ insn ^= B; ++ if ((insn & ~0x3fffffc) == 0) ++ resolv_vma = glink_vma + (insn ^ 0x2000000) - 0x2000000; ++ ++ /* ... or fall through a bunch of NOPs. */ ++ else if ((insn ^ B ^ NOP) == 0) ++ for (i = 4; ++ bfd_get_section_contents (abfd, glink, buf, ++ glink_vma - glink->vma + i, 4); ++ i += 4) ++ if (bfd_get_32 (abfd, buf) != NOP) ++ { ++ resolv_vma = glink_vma + i; ++ break; ++ } ++ } ++ ++ count = relplt->size / sizeof (Elf32_External_Rela); ++ stub_vma = glink_vma - (bfd_vma) count * 16; ++ /* If the stubs are those for -shared/-pie then we might have ++ multiple stubs for each plt entry. If that is the case then ++ there is no way to associate stubs with their plt entries short ++ of figuring out the GOT pointer value used in the stub. */ ++ if (!is_nonpic_glink_stub (abfd, glink, ++ glink_vma - GLINK_ENTRY_SIZE - glink->vma)) ++ return 0; ++ ++ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; ++ if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) ++ return -1; ++ ++ size = count * sizeof (asymbol); ++ p = relplt->relocation; ++ for (i = 0; i < count; i++, p++) ++ { ++ size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); ++ if (p->addend != 0) ++ size += sizeof ("+0x") - 1 + 8; ++ } ++ ++ size += sizeof (asymbol) + sizeof ("__glink"); ++ ++ if (resolv_vma) ++ size += sizeof (asymbol) + sizeof ("__glink_PLTresolve"); ++ ++ s = *ret = bfd_malloc (size); ++ if (s == NULL) ++ return -1; ++ ++ names = (char *) (s + count + 1 + (resolv_vma != 0)); ++ p = relplt->relocation; ++ for (i = 0; i < count; i++, p++) ++ { ++ size_t len; ++ ++ *s = **p->sym_ptr_ptr; ++ /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since ++ we are defining a symbol, ensure one of them is set. */ ++ if ((s->flags & BSF_LOCAL) == 0) ++ s->flags |= BSF_GLOBAL; ++ s->flags |= BSF_SYNTHETIC; ++ s->section = glink; ++ s->value = stub_vma - glink->vma; ++ s->name = names; ++ s->udata.p = NULL; ++ len = strlen ((*p->sym_ptr_ptr)->name); ++ memcpy (names, (*p->sym_ptr_ptr)->name, len); ++ names += len; ++ if (p->addend != 0) ++ { ++ memcpy (names, "+0x", sizeof ("+0x") - 1); ++ names += sizeof ("+0x") - 1; ++ bfd_sprintf_vma (abfd, names, p->addend); ++ names += strlen (names); ++ } ++ memcpy (names, "@plt", sizeof ("@plt")); ++ names += sizeof ("@plt"); ++ ++s; ++ stub_vma += 16; ++ } ++ ++ /* Add a symbol at the start of the glink branch table. */ ++ memset (s, 0, sizeof *s); ++ s->the_bfd = abfd; ++ s->flags = BSF_GLOBAL | BSF_SYNTHETIC; ++ s->section = glink; ++ s->value = glink_vma - glink->vma; ++ s->name = names; ++ memcpy (names, "__glink", sizeof ("__glink")); ++ names += sizeof ("__glink"); ++ s++; ++ count++; ++ ++ if (resolv_vma) ++ { ++ /* Add a symbol for the glink PLT resolver. */ ++ memset (s, 0, sizeof *s); ++ s->the_bfd = abfd; ++ s->flags = BSF_GLOBAL | BSF_SYNTHETIC; ++ s->section = glink; ++ s->value = resolv_vma - glink->vma; ++ s->name = names; ++ memcpy (names, "__glink_PLTresolve", sizeof ("__glink_PLTresolve")); ++ names += sizeof ("__glink_PLTresolve"); ++ s++; ++ count++; ++ } ++ ++ return count; ++} ++ ++/* The following functions are specific to the ELF linker, while ++ functions above are used generally. They appear in this file more ++ or less in the order in which they are called. eg. ++ ppc_elf_check_relocs is called early in the link process, ++ ppc_elf_finish_dynamic_sections is one of the last functions ++ called. */ ++ ++/* Track PLT entries needed for a given symbol. We might need more ++ than one glink entry per symbol when generating a pic binary. */ ++struct plt_entry ++{ ++ struct plt_entry *next; ++ ++ /* -fPIC uses multiple GOT sections, one per file, called ".got2". ++ This field stores the offset into .got2 used to initialise the ++ GOT pointer reg. It will always be at least 32768. (Current ++ gcc always uses an offset of 32768, but ld -r will pack .got2 ++ sections together resulting in larger offsets). */ ++ bfd_vma addend; ++ ++ /* The .got2 section. */ ++ asection *sec; ++ ++ /* PLT refcount or offset. */ ++ union ++ { ++ bfd_signed_vma refcount; ++ bfd_vma offset; ++ } plt; ++ ++ /* .glink stub offset. */ ++ bfd_vma glink_offset; ++}; ++ ++/* Of those relocs that might be copied as dynamic relocs, this function ++ selects those that must be copied when linking a shared library, ++ even when the symbol is local. */ ++ ++static int ++must_be_dyn_reloc (struct bfd_link_info *info, ++ enum elf_ppc_reloc_type r_type) ++{ ++ switch (r_type) ++ { ++ default: ++ return 1; ++ ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ case R_PPC_REL32: ++ return 0; ++ ++ case R_PPC_TPREL32: ++ case R_PPC_TPREL16: ++ case R_PPC_TPREL16_LO: ++ case R_PPC_TPREL16_HI: ++ case R_PPC_TPREL16_HA: ++ return !info->executable; ++ } ++} ++ ++/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid ++ copying dynamic variables from a shared lib into an app's dynbss ++ section, and instead use a dynamic relocation to point into the ++ shared lib. */ ++#define ELIMINATE_COPY_RELOCS 1 ++ ++/* PPC ELF linker hash entry. */ ++ ++struct ppc_elf_link_hash_entry ++{ ++ struct elf_link_hash_entry elf; ++ ++ /* If this symbol is used in the linker created sections, the processor ++ specific backend uses this field to map the field into the offset ++ from the beginning of the section. */ ++ elf_linker_section_pointers_t *linker_section_pointer; ++ ++ /* Track dynamic relocs copied for this symbol. */ ++ struct elf_dyn_relocs *dyn_relocs; ++ ++ /* Contexts in which symbol is used in the GOT (or TOC). ++ TLS_GD .. TLS_TLS bits are or'd into the mask as the ++ corresponding relocs are encountered during check_relocs. ++ tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to ++ indicate the corresponding GOT entry type is not needed. */ ++#define TLS_GD 1 /* GD reloc. */ ++#define TLS_LD 2 /* LD reloc. */ ++#define TLS_TPREL 4 /* TPREL reloc, => IE. */ ++#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */ ++#define TLS_TLS 16 /* Any TLS reloc. */ ++#define TLS_TPRELGD 32 /* TPREL reloc resulting from GD->IE. */ ++#define PLT_IFUNC 64 /* STT_GNU_IFUNC. */ ++ char tls_mask; ++ ++ /* Nonzero if we have seen a small data relocation referring to this ++ symbol. */ ++ unsigned char has_sda_refs; ++}; ++ ++#define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent)) ++ ++/* PPC ELF linker hash table. */ ++ ++struct ppc_elf_link_hash_table ++{ ++ struct elf_link_hash_table elf; ++ ++ /* Short-cuts to get to dynamic linker sections. */ ++ asection *got; ++ asection *relgot; ++ asection *glink; ++ asection *plt; ++ asection *relplt; ++ asection *iplt; ++ asection *reliplt; ++ asection *dynbss; ++ asection *relbss; ++ asection *dynsbss; ++ asection *relsbss; ++ elf_linker_section_t sdata[2]; ++ asection *sbss; ++ asection *glink_eh_frame; ++ ++ /* The (unloaded but important) .rela.plt.unloaded on VxWorks. */ ++ asection *srelplt2; ++ ++ /* The .got.plt section (VxWorks only)*/ ++ asection *sgotplt; ++ ++ /* Shortcut to __tls_get_addr. */ ++ struct elf_link_hash_entry *tls_get_addr; ++ ++ /* The bfd that forced an old-style PLT. */ ++ bfd *old_bfd; ++ ++ /* TLS local dynamic got entry handling. */ ++ union { ++ bfd_signed_vma refcount; ++ bfd_vma offset; ++ } tlsld_got; ++ ++ /* Offset of branch table to PltResolve function in glink. */ ++ bfd_vma glink_pltresolve; ++ ++ /* Size of reserved GOT entries. */ ++ unsigned int got_header_size; ++ /* Non-zero if allocating the header left a gap. */ ++ unsigned int got_gap; ++ ++ /* The type of PLT we have chosen to use. */ ++ enum ppc_elf_plt_type plt_type; ++ ++ /* Set if we should emit symbols for stubs. */ ++ unsigned int emit_stub_syms:1; ++ ++ /* Set if __tls_get_addr optimization should not be done. */ ++ unsigned int no_tls_get_addr_opt:1; ++ ++ /* True if the target system is VxWorks. */ ++ unsigned int is_vxworks:1; ++ ++ /* The size of PLT entries. */ ++ int plt_entry_size; ++ /* The distance between adjacent PLT slots. */ ++ int plt_slot_size; ++ /* The size of the first PLT entry. */ ++ int plt_initial_entry_size; ++ ++ /* Small local sym cache. */ ++ struct sym_cache sym_cache; ++}; ++ ++/* Rename some of the generic section flags to better document how they ++ are used for ppc32. The flags are only valid for ppc32 elf objects. */ ++ ++/* Nonzero if this section has TLS related relocations. */ ++#define has_tls_reloc sec_flg0 ++ ++/* Nonzero if this section has a call to __tls_get_addr. */ ++#define has_tls_get_addr_call sec_flg1 ++ ++/* Get the PPC ELF linker hash table from a link_info structure. */ ++ ++#define ppc_elf_hash_table(p) \ ++ (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ ++ == PPC32_ELF_DATA ? ((struct ppc_elf_link_hash_table *) ((p)->hash)) : NULL) ++ ++/* Create an entry in a PPC ELF linker hash table. */ ++ ++static struct bfd_hash_entry * ++ppc_elf_link_hash_newfunc (struct bfd_hash_entry *entry, ++ struct bfd_hash_table *table, ++ const char *string) ++{ ++ /* Allocate the structure if it has not already been allocated by a ++ subclass. */ ++ if (entry == NULL) ++ { ++ entry = bfd_hash_allocate (table, ++ sizeof (struct ppc_elf_link_hash_entry)); ++ if (entry == NULL) ++ return entry; ++ } ++ ++ /* Call the allocation method of the superclass. */ ++ entry = _bfd_elf_link_hash_newfunc (entry, table, string); ++ if (entry != NULL) ++ { ++ ppc_elf_hash_entry (entry)->linker_section_pointer = NULL; ++ ppc_elf_hash_entry (entry)->dyn_relocs = NULL; ++ ppc_elf_hash_entry (entry)->tls_mask = 0; ++ ppc_elf_hash_entry (entry)->has_sda_refs = 0; ++ } ++ ++ return entry; ++} ++ ++/* Create a PPC ELF linker hash table. */ ++ ++static struct bfd_link_hash_table * ++ppc_elf_link_hash_table_create (bfd *abfd) ++{ ++ struct ppc_elf_link_hash_table *ret; ++ ++ ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table)); ++ if (ret == NULL) ++ return NULL; ++ ++ if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, ++ ppc_elf_link_hash_newfunc, ++ sizeof (struct ppc_elf_link_hash_entry), ++ PPC32_ELF_DATA)) ++ { ++ free (ret); ++ return NULL; ++ } ++ ++ ret->elf.init_plt_refcount.refcount = 0; ++ ret->elf.init_plt_refcount.glist = NULL; ++ ret->elf.init_plt_offset.offset = 0; ++ ret->elf.init_plt_offset.glist = NULL; ++ ++ ret->sdata[0].name = ".sdata"; ++ ret->sdata[0].sym_name = "_SDA_BASE_"; ++ ret->sdata[0].bss_name = ".sbss"; ++ ++ ret->sdata[1].name = ".sdata2"; ++ ret->sdata[1].sym_name = "_SDA2_BASE_"; ++ ret->sdata[1].bss_name = ".sbss2"; ++ ++ ret->plt_entry_size = 12; ++ ret->plt_slot_size = 8; ++ ret->plt_initial_entry_size = 72; ++ ++ return &ret->elf.root; ++} ++ ++/* Create .got and the related sections. */ ++ ++static bfd_boolean ++ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ asection *s; ++ flagword flags; ++ ++ if (!_bfd_elf_create_got_section (abfd, info)) ++ return FALSE; ++ ++ htab = ppc_elf_hash_table (info); ++ htab->got = s = bfd_get_linker_section (abfd, ".got"); ++ if (s == NULL) ++ abort (); ++ ++ if (htab->is_vxworks) ++ { ++ htab->sgotplt = bfd_get_linker_section (abfd, ".got.plt"); ++ if (!htab->sgotplt) ++ abort (); ++ } ++ else ++ { ++ /* The powerpc .got has a blrl instruction in it. Mark it ++ executable. */ ++ flags = (SEC_ALLOC | SEC_LOAD | /*SEC_CODE |*/ SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ if (!bfd_set_section_flags (abfd, s, flags)) ++ return FALSE; ++ } ++ ++ htab->relgot = bfd_get_linker_section (abfd, ".rela.got"); ++ if (!htab->relgot) ++ abort (); ++ ++ return TRUE; ++} ++ ++static bfd_boolean ++ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info) ++{ ++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); ++ asection *s; ++ flagword flags; ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags); ++ htab->glink = s; ++ if (s == NULL ++ || !bfd_set_section_alignment (abfd, s, 4)) ++ return FALSE; ++ ++ if (!info->no_ld_generated_unwind_info) ++ { ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ s = bfd_make_section_anyway_with_flags (abfd, ".eh_frame", flags); ++ htab->glink_eh_frame = s; ++ if (s == NULL ++ || !bfd_set_section_alignment (abfd, s, 2)) ++ return FALSE; ++ } ++ ++ flags = SEC_ALLOC | SEC_LINKER_CREATED; ++ s = bfd_make_section_anyway_with_flags (abfd, ".iplt", flags); ++ htab->iplt = s; ++ if (s == NULL ++ || !bfd_set_section_alignment (abfd, s, 4)) ++ return FALSE; ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ s = bfd_make_section_anyway_with_flags (abfd, ".rela.iplt", flags); ++ htab->reliplt = s; ++ if (s == NULL ++ || ! bfd_set_section_alignment (abfd, s, 2)) ++ return FALSE; ++ return TRUE; ++} ++ ++/* We have to create .dynsbss and .rela.sbss here so that they get mapped ++ to output sections (just like _bfd_elf_create_dynamic_sections has ++ to create .dynbss and .rela.bss). */ ++ ++static bfd_boolean ++ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ asection *s; ++ flagword flags; ++ ++ htab = ppc_elf_hash_table (info); ++ ++ if (htab->got == NULL ++ && !ppc_elf_create_got (abfd, info)) ++ return FALSE; ++ ++ if (!_bfd_elf_create_dynamic_sections (abfd, info)) ++ return FALSE; ++ ++ if (htab->glink == NULL ++ && !ppc_elf_create_glink (abfd, info)) ++ return FALSE; ++ ++ htab->dynbss = bfd_get_linker_section (abfd, ".dynbss"); ++ s = bfd_make_section_anyway_with_flags (abfd, ".dynsbss", ++ SEC_ALLOC | SEC_LINKER_CREATED); ++ htab->dynsbss = s; ++ if (s == NULL) ++ return FALSE; ++ ++ if (! info->shared) ++ { ++ htab->relbss = bfd_get_linker_section (abfd, ".rela.bss"); ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ s = bfd_make_section_anyway_with_flags (abfd, ".rela.sbss", flags); ++ htab->relsbss = s; ++ if (s == NULL ++ || ! bfd_set_section_alignment (abfd, s, 2)) ++ return FALSE; ++ } ++ ++ if (htab->is_vxworks ++ && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2)) ++ return FALSE; ++ ++ htab->relplt = bfd_get_linker_section (abfd, ".rela.plt"); ++ htab->plt = s = bfd_get_linker_section (abfd, ".plt"); ++ if (s == NULL) ++ abort (); ++ ++ flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED | SEC_READONLY; ++ if (htab->plt_type == PLT_VXWORKS) ++ /* The VxWorks PLT is a loaded section with contents. */ ++ flags |= SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY; ++ return bfd_set_section_flags (abfd, s, flags); ++} ++ ++/* Copy the extra info we tack onto an elf_link_hash_entry. */ ++ ++static void ++ppc_elf_copy_indirect_symbol (struct bfd_link_info *info, ++ struct elf_link_hash_entry *dir, ++ struct elf_link_hash_entry *ind) ++{ ++ struct ppc_elf_link_hash_entry *edir, *eind; ++ ++ edir = (struct ppc_elf_link_hash_entry *) dir; ++ eind = (struct ppc_elf_link_hash_entry *) ind; ++ ++ edir->tls_mask |= eind->tls_mask; ++ edir->has_sda_refs |= eind->has_sda_refs; ++ ++ /* If called to transfer flags for a weakdef during processing ++ of elf_adjust_dynamic_symbol, don't copy non_got_ref. ++ We clear it ourselves for ELIMINATE_COPY_RELOCS. */ ++ if (!(ELIMINATE_COPY_RELOCS ++ && eind->elf.root.type != bfd_link_hash_indirect ++ && edir->elf.dynamic_adjusted)) ++ edir->elf.non_got_ref |= eind->elf.non_got_ref; ++ ++ edir->elf.ref_dynamic |= eind->elf.ref_dynamic; ++ edir->elf.ref_regular |= eind->elf.ref_regular; ++ edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak; ++ edir->elf.needs_plt |= eind->elf.needs_plt; ++ edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed; ++ ++ if (eind->dyn_relocs != NULL) ++ { ++ if (edir->dyn_relocs != NULL) ++ { ++ struct elf_dyn_relocs **pp; ++ struct elf_dyn_relocs *p; ++ ++ /* Add reloc counts against the indirect sym to the direct sym ++ list. Merge any entries against the same section. */ ++ for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) ++ { ++ struct elf_dyn_relocs *q; ++ ++ for (q = edir->dyn_relocs; q != NULL; q = q->next) ++ if (q->sec == p->sec) ++ { ++ q->pc_count += p->pc_count; ++ q->count += p->count; ++ *pp = p->next; ++ break; ++ } ++ if (q == NULL) ++ pp = &p->next; ++ } ++ *pp = edir->dyn_relocs; ++ } ++ ++ edir->dyn_relocs = eind->dyn_relocs; ++ eind->dyn_relocs = NULL; ++ } ++ ++ /* If we were called to copy over info for a weak sym, that's all. ++ You might think dyn_relocs need not be copied over; After all, ++ both syms will be dynamic or both non-dynamic so we're just ++ moving reloc accounting around. However, ELIMINATE_COPY_RELOCS ++ code in ppc_elf_adjust_dynamic_symbol needs to check for ++ dyn_relocs in read-only sections, and it does so on what is the ++ DIR sym here. */ ++ if (eind->elf.root.type != bfd_link_hash_indirect) ++ return; ++ ++ /* Copy over the GOT refcount entries that we may have already seen to ++ the symbol which just became indirect. */ ++ edir->elf.got.refcount += eind->elf.got.refcount; ++ eind->elf.got.refcount = 0; ++ ++ /* And plt entries. */ ++ if (eind->elf.plt.plist != NULL) ++ { ++ if (edir->elf.plt.plist != NULL) ++ { ++ struct plt_entry **entp; ++ struct plt_entry *ent; ++ ++ for (entp = &eind->elf.plt.plist; (ent = *entp) != NULL; ) ++ { ++ struct plt_entry *dent; ++ ++ for (dent = edir->elf.plt.plist; dent != NULL; dent = dent->next) ++ if (dent->sec == ent->sec && dent->addend == ent->addend) ++ { ++ dent->plt.refcount += ent->plt.refcount; ++ *entp = ent->next; ++ break; ++ } ++ if (dent == NULL) ++ entp = &ent->next; ++ } ++ *entp = edir->elf.plt.plist; ++ } ++ ++ edir->elf.plt.plist = eind->elf.plt.plist; ++ eind->elf.plt.plist = NULL; ++ } ++ ++ if (eind->elf.dynindx != -1) ++ { ++ if (edir->elf.dynindx != -1) ++ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, ++ edir->elf.dynstr_index); ++ edir->elf.dynindx = eind->elf.dynindx; ++ edir->elf.dynstr_index = eind->elf.dynstr_index; ++ eind->elf.dynindx = -1; ++ eind->elf.dynstr_index = 0; ++ } ++} ++ ++/* Hook called by the linker routine which adds symbols from an object ++ file. We use it to put .comm items in .sbss, and not .bss. */ ++ ++static bfd_boolean ++ppc_elf_add_symbol_hook (bfd *abfd, ++ struct bfd_link_info *info, ++ Elf_Internal_Sym *sym, ++ const char **namep ATTRIBUTE_UNUSED, ++ flagword *flagsp ATTRIBUTE_UNUSED, ++ asection **secp, ++ bfd_vma *valp) ++{ ++ if (sym->st_shndx == SHN_COMMON ++ && !info->relocatable ++ && is_ppc_elf (info->output_bfd) ++ && sym->st_size <= elf_gp_size (abfd)) ++ { ++ /* Common symbols less than or equal to -G nn bytes are automatically ++ put into .sbss. */ ++ struct ppc_elf_link_hash_table *htab; ++ ++ htab = ppc_elf_hash_table (info); ++ if (htab->sbss == NULL) ++ { ++ flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED; ++ ++ if (!htab->elf.dynobj) ++ htab->elf.dynobj = abfd; ++ ++ htab->sbss = bfd_make_section_anyway_with_flags (htab->elf.dynobj, ++ ".sbss", ++ flags); ++ if (htab->sbss == NULL) ++ return FALSE; ++ } ++ ++ *secp = htab->sbss; ++ *valp = sym->st_size; ++ } ++ ++ if ((abfd->flags & DYNAMIC) == 0 ++ && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC ++ || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)) ++ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; ++ ++ return TRUE; ++} ++ ++static bfd_boolean ++create_sdata_sym (struct bfd_link_info *info, elf_linker_section_t *lsect) ++{ ++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); ++ ++ lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name, ++ TRUE, FALSE, TRUE); ++ if (lsect->sym == NULL) ++ return FALSE; ++ if (lsect->sym->root.type == bfd_link_hash_new) ++ lsect->sym->non_elf = 0; ++ lsect->sym->ref_regular = 1; ++ _bfd_elf_link_hash_hide_symbol (info, lsect->sym, TRUE); ++ return TRUE; ++} ++ ++/* Create a special linker section. */ ++ ++static bfd_boolean ++ppc_elf_create_linker_section (bfd *abfd, ++ struct bfd_link_info *info, ++ flagword flags, ++ elf_linker_section_t *lsect) ++{ ++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); ++ asection *s; ++ ++ flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED); ++ ++ /* Record the first bfd that needs the special sections. */ ++ if (!htab->elf.dynobj) ++ htab->elf.dynobj = abfd; ++ ++ s = bfd_make_section_anyway_with_flags (htab->elf.dynobj, ++ lsect->name, ++ flags); ++ if (s == NULL ++ || !bfd_set_section_alignment (htab->elf.dynobj, s, 2)) ++ return FALSE; ++ lsect->section = s; ++ ++ return create_sdata_sym (info, lsect); ++} ++ ++/* Find a linker generated pointer with a given addend and type. */ ++ ++static elf_linker_section_pointers_t * ++elf_find_pointer_linker_section ++ (elf_linker_section_pointers_t *linker_pointers, ++ bfd_vma addend, ++ elf_linker_section_t *lsect) ++{ ++ for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next) ++ if (lsect == linker_pointers->lsect && addend == linker_pointers->addend) ++ return linker_pointers; ++ ++ return NULL; ++} ++ ++/* Allocate a pointer to live in a linker created section. */ ++ ++static bfd_boolean ++elf_create_pointer_linker_section (bfd *abfd, ++ elf_linker_section_t *lsect, ++ struct elf_link_hash_entry *h, ++ const Elf_Internal_Rela *rel) ++{ ++ elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL; ++ elf_linker_section_pointers_t *linker_section_ptr; ++ unsigned long r_symndx = ELF32_R_SYM (rel->r_info); ++ bfd_size_type amt; ++ ++ BFD_ASSERT (lsect != NULL); ++ ++ /* Is this a global symbol? */ ++ if (h != NULL) ++ { ++ struct ppc_elf_link_hash_entry *eh; ++ ++ /* Has this symbol already been allocated? If so, our work is done. */ ++ eh = (struct ppc_elf_link_hash_entry *) h; ++ if (elf_find_pointer_linker_section (eh->linker_section_pointer, ++ rel->r_addend, ++ lsect)) ++ return TRUE; ++ ++ ptr_linker_section_ptr = &eh->linker_section_pointer; ++ } ++ else ++ { ++ BFD_ASSERT (is_ppc_elf (abfd)); ++ ++ /* Allocation of a pointer to a local symbol. */ ++ elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd); ++ ++ /* Allocate a table to hold the local symbols if first time. */ ++ if (!ptr) ++ { ++ unsigned int num_symbols = elf_symtab_hdr (abfd).sh_info; ++ ++ amt = num_symbols; ++ amt *= sizeof (elf_linker_section_pointers_t *); ++ ptr = bfd_zalloc (abfd, amt); ++ ++ if (!ptr) ++ return FALSE; ++ ++ elf_local_ptr_offsets (abfd) = ptr; ++ } ++ ++ /* Has this symbol already been allocated? If so, our work is done. */ ++ if (elf_find_pointer_linker_section (ptr[r_symndx], ++ rel->r_addend, ++ lsect)) ++ return TRUE; ++ ++ ptr_linker_section_ptr = &ptr[r_symndx]; ++ } ++ ++ /* Allocate space for a pointer in the linker section, and allocate ++ a new pointer record from internal memory. */ ++ BFD_ASSERT (ptr_linker_section_ptr != NULL); ++ amt = sizeof (elf_linker_section_pointers_t); ++ linker_section_ptr = bfd_alloc (abfd, amt); ++ ++ if (!linker_section_ptr) ++ return FALSE; ++ ++ linker_section_ptr->next = *ptr_linker_section_ptr; ++ linker_section_ptr->addend = rel->r_addend; ++ linker_section_ptr->lsect = lsect; ++ *ptr_linker_section_ptr = linker_section_ptr; ++ ++ linker_section_ptr->offset = lsect->section->size; ++ lsect->section->size += 4; ++ ++#ifdef DEBUG ++ fprintf (stderr, ++ "Create pointer in linker section %s, offset = %ld, section size = %ld\n", ++ lsect->name, (long) linker_section_ptr->offset, ++ (long) lsect->section->size); ++#endif ++ ++ return TRUE; ++} ++ ++static struct plt_entry ** ++update_local_sym_info (bfd *abfd, ++ Elf_Internal_Shdr *symtab_hdr, ++ unsigned long r_symndx, ++ int tls_type) ++{ ++ bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd); ++ struct plt_entry **local_plt; ++ char *local_got_tls_masks; ++ ++ if (local_got_refcounts == NULL) ++ { ++ bfd_size_type size = symtab_hdr->sh_info; ++ ++ size *= (sizeof (*local_got_refcounts) ++ + sizeof (*local_plt) ++ + sizeof (*local_got_tls_masks)); ++ local_got_refcounts = bfd_zalloc (abfd, size); ++ if (local_got_refcounts == NULL) ++ return NULL; ++ elf_local_got_refcounts (abfd) = local_got_refcounts; ++ } ++ ++ local_plt = (struct plt_entry **) (local_got_refcounts + symtab_hdr->sh_info); ++ local_got_tls_masks = (char *) (local_plt + symtab_hdr->sh_info); ++ local_got_tls_masks[r_symndx] |= tls_type; ++ if (tls_type != PLT_IFUNC) ++ local_got_refcounts[r_symndx] += 1; ++ return local_plt + r_symndx; ++} ++ ++static bfd_boolean ++update_plt_info (bfd *abfd, struct plt_entry **plist, ++ asection *sec, bfd_vma addend) ++{ ++ struct plt_entry *ent; ++ ++ if (addend < 32768) ++ sec = NULL; ++ for (ent = *plist; ent != NULL; ent = ent->next) ++ if (ent->sec == sec && ent->addend == addend) ++ break; ++ if (ent == NULL) ++ { ++ bfd_size_type amt = sizeof (*ent); ++ ent = bfd_alloc (abfd, amt); ++ if (ent == NULL) ++ return FALSE; ++ ent->next = *plist; ++ ent->sec = sec; ++ ent->addend = addend; ++ ent->plt.refcount = 0; ++ *plist = ent; ++ } ++ ent->plt.refcount += 1; ++ return TRUE; ++} ++ ++static struct plt_entry * ++find_plt_ent (struct plt_entry **plist, asection *sec, bfd_vma addend) ++{ ++ struct plt_entry *ent; ++ ++ if (addend < 32768) ++ sec = NULL; ++ for (ent = *plist; ent != NULL; ent = ent->next) ++ if (ent->sec == sec && ent->addend == addend) ++ break; ++ return ent; ++} ++ ++static bfd_boolean ++is_branch_reloc (enum elf_ppc_reloc_type r_type) ++{ ++ return (r_type == R_PPC_PLTREL24 ++ || r_type == R_PPC_LOCAL24PC ++ || r_type == R_PPC_REL24 ++ || r_type == R_PPC_REL14 ++ || r_type == R_PPC_REL14_BRTAKEN ++ || r_type == R_PPC_REL14_BRNTAKEN ++ || r_type == R_PPC_ADDR24 ++ || r_type == R_PPC_ADDR14 ++ || r_type == R_PPC_ADDR14_BRTAKEN ++ || r_type == R_PPC_ADDR14_BRNTAKEN); ++} ++ ++static void ++bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type) ++{ ++ (*_bfd_error_handler) ++ (_("%B: relocation %s cannot be used when making a shared object"), ++ abfd, ++ ppc_elf_howto_table[r_type]->name); ++ bfd_set_error (bfd_error_bad_value); ++} ++ ++/* Look through the relocs for a section during the first phase, and ++ allocate space in the global offset table or procedure linkage ++ table. */ ++ ++static bfd_boolean ++ppc_elf_check_relocs (bfd *abfd, ++ struct bfd_link_info *info, ++ asection *sec, ++ const Elf_Internal_Rela *relocs) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes; ++ const Elf_Internal_Rela *rel; ++ const Elf_Internal_Rela *rel_end; ++ asection *got2, *sreloc; ++ struct elf_link_hash_entry *tga; ++ ++ if (info->relocatable) ++ return TRUE; ++ ++ /* Don't do anything special with non-loaded, non-alloced sections. ++ In particular, any relocs in such sections should not affect GOT ++ and PLT reference counting (ie. we don't allow them to create GOT ++ or PLT entries), there's no possibility or desire to optimize TLS ++ relocs, and there's not much point in propagating relocs to shared ++ libs that the dynamic linker won't relocate. */ ++ if ((sec->flags & SEC_ALLOC) == 0) ++ return TRUE; ++ ++#ifdef DEBUG ++ _bfd_error_handler ("ppc_elf_check_relocs called for section %A in %B", ++ sec, abfd); ++#endif ++ ++ BFD_ASSERT (is_ppc_elf (abfd)); ++ ++ /* Initialize howto table if not already done. */ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ ppc_elf_howto_init (); ++ ++ htab = ppc_elf_hash_table (info); ++ if (htab->glink == NULL) ++ { ++ if (htab->elf.dynobj == NULL) ++ htab->elf.dynobj = abfd; ++ if (!ppc_elf_create_glink (htab->elf.dynobj, info)) ++ return FALSE; ++ } ++ tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", ++ FALSE, FALSE, TRUE); ++ symtab_hdr = &elf_symtab_hdr (abfd); ++ sym_hashes = elf_sym_hashes (abfd); ++ got2 = bfd_get_section_by_name (abfd, ".got2"); ++ sreloc = NULL; ++ ++ rel_end = relocs + sec->reloc_count; ++ for (rel = relocs; rel < rel_end; rel++) ++ { ++ unsigned long r_symndx; ++ enum elf_ppc_reloc_type r_type; ++ struct elf_link_hash_entry *h; ++ int tls_type; ++ ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx < symtab_hdr->sh_info) ++ h = NULL; ++ else ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ } ++ ++ /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. ++ This shows up in particular in an R_PPC_ADDR32 in the eabi ++ startup code. */ ++ if (h != NULL ++ && htab->got == NULL ++ && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) ++ { ++ if (htab->elf.dynobj == NULL) ++ htab->elf.dynobj = abfd; ++ if (!ppc_elf_create_got (htab->elf.dynobj, info)) ++ return FALSE; ++ BFD_ASSERT (h == htab->elf.hgot); ++ } ++ ++ tls_type = 0; ++ r_type = ELF32_R_TYPE (rel->r_info); ++ if (h == NULL && !htab->is_vxworks) ++ { ++ Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache, ++ abfd, r_symndx); ++ if (isym == NULL) ++ return FALSE; ++ ++ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC ++ && (!info->shared ++ || is_branch_reloc (r_type))) ++ { ++ struct plt_entry **ifunc; ++ bfd_vma addend; ++ ++ ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, ++ PLT_IFUNC); ++ if (ifunc == NULL) ++ return FALSE; ++ ++ /* STT_GNU_IFUNC symbols must have a PLT entry; ++ In a non-pie executable even when there are ++ no plt calls. */ ++ addend = 0; ++ if (r_type == R_PPC_PLTREL24) ++ { ++ ppc_elf_tdata (abfd)->makes_plt_call = 1; ++ if (info->shared) ++ addend = rel->r_addend; ++ } ++ if (!update_plt_info (abfd, ifunc, got2, addend)) ++ return FALSE; ++ } ++ } ++ ++ if (!htab->is_vxworks ++ && is_branch_reloc (r_type) ++ && h != NULL ++ && h == tga) ++ { ++ if (rel != relocs ++ && (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD ++ || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD)) ++ /* We have a new-style __tls_get_addr call with a marker ++ reloc. */ ++ ; ++ else ++ /* Mark this section as having an old-style call. */ ++ sec->has_tls_get_addr_call = 1; ++ } ++ ++ switch (r_type) ++ { ++ case R_PPC_TLSGD: ++ case R_PPC_TLSLD: ++ /* These special tls relocs tie a call to __tls_get_addr with ++ its parameter symbol. */ ++ break; ++ ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ case R_PPC_GOT_TLSLD16_HI: ++ case R_PPC_GOT_TLSLD16_HA: ++ tls_type = TLS_TLS | TLS_LD; ++ goto dogottls; ++ ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ case R_PPC_GOT_TLSGD16_HI: ++ case R_PPC_GOT_TLSGD16_HA: ++ tls_type = TLS_TLS | TLS_GD; ++ goto dogottls; ++ ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ case R_PPC_GOT_TPREL16_HI: ++ case R_PPC_GOT_TPREL16_HA: ++ if (!info->executable) ++ info->flags |= DF_STATIC_TLS; ++ tls_type = TLS_TLS | TLS_TPREL; ++ goto dogottls; ++ ++ case R_PPC_GOT_DTPREL16: ++ case R_PPC_GOT_DTPREL16_LO: ++ case R_PPC_GOT_DTPREL16_HI: ++ case R_PPC_GOT_DTPREL16_HA: ++ tls_type = TLS_TLS | TLS_DTPREL; ++ dogottls: ++ sec->has_tls_reloc = 1; ++ /* Fall thru */ ++ ++ /* GOT16 relocations */ ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ /* This symbol requires a global offset table entry. */ ++ if (htab->got == NULL) ++ { ++ if (htab->elf.dynobj == NULL) ++ htab->elf.dynobj = abfd; ++ if (!ppc_elf_create_got (htab->elf.dynobj, info)) ++ return FALSE; ++ } ++ if (h != NULL) ++ { ++ h->got.refcount += 1; ++ ppc_elf_hash_entry (h)->tls_mask |= tls_type; ++ } ++ else ++ /* This is a global offset table entry for a local symbol. */ ++ if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, tls_type)) ++ return FALSE; ++ ++ /* We may also need a plt entry if the symbol turns out to be ++ an ifunc. */ ++ if (h != NULL && !info->shared) ++ { ++ if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) ++ return FALSE; ++ } ++ break; ++ ++ /* Indirect .sdata relocation. */ ++ case R_PPC_EMB_SDAI16: ++ if (info->shared) ++ { ++ bad_shared_reloc (abfd, r_type); ++ return FALSE; ++ } ++ if (htab->sdata[0].section == NULL ++ && !ppc_elf_create_linker_section (abfd, info, 0, ++ &htab->sdata[0])) ++ return FALSE; ++ if (!elf_create_pointer_linker_section (abfd, &htab->sdata[0], ++ h, rel)) ++ return FALSE; ++ if (h != NULL) ++ { ++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE; ++ h->non_got_ref = TRUE; ++ } ++ break; ++ ++ /* Indirect .sdata2 relocation. */ ++ case R_PPC_EMB_SDA2I16: ++ if (info->shared) ++ { ++ bad_shared_reloc (abfd, r_type); ++ return FALSE; ++ } ++ if (htab->sdata[1].section == NULL ++ && !ppc_elf_create_linker_section (abfd, info, SEC_READONLY, ++ &htab->sdata[1])) ++ return FALSE; ++ if (!elf_create_pointer_linker_section (abfd, &htab->sdata[1], ++ h, rel)) ++ return FALSE; ++ if (h != NULL) ++ { ++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE; ++ h->non_got_ref = TRUE; ++ } ++ break; ++ ++ case R_PPC_VLE_SDAREL_LO16A: ++ case R_PPC_VLE_SDAREL_LO16D: ++ case R_PPC_VLE_SDAREL_HI16A: ++ case R_PPC_VLE_SDAREL_HI16D: ++ case R_PPC_VLE_SDAREL_HA16A: ++ case R_PPC_VLE_SDAREL_HA16D: ++ case R_PPC_SDAREL16: ++ if (htab->sdata[0].sym == NULL ++ && !create_sdata_sym (info, &htab->sdata[0])) ++ return FALSE; ++ ++ if (htab->sdata[1].sym == NULL ++ && !create_sdata_sym (info, &htab->sdata[1])) ++ return FALSE; ++ ++ if (h != NULL) ++ { ++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE; ++ h->non_got_ref = TRUE; ++ } ++ break; ++ ++ case R_PPC_VLE_REL8: ++ case R_PPC_VLE_REL15: ++ case R_PPC_VLE_REL24: ++ case R_PPC_VLE_LO16A: ++ case R_PPC_VLE_LO16D: ++ case R_PPC_VLE_HI16A: ++ case R_PPC_VLE_HI16D: ++ case R_PPC_VLE_HA16A: ++ case R_PPC_VLE_HA16D: ++ break; ++ ++ case R_PPC_EMB_SDA2REL: ++ if (info->shared) ++ { ++ bad_shared_reloc (abfd, r_type); ++ return FALSE; ++ } ++ if (htab->sdata[1].sym == NULL ++ && !create_sdata_sym (info, &htab->sdata[1])) ++ return FALSE; ++ if (h != NULL) ++ { ++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE; ++ h->non_got_ref = TRUE; ++ } ++ break; ++ ++ case R_PPC_VLE_SDA21_LO: ++ case R_PPC_VLE_SDA21: ++ case R_PPC_EMB_SDA21: ++ case R_PPC_EMB_RELSDA: ++ if (info->shared) ++ { ++ bad_shared_reloc (abfd, r_type); ++ return FALSE; ++ } ++ if (htab->sdata[0].sym == NULL ++ && !create_sdata_sym (info, &htab->sdata[0])) ++ return FALSE; ++ if (htab->sdata[1].sym == NULL ++ && !create_sdata_sym (info, &htab->sdata[1])) ++ return FALSE; ++ if (h != NULL) ++ { ++ ppc_elf_hash_entry (h)->has_sda_refs = TRUE; ++ h->non_got_ref = TRUE; ++ } ++ break; ++ ++ case R_PPC_EMB_NADDR32: ++ case R_PPC_EMB_NADDR16: ++ case R_PPC_EMB_NADDR16_LO: ++ case R_PPC_EMB_NADDR16_HI: ++ case R_PPC_EMB_NADDR16_HA: ++ if (info->shared) ++ { ++ bad_shared_reloc (abfd, r_type); ++ return FALSE; ++ } ++ if (h != NULL) ++ h->non_got_ref = TRUE; ++ break; ++ ++ case R_PPC_PLTREL24: ++ if (h == NULL) ++ break; ++ /* Fall through */ ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL32: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++#ifdef DEBUG ++ fprintf (stderr, "Reloc requires a PLT entry\n"); ++#endif ++ /* This symbol requires a procedure linkage table entry. We ++ actually build the entry in finish_dynamic_symbol, ++ because this might be a case of linking PIC code without ++ linking in any dynamic objects, in which case we don't ++ need to generate a procedure linkage table after all. */ ++ ++ if (h == NULL) ++ { ++ /* It does not make sense to have a procedure linkage ++ table entry for a local symbol. */ ++ info->callbacks->einfo (_("%P: %H: %s reloc against local symbol\n"), ++ abfd, sec, rel->r_offset, ++ ppc_elf_howto_table[r_type]->name); ++ bfd_set_error (bfd_error_bad_value); ++ return FALSE; ++ } ++ else ++ { ++ bfd_vma addend = 0; ++ ++ if (r_type == R_PPC_PLTREL24) ++ { ++ ppc_elf_tdata (abfd)->makes_plt_call = 1; ++ if (info->shared) ++ addend = rel->r_addend; ++ } ++ h->needs_plt = 1; ++ if (!update_plt_info (abfd, &h->plt.plist, got2, addend)) ++ return FALSE; ++ } ++ break; ++ ++ /* The following relocations don't need to propagate the ++ relocation if linking a shared object since they are ++ section relative. */ ++ case R_PPC_SECTOFF: ++ case R_PPC_SECTOFF_LO: ++ case R_PPC_SECTOFF_HI: ++ case R_PPC_SECTOFF_HA: ++ case R_PPC_DTPREL16: ++ case R_PPC_DTPREL16_LO: ++ case R_PPC_DTPREL16_HI: ++ case R_PPC_DTPREL16_HA: ++ case R_PPC_TOC16: ++ break; ++ ++ case R_PPC_REL16: ++ case R_PPC_REL16_LO: ++ case R_PPC_REL16_HI: ++ case R_PPC_REL16_HA: ++ ppc_elf_tdata (abfd)->has_rel16 = 1; ++ break; ++ ++ /* These are just markers. */ ++ case R_PPC_TLS: ++ case R_PPC_EMB_MRKREF: ++ case R_PPC_NONE: ++ case R_PPC_max: ++ case R_PPC_RELAX: ++ case R_PPC_RELAX_PLT: ++ case R_PPC_RELAX_PLTREL24: ++ break; ++ ++ /* These should only appear in dynamic objects. */ ++ case R_PPC_COPY: ++ case R_PPC_GLOB_DAT: ++ case R_PPC_JMP_SLOT: ++ case R_PPC_RELATIVE: ++ case R_PPC_IRELATIVE: ++ break; ++ ++ /* These aren't handled yet. We'll report an error later. */ ++ case R_PPC_ADDR30: ++ case R_PPC_EMB_RELSEC16: ++ case R_PPC_EMB_RELST_LO: ++ case R_PPC_EMB_RELST_HI: ++ case R_PPC_EMB_RELST_HA: ++ case R_PPC_EMB_BIT_FLD: ++ break; ++ ++ /* These don't work with a GOT */ ++ case R_PPC_AMIGAOS_BREL: ++ case R_PPC_AMIGAOS_BREL_HI: ++ case R_PPC_AMIGAOS_BREL_LO: ++ case R_PPC_AMIGAOS_BREL_HA: ++ break; ++ ++ /* This refers only to functions defined in the shared library. */ ++ case R_PPC_LOCAL24PC: ++ if (h != NULL && h == htab->elf.hgot && htab->plt_type == PLT_UNSET) ++ { ++ htab->plt_type = PLT_OLD; ++ htab->old_bfd = abfd; ++ } ++ break; ++ ++ /* This relocation describes the C++ object vtable hierarchy. ++ Reconstruct it for later use during GC. */ ++ case R_PPC_GNU_VTINHERIT: ++ if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) ++ return FALSE; ++ break; ++ ++ /* This relocation describes which C++ vtable entries are actually ++ used. Record for later use during GC. */ ++ case R_PPC_GNU_VTENTRY: ++ BFD_ASSERT (h != NULL); ++ if (h != NULL ++ && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) ++ return FALSE; ++ break; ++ ++ /* We shouldn't really be seeing these. */ ++ case R_PPC_TPREL32: ++ case R_PPC_TPREL16: ++ case R_PPC_TPREL16_LO: ++ case R_PPC_TPREL16_HI: ++ case R_PPC_TPREL16_HA: ++ if (!info->executable) ++ info->flags |= DF_STATIC_TLS; ++ goto dodyn; ++ ++ /* Nor these. */ ++ case R_PPC_DTPMOD32: ++ case R_PPC_DTPREL32: ++ goto dodyn; ++ ++ case R_PPC_REL32: ++ if (h == NULL ++ && got2 != NULL ++ && (sec->flags & SEC_CODE) != 0 ++ && info->shared ++ && htab->plt_type == PLT_UNSET) ++ { ++ /* Old -fPIC gcc code has .long LCTOC1-LCFx just before ++ the start of a function, which assembles to a REL32 ++ reference to .got2. If we detect one of these, then ++ force the old PLT layout because the linker cannot ++ reliably deduce the GOT pointer value needed for ++ PLT call stubs. */ ++ asection *s; ++ Elf_Internal_Sym *isym; ++ ++ isym = bfd_sym_from_r_symndx (&htab->sym_cache, ++ abfd, r_symndx); ++ if (isym == NULL) ++ return FALSE; ++ ++ s = bfd_section_from_elf_index (abfd, isym->st_shndx); ++ if (s == got2) ++ { ++ htab->plt_type = PLT_OLD; ++ htab->old_bfd = abfd; ++ } ++ } ++ if (h == NULL || h == htab->elf.hgot) ++ break; ++ /* fall through */ ++ ++ case R_PPC_ADDR32: ++ case R_PPC_ADDR16: ++ case R_PPC_ADDR16_LO: ++ case R_PPC_ADDR16_HI: ++ case R_PPC_ADDR16_HA: ++ case R_PPC_UADDR32: ++ case R_PPC_UADDR16: ++ if (h != NULL && !info->shared) ++ { ++ /* We may need a plt entry if the symbol turns out to be ++ a function defined in a dynamic object. */ ++ if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) ++ return FALSE; ++ ++ /* We may need a copy reloc too. */ ++ h->non_got_ref = 1; ++ h->pointer_equality_needed = 1; ++ } ++ goto dodyn; ++ ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ if (h == NULL) ++ break; ++ if (h == htab->elf.hgot) ++ { ++ if (htab->plt_type == PLT_UNSET) ++ { ++ htab->plt_type = PLT_OLD; ++ htab->old_bfd = abfd; ++ } ++ break; ++ } ++ /* fall through */ ++ ++ case R_PPC_ADDR24: ++ case R_PPC_ADDR14: ++ case R_PPC_ADDR14_BRTAKEN: ++ case R_PPC_ADDR14_BRNTAKEN: ++ if (h != NULL && !info->shared) ++ { ++ /* We may need a plt entry if the symbol turns out to be ++ a function defined in a dynamic object. */ ++ h->needs_plt = 1; ++ if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) ++ return FALSE; ++ break; ++ } ++ ++ dodyn: ++ /* If we are creating a shared library, and this is a reloc ++ against a global symbol, or a non PC relative reloc ++ against a local symbol, then we need to copy the reloc ++ into the shared library. However, if we are linking with ++ -Bsymbolic, we do not need to copy a reloc against a ++ global symbol which is defined in an object we are ++ including in the link (i.e., DEF_REGULAR is set). At ++ this point we have not seen all the input files, so it is ++ possible that DEF_REGULAR is not set now but will be set ++ later (it is never cleared). In case of a weak definition, ++ DEF_REGULAR may be cleared later by a strong definition in ++ a shared library. We account for that possibility below by ++ storing information in the dyn_relocs field of the hash ++ table entry. A similar situation occurs when creating ++ shared libraries and symbol visibility changes render the ++ symbol local. ++ ++ If on the other hand, we are creating an executable, we ++ may need to keep relocations for symbols satisfied by a ++ dynamic library if we manage to avoid copy relocs for the ++ symbol. */ ++ if ((info->shared ++ && (must_be_dyn_reloc (info, r_type) ++ || (h != NULL ++ && (! info->symbolic ++ || h->root.type == bfd_link_hash_defweak ++ || !h->def_regular)))) ++ || (ELIMINATE_COPY_RELOCS ++ && !info->shared ++ && h != NULL ++ && (h->root.type == bfd_link_hash_defweak ++ || !h->def_regular))) ++ { ++ struct elf_dyn_relocs *p; ++ struct elf_dyn_relocs **rel_head; ++ ++#ifdef DEBUG ++ fprintf (stderr, ++ "ppc_elf_check_relocs needs to " ++ "create relocation for %s\n", ++ (h && h->root.root.string ++ ? h->root.root.string : "<unknown>")); ++#endif ++ if (sreloc == NULL) ++ { ++ if (htab->elf.dynobj == NULL) ++ htab->elf.dynobj = abfd; ++ ++ sreloc = _bfd_elf_make_dynamic_reloc_section ++ (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE); ++ ++ if (sreloc == NULL) ++ return FALSE; ++ } ++ ++ /* If this is a global symbol, we count the number of ++ relocations we need for this symbol. */ ++ if (h != NULL) ++ { ++ rel_head = &ppc_elf_hash_entry (h)->dyn_relocs; ++ } ++ else ++ { ++ /* Track dynamic relocs needed for local syms too. ++ We really need local syms available to do this ++ easily. Oh well. */ ++ asection *s; ++ void *vpp; ++ Elf_Internal_Sym *isym; ++ ++ isym = bfd_sym_from_r_symndx (&htab->sym_cache, ++ abfd, r_symndx); ++ if (isym == NULL) ++ return FALSE; ++ ++ s = bfd_section_from_elf_index (abfd, isym->st_shndx); ++ if (s == NULL) ++ s = sec; ++ ++ vpp = &elf_section_data (s)->local_dynrel; ++ rel_head = (struct elf_dyn_relocs **) vpp; ++ } ++ ++ p = *rel_head; ++ if (p == NULL || p->sec != sec) ++ { ++ p = bfd_alloc (htab->elf.dynobj, sizeof *p); ++ if (p == NULL) ++ return FALSE; ++ p->next = *rel_head; ++ *rel_head = p; ++ p->sec = sec; ++ p->count = 0; ++ p->pc_count = 0; ++ } ++ ++ p->count += 1; ++ if (!must_be_dyn_reloc (info, r_type)) ++ p->pc_count += 1; ++ } ++ ++ break; ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++/* Merge object attributes from IBFD into OBFD. Raise an error if ++ there are conflicting attributes. */ ++static bfd_boolean ++ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) ++{ ++ obj_attribute *in_attr, *in_attrs; ++ obj_attribute *out_attr, *out_attrs; ++ ++ if (!elf_known_obj_attributes_proc (obfd)[0].i) ++ { ++ /* This is the first object. Copy the attributes. */ ++ _bfd_elf_copy_obj_attributes (ibfd, obfd); ++ ++ /* Use the Tag_null value to indicate the attributes have been ++ initialized. */ ++ elf_known_obj_attributes_proc (obfd)[0].i = 1; ++ ++ return TRUE; ++ } ++ ++ in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; ++ out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; ++ ++ /* Check for conflicting Tag_GNU_Power_ABI_FP attributes and merge ++ non-conflicting ones. */ ++ in_attr = &in_attrs[Tag_GNU_Power_ABI_FP]; ++ out_attr = &out_attrs[Tag_GNU_Power_ABI_FP]; ++ if (in_attr->i != out_attr->i) ++ { ++ out_attr->type = 1; ++ if (out_attr->i == 0) ++ out_attr->i = in_attr->i; ++ else if (in_attr->i == 0) ++ ; ++ else if (out_attr->i == 1 && in_attr->i == 2) ++ _bfd_error_handler ++ (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd); ++ else if (out_attr->i == 1 && in_attr->i == 3) ++ _bfd_error_handler ++ (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"), ++ obfd, ibfd); ++ else if (out_attr->i == 3 && in_attr->i == 1) ++ _bfd_error_handler ++ (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"), ++ ibfd, obfd); ++ else if (out_attr->i == 3 && in_attr->i == 2) ++ _bfd_error_handler ++ (_("Warning: %B uses soft float, %B uses single-precision hard float"), ++ ibfd, obfd); ++ else if (out_attr->i == 2 && (in_attr->i == 1 || in_attr->i == 3)) ++ _bfd_error_handler ++ (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd); ++ else if (in_attr->i > 3) ++ _bfd_error_handler ++ (_("Warning: %B uses unknown floating point ABI %d"), ibfd, ++ in_attr->i); ++ else ++ _bfd_error_handler ++ (_("Warning: %B uses unknown floating point ABI %d"), obfd, ++ out_attr->i); ++ } ++ ++ /* Check for conflicting Tag_GNU_Power_ABI_Vector attributes and ++ merge non-conflicting ones. */ ++ in_attr = &in_attrs[Tag_GNU_Power_ABI_Vector]; ++ out_attr = &out_attrs[Tag_GNU_Power_ABI_Vector]; ++ if (in_attr->i != out_attr->i) ++ { ++ const char *in_abi = NULL, *out_abi = NULL; ++ ++ switch (in_attr->i) ++ { ++ case 1: in_abi = "generic"; break; ++ case 2: in_abi = "AltiVec"; break; ++ case 3: in_abi = "SPE"; break; ++ } ++ ++ switch (out_attr->i) ++ { ++ case 1: out_abi = "generic"; break; ++ case 2: out_abi = "AltiVec"; break; ++ case 3: out_abi = "SPE"; break; ++ } ++ ++ out_attr->type = 1; ++ if (out_attr->i == 0) ++ out_attr->i = in_attr->i; ++ else if (in_attr->i == 0) ++ ; ++ /* For now, allow generic to transition to AltiVec or SPE ++ without a warning. If GCC marked files with their stack ++ alignment and used don't-care markings for files which are ++ not affected by the vector ABI, we could warn about this ++ case too. */ ++ else if (out_attr->i == 1) ++ out_attr->i = in_attr->i; ++ else if (in_attr->i == 1) ++ ; ++ else if (in_abi == NULL) ++ _bfd_error_handler ++ (_("Warning: %B uses unknown vector ABI %d"), ibfd, ++ in_attr->i); ++ else if (out_abi == NULL) ++ _bfd_error_handler ++ (_("Warning: %B uses unknown vector ABI %d"), obfd, ++ in_attr->i); ++ else ++ _bfd_error_handler ++ (_("Warning: %B uses vector ABI \"%s\", %B uses \"%s\""), ++ ibfd, obfd, in_abi, out_abi); ++ } ++ ++ /* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes ++ and merge non-conflicting ones. */ ++ in_attr = &in_attrs[Tag_GNU_Power_ABI_Struct_Return]; ++ out_attr = &out_attrs[Tag_GNU_Power_ABI_Struct_Return]; ++ if (in_attr->i != out_attr->i) ++ { ++ out_attr->type = 1; ++ if (out_attr->i == 0) ++ out_attr->i = in_attr->i; ++ else if (in_attr->i == 0) ++ ; ++ else if (out_attr->i == 1 && in_attr->i == 2) ++ _bfd_error_handler ++ (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), obfd, ibfd); ++ else if (out_attr->i == 2 && in_attr->i == 1) ++ _bfd_error_handler ++ (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), ibfd, obfd); ++ else if (in_attr->i > 2) ++ _bfd_error_handler ++ (_("Warning: %B uses unknown small structure return convention %d"), ibfd, ++ in_attr->i); ++ else ++ _bfd_error_handler ++ (_("Warning: %B uses unknown small structure return convention %d"), obfd, ++ out_attr->i); ++ } ++ ++ /* Merge Tag_compatibility attributes and any common GNU ones. */ ++ _bfd_elf_merge_object_attributes (ibfd, obfd); ++ ++ return TRUE; ++} ++ ++/* Merge backend specific data from an object file to the output ++ object file when linking. */ ++ ++static bfd_boolean ++ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) ++{ ++ flagword old_flags; ++ flagword new_flags; ++ bfd_boolean error; ++ ++ if (!is_ppc_elf (ibfd) || !is_ppc_elf (obfd)) ++ return TRUE; ++ ++ /* Check if we have the same endianness. */ ++ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) ++ return FALSE; ++ ++ if (!ppc_elf_merge_obj_attributes (ibfd, obfd)) ++ return FALSE; ++ ++ new_flags = elf_elfheader (ibfd)->e_flags; ++ old_flags = elf_elfheader (obfd)->e_flags; ++ if (!elf_flags_init (obfd)) ++ { ++ /* First call, no flags set. */ ++ elf_flags_init (obfd) = TRUE; ++ elf_elfheader (obfd)->e_flags = new_flags; ++ } ++ ++ /* Compatible flags are ok. */ ++ else if (new_flags == old_flags) ++ ; ++ ++ /* Incompatible flags. */ ++ else ++ { ++ /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib ++ to be linked with either. */ ++ error = FALSE; ++ if ((new_flags & EF_PPC_RELOCATABLE) != 0 ++ && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0) ++ { ++ error = TRUE; ++ (*_bfd_error_handler) ++ (_("%B: compiled with -mrelocatable and linked with " ++ "modules compiled normally"), ibfd); ++ } ++ else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0 ++ && (old_flags & EF_PPC_RELOCATABLE) != 0) ++ { ++ error = TRUE; ++ (*_bfd_error_handler) ++ (_("%B: compiled normally and linked with " ++ "modules compiled with -mrelocatable"), ibfd); ++ } ++ ++ /* The output is -mrelocatable-lib iff both the input files are. */ ++ if (! (new_flags & EF_PPC_RELOCATABLE_LIB)) ++ elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB; ++ ++ /* The output is -mrelocatable iff it can't be -mrelocatable-lib, ++ but each input file is either -mrelocatable or -mrelocatable-lib. */ ++ if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB) ++ && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)) ++ && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))) ++ elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE; ++ ++ /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if ++ any module uses it. */ ++ elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB); ++ ++ new_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ old_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ ++ /* Warn about any other mismatches. */ ++ if (new_flags != old_flags) ++ { ++ error = TRUE; ++ (*_bfd_error_handler) ++ (_("%B: uses different e_flags (0x%lx) fields " ++ "than previous modules (0x%lx)"), ++ ibfd, (long) new_flags, (long) old_flags); ++ } ++ ++ if (error) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++static void ++ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents, ++ bfd_vma offset, bfd_vma relocation, ++ split16_format_type split16_format) ++ ++{ ++ bfd_vma insn, top5, bottom11; ++ ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ top5 = relocation >> 11; ++ top5 = top5 << (split16_format == split16a_type ? 20 : 16); ++ bottom11 = relocation & 0x7ff; ++ insn |= top5; ++ insn |= bottom11; ++ bfd_put_32 (output_bfd, insn, contents + offset); ++} ++ ++ ++/* Choose which PLT scheme to use, and set .plt flags appropriately. ++ Returns -1 on error, 0 for old PLT, 1 for new PLT. */ ++int ++ppc_elf_amigaos_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *info, ++ enum ppc_elf_plt_type plt_style, ++ int emit_stub_syms) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ flagword flags; ++ ++ htab = ppc_elf_hash_table (info); ++ ++ htab->emit_stub_syms = emit_stub_syms; ++ ++ if (htab->plt_type == PLT_UNSET) ++ { ++ struct elf_link_hash_entry *h; ++ ++ if (plt_style == PLT_OLD) ++ htab->plt_type = PLT_OLD; ++ else if (info->shared ++ && htab->elf.dynamic_sections_created ++ && (h = elf_link_hash_lookup (&htab->elf, "_mcount", ++ FALSE, FALSE, TRUE)) != NULL ++ && (h->type == STT_FUNC ++ || h->needs_plt) ++ && h->ref_regular ++ && !(SYMBOL_CALLS_LOCAL (info, h) ++ || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT ++ && h->root.type == bfd_link_hash_undefweak))) ++ { ++ /* Profiling of shared libs (and pies) is not supported with ++ secure plt, because ppc32 does profiling before a ++ function prologue and a secure plt pic call stubs needs ++ r30 to be set up. */ ++ htab->plt_type = PLT_OLD; ++ } ++ else ++ { ++ bfd *ibfd; ++ enum ppc_elf_plt_type plt_type = plt_style; ++ ++ /* Look through the reloc flags left by ppc_elf_check_relocs. ++ Use the old style bss plt if a file makes plt calls ++ without using the new relocs, and if ld isn't given ++ --secure-plt and we never see REL16 relocs. */ ++ if (plt_type == PLT_UNSET) ++ plt_type = PLT_OLD; ++ for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next) ++ if (is_ppc_elf (ibfd)) ++ { ++ if (ppc_elf_tdata (ibfd)->has_rel16) ++ plt_type = PLT_NEW; ++ else if (ppc_elf_tdata (ibfd)->makes_plt_call) ++ { ++ plt_type = PLT_OLD; ++ htab->old_bfd = ibfd; ++ break; ++ } ++ } ++ htab->plt_type = plt_type; ++ } ++ } ++ if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW) ++ { ++ if (htab->old_bfd != NULL) ++ info->callbacks->einfo (_("%P: bss-plt forced due to %B\n"), ++ htab->old_bfd); ++ else ++ info->callbacks->einfo (_("%P: bss-plt forced by profiling\n")); ++ } ++ ++ BFD_ASSERT (htab->plt_type != PLT_VXWORKS); ++ ++ if (htab->plt_type == PLT_NEW) ++ { ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ ++ /* The new PLT is a loaded section. */ ++ if (htab->plt != NULL ++ && !bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags)) ++ return -1; ++ ++ /* The new GOT is not executable. */ ++ if (htab->got != NULL ++ && !bfd_set_section_flags (htab->elf.dynobj, htab->got, flags)) ++ return -1; ++ } ++ else ++ { ++ /* Stop an unused .glink section from affecting .text alignment. */ ++ if (htab->glink != NULL ++ && !bfd_set_section_alignment (htab->elf.dynobj, htab->glink, 0)) ++ return -1; ++ } ++ return htab->plt_type == PLT_NEW; ++} ++ ++/* Return the section that should be marked against GC for a given ++ relocation. */ ++ ++static asection * ++ppc_elf_gc_mark_hook (asection *sec, ++ struct bfd_link_info *info, ++ Elf_Internal_Rela *rel, ++ struct elf_link_hash_entry *h, ++ Elf_Internal_Sym *sym) ++{ ++ if (h != NULL) ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_PPC_GNU_VTINHERIT: ++ case R_PPC_GNU_VTENTRY: ++ return NULL; ++ } ++ ++ return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); ++} ++ ++/* Update the got, plt and dynamic reloc reference counts for the ++ section being removed. */ ++ ++static bfd_boolean ++ppc_elf_gc_sweep_hook (bfd *abfd, ++ struct bfd_link_info *info, ++ asection *sec, ++ const Elf_Internal_Rela *relocs) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes; ++ bfd_signed_vma *local_got_refcounts; ++ const Elf_Internal_Rela *rel, *relend; ++ asection *got2; ++ ++ if (info->relocatable) ++ return TRUE; ++ ++ if ((sec->flags & SEC_ALLOC) == 0) ++ return TRUE; ++ ++ elf_section_data (sec)->local_dynrel = NULL; ++ ++ htab = ppc_elf_hash_table (info); ++ symtab_hdr = &elf_symtab_hdr (abfd); ++ sym_hashes = elf_sym_hashes (abfd); ++ local_got_refcounts = elf_local_got_refcounts (abfd); ++ got2 = bfd_get_section_by_name (abfd, ".got2"); ++ ++ relend = relocs + sec->reloc_count; ++ for (rel = relocs; rel < relend; rel++) ++ { ++ unsigned long r_symndx; ++ enum elf_ppc_reloc_type r_type; ++ struct elf_link_hash_entry *h = NULL; ++ ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ struct elf_dyn_relocs **pp, *p; ++ struct ppc_elf_link_hash_entry *eh; ++ ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ eh = (struct ppc_elf_link_hash_entry *) h; ++ ++ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) ++ if (p->sec == sec) ++ { ++ /* Everything must go for SEC. */ ++ *pp = p->next; ++ break; ++ } ++ } ++ ++ r_type = ELF32_R_TYPE (rel->r_info); ++ if (!htab->is_vxworks ++ && h == NULL ++ && local_got_refcounts != NULL ++ && (!info->shared ++ || is_branch_reloc (r_type))) ++ { ++ struct plt_entry **local_plt = (struct plt_entry **) ++ (local_got_refcounts + symtab_hdr->sh_info); ++ char *local_got_tls_masks = (char *) ++ (local_plt + symtab_hdr->sh_info); ++ if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) ++ { ++ struct plt_entry **ifunc = local_plt + r_symndx; ++ bfd_vma addend = 0; ++ struct plt_entry *ent; ++ ++ if (r_type == R_PPC_PLTREL24 && info->shared) ++ addend = rel->r_addend; ++ ent = find_plt_ent (ifunc, got2, addend); ++ if (ent->plt.refcount > 0) ++ ent->plt.refcount -= 1; ++ continue; ++ } ++ } ++ ++ switch (r_type) ++ { ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ case R_PPC_GOT_TLSLD16_HI: ++ case R_PPC_GOT_TLSLD16_HA: ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ case R_PPC_GOT_TLSGD16_HI: ++ case R_PPC_GOT_TLSGD16_HA: ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ case R_PPC_GOT_TPREL16_HI: ++ case R_PPC_GOT_TPREL16_HA: ++ case R_PPC_GOT_DTPREL16: ++ case R_PPC_GOT_DTPREL16_LO: ++ case R_PPC_GOT_DTPREL16_HI: ++ case R_PPC_GOT_DTPREL16_HA: ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ if (h != NULL) ++ { ++ if (h->got.refcount > 0) ++ h->got.refcount--; ++ if (!info->shared) ++ { ++ struct plt_entry *ent; ++ ++ ent = find_plt_ent (&h->plt.plist, NULL, 0); ++ if (ent != NULL && ent->plt.refcount > 0) ++ ent->plt.refcount -= 1; ++ } ++ } ++ else if (local_got_refcounts != NULL) ++ { ++ if (local_got_refcounts[r_symndx] > 0) ++ local_got_refcounts[r_symndx]--; ++ } ++ break; ++ ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ case R_PPC_REL32: ++ if (h == NULL || h == htab->elf.hgot) ++ break; ++ /* Fall thru */ ++ ++ case R_PPC_ADDR32: ++ case R_PPC_ADDR24: ++ case R_PPC_ADDR16: ++ case R_PPC_ADDR16_LO: ++ case R_PPC_ADDR16_HI: ++ case R_PPC_ADDR16_HA: ++ case R_PPC_ADDR14: ++ case R_PPC_ADDR14_BRTAKEN: ++ case R_PPC_ADDR14_BRNTAKEN: ++ case R_PPC_UADDR32: ++ case R_PPC_UADDR16: ++ if (info->shared) ++ break; ++ ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL24: ++ case R_PPC_PLTREL32: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++ if (h != NULL) ++ { ++ bfd_vma addend = 0; ++ struct plt_entry *ent; ++ ++ if (r_type == R_PPC_PLTREL24 && info->shared) ++ addend = rel->r_addend; ++ ent = find_plt_ent (&h->plt.plist, got2, addend); ++ if (ent != NULL && ent->plt.refcount > 0) ++ ent->plt.refcount -= 1; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ return TRUE; ++} ++ ++/* Set plt output section type, htab->tls_get_addr, and call the ++ generic ELF tls_setup function. */ ++ ++asection * ++ppc_elf_amigaos_tls_setup (bfd *obfd, ++ struct bfd_link_info *info, ++ int no_tls_get_addr_opt) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ ++ htab = ppc_elf_hash_table (info); ++ htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", ++ FALSE, FALSE, TRUE); ++ if (!no_tls_get_addr_opt) ++ { ++ struct elf_link_hash_entry *opt, *tga; ++ opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt", ++ FALSE, FALSE, TRUE); ++ if (opt != NULL ++ && (opt->root.type == bfd_link_hash_defined ++ || opt->root.type == bfd_link_hash_defweak)) ++ { ++ /* If glibc supports an optimized __tls_get_addr call stub, ++ signalled by the presence of __tls_get_addr_opt, and we'll ++ be calling __tls_get_addr via a plt call stub, then ++ make __tls_get_addr point to __tls_get_addr_opt. */ ++ tga = htab->tls_get_addr; ++ if (htab->elf.dynamic_sections_created ++ && tga != NULL ++ && (tga->type == STT_FUNC ++ || tga->needs_plt) ++ && !(SYMBOL_CALLS_LOCAL (info, tga) ++ || (ELF_ST_VISIBILITY (tga->other) != STV_DEFAULT ++ && tga->root.type == bfd_link_hash_undefweak))) ++ { ++ struct plt_entry *ent; ++ for (ent = tga->plt.plist; ent != NULL; ent = ent->next) ++ if (ent->plt.refcount > 0) ++ break; ++ if (ent != NULL) ++ { ++ tga->root.type = bfd_link_hash_indirect; ++ tga->root.u.i.link = &opt->root; ++ ppc_elf_copy_indirect_symbol (info, opt, tga); ++ if (opt->dynindx != -1) ++ { ++ /* Use __tls_get_addr_opt in dynamic relocations. */ ++ opt->dynindx = -1; ++ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, ++ opt->dynstr_index); ++ if (!bfd_elf_link_record_dynamic_symbol (info, opt)) ++ return FALSE; ++ } ++ htab->tls_get_addr = opt; ++ } ++ } ++ } ++ else ++ no_tls_get_addr_opt = TRUE; ++ } ++ htab->no_tls_get_addr_opt = no_tls_get_addr_opt; ++ if (htab->plt_type == PLT_NEW ++ && htab->plt != NULL ++ && htab->plt->output_section != NULL) ++ { ++ elf_section_type (htab->plt->output_section) = SHT_PROGBITS; ++ elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE; ++ } ++ ++ return _bfd_elf_tls_setup (obfd, info); ++} ++ ++/* Return TRUE iff REL is a branch reloc with a global symbol matching ++ HASH. */ ++ ++static bfd_boolean ++branch_reloc_hash_match (const bfd *ibfd, ++ const Elf_Internal_Rela *rel, ++ const struct elf_link_hash_entry *hash) ++{ ++ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); ++ enum elf_ppc_reloc_type r_type = ELF32_R_TYPE (rel->r_info); ++ unsigned int r_symndx = ELF32_R_SYM (rel->r_info); ++ ++ if (r_symndx >= symtab_hdr->sh_info && is_branch_reloc (r_type)) ++ { ++ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); ++ struct elf_link_hash_entry *h; ++ ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ if (h == hash) ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++/* Run through all the TLS relocs looking for optimization ++ opportunities. */ ++ ++bfd_boolean ++ppc_elf_amigaos_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *info) ++{ ++ bfd *ibfd; ++ asection *sec; ++ struct ppc_elf_link_hash_table *htab; ++ int pass; ++ ++ if (info->relocatable || !info->executable) ++ return TRUE; ++ ++ htab = ppc_elf_hash_table (info); ++ if (htab == NULL) ++ return FALSE; ++ ++ /* Make two passes through the relocs. First time check that tls ++ relocs involved in setting up a tls_get_addr call are indeed ++ followed by such a call. If they are not, don't do any tls ++ optimization. On the second pass twiddle tls_mask flags to ++ notify relocate_section that optimization can be done, and ++ adjust got and plt refcounts. */ ++ for (pass = 0; pass < 2; ++pass) ++ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) ++ { ++ Elf_Internal_Sym *locsyms = NULL; ++ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); ++ asection *got2 = bfd_get_section_by_name (ibfd, ".got2"); ++ ++ for (sec = ibfd->sections; sec != NULL; sec = sec->next) ++ if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) ++ { ++ Elf_Internal_Rela *relstart, *rel, *relend; ++ int expecting_tls_get_addr = 0; ++ ++ /* Read the relocations. */ ++ relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, ++ info->keep_memory); ++ if (relstart == NULL) ++ return FALSE; ++ ++ relend = relstart + sec->reloc_count; ++ for (rel = relstart; rel < relend; rel++) ++ { ++ enum elf_ppc_reloc_type r_type; ++ unsigned long r_symndx; ++ struct elf_link_hash_entry *h = NULL; ++ char *tls_mask; ++ char tls_set, tls_clear; ++ bfd_boolean is_local; ++ bfd_signed_vma *got_count; ++ ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ struct elf_link_hash_entry **sym_hashes; ++ ++ sym_hashes = elf_sym_hashes (ibfd); ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ } ++ ++ is_local = FALSE; ++ if (h == NULL ++ || !h->def_dynamic) ++ is_local = TRUE; ++ ++ r_type = ELF32_R_TYPE (rel->r_info); ++ /* If this section has old-style __tls_get_addr calls ++ without marker relocs, then check that each ++ __tls_get_addr call reloc is preceded by a reloc ++ that conceivably belongs to the __tls_get_addr arg ++ setup insn. If we don't find matching arg setup ++ relocs, don't do any tls optimization. */ ++ if (pass == 0 ++ && sec->has_tls_get_addr_call ++ && h != NULL ++ && h == htab->tls_get_addr ++ && !expecting_tls_get_addr ++ && is_branch_reloc (r_type)) ++ { ++ info->callbacks->minfo ("%H __tls_get_addr lost arg, " ++ "TLS optimization disabled\n", ++ ibfd, sec, rel->r_offset); ++ if (elf_section_data (sec)->relocs != relstart) ++ free (relstart); ++ return TRUE; ++ } ++ ++ expecting_tls_get_addr = 0; ++ switch (r_type) ++ { ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ expecting_tls_get_addr = 1; ++ /* Fall thru */ ++ ++ case R_PPC_GOT_TLSLD16_HI: ++ case R_PPC_GOT_TLSLD16_HA: ++ /* These relocs should never be against a symbol ++ defined in a shared lib. Leave them alone if ++ that turns out to be the case. */ ++ if (!is_local) ++ continue; ++ ++ /* LD -> LE */ ++ tls_set = 0; ++ tls_clear = TLS_LD; ++ break; ++ ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ expecting_tls_get_addr = 1; ++ /* Fall thru */ ++ ++ case R_PPC_GOT_TLSGD16_HI: ++ case R_PPC_GOT_TLSGD16_HA: ++ if (is_local) ++ /* GD -> LE */ ++ tls_set = 0; ++ else ++ /* GD -> IE */ ++ tls_set = TLS_TLS | TLS_TPRELGD; ++ tls_clear = TLS_GD; ++ break; ++ ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ case R_PPC_GOT_TPREL16_HI: ++ case R_PPC_GOT_TPREL16_HA: ++ if (is_local) ++ { ++ /* IE -> LE */ ++ tls_set = 0; ++ tls_clear = TLS_TPREL; ++ break; ++ } ++ else ++ continue; ++ ++ case R_PPC_TLSGD: ++ case R_PPC_TLSLD: ++ expecting_tls_get_addr = 2; ++ tls_set = 0; ++ tls_clear = 0; ++ break; ++ ++ default: ++ continue; ++ } ++ ++ if (pass == 0) ++ { ++ if (!expecting_tls_get_addr ++ || (expecting_tls_get_addr == 1 ++ && !sec->has_tls_get_addr_call)) ++ continue; ++ ++ if (rel + 1 < relend ++ && branch_reloc_hash_match (ibfd, rel + 1, ++ htab->tls_get_addr)) ++ continue; ++ ++ /* Uh oh, we didn't find the expected call. We ++ could just mark this symbol to exclude it ++ from tls optimization but it's safer to skip ++ the entire optimization. */ ++ info->callbacks->minfo (_("%H arg lost __tls_get_addr, " ++ "TLS optimization disabled\n"), ++ ibfd, sec, rel->r_offset); ++ if (elf_section_data (sec)->relocs != relstart) ++ free (relstart); ++ return TRUE; ++ } ++ ++ if (expecting_tls_get_addr) ++ { ++ struct plt_entry *ent; ++ bfd_vma addend = 0; ++ ++ if (info->shared ++ && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24) ++ addend = rel[1].r_addend; ++ ent = find_plt_ent (&htab->tls_get_addr->plt.plist, ++ got2, addend); ++ if (ent != NULL && ent->plt.refcount > 0) ++ ent->plt.refcount -= 1; ++ ++ if (expecting_tls_get_addr == 2) ++ continue; ++ } ++ ++ if (h != NULL) ++ { ++ tls_mask = &ppc_elf_hash_entry (h)->tls_mask; ++ got_count = &h->got.refcount; ++ } ++ else ++ { ++ bfd_signed_vma *lgot_refs; ++ struct plt_entry **local_plt; ++ char *lgot_masks; ++ ++ if (locsyms == NULL) ++ { ++ locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; ++ if (locsyms == NULL) ++ locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, ++ symtab_hdr->sh_info, ++ 0, NULL, NULL, NULL); ++ if (locsyms == NULL) ++ { ++ if (elf_section_data (sec)->relocs != relstart) ++ free (relstart); ++ return FALSE; ++ } ++ } ++ lgot_refs = elf_local_got_refcounts (ibfd); ++ if (lgot_refs == NULL) ++ abort (); ++ local_plt = (struct plt_entry **) ++ (lgot_refs + symtab_hdr->sh_info); ++ lgot_masks = (char *) (local_plt + symtab_hdr->sh_info); ++ tls_mask = &lgot_masks[r_symndx]; ++ got_count = &lgot_refs[r_symndx]; ++ } ++ ++ if (tls_set == 0) ++ { ++ /* We managed to get rid of a got entry. */ ++ if (*got_count > 0) ++ *got_count -= 1; ++ } ++ ++ *tls_mask |= tls_set; ++ *tls_mask &= ~tls_clear; ++ } ++ ++ if (elf_section_data (sec)->relocs != relstart) ++ free (relstart); ++ } ++ ++ if (locsyms != NULL ++ && (symtab_hdr->contents != (unsigned char *) locsyms)) ++ { ++ if (!info->keep_memory) ++ free (locsyms); ++ else ++ symtab_hdr->contents = (unsigned char *) locsyms; ++ } ++ } ++ return TRUE; ++} ++ ++/* Return true if we have dynamic relocs that apply to read-only sections. */ ++ ++static bfd_boolean ++readonly_dynrelocs (struct elf_link_hash_entry *h) ++{ ++ struct elf_dyn_relocs *p; ++ ++ for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) ++ { ++ asection *s = p->sec->output_section; ++ ++ if (s != NULL ++ && ((s->flags & (SEC_READONLY | SEC_ALLOC)) ++ == (SEC_READONLY | SEC_ALLOC))) ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++/* Adjust a symbol defined by a dynamic object and referenced by a ++ regular object. The current definition is in some section of the ++ dynamic object, but we're not including those sections. We have to ++ change the definition to something the rest of the link can ++ understand. */ ++ ++static bfd_boolean ++ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, ++ struct elf_link_hash_entry *h) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ asection *s; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n", ++ h->root.root.string); ++#endif ++ ++ /* Make sure we know what is going on here. */ ++ htab = ppc_elf_hash_table (info); ++ BFD_ASSERT (htab->elf.dynobj != NULL ++ && (h->needs_plt ++ || h->type == STT_GNU_IFUNC ++ || h->u.weakdef != NULL ++ || (h->def_dynamic ++ && h->ref_regular ++ && !h->def_regular))); ++ ++ /* Deal with function syms. */ ++ if (h->type == STT_FUNC ++ || h->type == STT_GNU_IFUNC ++ || h->needs_plt) ++ { ++ /* Clear procedure linkage table information for any symbol that ++ won't need a .plt entry. */ ++ struct plt_entry *ent; ++ for (ent = h->plt.plist; ent != NULL; ent = ent->next) ++ if (ent->plt.refcount > 0) ++ break; ++ if (ent == NULL ++ || (h->type != STT_GNU_IFUNC ++ && (SYMBOL_CALLS_LOCAL (info, h) ++ || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT ++ && h->root.type == bfd_link_hash_undefweak)))) ++ { ++ /* A PLT entry is not required/allowed when: ++ ++ 1. We are not using ld.so; because then the PLT entry ++ can't be set up, so we can't use one. In this case, ++ ppc_elf_adjust_dynamic_symbol won't even be called. ++ ++ 2. GC has rendered the entry unused. ++ ++ 3. We know for certain that a call to this symbol ++ will go to this object, or will remain undefined. */ ++ h->plt.plist = NULL; ++ h->needs_plt = 0; ++ } ++ else ++ { ++ /* After adjust_dynamic_symbol, non_got_ref set in the ++ non-shared case means that we have allocated space in ++ .dynbss for the symbol and thus dyn_relocs for this ++ symbol should be discarded. ++ If we get here we know we are making a PLT entry for this ++ symbol, and in an executable we'd normally resolve ++ relocations against this symbol to the PLT entry. Allow ++ dynamic relocs if the reference is weak, and the dynamic ++ relocs will not cause text relocation. */ ++ if (!h->ref_regular_nonweak ++ && h->non_got_ref ++ && h->type != STT_GNU_IFUNC ++ && !htab->is_vxworks ++ && !ppc_elf_hash_entry (h)->has_sda_refs ++ && !readonly_dynrelocs (h)) ++ h->non_got_ref = 0; ++ } ++ return TRUE; ++ } ++ else ++ h->plt.plist = NULL; ++ ++ /* If this is a weak symbol, and there is a real definition, the ++ processor independent code will have arranged for us to see the ++ real definition first, and we can just use the same value. */ ++ if (h->u.weakdef != NULL) ++ { ++ BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined ++ || h->u.weakdef->root.type == bfd_link_hash_defweak); ++ h->root.u.def.section = h->u.weakdef->root.u.def.section; ++ h->root.u.def.value = h->u.weakdef->root.u.def.value; ++ if (ELIMINATE_COPY_RELOCS) ++ h->non_got_ref = h->u.weakdef->non_got_ref; ++ return TRUE; ++ } ++ ++ /* This is a reference to a symbol defined by a dynamic object which ++ is not a function. */ ++ ++ /* If we are creating a shared library, we must presume that the ++ only references to the symbol are via the global offset table. ++ For such cases we need not do anything here; the relocations will ++ be handled correctly by relocate_section. */ ++ if (info->shared) ++ return TRUE; ++ ++ /* If there are no references to this symbol that do not use the ++ GOT, we don't need to generate a copy reloc. */ ++ if (!h->non_got_ref) ++ return TRUE; ++ ++ /* If we didn't find any dynamic relocs in read-only sections, then ++ we'll be keeping the dynamic relocs and avoiding the copy reloc. ++ We can't do this if there are any small data relocations. This ++ doesn't work on VxWorks, where we can not have dynamic ++ relocations (other than copy and jump slot relocations) in an ++ executable. */ ++ if (ELIMINATE_COPY_RELOCS ++ && !ppc_elf_hash_entry (h)->has_sda_refs ++ && !htab->is_vxworks ++ && !h->def_regular ++ && !readonly_dynrelocs (h)) ++ { ++ h->non_got_ref = 0; ++ return TRUE; ++ } ++ ++ /* We must allocate the symbol in our .dynbss section, which will ++ become part of the .bss section of the executable. There will be ++ an entry for this symbol in the .dynsym section. The dynamic ++ object will contain position independent code, so all references ++ from the dynamic object to this symbol will go through the global ++ offset table. The dynamic linker will use the .dynsym entry to ++ determine the address it must put in the global offset table, so ++ both the dynamic object and the regular object will refer to the ++ same memory location for the variable. ++ ++ Of course, if the symbol is referenced using SDAREL relocs, we ++ must instead allocate it in .sbss. */ ++ ++ if (ppc_elf_hash_entry (h)->has_sda_refs) ++ s = htab->dynsbss; ++ else ++ s = htab->dynbss; ++ BFD_ASSERT (s != NULL); ++ ++ /* We must generate a R_PPC_COPY reloc to tell the dynamic linker to ++ copy the initial value out of the dynamic object and into the ++ runtime process image. We need to remember the offset into the ++ .rela.bss section we are going to use. */ ++ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) ++ { ++ asection *srel; ++ ++ if (ppc_elf_hash_entry (h)->has_sda_refs) ++ srel = htab->relsbss; ++ else ++ srel = htab->relbss; ++ BFD_ASSERT (srel != NULL); ++ srel->size += sizeof (Elf32_External_Rela); ++ h->needs_copy = 1; ++ } ++ ++ return _bfd_elf_adjust_dynamic_copy (h, s); ++} ++ ++/* Generate a symbol to mark plt call stubs. For non-PIC code the sym is ++ xxxxxxxx.plt_call32.<callee> where xxxxxxxx is a hex number, usually 0, ++ specifying the addend on the plt relocation. For -fpic code, the sym ++ is xxxxxxxx.plt_pic32.<callee>, and for -fPIC ++ xxxxxxxx.got2.plt_pic32.<callee>. */ ++ ++static bfd_boolean ++add_stub_sym (struct plt_entry *ent, ++ struct elf_link_hash_entry *h, ++ struct bfd_link_info *info) ++{ ++ struct elf_link_hash_entry *sh; ++ size_t len1, len2, len3; ++ char *name; ++ const char *stub; ++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); ++ ++ if (info->shared) ++ stub = ".plt_pic32."; ++ else ++ stub = ".plt_call32."; ++ ++ len1 = strlen (h->root.root.string); ++ len2 = strlen (stub); ++ len3 = 0; ++ if (ent->sec) ++ len3 = strlen (ent->sec->name); ++ name = bfd_malloc (len1 + len2 + len3 + 9); ++ if (name == NULL) ++ return FALSE; ++ sprintf (name, "%08x", (unsigned) ent->addend & 0xffffffff); ++ if (ent->sec) ++ memcpy (name + 8, ent->sec->name, len3); ++ memcpy (name + 8 + len3, stub, len2); ++ memcpy (name + 8 + len3 + len2, h->root.root.string, len1 + 1); ++ sh = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); ++ if (sh == NULL) ++ return FALSE; ++ if (sh->root.type == bfd_link_hash_new) ++ { ++ sh->root.type = bfd_link_hash_defined; ++ sh->root.u.def.section = htab->glink; ++ sh->root.u.def.value = ent->glink_offset; ++ sh->ref_regular = 1; ++ sh->def_regular = 1; ++ sh->ref_regular_nonweak = 1; ++ sh->forced_local = 1; ++ sh->non_elf = 0; ++ } ++ return TRUE; ++} ++ ++/* Allocate NEED contiguous space in .got, and return the offset. ++ Handles allocation of the got header when crossing 32k. */ ++ ++static bfd_vma ++allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need) ++{ ++ bfd_vma where; ++ unsigned int max_before_header; ++ ++ if (htab->plt_type == PLT_VXWORKS) ++ { ++ where = htab->got->size; ++ htab->got->size += need; ++ } ++ else ++ { ++ max_before_header = htab->plt_type == PLT_NEW ? 32768 : 32764; ++ if (need <= htab->got_gap) ++ { ++ where = max_before_header - htab->got_gap; ++ htab->got_gap -= need; ++ } ++ else ++ { ++ if (htab->got->size + need > max_before_header ++ && htab->got->size <= max_before_header) ++ { ++ htab->got_gap = max_before_header - htab->got->size; ++ htab->got->size = max_before_header + htab->got_header_size; ++ } ++ where = htab->got->size; ++ htab->got->size += need; ++ } ++ } ++ return where; ++} ++ ++/* Allocate space in associated reloc sections for dynamic relocs. */ ++ ++static bfd_boolean ++allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) ++{ ++ struct bfd_link_info *info = inf; ++ struct ppc_elf_link_hash_entry *eh; ++ struct ppc_elf_link_hash_table *htab; ++ struct elf_dyn_relocs *p; ++ ++ if (h->root.type == bfd_link_hash_indirect) ++ return TRUE; ++ ++ htab = ppc_elf_hash_table (info); ++ if (htab->elf.dynamic_sections_created ++ || h->type == STT_GNU_IFUNC) ++ { ++ struct plt_entry *ent; ++ bfd_boolean doneone = FALSE; ++ bfd_vma plt_offset = 0, glink_offset = 0; ++ bfd_boolean dyn; ++ ++ for (ent = h->plt.plist; ent != NULL; ent = ent->next) ++ if (ent->plt.refcount > 0) ++ { ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1 ++ && !h->forced_local ++ && !h->def_regular ++ && htab->elf.dynamic_sections_created) ++ { ++ if (! bfd_elf_link_record_dynamic_symbol (info, h)) ++ return FALSE; ++ } ++ ++ dyn = htab->elf.dynamic_sections_created; ++ if (info->shared ++ || h->type == STT_GNU_IFUNC ++ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) ++ { ++ asection *s = htab->plt; ++ if (!dyn || h->dynindx == -1) ++ s = htab->iplt; ++ ++ if (htab->plt_type == PLT_NEW || !dyn || h->dynindx == -1) ++ { ++ if (!doneone) ++ { ++ plt_offset = s->size; ++ s->size += 4; ++ } ++ ent->plt.offset = plt_offset; ++ ++ s = htab->glink; ++ if (!doneone || info->shared) ++ { ++ glink_offset = s->size; ++ s->size += GLINK_ENTRY_SIZE; ++ if (h == htab->tls_get_addr ++ && !htab->no_tls_get_addr_opt) ++ s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE; ++ } ++ if (!doneone ++ && !info->shared ++ && h->def_dynamic ++ && !h->def_regular) ++ { ++ h->root.u.def.section = s; ++ h->root.u.def.value = glink_offset; ++ } ++ ent->glink_offset = glink_offset; ++ ++ if (htab->emit_stub_syms ++ && !add_stub_sym (ent, h, info)) ++ return FALSE; ++ } ++ else ++ { ++ if (!doneone) ++ { ++ /* If this is the first .plt entry, make room ++ for the special first entry. */ ++ if (s->size == 0) ++ s->size += htab->plt_initial_entry_size; ++ ++ /* The PowerPC PLT is actually composed of two ++ parts, the first part is 2 words (for a load ++ and a jump), and then there is a remaining ++ word available at the end. */ ++ plt_offset = (htab->plt_initial_entry_size ++ + (htab->plt_slot_size ++ * ((s->size ++ - htab->plt_initial_entry_size) ++ / htab->plt_entry_size))); ++ ++ /* If this symbol is not defined in a regular ++ file, and we are not generating a shared ++ library, then set the symbol to this location ++ in the .plt. This is to avoid text ++ relocations, and is required to make ++ function pointers compare as equal between ++ the normal executable and the shared library. */ ++ if (! info->shared ++ && h->def_dynamic ++ && !h->def_regular) ++ { ++ h->root.u.def.section = s; ++ h->root.u.def.value = plt_offset; ++ } ++ ++ /* Make room for this entry. */ ++ s->size += htab->plt_entry_size; ++ /* After the 8192nd entry, room for two entries ++ is allocated. */ ++ if (htab->plt_type == PLT_OLD ++ && (s->size - htab->plt_initial_entry_size) ++ / htab->plt_entry_size ++ > PLT_NUM_SINGLE_ENTRIES) ++ s->size += htab->plt_entry_size; ++ } ++ ent->plt.offset = plt_offset; ++ } ++ ++ /* We also need to make an entry in the .rela.plt section. */ ++ if (!doneone) ++ { ++ if (!htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ htab->reliplt->size += sizeof (Elf32_External_Rela); ++ else ++ { ++ htab->relplt->size += sizeof (Elf32_External_Rela); ++ ++ if (htab->plt_type == PLT_VXWORKS) ++ { ++ /* Allocate space for the unloaded relocations. */ ++ if (!info->shared ++ && htab->elf.dynamic_sections_created) ++ { ++ if (ent->plt.offset ++ == (bfd_vma) htab->plt_initial_entry_size) ++ { ++ htab->srelplt2->size ++ += (sizeof (Elf32_External_Rela) ++ * VXWORKS_PLTRESOLVE_RELOCS); ++ } ++ ++ htab->srelplt2->size ++ += (sizeof (Elf32_External_Rela) ++ * VXWORKS_PLT_NON_JMP_SLOT_RELOCS); ++ } ++ ++ /* Every PLT entry has an associated GOT entry in ++ .got.plt. */ ++ htab->sgotplt->size += 4; ++ } ++ } ++ doneone = TRUE; ++ } ++ } ++ else ++ ent->plt.offset = (bfd_vma) -1; ++ } ++ else ++ ent->plt.offset = (bfd_vma) -1; ++ ++ if (!doneone) ++ { ++ h->plt.plist = NULL; ++ h->needs_plt = 0; ++ } ++ } ++ else ++ { ++ h->plt.plist = NULL; ++ h->needs_plt = 0; ++ } ++ ++ eh = (struct ppc_elf_link_hash_entry *) h; ++ if (eh->elf.got.refcount > 0) ++ { ++ bfd_boolean dyn; ++ unsigned int need; ++ ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (eh->elf.dynindx == -1 ++ && !eh->elf.forced_local ++ && eh->elf.type != STT_GNU_IFUNC ++ && htab->elf.dynamic_sections_created) ++ { ++ if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf)) ++ return FALSE; ++ } ++ ++ need = 0; ++ if ((eh->tls_mask & TLS_TLS) != 0) ++ { ++ if ((eh->tls_mask & TLS_LD) != 0) ++ { ++ if (!eh->elf.def_dynamic) ++ /* We'll just use htab->tlsld_got.offset. This should ++ always be the case. It's a little odd if we have ++ a local dynamic reloc against a non-local symbol. */ ++ htab->tlsld_got.refcount += 1; ++ else ++ need += 8; ++ } ++ if ((eh->tls_mask & TLS_GD) != 0) ++ need += 8; ++ if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0) ++ need += 4; ++ if ((eh->tls_mask & TLS_DTPREL) != 0) ++ need += 4; ++ } ++ else ++ need += 4; ++ if (need == 0) ++ eh->elf.got.offset = (bfd_vma) -1; ++ else ++ { ++ eh->elf.got.offset = allocate_got (htab, need); ++ dyn = htab->elf.dynamic_sections_created; ++ if ((info->shared ++ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf)) ++ && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT ++ || eh->elf.root.type != bfd_link_hash_undefweak)) ++ { ++ asection *rsec = htab->relgot; ++ /* All the entries we allocated need relocs. ++ Except LD only needs one. */ ++ if ((eh->tls_mask & TLS_LD) != 0 ++ && eh->elf.def_dynamic) ++ need -= 4; ++ rsec->size += need * (sizeof (Elf32_External_Rela) / 4); ++ } ++ } ++ } ++ else ++ eh->elf.got.offset = (bfd_vma) -1; ++ ++ if (eh->dyn_relocs == NULL ++ || !htab->elf.dynamic_sections_created) ++ return TRUE; ++ ++ /* In the shared -Bsymbolic case, discard space allocated for ++ dynamic pc-relative relocs against symbols which turn out to be ++ defined in regular objects. For the normal shared case, discard ++ space for relocs that have become local due to symbol visibility ++ changes. */ ++ ++ if (info->shared) ++ { ++ /* Relocs that use pc_count are those that appear on a call insn, ++ or certain REL relocs (see must_be_dyn_reloc) that can be ++ generated via assembly. We want calls to protected symbols to ++ resolve directly to the function rather than going via the plt. ++ If people want function pointer comparisons to work as expected ++ then they should avoid writing weird assembly. */ ++ if (SYMBOL_CALLS_LOCAL (info, h)) ++ { ++ struct elf_dyn_relocs **pp; ++ ++ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) ++ { ++ p->count -= p->pc_count; ++ p->pc_count = 0; ++ if (p->count == 0) ++ *pp = p->next; ++ else ++ pp = &p->next; ++ } ++ } ++ ++ if (htab->is_vxworks) ++ { ++ struct elf_dyn_relocs **pp; ++ ++ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) ++ { ++ if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) ++ *pp = p->next; ++ else ++ pp = &p->next; ++ } ++ } ++ ++ /* Discard relocs on undefined symbols that must be local. */ ++ if (eh->dyn_relocs != NULL ++ && h->root.type == bfd_link_hash_undefined ++ && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN ++ || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)) ++ eh->dyn_relocs = NULL; ++ ++ /* Also discard relocs on undefined weak syms with non-default ++ visibility. */ ++ if (eh->dyn_relocs != NULL ++ && h->root.type == bfd_link_hash_undefweak) ++ { ++ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) ++ eh->dyn_relocs = NULL; ++ ++ /* Make sure undefined weak symbols are output as a dynamic ++ symbol in PIEs. */ ++ else if (h->dynindx == -1 ++ && !h->forced_local ++ && !h->def_regular) ++ { ++ if (! bfd_elf_link_record_dynamic_symbol (info, h)) ++ return FALSE; ++ } ++ } ++ } ++ else if (ELIMINATE_COPY_RELOCS) ++ { ++ /* For the non-shared case, discard space for relocs against ++ symbols which turn out to need copy relocs or are not ++ dynamic. */ ++ ++ if (!h->non_got_ref ++ && !h->def_regular) ++ { ++ /* Make sure this symbol is output as a dynamic symbol. ++ Undefined weak syms won't yet be marked as dynamic. */ ++ if (h->dynindx == -1 ++ && !h->forced_local) ++ { ++ if (! bfd_elf_link_record_dynamic_symbol (info, h)) ++ return FALSE; ++ } ++ ++ /* If that succeeded, we know we'll be keeping all the ++ relocs. */ ++ if (h->dynindx != -1) ++ goto keep; ++ } ++ ++ eh->dyn_relocs = NULL; ++ ++ keep: ; ++ } ++ ++ /* Finally, allocate space. */ ++ for (p = eh->dyn_relocs; p != NULL; p = p->next) ++ { ++ asection *sreloc = elf_section_data (p->sec)->sreloc; ++ if (!htab->elf.dynamic_sections_created) ++ sreloc = htab->reliplt; ++ sreloc->size += p->count * sizeof (Elf32_External_Rela); ++ } ++ ++ return TRUE; ++} ++ ++/* Set DF_TEXTREL if we find any dynamic relocs that apply to ++ read-only sections. */ ++ ++static bfd_boolean ++maybe_set_textrel (struct elf_link_hash_entry *h, void *info) ++{ ++ if (h->root.type == bfd_link_hash_indirect) ++ return TRUE; ++ ++ if (readonly_dynrelocs (h)) ++ { ++ ((struct bfd_link_info *) info)->flags |= DF_TEXTREL; ++ ++ /* Not an error, just cut short the traversal. */ ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++static const unsigned char glink_eh_frame_cie[] = ++{ ++ 0, 0, 0, 16, /* length. */ ++ 0, 0, 0, 0, /* id. */ ++ 1, /* CIE version. */ ++ 'z', 'R', 0, /* Augmentation string. */ ++ 4, /* Code alignment. */ ++ 0x7c, /* Data alignment. */ ++ 65, /* RA reg. */ ++ 1, /* Augmentation size. */ ++ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */ ++ DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */ ++}; ++ ++/* Set the sizes of the dynamic sections. */ ++ ++static bfd_boolean ++ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *info) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ asection *s; ++ bfd_boolean relocs; ++ bfd *ibfd; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections called\n"); ++#endif ++ ++ htab = ppc_elf_hash_table (info); ++ BFD_ASSERT (htab->elf.dynobj != NULL); ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections: dynamic_sections_created = %d\n", elf_hash_table (info)->dynamic_sections_created); ++#endif ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ /* Set the contents of the .interp section to the interpreter. */ ++ if (info->executable) ++ { ++ s = bfd_get_linker_section (htab->elf.dynobj, ".interp"); ++ BFD_ASSERT (s != NULL); ++ s->size = sizeof ELF_DYNAMIC_INTERPRETER; ++ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; ++ } ++ } ++ ++ if (htab->plt_type == PLT_OLD) ++ htab->got_header_size = 16; ++ else if (htab->plt_type == PLT_NEW) ++ htab->got_header_size = 12; ++ ++ /* Set up .got offsets for local syms, and space for local dynamic ++ relocs. */ ++ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) ++ { ++ bfd_signed_vma *local_got; ++ bfd_signed_vma *end_local_got; ++ struct plt_entry **local_plt; ++ struct plt_entry **end_local_plt; ++ char *lgot_masks; ++ bfd_size_type locsymcount; ++ Elf_Internal_Shdr *symtab_hdr; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections: is_ppc_elf() = %d (flavour = %d)\n", is_ppc_elf (ibfd), bfd_get_flavour (ibfd)); ++#endif ++ ++ if (!is_ppc_elf (ibfd)) ++ continue; ++ ++ for (s = ibfd->sections; s != NULL; s = s->next) ++ { ++ struct elf_dyn_relocs *p; ++ ++ for (p = ((struct elf_dyn_relocs *) ++ elf_section_data (s)->local_dynrel); ++ p != NULL; ++ p = p->next) ++ { ++ if (!bfd_is_abs_section (p->sec) ++ && bfd_is_abs_section (p->sec->output_section)) ++ { ++ /* Input section has been discarded, either because ++ it is a copy of a linkonce section or due to ++ linker script /DISCARD/, so we'll be discarding ++ the relocs too. */ ++ } ++ else if (htab->is_vxworks ++ && strcmp (p->sec->output_section->name, ++ ".tls_vars") == 0) ++ { ++ /* Relocations in vxworks .tls_vars sections are ++ handled specially by the loader. */ ++ } ++ else if (p->count != 0) ++ { ++ asection *sreloc = elf_section_data (p->sec)->sreloc; ++ if (!htab->elf.dynamic_sections_created) ++ sreloc = htab->reliplt; ++ sreloc->size += p->count * sizeof (Elf32_External_Rela); ++ if ((p->sec->output_section->flags ++ & (SEC_READONLY | SEC_ALLOC)) ++ == (SEC_READONLY | SEC_ALLOC)) ++ info->flags |= DF_TEXTREL; ++ } ++ } ++ } ++ ++ local_got = elf_local_got_refcounts (ibfd); ++ if (!local_got) ++ continue; ++ ++ symtab_hdr = &elf_symtab_hdr (ibfd); ++ locsymcount = symtab_hdr->sh_info; ++ end_local_got = local_got + locsymcount; ++ local_plt = (struct plt_entry **) end_local_got; ++ end_local_plt = local_plt + locsymcount; ++ lgot_masks = (char *) end_local_plt; ++ ++ for (; local_got < end_local_got; ++local_got, ++lgot_masks) ++ if (*local_got > 0) ++ { ++ unsigned int need = 0; ++ if ((*lgot_masks & TLS_TLS) != 0) ++ { ++ if ((*lgot_masks & TLS_GD) != 0) ++ need += 8; ++ if ((*lgot_masks & TLS_LD) != 0) ++ htab->tlsld_got.refcount += 1; ++ if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0) ++ need += 4; ++ if ((*lgot_masks & TLS_DTPREL) != 0) ++ need += 4; ++ } ++ else ++ need += 4; ++ if (need == 0) ++ *local_got = (bfd_vma) -1; ++ else ++ { ++ *local_got = allocate_got (htab, need); ++ if (info->shared) ++ htab->relgot->size += (need ++ * (sizeof (Elf32_External_Rela) / 4)); ++ } ++ } ++ else ++ *local_got = (bfd_vma) -1; ++ ++ if (htab->is_vxworks) ++ continue; ++ ++ /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */ ++ for (; local_plt < end_local_plt; ++local_plt) ++ { ++ struct plt_entry *ent; ++ bfd_boolean doneone = FALSE; ++ bfd_vma plt_offset = 0, glink_offset = 0; ++ ++ for (ent = *local_plt; ent != NULL; ent = ent->next) ++ if (ent->plt.refcount > 0) ++ { ++ s = htab->iplt; ++ ++ if (!doneone) ++ { ++ plt_offset = s->size; ++ s->size += 4; ++ } ++ ent->plt.offset = plt_offset; ++ ++ s = htab->glink; ++ if (!doneone || info->shared) ++ { ++ glink_offset = s->size; ++ s->size += GLINK_ENTRY_SIZE; ++ } ++ ent->glink_offset = glink_offset; ++ ++ if (!doneone) ++ { ++ htab->reliplt->size += sizeof (Elf32_External_Rela); ++ doneone = TRUE; ++ } ++ } ++ else ++ ent->plt.offset = (bfd_vma) -1; ++ } ++ } ++ ++ /* Allocate space for global sym dynamic relocs. */ ++ elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info); ++ ++ if (htab->tlsld_got.refcount > 0) ++ { ++ htab->tlsld_got.offset = allocate_got (htab, 8); ++ if (info->shared) ++ htab->relgot->size += sizeof (Elf32_External_Rela); ++ } ++ else ++ htab->tlsld_got.offset = (bfd_vma) -1; ++ ++ if (htab->got != NULL && htab->plt_type != PLT_VXWORKS) ++ { ++ unsigned int g_o_t = 32768; ++ ++ /* If we haven't allocated the header, do so now. When we get here, ++ for old plt/got the got size will be 0 to 32764 (not allocated), ++ or 32780 to 65536 (header allocated). For new plt/got, the ++ corresponding ranges are 0 to 32768 and 32780 to 65536. */ ++ if (htab->got->size <= 32768) ++ { ++ g_o_t = htab->got->size; ++ if (htab->plt_type == PLT_OLD) ++ g_o_t += 4; ++ htab->got->size += htab->got_header_size; ++ } ++ ++ htab->elf.hgot->root.u.def.value = g_o_t; ++ } ++ if (info->shared) ++ { ++ struct elf_link_hash_entry *sda = htab->sdata[0].sym; ++ if (sda != NULL ++ && !(sda->root.type == bfd_link_hash_defined ++ || sda->root.type == bfd_link_hash_defweak)) ++ { ++ sda->root.type = bfd_link_hash_defined; ++ sda->root.u.def.section = htab->elf.hgot->root.u.def.section; ++ sda->root.u.def.value = htab->elf.hgot->root.u.def.value; ++ } ++ } ++ ++ if (htab->glink != NULL ++ && htab->glink->size != 0 ++ && htab->elf.dynamic_sections_created) ++ { ++ htab->glink_pltresolve = htab->glink->size; ++ /* Space for the branch table. */ ++ htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4; ++ /* Pad out to align the start of PLTresolve. */ ++ htab->glink->size += -htab->glink->size & 15; ++ htab->glink->size += GLINK_PLTRESOLVE; ++ ++ if (htab->emit_stub_syms) ++ { ++ struct elf_link_hash_entry *sh; ++ sh = elf_link_hash_lookup (&htab->elf, "__glink", ++ TRUE, FALSE, FALSE); ++ if (sh == NULL) ++ return FALSE; ++ if (sh->root.type == bfd_link_hash_new) ++ { ++ sh->root.type = bfd_link_hash_defined; ++ sh->root.u.def.section = htab->glink; ++ sh->root.u.def.value = htab->glink_pltresolve; ++ sh->ref_regular = 1; ++ sh->def_regular = 1; ++ sh->ref_regular_nonweak = 1; ++ sh->forced_local = 1; ++ sh->non_elf = 0; ++ } ++ sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve", ++ TRUE, FALSE, FALSE); ++ if (sh == NULL) ++ return FALSE; ++ if (sh->root.type == bfd_link_hash_new) ++ { ++ sh->root.type = bfd_link_hash_defined; ++ sh->root.u.def.section = htab->glink; ++ sh->root.u.def.value = htab->glink->size - GLINK_PLTRESOLVE; ++ sh->ref_regular = 1; ++ sh->def_regular = 1; ++ sh->ref_regular_nonweak = 1; ++ sh->forced_local = 1; ++ sh->non_elf = 0; ++ } ++ } ++ } ++ ++ if (htab->glink != NULL ++ && htab->glink->size != 0 ++ && htab->glink_eh_frame != NULL ++ && !bfd_is_abs_section (htab->glink_eh_frame->output_section) ++ && _bfd_elf_eh_frame_present (info)) ++ { ++ s = htab->glink_eh_frame; ++ s->size = sizeof (glink_eh_frame_cie) + 20; ++ if (info->shared) ++ { ++ s->size += 4; ++ if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256) ++ s->size += 4; ++ } ++ } ++ ++ /* We've now determined the sizes of the various dynamic sections. ++ Allocate memory for them. */ ++ relocs = FALSE; ++ for (s = htab->elf.dynobj->sections; s != NULL; s = s->next) ++ { ++ bfd_boolean strip_section = TRUE; ++ ++ if ((s->flags & SEC_LINKER_CREATED) == 0) ++ continue; ++ ++ if (s == htab->plt ++ || s == htab->got) ++ { ++ /* We'd like to strip these sections if they aren't needed, but if ++ we've exported dynamic symbols from them we must leave them. ++ It's too late to tell BFD to get rid of the symbols. */ ++ if (htab->elf.hplt != NULL) ++ strip_section = FALSE; ++ /* Strip this section if we don't need it; see the ++ comment below. */ ++ } ++ else if (s == htab->iplt ++ || s == htab->glink ++ || s == htab->glink_eh_frame ++ || s == htab->sgotplt ++ || s == htab->sbss ++ || s == htab->dynbss ++ || s == htab->dynsbss ++ || s == htab->sdata[0].section ++ || s == htab->sdata[1].section) ++ { ++ /* Strip these too. */ ++ } ++ else if (CONST_STRNEQ (bfd_get_section_name (htab->elf.dynobj, s), ++ ".rela")) ++ { ++ if (s->size != 0) ++ { ++ /* Remember whether there are any relocation sections. */ ++ relocs = TRUE; ++ ++ /* We use the reloc_count field as a counter if we need ++ to copy relocs into the output file. */ ++ s->reloc_count = 0; ++ } ++ } ++ else ++ { ++ /* It's not one of our sections, so don't allocate space. */ ++ continue; ++ } ++ ++ if (s->size == 0 && strip_section) ++ { ++ /* If we don't need this section, strip it from the ++ output file. This is mostly to handle .rela.bss and ++ .rela.plt. We must create both sections in ++ create_dynamic_sections, because they must be created ++ before the linker maps input sections to output ++ sections. The linker does that before ++ adjust_dynamic_symbol is called, and it is that ++ function which decides whether anything needs to go ++ into these sections. */ ++ s->flags |= SEC_EXCLUDE; ++ continue; ++ } ++ ++ if ((s->flags & SEC_HAS_CONTENTS) == 0) ++ continue; ++ ++ /* Allocate memory for the section contents. */ ++ s->contents = bfd_zalloc (htab->elf.dynobj, s->size); ++ if (s->contents == NULL) ++ return FALSE; ++ } ++ ++ if (htab->elf.dynamic_sections_created) ++ { ++ /* Add some entries to the .dynamic section. We fill in the ++ values later, in ppc_elf_finish_dynamic_sections, but we ++ must add the entries now so that we get the correct size for ++ the .dynamic section. The DT_DEBUG entry is filled in by the ++ dynamic linker and used by the debugger. */ ++#define add_dynamic_entry(TAG, VAL) \ ++ _bfd_elf_add_dynamic_entry (info, TAG, VAL) ++ ++ if (info->executable) ++ { ++ if (!add_dynamic_entry (DT_DEBUG, 0)) ++ return FALSE; ++ } ++ ++ if (htab->plt != NULL && htab->plt->size != 0) ++ { ++ if (!add_dynamic_entry (DT_PLTGOT, 0) ++ || !add_dynamic_entry (DT_PLTRELSZ, 0) ++ || !add_dynamic_entry (DT_PLTREL, DT_RELA) ++ || !add_dynamic_entry (DT_JMPREL, 0)) ++ return FALSE; ++ } ++ ++ if (htab->glink != NULL && htab->glink->size != 0) ++ { ++ if (!add_dynamic_entry (DT_PPC_GOT, 0)) ++ return FALSE; ++ if (!htab->no_tls_get_addr_opt ++ && htab->tls_get_addr != NULL ++ && htab->tls_get_addr->plt.plist != NULL ++ && !add_dynamic_entry (DT_PPC_TLSOPT, 0)) ++ return FALSE; ++ } ++ ++ if (relocs) ++ { ++ if (!add_dynamic_entry (DT_RELA, 0) ++ || !add_dynamic_entry (DT_RELASZ, 0) ++ || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) ++ return FALSE; ++ } ++ ++ /* If any dynamic relocs apply to a read-only section, then we ++ need a DT_TEXTREL entry. */ ++ if ((info->flags & DF_TEXTREL) == 0) ++ elf_link_hash_traverse (elf_hash_table (info), maybe_set_textrel, ++ info); ++ ++ if ((info->flags & DF_TEXTREL) != 0) ++ { ++ if (!add_dynamic_entry (DT_TEXTREL, 0)) ++ return FALSE; ++ } ++ if (htab->is_vxworks ++ && !elf_vxworks_add_dynamic_entries (output_bfd, info)) ++ return FALSE; ++ ++ /* Flag it as a version 2 dynamic binary */ ++ if (!add_dynamic_entry(DT_AMIGAOS_DYNVERSION, 2)) ++ return FALSE; ++ } ++#undef add_dynamic_entry ++ ++ if (htab->glink_eh_frame != NULL ++ && htab->glink_eh_frame->contents != NULL) ++ { ++ unsigned char *p = htab->glink_eh_frame->contents; ++ bfd_vma val; ++ ++ memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); ++ /* CIE length (rewrite in case little-endian). */ ++ bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p); ++ p += sizeof (glink_eh_frame_cie); ++ /* FDE length. */ ++ val = htab->glink_eh_frame->size - 4 - sizeof (glink_eh_frame_cie); ++ bfd_put_32 (htab->elf.dynobj, val, p); ++ p += 4; ++ /* CIE pointer. */ ++ val = p - htab->glink_eh_frame->contents; ++ bfd_put_32 (htab->elf.dynobj, val, p); ++ p += 4; ++ /* Offset to .glink. Set later. */ ++ p += 4; ++ /* .glink size. */ ++ bfd_put_32 (htab->elf.dynobj, htab->glink->size, p); ++ p += 4; ++ /* Augmentation. */ ++ p += 1; ++ ++ if (info->shared ++ && htab->elf.dynamic_sections_created) ++ { ++ bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2; ++ if (adv < 64) ++ *p++ = DW_CFA_advance_loc + adv; ++ else if (adv < 256) ++ { ++ *p++ = DW_CFA_advance_loc1; ++ *p++ = adv; ++ } ++ else if (adv < 65536) ++ { ++ *p++ = DW_CFA_advance_loc2; ++ bfd_put_16 (htab->elf.dynobj, adv, p); ++ p += 2; ++ } ++ else ++ { ++ *p++ = DW_CFA_advance_loc4; ++ bfd_put_32 (htab->elf.dynobj, adv, p); ++ p += 4; ++ } ++ *p++ = DW_CFA_register; ++ *p++ = 65; ++ p++; ++ *p++ = DW_CFA_advance_loc + 4; ++ *p++ = DW_CFA_restore_extended; ++ *p++ = 65; ++ } ++ BFD_ASSERT ((bfd_vma) ((p + 3 - htab->glink_eh_frame->contents) & -4) ++ == htab->glink_eh_frame->size); ++ } ++ ++ return TRUE; ++} ++ ++/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ ++ ++static bfd_boolean ++ppc_elf_hash_symbol (struct elf_link_hash_entry *h) ++{ ++ if (h->plt.plist != NULL ++ && !h->def_regular ++ && (!h->pointer_equality_needed ++ || !h->ref_regular_nonweak)) ++ return FALSE; ++ ++ return _bfd_elf_hash_symbol (h); ++} ++ ++#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) ++ ++/* Relaxation trampolines. r12 is available for clobbering (r11, is ++ used for some functions that are allowed to break the ABI). */ ++static const int shared_stub_entry[] = ++ { ++ 0x7c0802a6, /* mflr 0 */ ++ 0x429f0005, /* bcl 20, 31, .Lxxx */ ++ 0x7d8802a6, /* mflr 12 */ ++ 0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */ ++ 0x398c0008, /* addi 12, 12, (xxx-.Lxxx)@l */ ++ 0x7c0803a6, /* mtlr 0 */ ++ 0x7d8903a6, /* mtctr 12 */ ++ 0x4e800420, /* bctr */ ++ }; ++ ++static const int stub_entry[] = ++ { ++ 0x3d800000, /* lis 12,xxx@ha */ ++ 0x398c0000, /* addi 12,12,xxx@l */ ++ 0x7d8903a6, /* mtctr 12 */ ++ 0x4e800420, /* bctr */ ++ }; ++ ++static bfd_boolean ++ppc_elf_relax_section (bfd *abfd, ++ asection *isec, ++ struct bfd_link_info *link_info, ++ bfd_boolean *again) ++{ ++ struct one_fixup ++ { ++ struct one_fixup *next; ++ asection *tsec; ++ /* Final link, can use the symbol offset. For a ++ relocatable link we use the symbol's index. */ ++ bfd_vma toff; ++ bfd_vma trampoff; ++ }; ++ ++ Elf_Internal_Shdr *symtab_hdr; ++ bfd_byte *contents = NULL; ++ Elf_Internal_Sym *isymbuf = NULL; ++ Elf_Internal_Rela *internal_relocs = NULL; ++ Elf_Internal_Rela *irel, *irelend; ++ struct one_fixup *fixups = NULL; ++ unsigned changes = 0; ++ struct ppc_elf_link_hash_table *htab; ++ bfd_size_type trampoff; ++ asection *got2; ++ bfd_boolean maybe_pasted; ++ ++ *again = FALSE; ++ ++ /* Nothing to do if there are no relocations, and no need to do ++ anything with non-alloc or non-code sections. */ ++ if ((isec->flags & SEC_ALLOC) == 0 ++ || (isec->flags & SEC_CODE) == 0 ++ || (isec->flags & SEC_RELOC) == 0 ++ || isec->reloc_count == 0) ++ return TRUE; ++ ++ /* We cannot represent the required PIC relocs in the output, so don't ++ do anything. The linker doesn't support mixing -shared and -r ++ anyway. */ ++ if (link_info->relocatable && link_info->shared) ++ return TRUE; ++ ++ trampoff = (isec->size + 3) & (bfd_vma) -4; ++ maybe_pasted = (strcmp (isec->output_section->name, ".init") == 0 ++ || strcmp (isec->output_section->name, ".fini") == 0); ++ /* Space for a branch around any trampolines. */ ++ if (maybe_pasted) ++ trampoff += 4; ++ ++ symtab_hdr = &elf_symtab_hdr (abfd); ++ ++ /* Get a copy of the native relocations. */ ++ internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, ++ link_info->keep_memory); ++ if (internal_relocs == NULL) ++ goto error_return; ++ ++ htab = ppc_elf_hash_table (link_info); ++ got2 = bfd_get_section_by_name (abfd, ".got2"); ++ ++ irelend = internal_relocs + isec->reloc_count; ++ for (irel = internal_relocs; irel < irelend; irel++) ++ { ++ unsigned long r_type = ELF32_R_TYPE (irel->r_info); ++ bfd_vma toff, roff; ++ asection *tsec; ++ struct one_fixup *f; ++ size_t insn_offset = 0; ++ bfd_vma max_branch_offset, val; ++ bfd_byte *hit_addr; ++ unsigned long t0; ++ struct elf_link_hash_entry *h; ++ struct plt_entry **plist; ++ unsigned char sym_type; ++ ++ switch (r_type) ++ { ++ case R_PPC_REL24: ++ case R_PPC_LOCAL24PC: ++ case R_PPC_PLTREL24: ++ max_branch_offset = 1 << 25; ++ break; ++ ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ max_branch_offset = 1 << 15; ++ break; ++ ++ default: ++ continue; ++ } ++ ++ /* Get the value of the symbol referred to by the reloc. */ ++ h = NULL; ++ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) ++ { ++ /* A local symbol. */ ++ Elf_Internal_Sym *isym; ++ ++ /* Read this BFD's local symbols. */ ++ if (isymbuf == NULL) ++ { ++ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; ++ if (isymbuf == NULL) ++ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, ++ symtab_hdr->sh_info, 0, ++ NULL, NULL, NULL); ++ if (isymbuf == 0) ++ goto error_return; ++ } ++ isym = isymbuf + ELF32_R_SYM (irel->r_info); ++ if (isym->st_shndx == SHN_UNDEF) ++ tsec = bfd_und_section_ptr; ++ else if (isym->st_shndx == SHN_ABS) ++ tsec = bfd_abs_section_ptr; ++ else if (isym->st_shndx == SHN_COMMON) ++ tsec = bfd_com_section_ptr; ++ else ++ tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); ++ ++ toff = isym->st_value; ++ sym_type = ELF_ST_TYPE (isym->st_info); ++ } ++ else ++ { ++ /* Global symbol handling. */ ++ unsigned long indx; ++ ++ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; ++ h = elf_sym_hashes (abfd)[indx]; ++ ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ ++ if (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ { ++ tsec = h->root.u.def.section; ++ toff = h->root.u.def.value; ++ } ++ else if (h->root.type == bfd_link_hash_undefined ++ || h->root.type == bfd_link_hash_undefweak) ++ { ++ tsec = bfd_und_section_ptr; ++ toff = link_info->relocatable ? indx : 0; ++ } ++ else ++ continue; ++ ++ sym_type = h->type; ++ } ++ ++ /* The condition here under which we call find_plt_ent must ++ match that in relocate_section. If we call find_plt_ent here ++ but not in relocate_section, or vice versa, then the branch ++ destination used here may be incorrect. */ ++ plist = NULL; ++ if (h != NULL) ++ { ++ /* We know is_branch_reloc (r_type) is true. */ ++ if (h->type == STT_GNU_IFUNC ++ || r_type == R_PPC_PLTREL24) ++ plist = &h->plt.plist; ++ } ++ else if (sym_type == STT_GNU_IFUNC ++ && elf_local_got_offsets (abfd) != NULL) ++ { ++ bfd_vma *local_got_offsets = elf_local_got_offsets (abfd); ++ struct plt_entry **local_plt = (struct plt_entry **) ++ (local_got_offsets + symtab_hdr->sh_info); ++ plist = local_plt + ELF32_R_SYM (irel->r_info); ++ } ++ if (plist != NULL) ++ { ++ bfd_vma addend = 0; ++ struct plt_entry *ent; ++ ++ if (r_type == R_PPC_PLTREL24 && link_info->shared) ++ addend = irel->r_addend; ++ ent = find_plt_ent (plist, got2, addend); ++ if (ent != NULL) ++ { ++ if (htab->plt_type == PLT_NEW ++ || h == NULL ++ || !htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ { ++ tsec = htab->glink; ++ toff = ent->glink_offset; ++ } ++ else ++ { ++ tsec = htab->plt; ++ toff = ent->plt.offset; ++ } ++ } ++ } ++ ++ /* If the branch and target are in the same section, you have ++ no hope of adding stubs. We'll error out later should the ++ branch overflow. */ ++ if (tsec == isec) ++ continue; ++ ++ /* There probably isn't any reason to handle symbols in ++ SEC_MERGE sections; SEC_MERGE doesn't seem a likely ++ attribute for a code section, and we are only looking at ++ branches. However, implement it correctly here as a ++ reference for other target relax_section functions. */ ++ if (0 && tsec->sec_info_type == SEC_INFO_TYPE_MERGE) ++ { ++ /* At this stage in linking, no SEC_MERGE symbol has been ++ adjusted, so all references to such symbols need to be ++ passed through _bfd_merged_section_offset. (Later, in ++ relocate_section, all SEC_MERGE symbols *except* for ++ section symbols have been adjusted.) ++ ++ gas may reduce relocations against symbols in SEC_MERGE ++ sections to a relocation against the section symbol when ++ the original addend was zero. When the reloc is against ++ a section symbol we should include the addend in the ++ offset passed to _bfd_merged_section_offset, since the ++ location of interest is the original symbol. On the ++ other hand, an access to "sym+addend" where "sym" is not ++ a section symbol should not include the addend; Such an ++ access is presumed to be an offset from "sym"; The ++ location of interest is just "sym". */ ++ if (sym_type == STT_SECTION) ++ toff += irel->r_addend; ++ ++ toff = _bfd_merged_section_offset (abfd, &tsec, ++ elf_section_data (tsec)->sec_info, ++ toff); ++ ++ if (sym_type != STT_SECTION) ++ toff += irel->r_addend; ++ } ++ /* PLTREL24 addends are special. */ ++ else if (r_type != R_PPC_PLTREL24) ++ toff += irel->r_addend; ++ ++ /* Attempted -shared link of non-pic code loses. */ ++ if (tsec->output_section == NULL) ++ continue; ++ ++ roff = irel->r_offset; ++ ++ /* If the branch is in range, no need to do anything. */ ++ if (tsec != bfd_und_section_ptr ++ && (!link_info->relocatable ++ /* A relocatable link may have sections moved during ++ final link, so do not presume they remain in range. */ ++ || tsec->output_section == isec->output_section)) ++ { ++ bfd_vma symaddr, reladdr; ++ ++ symaddr = tsec->output_section->vma + tsec->output_offset + toff; ++ reladdr = isec->output_section->vma + isec->output_offset + roff; ++ if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset) ++ continue; ++ } ++ ++ /* Look for an existing fixup to this address. */ ++ for (f = fixups; f ; f = f->next) ++ if (f->tsec == tsec && f->toff == toff) ++ break; ++ ++ if (f == NULL) ++ { ++ size_t size; ++ unsigned long stub_rtype; ++ ++ val = trampoff - roff; ++ if (val >= max_branch_offset) ++ /* Oh dear, we can't reach a trampoline. Don't try to add ++ one. We'll report an error later. */ ++ continue; ++ ++ if (link_info->shared) ++ { ++ size = 4 * ARRAY_SIZE (shared_stub_entry); ++ insn_offset = 12; ++ } ++ else ++ { ++ size = 4 * ARRAY_SIZE (stub_entry); ++ insn_offset = 0; ++ } ++ stub_rtype = R_PPC_RELAX; ++ if (tsec == htab->plt ++ || tsec == htab->glink) ++ { ++ stub_rtype = R_PPC_RELAX_PLT; ++ if (r_type == R_PPC_PLTREL24) ++ stub_rtype = R_PPC_RELAX_PLTREL24; ++ } ++ ++ /* Hijack the old relocation. Since we need two ++ relocations for this use a "composite" reloc. */ ++ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), ++ stub_rtype); ++ irel->r_offset = trampoff + insn_offset; ++ if (r_type == R_PPC_PLTREL24 ++ && stub_rtype != R_PPC_RELAX_PLTREL24) ++ irel->r_addend = 0; ++ ++ /* Record the fixup so we don't do it again this section. */ ++ f = bfd_malloc (sizeof (*f)); ++ f->next = fixups; ++ f->tsec = tsec; ++ f->toff = toff; ++ f->trampoff = trampoff; ++ fixups = f; ++ ++ trampoff += size; ++ changes++; ++ } ++ else ++ { ++ val = f->trampoff - roff; ++ if (val >= max_branch_offset) ++ continue; ++ ++ /* Nop out the reloc, since we're finalizing things here. */ ++ irel->r_info = ELF32_R_INFO (0, R_PPC_NONE); ++ } ++ ++ /* Get the section contents. */ ++ if (contents == NULL) ++ { ++ /* Get cached copy if it exists. */ ++ if (elf_section_data (isec)->this_hdr.contents != NULL) ++ contents = elf_section_data (isec)->this_hdr.contents; ++ else ++ { ++ /* Go get them off disk. */ ++ if (!bfd_malloc_and_get_section (abfd, isec, &contents)) ++ goto error_return; ++ } ++ } ++ ++ /* Fix up the existing branch to hit the trampoline. */ ++ hit_addr = contents + roff; ++ switch (r_type) ++ { ++ case R_PPC_REL24: ++ case R_PPC_LOCAL24PC: ++ case R_PPC_PLTREL24: ++ t0 = bfd_get_32 (abfd, hit_addr); ++ t0 &= ~0x3fffffc; ++ t0 |= val & 0x3fffffc; ++ bfd_put_32 (abfd, t0, hit_addr); ++ break; ++ ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ t0 = bfd_get_32 (abfd, hit_addr); ++ t0 &= ~0xfffc; ++ t0 |= val & 0xfffc; ++ bfd_put_32 (abfd, t0, hit_addr); ++ break; ++ } ++ } ++ ++ /* Write out the trampolines. */ ++ if (fixups != NULL) ++ { ++ const int *stub; ++ bfd_byte *dest; ++ int i, size; ++ ++ do ++ { ++ struct one_fixup *f = fixups; ++ fixups = fixups->next; ++ free (f); ++ } ++ while (fixups); ++ ++ contents = bfd_realloc_or_free (contents, trampoff); ++ if (contents == NULL) ++ goto error_return; ++ ++ isec->size = (isec->size + 3) & (bfd_vma) -4; ++ dest = contents + isec->size; ++ /* Branch around the trampolines. */ ++ if (maybe_pasted) ++ { ++ bfd_vma val = B + trampoff - isec->size; ++ bfd_put_32 (abfd, val, dest); ++ dest += 4; ++ } ++ isec->size = trampoff; ++ ++ if (link_info->shared) ++ { ++ stub = shared_stub_entry; ++ size = ARRAY_SIZE (shared_stub_entry); ++ } ++ else ++ { ++ stub = stub_entry; ++ size = ARRAY_SIZE (stub_entry); ++ } ++ ++ i = 0; ++ while (dest < contents + trampoff) ++ { ++ bfd_put_32 (abfd, stub[i], dest); ++ i++; ++ if (i == size) ++ i = 0; ++ dest += 4; ++ } ++ BFD_ASSERT (i == 0); ++ } ++ ++ if (isymbuf != NULL ++ && symtab_hdr->contents != (unsigned char *) isymbuf) ++ { ++ if (! link_info->keep_memory) ++ free (isymbuf); ++ else ++ { ++ /* Cache the symbols for elf_link_input_bfd. */ ++ symtab_hdr->contents = (unsigned char *) isymbuf; ++ } ++ } ++ ++ if (contents != NULL ++ && elf_section_data (isec)->this_hdr.contents != contents) ++ { ++ if (!changes && !link_info->keep_memory) ++ free (contents); ++ else ++ { ++ /* Cache the section contents for elf_link_input_bfd. */ ++ elf_section_data (isec)->this_hdr.contents = contents; ++ } ++ } ++ ++ if (changes != 0) ++ { ++ /* Append sufficient NOP relocs so we can write out relocation ++ information for the trampolines. */ ++ Elf_Internal_Shdr *rel_hdr; ++ Elf_Internal_Rela *new_relocs = bfd_malloc ((changes + isec->reloc_count) ++ * sizeof (*new_relocs)); ++ unsigned ix; ++ ++ if (!new_relocs) ++ goto error_return; ++ memcpy (new_relocs, internal_relocs, ++ isec->reloc_count * sizeof (*new_relocs)); ++ for (ix = changes; ix--;) ++ { ++ irel = new_relocs + ix + isec->reloc_count; ++ ++ irel->r_info = ELF32_R_INFO (0, R_PPC_NONE); ++ } ++ if (internal_relocs != elf_section_data (isec)->relocs) ++ free (internal_relocs); ++ elf_section_data (isec)->relocs = new_relocs; ++ isec->reloc_count += changes; ++ rel_hdr = _bfd_elf_single_rel_hdr (isec); ++ rel_hdr->sh_size += changes * rel_hdr->sh_entsize; ++ } ++ else if (elf_section_data (isec)->relocs != internal_relocs) ++ free (internal_relocs); ++ ++ *again = changes != 0; ++ if (!*again && link_info->relocatable) ++ { ++ /* Convert the internal relax relocs to external form. */ ++ for (irel = internal_relocs; irel < irelend; irel++) ++ if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX) ++ { ++ unsigned long r_symndx = ELF32_R_SYM (irel->r_info); ++ ++ /* Rewrite the reloc and convert one of the trailing nop ++ relocs to describe this relocation. */ ++ BFD_ASSERT (ELF32_R_TYPE (irelend[-1].r_info) == R_PPC_NONE); ++ /* The relocs are at the bottom 2 bytes */ ++ irel[0].r_offset += 2; ++ memmove (irel + 1, irel, (irelend - irel - 1) * sizeof (*irel)); ++ irel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); ++ irel[1].r_offset += 4; ++ irel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); ++ irel++; ++ } ++ } ++ ++ return TRUE; ++ ++ error_return: ++ if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) ++ free (isymbuf); ++ if (contents != NULL ++ && elf_section_data (isec)->this_hdr.contents != contents) ++ free (contents); ++ if (internal_relocs != NULL ++ && elf_section_data (isec)->relocs != internal_relocs) ++ free (internal_relocs); ++ return FALSE; ++} ++ ++/* What to do when ld finds relocations against symbols defined in ++ discarded sections. */ ++ ++static unsigned int ++ppc_elf_action_discarded (asection *sec) ++{ ++ if (strcmp (".fixup", sec->name) == 0) ++ return 0; ++ ++ if (strcmp (".got2", sec->name) == 0) ++ return 0; ++ ++ return _bfd_elf_default_action_discarded (sec); ++} ++ ++/* Fill in the address for a pointer generated in a linker section. */ ++ ++static bfd_vma ++elf_finish_pointer_linker_section (bfd *input_bfd, ++ elf_linker_section_t *lsect, ++ struct elf_link_hash_entry *h, ++ bfd_vma relocation, ++ const Elf_Internal_Rela *rel) ++{ ++ elf_linker_section_pointers_t *linker_section_ptr; ++ ++ BFD_ASSERT (lsect != NULL); ++ ++ if (h != NULL) ++ { ++ /* Handle global symbol. */ ++ struct ppc_elf_link_hash_entry *eh; ++ ++ eh = (struct ppc_elf_link_hash_entry *) h; ++ BFD_ASSERT (eh->elf.def_regular); ++ linker_section_ptr = eh->linker_section_pointer; ++ } ++ else ++ { ++ /* Handle local symbol. */ ++ unsigned long r_symndx = ELF32_R_SYM (rel->r_info); ++ ++ BFD_ASSERT (is_ppc_elf (input_bfd)); ++ BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL); ++ linker_section_ptr = elf_local_ptr_offsets (input_bfd)[r_symndx]; ++ } ++ ++ linker_section_ptr = elf_find_pointer_linker_section (linker_section_ptr, ++ rel->r_addend, ++ lsect); ++ BFD_ASSERT (linker_section_ptr != NULL); ++ ++ /* Offset will always be a multiple of four, so use the bottom bit ++ as a "written" flag. */ ++ if ((linker_section_ptr->offset & 1) == 0) ++ { ++ bfd_put_32 (lsect->section->owner, ++ relocation + linker_section_ptr->addend, ++ lsect->section->contents + linker_section_ptr->offset); ++ linker_section_ptr->offset += 1; ++ } ++ ++ relocation = (lsect->section->output_section->vma ++ + lsect->section->output_offset ++ + linker_section_ptr->offset - 1 ++ - SYM_VAL (lsect->sym)); ++ ++#ifdef DEBUG ++ fprintf (stderr, ++ "Finish pointer in linker section %s, offset = %ld (0x%lx)\n", ++ lsect->name, (long) relocation, (long) relocation); ++#endif ++ ++ return relocation; ++} ++ ++#define PPC_LO(v) ((v) & 0xffff) ++#define PPC_HI(v) (((v) >> 16) & 0xffff) ++#define PPC_HA(v) PPC_HI ((v) + 0x8000) ++ ++static void ++write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p, ++ struct bfd_link_info *info) ++{ ++ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); ++ bfd *output_bfd = info->output_bfd; ++ bfd_vma plt; ++ ++ plt = ((ent->plt.offset & ~1) ++ + plt_sec->output_section->vma ++ + plt_sec->output_offset); ++ ++ if (info->shared) ++ { ++ bfd_vma got = 0; ++ ++ if (ent->addend >= 32768) ++ got = (ent->addend ++ + ent->sec->output_section->vma ++ + ent->sec->output_offset); ++ else if (htab->elf.hgot != NULL) ++ got = SYM_VAL (htab->elf.hgot); ++ ++ plt -= got; ++ ++ if (plt + 0x8000 < 0x10000) ++ { ++ bfd_put_32 (output_bfd, LWZ_11_30 + PPC_LO (plt), p); ++ p += 4; ++ bfd_put_32 (output_bfd, MTCTR_11, p); ++ p += 4; ++ bfd_put_32 (output_bfd, BCTR, p); ++ p += 4; ++ bfd_put_32 (output_bfd, NOP, p); ++ p += 4; ++ } ++ else ++ { ++ bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (plt), p); ++ p += 4; ++ bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p); ++ p += 4; ++ bfd_put_32 (output_bfd, MTCTR_11, p); ++ p += 4; ++ bfd_put_32 (output_bfd, BCTR, p); ++ p += 4; ++ } ++ } ++ else ++ { ++ bfd_put_32 (output_bfd, LIS_11 + PPC_HA (plt), p); ++ p += 4; ++ bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p); ++ p += 4; ++ bfd_put_32 (output_bfd, MTCTR_11, p); ++ p += 4; ++ bfd_put_32 (output_bfd, BCTR, p); ++ p += 4; ++ } ++} ++ ++/* Return true if symbol is defined statically. */ ++ ++static bfd_boolean ++is_static_defined (struct elf_link_hash_entry *h) ++{ ++ return ((h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && h->root.u.def.section != NULL ++ && h->root.u.def.section->output_section != NULL); ++} ++ ++/* If INSN is an opcode that may be used with an @tls operand, return ++ the transformed insn for TLS optimisation, otherwise return 0. If ++ REG is non-zero only match an insn with RB or RA equal to REG. */ ++ ++unsigned int ++_bfd_elf_amigaos_ppc_at_tls_transform (unsigned int insn, unsigned int reg) ++{ ++ unsigned int rtra; ++ ++ if ((insn & (0x3f << 26)) != 31 << 26) ++ return 0; ++ ++ if (reg == 0 || ((insn >> 11) & 0x1f) == reg) ++ rtra = insn & ((1 << 26) - (1 << 16)); ++ else if (((insn >> 16) & 0x1f) == reg) ++ rtra = (insn & (0x1f << 21)) | ((insn & (0x1f << 11)) << 5); ++ else ++ return 0; ++ ++ if ((insn & (0x3ff << 1)) == 266 << 1) ++ /* add -> addi. */ ++ insn = 14 << 26; ++ else if ((insn & (0x1f << 1)) == 23 << 1 ++ && ((insn & (0x1f << 6)) < 14 << 6 ++ || ((insn & (0x1f << 6)) >= 16 << 6 ++ && (insn & (0x1f << 6)) < 24 << 6))) ++ /* load and store indexed -> dform. */ ++ insn = (32 | ((insn >> 6) & 0x1f)) << 26; ++ else if ((insn & (((0x1a << 5) | 0x1f) << 1)) == 21 << 1) ++ /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ ++ insn = ((58 | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1); ++ else if ((insn & (((0x1f << 5) | 0x1f) << 1)) == 341 << 1) ++ /* lwax -> lwa. */ ++ insn = (58 << 26) | 2; ++ else ++ return 0; ++ insn |= rtra; ++ return insn; ++} ++ ++/* If INSN is an opcode that may be used with an @tprel operand, return ++ the transformed insn for an undefined weak symbol, ie. with the ++ thread pointer REG operand removed. Otherwise return 0. */ ++ ++unsigned int ++_bfd_elf_amigaos_ppc_at_tprel_transform (unsigned int insn, unsigned int reg) ++{ ++ if ((insn & (0x1f << 16)) == reg << 16 ++ && ((insn & (0x3f << 26)) == 14u << 26 /* addi */ ++ || (insn & (0x3f << 26)) == 15u << 26 /* addis */ ++ || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ ++ || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ ++ || (insn & (0x3f << 26)) == 36u << 26 /* stw */ ++ || (insn & (0x3f << 26)) == 38u << 26 /* stb */ ++ || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ ++ || (insn & (0x3f << 26)) == 42u << 26 /* lha */ ++ || (insn & (0x3f << 26)) == 44u << 26 /* sth */ ++ || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ ++ || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ ++ || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ ++ || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ ++ || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ ++ || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ ++ || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */ ++ && (insn & 3) != 1) ++ || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */ ++ && ((insn & 3) == 0 || (insn & 3) == 3)))) ++ { ++ insn &= ~(0x1f << 16); ++ } ++ else if ((insn & (0x1f << 21)) == reg << 21 ++ && ((insn & (0x3e << 26)) == 24u << 26 /* ori, oris */ ++ || (insn & (0x3e << 26)) == 26u << 26 /* xori,xoris */ ++ || (insn & (0x3e << 26)) == 28u << 26 /* andi,andis */)) ++ { ++ insn &= ~(0x1f << 21); ++ insn |= (insn & (0x1f << 16)) << 5; ++ if ((insn & (0x3e << 26)) == 26 << 26 /* xori,xoris */) ++ insn -= 2 >> 26; /* convert to ori,oris */ ++ } ++ else ++ insn = 0; ++ return insn; ++} ++ ++static bfd_boolean ++is_insn_ds_form (unsigned int insn) ++{ ++ return ((insn & (0x3f << 26)) == 58u << 26 /* ld,ldu,lwa */ ++ || (insn & (0x3f << 26)) == 62u << 26 /* std,stdu,stq */ ++ || (insn & (0x3f << 26)) == 57u << 26 /* lfdp */ ++ || (insn & (0x3f << 26)) == 61u << 26 /* stfdp */); ++} ++ ++static bfd_boolean ++is_insn_dq_form (unsigned int insn) ++{ ++ return (insn & (0x3f << 26)) == 56u << 26; /* lq */ ++} ++ ++/* The RELOCATE_SECTION function is called by the ELF backend linker ++ to handle the relocations for a section. ++ ++ The relocs are always passed as Rela structures; if the section ++ actually uses Rel structures, the r_addend field will always be ++ zero. ++ ++ This function is responsible for adjust the section contents as ++ necessary, and (if using Rela relocs and generating a ++ relocatable output file) adjusting the reloc addend as ++ necessary. ++ ++ This function does not have to worry about setting the reloc ++ address or the reloc symbol index. ++ ++ LOCAL_SYMS is a pointer to the swapped in local symbols. ++ ++ LOCAL_SECTIONS is an array giving the section in the input file ++ corresponding to the st_shndx field of each local symbol. ++ ++ The global hash table entry for the global symbols can be found ++ via elf_sym_hashes (input_bfd). ++ ++ When generating relocatable output, this function must handle ++ STB_LOCAL/STT_SECTION symbols specially. The output symbol is ++ going to be the section symbol corresponding to the output ++ section, which means that the addend must be adjusted ++ accordingly. */ ++ ++static bfd_boolean ++ppc_elf_relocate_section (bfd *output_bfd, ++ struct bfd_link_info *info, ++ bfd *input_bfd, ++ asection *input_section, ++ bfd_byte *contents, ++ Elf_Internal_Rela *relocs, ++ Elf_Internal_Sym *local_syms, ++ asection **local_sections) ++{ ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes; ++ struct ppc_elf_link_hash_table *htab; ++ Elf_Internal_Rela *rel; ++ Elf_Internal_Rela *relend; ++ Elf_Internal_Rela outrel; ++ asection *got2, *sreloc = NULL; ++ bfd_vma *local_got_offsets; ++ bfd_boolean ret = TRUE; ++ bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0); ++ bfd_boolean is_vxworks_tls; ++ ++#ifdef DEBUG ++ _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, " ++ "%ld relocations%s", ++ input_bfd, input_section, ++ (long) input_section->reloc_count, ++ (info->relocatable) ? " (relocatable)" : ""); ++#endif ++ ++ got2 = bfd_get_section_by_name (input_bfd, ".got2"); ++ ++ /* Initialize howto table if not already done. */ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ ppc_elf_howto_init (); ++ ++ htab = ppc_elf_hash_table (info); ++ local_got_offsets = elf_local_got_offsets (input_bfd); ++ symtab_hdr = &elf_symtab_hdr (input_bfd); ++ sym_hashes = elf_sym_hashes (input_bfd); ++ /* We have to handle relocations in vxworks .tls_vars sections ++ specially, because the dynamic loader is 'weird'. */ ++ is_vxworks_tls = (htab->is_vxworks && info->shared ++ && !strcmp (input_section->output_section->name, ++ ".tls_vars")); ++ rel = relocs; ++ relend = relocs + input_section->reloc_count; ++ for (; rel < relend; rel++) ++ { ++ enum elf_ppc_reloc_type r_type; ++ bfd_vma addend; ++ bfd_reloc_status_type r; ++ Elf_Internal_Sym *sym; ++ asection *sec; ++ struct elf_link_hash_entry *h; ++ const char *sym_name; ++ reloc_howto_type *howto; ++ unsigned long r_symndx; ++ bfd_vma relocation; ++ bfd_vma branch_bit, from; ++ bfd_boolean unresolved_reloc; ++ bfd_boolean warned; ++ unsigned int tls_type, tls_mask, tls_gd; ++ struct plt_entry **ifunc; ++ ++ r_type = ELF32_R_TYPE (rel->r_info); ++ sym = NULL; ++ sec = NULL; ++ h = NULL; ++ unresolved_reloc = FALSE; ++ warned = FALSE; ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ ++ if (r_symndx < symtab_hdr->sh_info) ++ { ++ sym = local_syms + r_symndx; ++ sec = local_sections[r_symndx]; ++ sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); ++ ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); ++ } ++ else ++ { ++ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, ++ r_symndx, symtab_hdr, sym_hashes, ++ h, sec, relocation, ++ unresolved_reloc, warned); ++ ++ sym_name = h->root.root.string; ++ } ++ ++ if (sec != NULL && discarded_section (sec)) ++ { ++ /* For relocs against symbols from removed linkonce sections, ++ or sections discarded by a linker script, we just want the ++ section contents zeroed. Avoid any special processing. */ ++ howto = NULL; ++ if (r_type < R_PPC_max) ++ howto = ppc_elf_howto_table[r_type]; ++ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, ++ rel, 1, relend, howto, 0, contents); ++ } ++ ++ if (info->relocatable) ++ { ++ if (got2 != NULL ++ && r_type == R_PPC_PLTREL24 ++ && rel->r_addend != 0) ++ { ++ /* R_PPC_PLTREL24 is rather special. If non-zero, the ++ addend specifies the GOT pointer offset within .got2. */ ++ rel->r_addend += got2->output_offset; ++ } ++ continue; ++ } ++ ++ /* TLS optimizations. Replace instruction sequences and relocs ++ based on information we collected in tls_optimize. We edit ++ RELOCS so that --emit-relocs will output something sensible ++ for the final instruction stream. */ ++ tls_mask = 0; ++ tls_gd = 0; ++ if (h != NULL) ++ tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask; ++ else if (local_got_offsets != NULL) ++ { ++ struct plt_entry **local_plt; ++ char *lgot_masks; ++ local_plt ++ = (struct plt_entry **) (local_got_offsets + symtab_hdr->sh_info); ++ lgot_masks = (char *) (local_plt + symtab_hdr->sh_info); ++ tls_mask = lgot_masks[r_symndx]; ++ } ++ ++ /* Ensure reloc mapping code below stays sane. */ ++ if ((R_PPC_GOT_TLSLD16 & 3) != (R_PPC_GOT_TLSGD16 & 3) ++ || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TLSGD16_LO & 3) ++ || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TLSGD16_HI & 3) ++ || (R_PPC_GOT_TLSLD16_HA & 3) != (R_PPC_GOT_TLSGD16_HA & 3) ++ || (R_PPC_GOT_TLSLD16 & 3) != (R_PPC_GOT_TPREL16 & 3) ++ || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TPREL16_LO & 3) ++ || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TPREL16_HI & 3) ++ || (R_PPC_GOT_TLSLD16_HA & 3) != (R_PPC_GOT_TPREL16_HA & 3)) ++ abort (); ++ switch (r_type) ++ { ++ default: ++ break; ++ ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ if ((tls_mask & TLS_TLS) != 0 ++ && (tls_mask & TLS_TPREL) == 0) ++ { ++ bfd_vma insn; ++ ++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); ++ insn &= 31 << 21; ++ insn |= 0x3c020000; /* addis 0,2,0 */ ++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); ++ r_type = R_PPC_TPREL16_HA; ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ } ++ break; ++ ++ case R_PPC_TLS: ++ if ((tls_mask & TLS_TLS) != 0 ++ && (tls_mask & TLS_TPREL) == 0) ++ { ++ bfd_vma insn; ++ ++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset); ++ insn = _bfd_elf_ppc_at_tls_transform (insn, 2); ++ if (insn == 0) ++ abort (); ++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset); ++ r_type = R_PPC_TPREL16_LO; ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ ++ /* Was PPC_TLS which sits on insn boundary, now ++ PPC_TPREL16_LO which is at low-order half-word. */ ++ rel->r_offset += d_offset; ++ } ++ break; ++ ++ case R_PPC_GOT_TLSGD16_HI: ++ case R_PPC_GOT_TLSGD16_HA: ++ tls_gd = TLS_TPRELGD; ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) ++ goto tls_gdld_hi; ++ break; ++ ++ case R_PPC_GOT_TLSLD16_HI: ++ case R_PPC_GOT_TLSLD16_HA: ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) ++ { ++ tls_gdld_hi: ++ if ((tls_mask & tls_gd) != 0) ++ r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3) ++ + R_PPC_GOT_TPREL16); ++ else ++ { ++ bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); ++ rel->r_offset -= d_offset; ++ r_type = R_PPC_NONE; ++ } ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ } ++ break; ++ ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ tls_gd = TLS_TPRELGD; ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) ++ goto tls_ldgd_opt; ++ break; ++ ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) ++ { ++ unsigned int insn1, insn2; ++ bfd_vma offset; ++ ++ tls_ldgd_opt: ++ offset = (bfd_vma) -1; ++ /* If not using the newer R_PPC_TLSGD/LD to mark ++ __tls_get_addr calls, we must trust that the call ++ stays with its arg setup insns, ie. that the next ++ reloc is the __tls_get_addr call associated with ++ the current reloc. Edit both insns. */ ++ if (input_section->has_tls_get_addr_call ++ && rel + 1 < relend ++ && branch_reloc_hash_match (input_bfd, rel + 1, ++ htab->tls_get_addr)) ++ offset = rel[1].r_offset; ++ if ((tls_mask & tls_gd) != 0) ++ { ++ /* IE */ ++ insn1 = bfd_get_32 (output_bfd, ++ contents + rel->r_offset - d_offset); ++ insn1 &= (1 << 26) - 1; ++ insn1 |= 32 << 26; /* lwz */ ++ if (offset != (bfd_vma) -1) ++ { ++ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); ++ insn2 = 0x7c631214; /* add 3,3,2 */ ++ bfd_put_32 (output_bfd, insn2, contents + offset); ++ } ++ r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3) ++ + R_PPC_GOT_TPREL16); ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ } ++ else ++ { ++ /* LE */ ++ insn1 = 0x3c620000; /* addis 3,2,0 */ ++ if (tls_gd == 0) ++ { ++ /* Was an LD reloc. */ ++ for (r_symndx = 0; ++ r_symndx < symtab_hdr->sh_info; ++ r_symndx++) ++ if (local_sections[r_symndx] == sec) ++ break; ++ if (r_symndx >= symtab_hdr->sh_info) ++ r_symndx = STN_UNDEF; ++ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; ++ if (r_symndx != STN_UNDEF) ++ rel->r_addend -= (local_syms[r_symndx].st_value ++ + sec->output_offset ++ + sec->output_section->vma); ++ } ++ r_type = R_PPC_TPREL16_HA; ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ if (offset != (bfd_vma) -1) ++ { ++ rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO); ++ rel[1].r_offset = offset + d_offset; ++ rel[1].r_addend = rel->r_addend; ++ insn2 = 0x38630000; /* addi 3,3,0 */ ++ bfd_put_32 (output_bfd, insn2, contents + offset); ++ } ++ } ++ bfd_put_32 (output_bfd, insn1, ++ contents + rel->r_offset - d_offset); ++ if (tls_gd == 0) ++ { ++ /* We changed the symbol on an LD reloc. Start over ++ in order to get h, sym, sec etc. right. */ ++ rel--; ++ continue; ++ } ++ } ++ break; ++ ++ case R_PPC_TLSGD: ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) ++ { ++ unsigned int insn2; ++ bfd_vma offset = rel->r_offset; ++ ++ if ((tls_mask & TLS_TPRELGD) != 0) ++ { ++ /* IE */ ++ r_type = R_PPC_NONE; ++ insn2 = 0x7c631214; /* add 3,3,2 */ ++ } ++ else ++ { ++ /* LE */ ++ r_type = R_PPC_TPREL16_LO; ++ rel->r_offset += d_offset; ++ insn2 = 0x38630000; /* addi 3,3,0 */ ++ } ++ rel->r_info = ELF32_R_INFO (r_symndx, r_type); ++ bfd_put_32 (output_bfd, insn2, contents + offset); ++ /* Zap the reloc on the _tls_get_addr call too. */ ++ BFD_ASSERT (offset == rel[1].r_offset); ++ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); ++ } ++ break; ++ ++ case R_PPC_TLSLD: ++ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) ++ { ++ unsigned int insn2; ++ ++ for (r_symndx = 0; ++ r_symndx < symtab_hdr->sh_info; ++ r_symndx++) ++ if (local_sections[r_symndx] == sec) ++ break; ++ if (r_symndx >= symtab_hdr->sh_info) ++ r_symndx = STN_UNDEF; ++ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; ++ if (r_symndx != STN_UNDEF) ++ rel->r_addend -= (local_syms[r_symndx].st_value ++ + sec->output_offset ++ + sec->output_section->vma); ++ ++ rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO); ++ rel->r_offset += d_offset; ++ insn2 = 0x38630000; /* addi 3,3,0 */ ++ bfd_put_32 (output_bfd, insn2, ++ contents + rel->r_offset - d_offset); ++ /* Zap the reloc on the _tls_get_addr call too. */ ++ BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset); ++ rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); ++ rel--; ++ continue; ++ } ++ break; ++ } ++ ++ /* Handle other relocations that tweak non-addend part of insn. */ ++ branch_bit = 0; ++ switch (r_type) ++ { ++ default: ++ break; ++ ++ /* Branch taken prediction relocations. */ ++ case R_PPC_ADDR14_BRTAKEN: ++ case R_PPC_REL14_BRTAKEN: ++ branch_bit = BRANCH_PREDICT_BIT; ++ /* Fall thru */ ++ ++ /* Branch not taken prediction relocations. */ ++ case R_PPC_ADDR14_BRNTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ { ++ bfd_vma insn; ++ ++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset); ++ insn &= ~BRANCH_PREDICT_BIT; ++ insn |= branch_bit; ++ ++ from = (rel->r_offset ++ + input_section->output_offset ++ + input_section->output_section->vma); ++ ++ /* Invert 'y' bit if not the default. */ ++ if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0) ++ insn ^= BRANCH_PREDICT_BIT; ++ ++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset); ++ break; ++ } ++ } ++ ++ ifunc = NULL; ++ if (!htab->is_vxworks) ++ { ++ struct plt_entry *ent; ++ ++ if (h != NULL) ++ { ++ if (h->type == STT_GNU_IFUNC) ++ ifunc = &h->plt.plist; ++ } ++ else if (local_got_offsets != NULL ++ && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) ++ { ++ struct plt_entry **local_plt; ++ ++ local_plt = (struct plt_entry **) (local_got_offsets ++ + symtab_hdr->sh_info); ++ ifunc = local_plt + r_symndx; ++ } ++ ++ ent = NULL; ++ if (ifunc != NULL ++ && (!info->shared ++ || is_branch_reloc (r_type))) ++ { ++ addend = 0; ++ if (r_type == R_PPC_PLTREL24 && info->shared) ++ addend = rel->r_addend; ++ ent = find_plt_ent (ifunc, got2, addend); ++ } ++ if (ent != NULL) ++ { ++ if (h == NULL && (ent->plt.offset & 1) == 0) ++ { ++ Elf_Internal_Rela rela; ++ bfd_byte *loc; ++ ++ rela.r_offset = (htab->iplt->output_section->vma ++ + htab->iplt->output_offset ++ + ent->plt.offset); ++ rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); ++ rela.r_addend = relocation; ++ loc = htab->reliplt->contents; ++ loc += (htab->reliplt->reloc_count++ ++ * sizeof (Elf32_External_Rela)); ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ ++ ent->plt.offset |= 1; ++ } ++ if (h == NULL && (ent->glink_offset & 1) == 0) ++ { ++ unsigned char *p = ((unsigned char *) htab->glink->contents ++ + ent->glink_offset); ++ write_glink_stub (ent, htab->iplt, p, info); ++ ent->glink_offset |= 1; ++ } ++ ++ unresolved_reloc = FALSE; ++ if (htab->plt_type == PLT_NEW ++ || !htab->elf.dynamic_sections_created ++ || h == NULL) ++ relocation = (htab->glink->output_section->vma ++ + htab->glink->output_offset ++ + (ent->glink_offset & ~1)); ++ else ++ relocation = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + ent->plt.offset); ++ } ++ } ++ ++ addend = rel->r_addend; ++ tls_type = 0; ++ howto = NULL; ++ if (r_type < R_PPC_max) ++ howto = ppc_elf_howto_table[r_type]; ++ switch (r_type) ++ { ++ default: ++ info->callbacks->einfo ++ (_("%P: %B: unknown relocation type %d for symbol %s\n"), ++ input_bfd, (int) r_type, sym_name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ continue; ++ ++ case R_PPC_NONE: ++ case R_PPC_TLS: ++ case R_PPC_TLSGD: ++ case R_PPC_TLSLD: ++ case R_PPC_EMB_MRKREF: ++ case R_PPC_GNU_VTINHERIT: ++ case R_PPC_GNU_VTENTRY: ++ continue; ++ ++ /* GOT16 relocations. Like an ADDR16 using the symbol's ++ address in the GOT as relocation value instead of the ++ symbol's value itself. Also, create a GOT entry for the ++ symbol and put the symbol value there. */ ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ case R_PPC_GOT_TLSGD16_HI: ++ case R_PPC_GOT_TLSGD16_HA: ++ tls_type = TLS_TLS | TLS_GD; ++ goto dogot; ++ ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ case R_PPC_GOT_TLSLD16_HI: ++ case R_PPC_GOT_TLSLD16_HA: ++ tls_type = TLS_TLS | TLS_LD; ++ goto dogot; ++ ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ case R_PPC_GOT_TPREL16_HI: ++ case R_PPC_GOT_TPREL16_HA: ++ tls_type = TLS_TLS | TLS_TPREL; ++ goto dogot; ++ ++ case R_PPC_GOT_DTPREL16: ++ case R_PPC_GOT_DTPREL16_LO: ++ case R_PPC_GOT_DTPREL16_HI: ++ case R_PPC_GOT_DTPREL16_HA: ++ tls_type = TLS_TLS | TLS_DTPREL; ++ goto dogot; ++ ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ tls_mask = 0; ++ dogot: ++ { ++ /* Relocation is to the entry for this symbol in the global ++ offset table. */ ++ bfd_vma off; ++ bfd_vma *offp; ++ unsigned long indx; ++ ++ if (htab->got == NULL) ++ abort (); ++ ++ indx = 0; ++ if (tls_type == (TLS_TLS | TLS_LD) ++ && (h == NULL ++ || !h->def_dynamic)) ++ offp = &htab->tlsld_got.offset; ++ else if (h != NULL) ++ { ++ bfd_boolean dyn; ++ dyn = htab->elf.dynamic_sections_created; ++ if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) ++ || (info->shared ++ && SYMBOL_REFERENCES_LOCAL (info, h))) ++ /* This is actually a static link, or it is a ++ -Bsymbolic link and the symbol is defined ++ locally, or the symbol was forced to be local ++ because of a version file. */ ++ ; ++ else ++ { ++ BFD_ASSERT (h->dynindx != -1); ++ indx = h->dynindx; ++ unresolved_reloc = FALSE; ++ } ++ offp = &h->got.offset; ++ } ++ else ++ { ++ if (local_got_offsets == NULL) ++ abort (); ++ offp = &local_got_offsets[r_symndx]; ++ } ++ ++ /* The offset must always be a multiple of 4. We use the ++ least significant bit to record whether we have already ++ processed this entry. */ ++ off = *offp; ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ unsigned int tls_m = (tls_mask ++ & (TLS_LD | TLS_GD | TLS_DTPREL ++ | TLS_TPREL | TLS_TPRELGD)); ++ ++ if (offp == &htab->tlsld_got.offset) ++ tls_m = TLS_LD; ++ else if (h == NULL ++ || !h->def_dynamic) ++ tls_m &= ~TLS_LD; ++ ++ /* We might have multiple got entries for this sym. ++ Initialize them all. */ ++ do ++ { ++ int tls_ty = 0; ++ ++ if ((tls_m & TLS_LD) != 0) ++ { ++ tls_ty = TLS_TLS | TLS_LD; ++ tls_m &= ~TLS_LD; ++ } ++ else if ((tls_m & TLS_GD) != 0) ++ { ++ tls_ty = TLS_TLS | TLS_GD; ++ tls_m &= ~TLS_GD; ++ } ++ else if ((tls_m & TLS_DTPREL) != 0) ++ { ++ tls_ty = TLS_TLS | TLS_DTPREL; ++ tls_m &= ~TLS_DTPREL; ++ } ++ else if ((tls_m & (TLS_TPREL | TLS_TPRELGD)) != 0) ++ { ++ tls_ty = TLS_TLS | TLS_TPREL; ++ tls_m = 0; ++ } ++ ++ /* Generate relocs for the dynamic linker. */ ++ if ((info->shared || indx != 0) ++ && (offp == &htab->tlsld_got.offset ++ || h == NULL ++ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT ++ || h->root.type != bfd_link_hash_undefweak)) ++ { ++ asection *rsec = htab->relgot; ++ bfd_byte * loc; ++ ++ outrel.r_offset = (htab->got->output_section->vma ++ + htab->got->output_offset ++ + off); ++ outrel.r_addend = 0; ++ if (tls_ty & (TLS_LD | TLS_GD)) ++ { ++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32); ++ if (tls_ty == (TLS_TLS | TLS_GD)) ++ { ++ loc = rsec->contents; ++ loc += (rsec->reloc_count++ ++ * sizeof (Elf32_External_Rela)); ++ bfd_elf32_swap_reloca_out (output_bfd, ++ &outrel, loc); ++ outrel.r_offset += 4; ++ outrel.r_info ++ = ELF32_R_INFO (indx, R_PPC_DTPREL32); ++ } ++ } ++ else if (tls_ty == (TLS_TLS | TLS_DTPREL)) ++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32); ++ else if (tls_ty == (TLS_TLS | TLS_TPREL)) ++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_TPREL32); ++ else if (indx != 0) ++ outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT); ++ else if (ifunc != NULL) ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); ++ else ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ if (indx == 0 && tls_ty != (TLS_TLS | TLS_LD)) ++ { ++ outrel.r_addend += relocation; ++ if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL)) ++ outrel.r_addend -= htab->elf.tls_sec->vma; ++ } ++ loc = rsec->contents; ++ loc += (rsec->reloc_count++ ++ * sizeof (Elf32_External_Rela)); ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); ++ } ++ ++ /* Init the .got section contents if we're not ++ emitting a reloc. */ ++ else ++ { ++ bfd_vma value = relocation; ++ ++ if (tls_ty == (TLS_TLS | TLS_LD)) ++ value = 1; ++ else if (tls_ty != 0) ++ { ++ value -= htab->elf.tls_sec->vma + DTP_OFFSET; ++ if (tls_ty == (TLS_TLS | TLS_TPREL)) ++ value += DTP_OFFSET - TP_OFFSET; ++ ++ if (tls_ty == (TLS_TLS | TLS_GD)) ++ { ++ bfd_put_32 (output_bfd, value, ++ htab->got->contents + off + 4); ++ value = 1; ++ } ++ } ++ bfd_put_32 (output_bfd, value, ++ htab->got->contents + off); ++ } ++ ++ off += 4; ++ if (tls_ty & (TLS_LD | TLS_GD)) ++ off += 4; ++ } ++ while (tls_m != 0); ++ ++ off = *offp; ++ *offp = off | 1; ++ } ++ ++ if (off >= (bfd_vma) -2) ++ abort (); ++ ++ if ((tls_type & TLS_TLS) != 0) ++ { ++ if (tls_type != (TLS_TLS | TLS_LD)) ++ { ++ if ((tls_mask & TLS_LD) != 0 ++ && !(h == NULL ++ || !h->def_dynamic)) ++ off += 8; ++ if (tls_type != (TLS_TLS | TLS_GD)) ++ { ++ if ((tls_mask & TLS_GD) != 0) ++ off += 8; ++ if (tls_type != (TLS_TLS | TLS_DTPREL)) ++ { ++ if ((tls_mask & TLS_DTPREL) != 0) ++ off += 4; ++ } ++ } ++ } ++ } ++ ++ relocation = (htab->got->output_section->vma ++ + htab->got->output_offset ++ + off ++ - SYM_VAL (htab->elf.hgot)); ++ ++ /* Addends on got relocations don't make much sense. ++ x+off@got is actually x@got+off, and since the got is ++ generated by a hash table traversal, the value in the ++ got at entry m+n bears little relation to the entry m. */ ++ if (addend != 0) ++ info->callbacks->einfo ++ (_("%P: %H: non-zero addend on %s reloc against `%s'\n"), ++ input_bfd, input_section, rel->r_offset, ++ howto->name, ++ sym_name); ++ } ++ break; ++ ++ /* Relocations that need no special processing. */ ++ case R_PPC_LOCAL24PC: ++ /* It makes no sense to point a local relocation ++ at a symbol not in this object. */ ++ if (unresolved_reloc) ++ { ++ if (! (*info->callbacks->undefined_symbol) (info, ++ h->root.root.string, ++ input_bfd, ++ input_section, ++ rel->r_offset, ++ TRUE)) ++ return FALSE; ++ continue; ++ } ++ break; ++ ++ case R_PPC_DTPREL16: ++ case R_PPC_DTPREL16_LO: ++ case R_PPC_DTPREL16_HI: ++ case R_PPC_DTPREL16_HA: ++ addend -= htab->elf.tls_sec->vma + DTP_OFFSET; ++ break; ++ ++ /* Relocations that may need to be propagated if this is a shared ++ object. */ ++ case R_PPC_TPREL16: ++ case R_PPC_TPREL16_LO: ++ case R_PPC_TPREL16_HI: ++ case R_PPC_TPREL16_HA: ++ if (h != NULL ++ && h->root.type == bfd_link_hash_undefweak ++ && h->dynindx == -1) ++ { ++ /* Make this relocation against an undefined weak symbol ++ resolve to zero. This is really just a tweak, since ++ code using weak externs ought to check that they are ++ defined before using them. */ ++ bfd_byte *p = contents + rel->r_offset - d_offset; ++ unsigned int insn = bfd_get_32 (output_bfd, p); ++ insn = _bfd_elf_amigaos_ppc_at_tprel_transform (insn, 2); ++ if (insn != 0) ++ bfd_put_32 (output_bfd, insn, p); ++ break; ++ } ++ addend -= htab->elf.tls_sec->vma + TP_OFFSET; ++ /* The TPREL16 relocs shouldn't really be used in shared ++ libs as they will result in DT_TEXTREL being set, but ++ support them anyway. */ ++ goto dodyn; ++ ++ case R_PPC_TPREL32: ++ addend -= htab->elf.tls_sec->vma + TP_OFFSET; ++ goto dodyn; ++ ++ case R_PPC_DTPREL32: ++ addend -= htab->elf.tls_sec->vma + DTP_OFFSET; ++ goto dodyn; ++ ++ case R_PPC_DTPMOD32: ++ relocation = 1; ++ addend = 0; ++ goto dodyn; ++ ++ case R_PPC_REL16: ++ case R_PPC_REL16_LO: ++ case R_PPC_REL16_HI: ++ case R_PPC_REL16_HA: ++ break; ++ ++ case R_PPC_REL32: ++ if (h == NULL || h == htab->elf.hgot) ++ break; ++ /* fall through */ ++ ++ case R_PPC_ADDR32: ++ case R_PPC_ADDR16: ++ case R_PPC_ADDR16_LO: ++ case R_PPC_ADDR16_HI: ++ case R_PPC_ADDR16_HA: ++ case R_PPC_UADDR32: ++ case R_PPC_UADDR16: ++ goto dodyn; ++ ++ case R_PPC_VLE_REL8: ++ case R_PPC_VLE_REL15: ++ case R_PPC_VLE_REL24: ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ /* If these relocations are not to a named symbol, they can be ++ handled right here, no need to bother the dynamic linker. */ ++ if (SYMBOL_CALLS_LOCAL (info, h) ++ || h == htab->elf.hgot) ++ break; ++ /* fall through */ ++ ++ case R_PPC_ADDR24: ++ case R_PPC_ADDR14: ++ case R_PPC_ADDR14_BRTAKEN: ++ case R_PPC_ADDR14_BRNTAKEN: ++ if (h != NULL && !info->shared) ++ break; ++ /* fall through */ ++ ++ dodyn: ++ if ((input_section->flags & SEC_ALLOC) == 0 ++ || is_vxworks_tls) ++ break; ++ ++ if ((info->shared ++ && !(h != NULL ++ && ((h->root.type == bfd_link_hash_undefined ++ && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN ++ || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)) ++ || (h->root.type == bfd_link_hash_undefweak ++ && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT))) ++ && (must_be_dyn_reloc (info, r_type) ++ || !SYMBOL_CALLS_LOCAL (info, h))) ++ || (ELIMINATE_COPY_RELOCS ++ && !info->shared ++ && h != NULL ++ && h->dynindx != -1 ++ && !h->non_got_ref ++ && !h->def_regular)) ++ { ++ int skip; ++ bfd_byte * loc; ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_relocate_section needs to " ++ "create relocation for %s\n", ++ (h && h->root.root.string ++ ? h->root.root.string : "<unknown>")); ++#endif ++ ++ /* When generating a shared object, these relocations ++ are copied into the output file to be resolved at run ++ time. */ ++ if (sreloc == NULL) ++ { ++ sreloc = elf_section_data (input_section)->sreloc; ++ if (!htab->elf.dynamic_sections_created) ++ sreloc = htab->reliplt; ++ if (sreloc == NULL) ++ return FALSE; ++ } ++ ++ skip = 0; ++ outrel.r_offset = _bfd_elf_section_offset (output_bfd, info, ++ input_section, ++ rel->r_offset); ++ if (outrel.r_offset == (bfd_vma) -1 ++ || outrel.r_offset == (bfd_vma) -2) ++ skip = (int) outrel.r_offset; ++ outrel.r_offset += (input_section->output_section->vma ++ + input_section->output_offset); ++ ++ if (skip) ++ memset (&outrel, 0, sizeof outrel); ++ else if ((h != NULL ++ && (h->root.type == bfd_link_hash_undefined ++ || h->root.type == bfd_link_hash_undefweak)) ++ || !SYMBOL_REFERENCES_LOCAL (info, h)) ++ { ++ BFD_ASSERT (h->dynindx != -1); ++ unresolved_reloc = FALSE; ++ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); ++ outrel.r_addend = rel->r_addend; ++ } ++ else ++ { ++ outrel.r_addend = relocation + rel->r_addend; ++ ++ if (r_type != R_PPC_ADDR32) ++ { ++ long indx = 0; ++ ++ if (ifunc != NULL) ++ { ++ /* If we get here when building a static ++ executable, then the libc startup function ++ responsible for applying indirect function ++ relocations is going to complain about ++ the reloc type. ++ If we get here when building a dynamic ++ executable, it will be because we have ++ a text relocation. The dynamic loader ++ will set the text segment writable and ++ non-executable to apply text relocations. ++ So we'll segfault when trying to run the ++ indirection function to resolve the reloc. */ ++ info->callbacks->einfo ++ (_("%P: %H: relocation %s for indirect " ++ "function %s unsupported\n"), ++ input_bfd, input_section, rel->r_offset, ++ howto->name, ++ sym_name); ++ ret = FALSE; ++ } ++ else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec)) ++ ; ++ else if (sec == NULL || sec->owner == NULL) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ } ++ else ++ { ++ asection *osec; ++ ++ /* We are turning this relocation into one ++ against a section symbol. It would be ++ proper to subtract the symbol's value, ++ osec->vma, from the emitted reloc addend, ++ but ld.so expects buggy relocs. ++ FIXME: Why not always use a zero index? */ ++ osec = sec->output_section; ++ indx = elf_section_data (osec)->dynindx; ++ if (indx == 0) ++ { ++ osec = htab->elf.text_index_section; ++ indx = elf_section_data (osec)->dynindx; ++ } ++ BFD_ASSERT (indx != 0); ++#ifdef DEBUG ++ if (indx == 0) ++ printf ("indx=%ld section=%s flags=%08x name=%s\n", ++ indx, osec->name, osec->flags, ++ h->root.root.string); ++#endif ++ } ++ ++ outrel.r_info = ELF32_R_INFO (indx, r_type); ++ } ++ else if (ifunc != NULL) ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); ++ else ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ } ++ ++ loc = sreloc->contents; ++ loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); ++ ++ if (skip == -1) ++ continue; ++ ++ /* This reloc will be computed at runtime. We clear the memory ++ so that it contains predictable value. */ ++ if (! skip ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ || ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE)) ++ { ++ relocation = howto->pc_relative ? outrel.r_offset : 0; ++ addend = 0; ++ break; ++ } ++ } ++ break; ++ ++ case R_PPC_RELAX_PLT: ++ case R_PPC_RELAX_PLTREL24: ++ if (h != NULL) ++ { ++ struct plt_entry *ent; ++ bfd_vma got2_addend = 0; ++ ++ if (r_type == R_PPC_RELAX_PLTREL24) ++ { ++ if (info->shared) ++ got2_addend = addend; ++ addend = 0; ++ } ++ ent = find_plt_ent (&h->plt.plist, got2, got2_addend); ++ if (htab->plt_type == PLT_NEW) ++ relocation = (htab->glink->output_section->vma ++ + htab->glink->output_offset ++ + ent->glink_offset); ++ else ++ relocation = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + ent->plt.offset); ++ } ++ /* Fall thru */ ++ ++ case R_PPC_RELAX: ++ if (info->shared) ++ relocation -= (input_section->output_section->vma ++ + input_section->output_offset ++ + rel->r_offset - 4); ++ ++ { ++ unsigned long t0; ++ unsigned long t1; ++ ++ t0 = bfd_get_32 (output_bfd, contents + rel->r_offset); ++ t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4); ++ ++ /* We're clearing the bits for R_PPC_ADDR16_HA ++ and R_PPC_ADDR16_LO here. */ ++ t0 &= ~0xffff; ++ t1 &= ~0xffff; ++ ++ /* t0 is HA, t1 is LO */ ++ relocation += addend; ++ t0 |= ((relocation + 0x8000) >> 16) & 0xffff; ++ t1 |= relocation & 0xffff; ++ ++ bfd_put_32 (output_bfd, t0, contents + rel->r_offset); ++ bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4); ++ ++ /* Rewrite the reloc and convert one of the trailing nop ++ relocs to describe this relocation. */ ++ BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE); ++ /* The relocs are at the bottom 2 bytes */ ++ rel[0].r_offset += 2; ++ memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel)); ++ rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); ++ rel[1].r_offset += 4; ++ rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); ++ rel++; ++ } ++ continue; ++ ++ /* Indirect .sdata relocation. */ ++ case R_PPC_EMB_SDAI16: ++ BFD_ASSERT (htab->sdata[0].section != NULL); ++ if (!is_static_defined (htab->sdata[0].sym)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ relocation ++ = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[0], ++ h, relocation, rel); ++ addend = 0; ++ break; ++ ++ /* Indirect .sdata2 relocation. */ ++ case R_PPC_EMB_SDA2I16: ++ BFD_ASSERT (htab->sdata[1].section != NULL); ++ if (!is_static_defined (htab->sdata[1].sym)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ relocation ++ = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[1], ++ h, relocation, rel); ++ addend = 0; ++ break; ++ ++ /* Handle the TOC16 reloc. We want to use the offset within the .got ++ section, not the actual VMA. This is appropriate when generating ++ an embedded ELF object, for which the .got section acts like the ++ AIX .toc section. */ ++ case R_PPC_TOC16: /* phony GOT16 relocations */ ++ if (sec == NULL || sec->output_section == NULL) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ BFD_ASSERT (strcmp (bfd_get_section_name (sec->owner, sec), ++ ".got") == 0 ++ || strcmp (bfd_get_section_name (sec->owner, sec), ++ ".cgot") == 0); ++ ++ addend -= sec->output_section->vma + sec->output_offset + 0x8000; ++ break; ++ ++ case R_PPC_PLTREL24: ++ if (h != NULL && ifunc == NULL) ++ { ++ struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2, ++ info->shared ? addend : 0); ++ if (ent == NULL ++ || htab->plt == NULL) ++ { ++ /* We didn't make a PLT entry for this symbol. This ++ happens when statically linking PIC code, or when ++ using -Bsymbolic. */ ++ } ++ else ++ { ++ /* Relocation is to the entry for this symbol in the ++ procedure linkage table. */ ++ unresolved_reloc = FALSE; ++ if (htab->plt_type == PLT_NEW) ++ relocation = (htab->glink->output_section->vma ++ + htab->glink->output_offset ++ + ent->glink_offset); ++ else ++ relocation = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + ent->plt.offset); ++ } ++ } ++ ++ /* R_PPC_PLTREL24 is rather special. If non-zero, the ++ addend specifies the GOT pointer offset within .got2. ++ Don't apply it to the relocation field. */ ++ addend = 0; ++ break; ++ ++ /* Relocate against _SDA_BASE_. */ ++ case R_PPC_SDAREL16: ++ { ++ const char *name; ++ struct elf_link_hash_entry *sda = htab->sdata[0].sym; ++ ++ if (sec == NULL ++ || sec->output_section == NULL ++ || !is_static_defined (sda)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ addend -= SYM_VAL (sda); ++ ++ name = bfd_get_section_name (output_bfd, sec->output_section); ++ if (! ((CONST_STRNEQ (name, ".sdata") ++ && (name[6] == 0 || name[6] == '.')) ++ || (CONST_STRNEQ (name, ".sbss") ++ && (name[5] == 0 || name[5] == '.')))) ++ { ++ info->callbacks->einfo ++ (_("%P: %B: the target (%s) of a %s relocation is " ++ "in the wrong output section (%s)\n"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ } ++ } ++ break; ++ ++ /* Relocate against _SDA2_BASE_. */ ++ case R_PPC_EMB_SDA2REL: ++ { ++ const char *name; ++ struct elf_link_hash_entry *sda = htab->sdata[1].sym; ++ ++ if (sec == NULL ++ || sec->output_section == NULL ++ || !is_static_defined (sda)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ addend -= SYM_VAL (sda); ++ ++ name = bfd_get_section_name (output_bfd, sec->output_section); ++ if (! (CONST_STRNEQ (name, ".sdata2") ++ || CONST_STRNEQ (name, ".sbss2"))) ++ { ++ info->callbacks->einfo ++ (_("%P: %B: the target (%s) of a %s relocation is " ++ "in the wrong output section (%s)\n"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ } ++ } ++ break; ++#if 0 ++ case R_PPC_AMIGAOS_BREL: ++ case R_PPC_AMIGAOS_BREL_HI: ++ case R_PPC_AMIGAOS_BREL_LO: ++ case R_PPC_AMIGAOS_BREL_HA: ++ { ++ if (data_section == NULL) ++ data_section = bfd_get_section_by_name (output_bfd, ".data"); ++ ++ if (sec) ++ { ++ const char *name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sbss") != 0 ++ && strcmp (name, ".data") != 0 ++ && strcmp (name, ".bss") != 0 ++ && strncmp (name, ".ctors", 6) != 0 ++ && strncmp (name, ".dtors", 6) != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ } ++ } ++ ++ addend = addend - data_section->vma; ++ ++ if (r_type == R_PPC_AMIGAOS_BREL_HA) ++ addend += ((relocation + addend) & 0x8000) << 1; ++ ++ } ++ break; ++#endif ++ case R_PPC_VLE_LO16A: ++ relocation = (relocation + addend) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ relocation, split16a_type); ++ continue; ++ ++ case R_PPC_VLE_LO16D: ++ relocation = (relocation + addend) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ relocation, split16d_type); ++ continue; ++ ++ case R_PPC_VLE_HI16A: ++ relocation = ((relocation + addend) >> 16) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ relocation, split16a_type); ++ continue; ++ ++ case R_PPC_VLE_HI16D: ++ relocation = ((relocation + addend) >> 16) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ relocation, split16d_type); ++ continue; ++ ++ case R_PPC_VLE_HA16A: ++ { ++ bfd_vma value = relocation + addend; ++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16a_type); ++ } ++ continue; ++ ++ case R_PPC_VLE_HA16D: ++ { ++ bfd_vma value = relocation + addend; ++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16d_type); ++ } ++ continue; ++ ++ /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */ ++ case R_PPC_EMB_SDA21: ++ case R_PPC_VLE_SDA21: ++ case R_PPC_EMB_RELSDA: ++ case R_PPC_VLE_SDA21_LO: ++ { ++ const char *name; ++ int reg; ++ struct elf_link_hash_entry *sda = NULL; ++ ++ if (sec == NULL || sec->output_section == NULL) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ ++ name = bfd_get_section_name (output_bfd, sec->output_section); ++ if (((CONST_STRNEQ (name, ".sdata") ++ && (name[6] == 0 || name[6] == '.')) ++ || (CONST_STRNEQ (name, ".sbss") ++ && (name[5] == 0 || name[5] == '.')))) ++ { ++ reg = 13; ++ sda = htab->sdata[0].sym; ++ } ++ else if (CONST_STRNEQ (name, ".sdata2") ++ || CONST_STRNEQ (name, ".sbss2")) ++ { ++ reg = 2; ++ sda = htab->sdata[1].sym; ++ } ++ else if (strcmp (name, ".PPC.EMB.sdata0") == 0 ++ || strcmp (name, ".PPC.EMB.sbss0") == 0) ++ { ++ reg = 0; ++ } ++ else ++ { ++ info->callbacks->einfo ++ (_("%P: %B: the target (%s) of a %s relocation is " ++ "in the wrong output section (%s)\n"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ continue; ++ } ++ ++ if (sda != NULL) ++ { ++ if (!is_static_defined (sda)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ addend -= SYM_VAL (sda); ++ } ++ ++ if (reg == 0 ++ && (r_type == R_PPC_VLE_SDA21 ++ || r_type == R_PPC_VLE_SDA21_LO)) ++ { ++ /* Use the split20 format. */ ++ bfd_vma insn, bits12to15, bits21to31; ++ bfd_vma value = (relocation + rel->r_offset) & 0xffff; ++ /* Propagate sign bit, if necessary. */ ++ insn = (value & 0x8000) ? 0x70107800 : 0x70000000; ++ bits12to15 = value & 0x700; ++ bits21to31 = value & 0x7ff; ++ insn |= bits12to15; ++ insn |= bits21to31; ++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset); ++ continue; ++ } ++ else if (r_type == R_PPC_EMB_SDA21 ++ || r_type == R_PPC_VLE_SDA21 ++ || r_type == R_PPC_VLE_SDA21_LO) ++ { ++ bfd_vma insn; /* Fill in register field. */ ++ ++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset); ++ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); ++ bfd_put_32 (output_bfd, insn, contents + rel->r_offset); ++ } ++ } ++ break; ++ ++ case R_PPC_VLE_SDAREL_LO16A: ++ case R_PPC_VLE_SDAREL_LO16D: ++ case R_PPC_VLE_SDAREL_HI16A: ++ case R_PPC_VLE_SDAREL_HI16D: ++ case R_PPC_VLE_SDAREL_HA16A: ++ case R_PPC_VLE_SDAREL_HA16D: ++ { ++ bfd_vma value; ++ const char *name; ++ //int reg; ++ struct elf_link_hash_entry *sda = NULL; ++ ++ if (sec == NULL || sec->output_section == NULL) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ ++ name = bfd_get_section_name (output_bfd, sec->output_section); ++ if (((CONST_STRNEQ (name, ".sdata") ++ && (name[6] == 0 || name[6] == '.')) ++ || (CONST_STRNEQ (name, ".sbss") ++ && (name[5] == 0 || name[5] == '.')))) ++ { ++ //reg = 13; ++ sda = htab->sdata[0].sym; ++ } ++ else if (CONST_STRNEQ (name, ".sdata2") ++ || CONST_STRNEQ (name, ".sbss2")) ++ { ++ //reg = 2; ++ sda = htab->sdata[1].sym; ++ } ++ else ++ { ++ (*_bfd_error_handler) ++ (_("%B: the target (%s) of a %s relocation is " ++ "in the wrong output section (%s)"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ continue; ++ } ++ ++ if (sda != NULL) ++ { ++ if (!is_static_defined (sda)) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ } ++ ++ value = sda->root.u.def.section->output_section->vma ++ + sda->root.u.def.section->output_offset; ++ ++ if (r_type == R_PPC_VLE_SDAREL_LO16A) ++ { ++ value = (value + addend) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16a_type); ++ } ++ else if (r_type == R_PPC_VLE_SDAREL_LO16D) ++ { ++ value = (value + addend) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16d_type); ++ } ++ else if (r_type == R_PPC_VLE_SDAREL_HI16A) ++ { ++ value = ((value + addend) >> 16) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16a_type); ++ } ++ else if (r_type == R_PPC_VLE_SDAREL_HI16D) ++ { ++ value = ((value + addend) >> 16) & 0xffff; ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16d_type); ++ } ++ else if (r_type == R_PPC_VLE_SDAREL_HA16A) ++ { ++ value += addend; ++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16a_type); ++ } ++ else if (r_type == R_PPC_VLE_SDAREL_HA16D) ++ { ++ value += addend; ++ value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); ++ ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, ++ value, split16d_type); ++ } ++ } ++ continue; ++ ++ /* Relocate against the beginning of the section. */ ++ case R_PPC_SECTOFF: ++ case R_PPC_SECTOFF_LO: ++ case R_PPC_SECTOFF_HI: ++ case R_PPC_SECTOFF_HA: ++ if (sec == NULL || sec->output_section == NULL) ++ { ++ unresolved_reloc = TRUE; ++ break; ++ } ++ addend -= sec->output_section->vma; ++ break; ++ ++ /* Negative relocations. */ ++ case R_PPC_EMB_NADDR32: ++ case R_PPC_EMB_NADDR16: ++ case R_PPC_EMB_NADDR16_LO: ++ case R_PPC_EMB_NADDR16_HI: ++ case R_PPC_EMB_NADDR16_HA: ++ addend -= 2 * relocation; ++ break; ++ ++ case R_PPC_COPY: ++ case R_PPC_GLOB_DAT: ++ case R_PPC_JMP_SLOT: ++ case R_PPC_RELATIVE: ++ case R_PPC_IRELATIVE: ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL32: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++ case R_PPC_ADDR30: ++ case R_PPC_EMB_RELSEC16: ++ case R_PPC_EMB_RELST_LO: ++ case R_PPC_EMB_RELST_HI: ++ case R_PPC_EMB_RELST_HA: ++ case R_PPC_EMB_BIT_FLD: ++ info->callbacks->einfo ++ (_("%P: %B: relocation %s is not yet supported for symbol %s\n"), ++ input_bfd, ++ howto->name, ++ sym_name); ++ ++ bfd_set_error (bfd_error_invalid_operation); ++ ret = FALSE; ++ continue; ++ } ++ ++ /* Do any further special processing. */ ++ switch (r_type) ++ { ++ default: ++ break; ++ ++ case R_PPC_ADDR16_HA: ++ case R_PPC_REL16_HA: ++ case R_PPC_SECTOFF_HA: ++ case R_PPC_TPREL16_HA: ++ case R_PPC_DTPREL16_HA: ++ case R_PPC_EMB_NADDR16_HA: ++ case R_PPC_EMB_RELST_HA: ++ /* It's just possible that this symbol is a weak symbol ++ that's not actually defined anywhere. In that case, ++ 'sec' would be NULL, and we should leave the symbol ++ alone (it will be set to zero elsewhere in the link). */ ++ if (sec == NULL) ++ break; ++ /* Fall thru */ ++ ++ case R_PPC_PLT16_HA: ++ case R_PPC_GOT16_HA: ++ case R_PPC_GOT_TLSGD16_HA: ++ case R_PPC_GOT_TLSLD16_HA: ++ case R_PPC_GOT_TPREL16_HA: ++ case R_PPC_GOT_DTPREL16_HA: ++ /* Add 0x10000 if sign bit in 0:15 is set. ++ Bits 0:15 are not used. */ ++ addend += 0x8000; ++ break; ++ ++ case R_PPC_ADDR16: ++ case R_PPC_ADDR16_LO: ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_SDAREL16: ++ case R_PPC_SECTOFF: ++ case R_PPC_SECTOFF_LO: ++ case R_PPC_DTPREL16: ++ case R_PPC_DTPREL16_LO: ++ case R_PPC_TPREL16: ++ case R_PPC_TPREL16_LO: ++ case R_PPC_GOT_TLSGD16: ++ case R_PPC_GOT_TLSGD16_LO: ++ case R_PPC_GOT_TLSLD16: ++ case R_PPC_GOT_TLSLD16_LO: ++ case R_PPC_GOT_DTPREL16: ++ case R_PPC_GOT_DTPREL16_LO: ++ case R_PPC_GOT_TPREL16: ++ case R_PPC_GOT_TPREL16_LO: ++ { ++ /* The 32-bit ABI lacks proper relocations to deal with ++ certain 64-bit instructions. Prevent damage to bits ++ that make up part of the insn opcode. */ ++ unsigned int insn, mask, lobit; ++ ++ insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); ++ mask = 0; ++ if (is_insn_ds_form (insn)) ++ mask = 3; ++ else if (is_insn_dq_form (insn)) ++ mask = 15; ++ else ++ break; ++ lobit = mask & (relocation + addend); ++ if (lobit != 0) ++ { ++ addend -= lobit; ++ info->callbacks->einfo ++ (_("%P: %H: error: %s against `%s' not a multiple of %u\n"), ++ input_bfd, input_section, rel->r_offset, ++ howto->name, sym_name, mask + 1); ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ } ++ addend += insn & mask; ++ } ++ break; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, " ++ "offset = %ld, addend = %ld\n", ++ howto->name, ++ (int) r_type, ++ sym_name, ++ r_symndx, ++ (long) rel->r_offset, ++ (long) addend); ++#endif ++ ++ if (unresolved_reloc ++ && !((input_section->flags & SEC_DEBUGGING) != 0 ++ && h->def_dynamic) ++ && _bfd_elf_section_offset (output_bfd, info, input_section, ++ rel->r_offset) != (bfd_vma) -1) ++ { ++ info->callbacks->einfo ++ (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"), ++ input_bfd, input_section, rel->r_offset, ++ howto->name, ++ sym_name); ++ ret = FALSE; ++ } ++ ++ r = _bfd_final_link_relocate (howto, ++ input_bfd, ++ input_section, ++ contents, ++ rel->r_offset, ++ relocation, ++ addend); ++ ++#ifdef DEBUG ++ fprintf (stderr, "%p %p %p\n", (void *)rel->r_offset, (void *)relocation, (void *)addend); ++#endif ++ if (r != bfd_reloc_ok) ++ { ++ if (r == bfd_reloc_overflow) ++ { ++ if (warned) ++ continue; ++ if (h != NULL ++ && h->root.type == bfd_link_hash_undefweak ++ && howto->pc_relative) ++ { ++ /* Assume this is a call protected by other code that ++ detect the symbol is undefined. If this is the case, ++ we can safely ignore the overflow. If not, the ++ program is hosed anyway, and a little warning isn't ++ going to help. */ ++ ++ continue; ++ } ++ ++ if (! (*info->callbacks->reloc_overflow) (info, ++ (h ? &h->root : NULL), ++ sym_name, ++ howto->name, ++ rel->r_addend, ++ input_bfd, ++ input_section, ++ rel->r_offset)) ++ return FALSE; ++ } ++ else ++ { ++ info->callbacks->einfo ++ (_("%P: %H: %s reloc against `%s': error %d\n"), ++ input_bfd, input_section, rel->r_offset, ++ howto->name, sym_name, (int) r); ++ ret = FALSE; ++ } ++ } ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ return ret; ++} ++ ++/* Finish up dynamic symbol handling. We set the contents of various ++ dynamic sections here. */ ++ ++static bfd_boolean ++ppc_elf_finish_dynamic_symbol (bfd *output_bfd, ++ struct bfd_link_info *info, ++ struct elf_link_hash_entry *h, ++ Elf_Internal_Sym *sym) ++{ ++ struct ppc_elf_link_hash_table *htab; ++ struct plt_entry *ent; ++ bfd_boolean doneone; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s", ++ h->root.root.string); ++#endif ++ ++ htab = ppc_elf_hash_table (info); ++ BFD_ASSERT (htab->elf.dynobj != NULL); ++ ++ doneone = FALSE; ++ for (ent = h->plt.plist; ent != NULL; ent = ent->next) ++ if (ent->plt.offset != (bfd_vma) -1) ++ { ++ if (!doneone) ++ { ++ Elf_Internal_Rela rela; ++ bfd_byte *loc; ++ bfd_vma reloc_index; ++ ++ if (htab->plt_type == PLT_NEW ++ || !htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ reloc_index = ent->plt.offset / 4; ++ else ++ { ++ reloc_index = ((ent->plt.offset - htab->plt_initial_entry_size) ++ / htab->plt_slot_size); ++ if (reloc_index > PLT_NUM_SINGLE_ENTRIES ++ && htab->plt_type == PLT_OLD) ++ reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; ++ } ++ ++ /* This symbol has an entry in the procedure linkage table. ++ Set it up. */ ++ if (htab->plt_type == PLT_VXWORKS ++ && htab->elf.dynamic_sections_created ++ && h->dynindx != -1) ++ { ++ bfd_vma got_offset; ++ const bfd_vma *plt_entry; ++ ++ /* The first three entries in .got.plt are reserved. */ ++ got_offset = (reloc_index + 3) * 4; ++ ++ /* Use the right PLT. */ ++ plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry ++ : ppc_elf_vxworks_plt_entry; ++ ++ /* Fill in the .plt on VxWorks. */ ++ if (info->shared) ++ { ++ bfd_put_32 (output_bfd, ++ plt_entry[0] | PPC_HA (got_offset), ++ htab->plt->contents + ent->plt.offset + 0); ++ bfd_put_32 (output_bfd, ++ plt_entry[1] | PPC_LO (got_offset), ++ htab->plt->contents + ent->plt.offset + 4); ++ } ++ else ++ { ++ bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot); ++ ++ bfd_put_32 (output_bfd, ++ plt_entry[0] | PPC_HA (got_loc), ++ htab->plt->contents + ent->plt.offset + 0); ++ bfd_put_32 (output_bfd, ++ plt_entry[1] | PPC_LO (got_loc), ++ htab->plt->contents + ent->plt.offset + 4); ++ } ++ ++ bfd_put_32 (output_bfd, plt_entry[2], ++ htab->plt->contents + ent->plt.offset + 8); ++ bfd_put_32 (output_bfd, plt_entry[3], ++ htab->plt->contents + ent->plt.offset + 12); ++ ++ /* This instruction is an immediate load. The value loaded is ++ the byte offset of the R_PPC_JMP_SLOT relocation from the ++ start of the .rela.plt section. The value is stored in the ++ low-order 16 bits of the load instruction. */ ++ /* NOTE: It appears that this is now an index rather than a ++ prescaled offset. */ ++ bfd_put_32 (output_bfd, ++ plt_entry[4] | reloc_index, ++ htab->plt->contents + ent->plt.offset + 16); ++ /* This instruction is a PC-relative branch whose target is ++ the start of the PLT section. The address of this branch ++ instruction is 20 bytes beyond the start of this PLT entry. ++ The address is encoded in bits 6-29, inclusive. The value ++ stored is right-shifted by two bits, permitting a 26-bit ++ offset. */ ++ bfd_put_32 (output_bfd, ++ (plt_entry[5] ++ | (-(ent->plt.offset + 20) & 0x03fffffc)), ++ htab->plt->contents + ent->plt.offset + 20); ++ bfd_put_32 (output_bfd, plt_entry[6], ++ htab->plt->contents + ent->plt.offset + 24); ++ bfd_put_32 (output_bfd, plt_entry[7], ++ htab->plt->contents + ent->plt.offset + 28); ++ ++ /* Fill in the GOT entry corresponding to this PLT slot with ++ the address immediately after the "bctr" instruction ++ in this PLT entry. */ ++ bfd_put_32 (output_bfd, (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + ent->plt.offset + 16), ++ htab->sgotplt->contents + got_offset); ++ ++ if (!info->shared) ++ { ++ /* Fill in a couple of entries in .rela.plt.unloaded. */ ++ loc = htab->srelplt2->contents ++ + ((VXWORKS_PLTRESOLVE_RELOCS + reloc_index ++ * VXWORKS_PLT_NON_JMP_SLOT_RELOCS) ++ * sizeof (Elf32_External_Rela)); ++ ++ /* Provide the @ha relocation for the first instruction. */ ++ rela.r_offset = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + ent->plt.offset + 2); ++ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, ++ R_PPC_ADDR16_HA); ++ rela.r_addend = got_offset; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ loc += sizeof (Elf32_External_Rela); ++ ++ /* Provide the @l relocation for the second instruction. */ ++ rela.r_offset = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + ent->plt.offset + 6); ++ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, ++ R_PPC_ADDR16_LO); ++ rela.r_addend = got_offset; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ loc += sizeof (Elf32_External_Rela); ++ ++ /* Provide a relocation for the GOT entry corresponding to this ++ PLT slot. Point it at the middle of the .plt entry. */ ++ rela.r_offset = (htab->sgotplt->output_section->vma ++ + htab->sgotplt->output_offset ++ + got_offset); ++ rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx, ++ R_PPC_ADDR32); ++ rela.r_addend = ent->plt.offset + 16; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ } ++ ++ /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT. ++ In particular, the offset for the relocation is not the ++ address of the PLT entry for this function, as specified ++ by the ABI. Instead, the offset is set to the address of ++ the GOT slot for this function. See EABI 4.4.4.1. */ ++ rela.r_offset = (htab->sgotplt->output_section->vma ++ + htab->sgotplt->output_offset ++ + got_offset); ++ ++ } ++ else ++ { ++ asection *splt = htab->plt; ++ if (!htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ splt = htab->iplt; ++ ++ rela.r_offset = (splt->output_section->vma ++ + splt->output_offset ++ + ent->plt.offset); ++#ifdef DEBUG ++ fprintf (stderr, " r_offset = %p ", (void *)rela.r_offset); ++#endif ++ if (htab->plt_type == PLT_OLD ++ || !htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ { ++ /* We don't need to fill in the .plt. The ppc dynamic ++ linker will fill it in. */ ++#ifdef DEBUG ++ fprintf (stderr, " not filling in .plt "); ++#endif ++ } ++ else ++ { ++ bfd_vma val = (htab->glink_pltresolve + ent->plt.offset ++ + htab->glink->output_section->vma ++ + htab->glink->output_offset); ++ bfd_put_32 (output_bfd, val, ++ splt->contents + ent->plt.offset); ++ } ++ } ++ ++ /* Fill in the entry in the .rela.plt section. */ ++ rela.r_addend = 0; ++ if (!htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ { ++ BFD_ASSERT (h->type == STT_GNU_IFUNC ++ && h->def_regular ++ && (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak)); ++ rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); ++ rela.r_addend = SYM_VAL (h); ++ } ++ else ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); ++ ++ if (!htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ loc = (htab->reliplt->contents ++ + (htab->reliplt->reloc_count++ ++ * sizeof (Elf32_External_Rela))); ++ else ++ loc = (htab->relplt->contents ++ + reloc_index * sizeof (Elf32_External_Rela)); ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ ++#ifdef DEBUG ++ fprintf (stderr, " r_offset = %p r_addednd = %p, r_info = 0x%08x, h->def_regular = %d", (void *)rela.r_offset, (void *)rela.r_addend, (unsigned int)rela.r_info, (int)h->def_regular); ++#endif ++ if (!h->def_regular) ++ { ++ /* Mark the symbol as undefined, rather than as ++ defined in the .plt section. Leave the value if ++ there were any relocations where pointer equality ++ matters (this is a clue for the dynamic linker, to ++ make function pointer comparisons work between an ++ application and shared library), otherwise set it ++ to zero. */ ++ sym->st_shndx = SHN_UNDEF; ++ if (!h->pointer_equality_needed) ++ { ++ /* THF: This is peculiar. The compiler generates a R_PPC_REL24 for externally referenced ++ * symbols impoted from libc.so. Relocation in elf.library requires the symbol to have it's .plt ++ * stub value, but the linker specifically clears the value to 0, resulting in run-time ++ * errors when the binary tries to call libc functions. ++ */ ++ // sym->st_value = 0; ++ } ++ else if (!h->ref_regular_nonweak) ++ { ++ /* This breaks function pointer comparisons, but ++ that is better than breaking tests for a NULL ++ function pointer. */ ++ sym->st_value = 0; ++ } ++ } ++ else if (h->type == STT_GNU_IFUNC ++ && !info->shared) ++ { ++ /* Set the value of ifunc symbols in a non-pie ++ executable to the glink entry. This is to avoid ++ text relocations. We can't do this for ifunc in ++ allocate_dynrelocs, as we do for normal dynamic ++ function symbols with plt entries, because we need ++ to keep the original value around for the ifunc ++ relocation. */ ++ sym->st_shndx = (_bfd_elf_section_from_bfd_section ++ (output_bfd, htab->glink->output_section)); ++ sym->st_value = (ent->glink_offset ++ + htab->glink->output_offset ++ + htab->glink->output_section->vma); ++ } ++ doneone = TRUE; ++ } ++ ++ if (htab->plt_type == PLT_NEW ++ || !htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ { ++ unsigned char *p; ++ asection *splt = htab->plt; ++ if (!htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ splt = htab->iplt; ++ ++ p = (unsigned char *) htab->glink->contents + ent->glink_offset; ++ ++ if (h == htab->tls_get_addr && !htab->no_tls_get_addr_opt) ++ { ++ bfd_put_32 (output_bfd, LWZ_11_3, p); ++ p += 4; ++ bfd_put_32 (output_bfd, LWZ_12_3 + 4, p); ++ p += 4; ++ bfd_put_32 (output_bfd, MR_0_3, p); ++ p += 4; ++ bfd_put_32 (output_bfd, CMPWI_11_0, p); ++ p += 4; ++ bfd_put_32 (output_bfd, ADD_3_12_2, p); ++ p += 4; ++ bfd_put_32 (output_bfd, BEQLR, p); ++ p += 4; ++ bfd_put_32 (output_bfd, MR_3_0, p); ++ p += 4; ++ bfd_put_32 (output_bfd, NOP, p); ++ p += 4; ++ } ++ ++ write_glink_stub (ent, splt, p, info); ++ ++ if (!info->shared) ++ /* We only need one non-PIC glink stub. */ ++ break; ++ } ++ else ++ break; ++ } ++ ++ if (h->needs_copy) ++ { ++ asection *s; ++ Elf_Internal_Rela rela; ++ bfd_byte *loc; ++ ++ /* This symbols needs a copy reloc. Set it up. */ ++ ++#ifdef DEBUG ++ fprintf (stderr, ", copy"); ++#endif ++ ++ BFD_ASSERT (h->dynindx != -1); ++ ++ if (ppc_elf_hash_entry (h)->has_sda_refs) ++ s = htab->relsbss; ++ else ++ s = htab->relbss; ++ BFD_ASSERT (s != NULL); ++ ++ rela.r_offset = SYM_VAL (h); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY); ++ rela.r_addend = 0; ++ loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, " SYM_VAL(%p) ", (void *)SYM_VAL(h)); ++#endif ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ return TRUE; ++} ++ ++static enum elf_reloc_type_class ++ppc_elf_reloc_type_class (const Elf_Internal_Rela *rela) ++{ ++ switch (ELF32_R_TYPE (rela->r_info)) ++ { ++ case R_PPC_RELATIVE: ++ return reloc_class_relative; ++ case R_PPC_REL24: ++ case R_PPC_ADDR24: ++ case R_PPC_JMP_SLOT: ++ return reloc_class_plt; ++ case R_PPC_COPY: ++ return reloc_class_copy; ++ default: ++ return reloc_class_normal; ++ } ++} ++ ++/* Finish up the dynamic sections. */ ++ ++static bfd_boolean ++ppc_elf_finish_dynamic_sections (bfd *output_bfd, ++ struct bfd_link_info *info) ++{ ++ asection *sdyn; ++ asection *splt; ++ struct ppc_elf_link_hash_table *htab; ++ bfd_vma got; ++ bfd *dynobj; ++ bfd_boolean ret = TRUE; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); ++#endif ++ ++ htab = ppc_elf_hash_table (info); ++ dynobj = elf_hash_table (info)->dynobj; ++ sdyn = bfd_get_linker_section (dynobj, ".dynamic"); ++ if (htab->is_vxworks) ++ splt = bfd_get_linker_section (dynobj, ".plt"); ++ else ++ splt = NULL; ++ ++ got = 0; ++ if (htab->elf.hgot != NULL) ++ got = SYM_VAL (htab->elf.hgot); ++ ++ if (htab->elf.dynamic_sections_created) ++ { ++ Elf32_External_Dyn *dyncon, *dynconend; ++ ++ BFD_ASSERT (htab->plt != NULL && sdyn != NULL); ++ ++ dyncon = (Elf32_External_Dyn *) sdyn->contents; ++ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); ++ for (; dyncon < dynconend; dyncon++) ++ { ++ Elf_Internal_Dyn dyn; ++ asection *s; ++ ++ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); ++ ++ switch (dyn.d_tag) ++ { ++ case DT_PLTGOT: ++ if (htab->is_vxworks) ++ s = htab->sgotplt; ++ else ++ s = htab->plt; ++ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; ++ break; ++ ++ case DT_PLTRELSZ: ++ dyn.d_un.d_val = htab->relplt->size; ++ break; ++ ++ case DT_JMPREL: ++ s = htab->relplt; ++ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; ++ break; ++ ++ case DT_PPC_GOT: ++ dyn.d_un.d_ptr = got; ++ break; ++ ++ case DT_RELASZ: ++ if (htab->is_vxworks) ++ { ++ if (htab->relplt) ++ dyn.d_un.d_ptr -= htab->relplt->size; ++ break; ++ } ++ continue; ++ ++ default: ++ if (htab->is_vxworks ++ && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) ++ break; ++ continue; ++ } ++ ++ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); ++ } ++ } ++ ++ if (htab->got != NULL) ++ { ++ if (htab->elf.hgot->root.u.def.section == htab->got ++ || htab->elf.hgot->root.u.def.section == htab->sgotplt) ++ { ++ unsigned char *p = htab->elf.hgot->root.u.def.section->contents; ++ ++ p += htab->elf.hgot->root.u.def.value; ++ if (htab->plt_type == PLT_OLD) ++ { ++ /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 ++ so that a function can easily find the address of ++ _GLOBAL_OFFSET_TABLE_. */ ++ BFD_ASSERT (htab->elf.hgot->root.u.def.value - 4 ++ < htab->elf.hgot->root.u.def.section->size); ++ bfd_put_32 (output_bfd, 0x4e800021, p - 4); ++ } ++ ++ if (sdyn != NULL) ++ { ++ bfd_vma val = sdyn->output_section->vma + sdyn->output_offset; ++ BFD_ASSERT (htab->elf.hgot->root.u.def.value ++ < htab->elf.hgot->root.u.def.section->size); ++ bfd_put_32 (output_bfd, val, p); ++ } ++ } ++ else ++ { ++ info->callbacks->einfo (_("%P: %s not defined in linker created %s\n"), ++ htab->elf.hgot->root.root.string, ++ (htab->sgotplt != NULL ++ ? htab->sgotplt->name : htab->got->name)); ++ bfd_set_error (bfd_error_bad_value); ++ ret = FALSE; ++ } ++ ++ elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4; ++ } ++ ++ /* Fill in the first entry in the VxWorks procedure linkage table. */ ++ if (splt && splt->size > 0) ++ { ++ /* Use the right PLT. */ ++ const bfd_vma *plt_entry = (info->shared ++ ? ppc_elf_vxworks_pic_plt0_entry ++ : ppc_elf_vxworks_plt0_entry); ++ ++ if (!info->shared) ++ { ++ bfd_vma got_value = SYM_VAL (htab->elf.hgot); ++ ++ bfd_put_32 (output_bfd, plt_entry[0] | PPC_HA (got_value), ++ splt->contents + 0); ++ bfd_put_32 (output_bfd, plt_entry[1] | PPC_LO (got_value), ++ splt->contents + 4); ++ } ++ else ++ { ++ bfd_put_32 (output_bfd, plt_entry[0], splt->contents + 0); ++ bfd_put_32 (output_bfd, plt_entry[1], splt->contents + 4); ++ } ++ bfd_put_32 (output_bfd, plt_entry[2], splt->contents + 8); ++ bfd_put_32 (output_bfd, plt_entry[3], splt->contents + 12); ++ bfd_put_32 (output_bfd, plt_entry[4], splt->contents + 16); ++ bfd_put_32 (output_bfd, plt_entry[5], splt->contents + 20); ++ bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24); ++ bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28); ++ ++ if (! info->shared) ++ { ++ Elf_Internal_Rela rela; ++ bfd_byte *loc; ++ ++ loc = htab->srelplt2->contents; ++ ++ /* Output the @ha relocation for the first instruction. */ ++ rela.r_offset = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + 2); ++ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); ++ rela.r_addend = 0; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ loc += sizeof (Elf32_External_Rela); ++ ++ /* Output the @l relocation for the second instruction. */ ++ rela.r_offset = (htab->plt->output_section->vma ++ + htab->plt->output_offset ++ + 6); ++ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); ++ rela.r_addend = 0; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); ++ loc += sizeof (Elf32_External_Rela); ++ ++ /* Fix up the remaining relocations. They may have the wrong ++ symbol index for _G_O_T_ or _P_L_T_ depending on the order ++ in which symbols were output. */ ++ while (loc < htab->srelplt2->contents + htab->srelplt2->size) ++ { ++ Elf_Internal_Rela rel; ++ ++ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); ++ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); ++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); ++ loc += sizeof (Elf32_External_Rela); ++ ++ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); ++ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); ++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); ++ loc += sizeof (Elf32_External_Rela); ++ ++ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); ++ rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_PPC_ADDR32); ++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); ++ loc += sizeof (Elf32_External_Rela); ++ } ++ } ++ } ++ ++ if (htab->glink != NULL ++ && htab->glink->contents != NULL ++ && htab->elf.dynamic_sections_created) ++ { ++ unsigned char *p; ++ unsigned char *endp; ++ bfd_vma res0; ++ unsigned int i; ++ ++ /* ++ * PIC glink code is the following: ++ * ++ * # ith PLT code stub. ++ * addis 11,30,(plt+(i-1)*4-got)@ha ++ * lwz 11,(plt+(i-1)*4-got)@l(11) ++ * mtctr 11 ++ * bctr ++ * ++ * # A table of branches, one for each plt entry. ++ * # The idea is that the plt call stub loads ctr and r11 with these ++ * # addresses, so (r11 - res_0) gives the plt index * 4. ++ * res_0: b PLTresolve ++ * res_1: b PLTresolve ++ * . ++ * # Some number of entries towards the end can be nops ++ * res_n_m3: nop ++ * res_n_m2: nop ++ * res_n_m1: ++ * ++ * PLTresolve: ++ * addis 11,11,(1f-res_0)@ha ++ * mflr 0 ++ * bcl 20,31,1f ++ * 1: addi 11,11,(1b-res_0)@l ++ * mflr 12 ++ * mtlr 0 ++ * sub 11,11,12 # r11 = index * 4 ++ * addis 12,12,(got+4-1b)@ha ++ * lwz 0,(got+4-1b)@l(12) # got[1] address of dl_runtime_resolve ++ * lwz 12,(got+8-1b)@l(12) # got[2] contains the map address ++ * mtctr 0 ++ * add 0,11,11 ++ * add 11,0,11 # r11 = index * 12 = reloc offset. ++ * bctr ++ */ ++ static const unsigned int pic_plt_resolve[] = ++ { ++ ADDIS_11_11, ++ MFLR_0, ++ BCL_20_31, ++ ADDI_11_11, ++ MFLR_12, ++ MTLR_0, ++ SUB_11_11_12, ++ ADDIS_12_12, ++ LWZ_0_12, ++ LWZ_12_12, ++ MTCTR_0, ++ ADD_0_11_11, ++ ADD_11_0_11, ++ BCTR, ++ NOP, ++ NOP ++ }; ++ ++ /* ++ * Non-PIC glink code is a little simpler. ++ * ++ * # ith PLT code stub. ++ * lis 11,(plt+(i-1)*4)@ha ++ * lwz 11,(plt+(i-1)*4)@l(11) ++ * mtctr 11 ++ * bctr ++ * ++ * The branch table is the same, then comes ++ * ++ * PLTresolve: ++ * lis 12,(got+4)@ha ++ * addis 11,11,(-res_0)@ha ++ * lwz 0,(got+4)@l(12) # got[1] address of dl_runtime_resolve ++ * addi 11,11,(-res_0)@l # r11 = index * 4 ++ * mtctr 0 ++ * add 0,11,11 ++ * lwz 12,(got+8)@l(12) # got[2] contains the map address ++ * add 11,0,11 # r11 = index * 12 = reloc offset. ++ * bctr ++ */ ++ static const unsigned int plt_resolve[] = ++ { ++ LIS_12, ++ ADDIS_11_11, ++ LWZ_0_12, ++ ADDI_11_11, ++ MTCTR_0, ++ ADD_0_11_11, ++ LWZ_12_12, ++ ADD_11_0_11, ++ BCTR, ++ NOP, ++ NOP, ++ NOP, ++ NOP, ++ NOP, ++ NOP, ++ NOP ++ }; ++ ++ if (ARRAY_SIZE (pic_plt_resolve) != GLINK_PLTRESOLVE / 4) ++ abort (); ++ if (ARRAY_SIZE (plt_resolve) != GLINK_PLTRESOLVE / 4) ++ abort (); ++ ++ /* Build the branch table, one for each plt entry (less one), ++ and perhaps some padding. */ ++ p = htab->glink->contents; ++ p += htab->glink_pltresolve; ++ endp = htab->glink->contents; ++ endp += htab->glink->size - GLINK_PLTRESOLVE; ++ while (p < endp - 8 * 4) ++ { ++ bfd_put_32 (output_bfd, B + endp - p, p); ++ p += 4; ++ } ++ while (p < endp) ++ { ++ bfd_put_32 (output_bfd, NOP, p); ++ p += 4; ++ } ++ ++ res0 = (htab->glink_pltresolve ++ + htab->glink->output_section->vma ++ + htab->glink->output_offset); ++ ++ /* Last comes the PLTresolve stub. */ ++ if (info->shared) ++ { ++ bfd_vma bcl; ++ ++ for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++) ++ { ++ bfd_put_32 (output_bfd, pic_plt_resolve[i], p); ++ p += 4; ++ } ++ p -= 4 * ARRAY_SIZE (pic_plt_resolve); ++ ++ bcl = (htab->glink->size - GLINK_PLTRESOLVE + 3*4 ++ + htab->glink->output_section->vma ++ + htab->glink->output_offset); ++ ++ bfd_put_32 (output_bfd, ++ ADDIS_11_11 + PPC_HA (bcl - res0), p + 0*4); ++ bfd_put_32 (output_bfd, ++ ADDI_11_11 + PPC_LO (bcl - res0), p + 3*4); ++ bfd_put_32 (output_bfd, ++ ADDIS_12_12 + PPC_HA (got + 4 - bcl), p + 7*4); ++ if (PPC_HA (got + 4 - bcl) == PPC_HA (got + 8 - bcl)) ++ { ++ bfd_put_32 (output_bfd, ++ LWZ_0_12 + PPC_LO (got + 4 - bcl), p + 8*4); ++ bfd_put_32 (output_bfd, ++ LWZ_12_12 + PPC_LO (got + 8 - bcl), p + 9*4); ++ } ++ else ++ { ++ bfd_put_32 (output_bfd, ++ LWZU_0_12 + PPC_LO (got + 4 - bcl), p + 8*4); ++ bfd_put_32 (output_bfd, ++ LWZ_12_12 + 4, p + 9*4); ++ } ++ } ++ else ++ { ++ for (i = 0; i < ARRAY_SIZE (plt_resolve); i++) ++ { ++ bfd_put_32 (output_bfd, plt_resolve[i], p); ++ p += 4; ++ } ++ p -= 4 * ARRAY_SIZE (plt_resolve); ++ ++ bfd_put_32 (output_bfd, ++ LIS_12 + PPC_HA (got + 4), p + 0*4); ++ bfd_put_32 (output_bfd, ++ ADDIS_11_11 + PPC_HA (-res0), p + 1*4); ++ bfd_put_32 (output_bfd, ++ ADDI_11_11 + PPC_LO (-res0), p + 3*4); ++ if (PPC_HA (got + 4) == PPC_HA (got + 8)) ++ { ++ bfd_put_32 (output_bfd, ++ LWZ_0_12 + PPC_LO (got + 4), p + 2*4); ++ bfd_put_32 (output_bfd, ++ LWZ_12_12 + PPC_LO (got + 8), p + 6*4); ++ } ++ else ++ { ++ bfd_put_32 (output_bfd, ++ LWZU_0_12 + PPC_LO (got + 4), p + 2*4); ++ bfd_put_32 (output_bfd, ++ LWZ_12_12 + 4, p + 6*4); ++ } ++ } ++ } ++ ++ if (htab->glink_eh_frame != NULL ++ && htab->glink_eh_frame->contents != NULL) ++ { ++ unsigned char *p = htab->glink_eh_frame->contents; ++ bfd_vma val; ++ ++ p += sizeof (glink_eh_frame_cie); ++ /* FDE length. */ ++ p += 4; ++ /* CIE pointer. */ ++ p += 4; ++ /* Offset to .glink. */ ++ val = (htab->glink->output_section->vma ++ + htab->glink->output_offset); ++ val -= (htab->glink_eh_frame->output_section->vma ++ + htab->glink_eh_frame->output_offset); ++ val -= p - htab->glink_eh_frame->contents; ++ bfd_put_32 (htab->elf.dynobj, val, p); ++ ++ if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME ++ && !_bfd_elf_write_section_eh_frame (output_bfd, info, ++ htab->glink_eh_frame, ++ htab->glink_eh_frame->contents)) ++ return FALSE; ++ } ++ ++ return ret; ++} ++ ++#define TARGET_BIG_SYM bfd_elf32_amigaos_vec ++#define TARGET_BIG_NAME "elf32-amigaos" ++#define ELF_ARCH bfd_arch_powerpc ++#define ELF_TARGET_ID PPC32_ELF_DATA ++#define ELF_MACHINE_CODE EM_PPC ++#ifdef __QNXTARGET__ ++#define ELF_MAXPAGESIZE 0x1000 ++#else ++#define ELF_MAXPAGESIZE 0x10000 ++#endif ++#define ELF_MINPAGESIZE 0x1000 ++#define ELF_COMMONPAGESIZE 0x1000 ++#define elf_info_to_howto ppc_elf_info_to_howto ++ ++#ifdef EM_CYGNUS_POWERPC ++#define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC ++#endif ++ ++#ifdef EM_PPC_OLD ++#define ELF_MACHINE_ALT2 EM_PPC_OLD ++#endif ++ ++#define elf_backend_plt_not_loaded 1 ++#define elf_backend_can_gc_sections 1 ++#define elf_backend_can_refcount 1 ++#define elf_backend_rela_normal 1 ++ ++#define bfd_elf32_mkobject ppc_elf_mkobject ++#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data ++#define bfd_elf32_bfd_relax_section ppc_elf_relax_section ++#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup ++#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup ++#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags ++#define bfd_elf32_bfd_link_hash_table_create ppc_elf_link_hash_table_create ++#define bfd_elf32_get_synthetic_symtab ppc_elf_get_synthetic_symtab ++ ++#define elf_backend_object_p ppc_elf_object_p ++#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook ++#define elf_backend_gc_sweep_hook ppc_elf_gc_sweep_hook ++#define elf_backend_section_from_shdr ppc_elf_section_from_shdr ++#define elf_backend_relocate_section ppc_elf_relocate_section ++#define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections ++#define elf_backend_check_relocs ppc_elf_check_relocs ++#define elf_backend_copy_indirect_symbol ppc_elf_copy_indirect_symbol ++#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol ++#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook ++#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections ++#define elf_backend_hash_symbol ppc_elf_hash_symbol ++#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol ++#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections ++#define elf_backend_fake_sections ppc_elf_fake_sections ++#define elf_backend_additional_program_headers ppc_elf_additional_program_headers ++#define elf_backend_modify_segment_map ppc_elf_amigaos_modify_segment_map ++#define elf_backend_grok_prstatus ppc_elf_grok_prstatus ++#define elf_backend_grok_psinfo ppc_elf_grok_psinfo ++#define elf_backend_write_core_note ppc_elf_write_core_note ++#define elf_backend_reloc_type_class ppc_elf_reloc_type_class ++#define elf_backend_begin_write_processing ppc_elf_amigaos_begin_write_processing ++#define elf_backend_final_write_processing ppc_elf_amigaos_final_write_processing ++#define elf_backend_write_section ppc_elf_amigaos_write_section ++#define elf_backend_get_sec_type_attr ppc_elf_get_sec_type_attr ++#define elf_backend_plt_sym_val ppc_elf_plt_sym_val ++#define elf_backend_action_discarded ppc_elf_action_discarded ++#define elf_backend_init_index_section _bfd_elf_init_1_index_section ++#define elf_backend_post_process_headers _bfd_elf_set_osabi ++#define elf_backend_lookup_section_flags_hook ppc_elf_lookup_section_flags ++#define elf_backend_section_processing ppc_elf_amigaos_section_processing ++ ++#include "elf32-target.h" +--- /dev/null 2015-09-06 08:42:34.091999986 +0100 ++++ ld/emultempl/amigaos.em 2016-01-03 01:46:50.647001071 +0000 +@@ -0,0 +1,2513 @@ ++# This shell script emits a C file. -*- C -*- ++# It does some substitutions. ++# This file is now misnamed, because it supports both 32 bit and 64 bit ++# ELF emulations. ++test -z "${ELFSIZE}" && ELFSIZE=32 ++if [ -z "$MACHINE" ]; then ++ OUTPUT_ARCH=${ARCH} ++else ++ OUTPUT_ARCH=${ARCH}:${MACHINE} ++fi ++fragment <<EOF ++/* This file is is generated by a shell script. DO NOT EDIT! */ ++ ++/* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME} ++ Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, ++ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 ++ Free Software Foundation, Inc. ++ Written by Steve Chamberlain <sac@cygnus.com> ++ ELF support by Ian Lance Taylor <ian@cygnus.com> ++ ++ This file is part of the GNU Binutils. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, ++ MA 02110-1301, USA. */ ++ ++#define TARGET_IS_${EMULATION_NAME} ++ ++#include "sysdep.h" ++#include "bfd.h" ++#include "libiberty.h" ++#include "filenames.h" ++#include "safe-ctype.h" ++#include "getopt.h" ++#include "md5.h" ++#include "sha1.h" ++#include <fcntl.h> ++ ++#include "bfdlink.h" ++ ++#include "ld.h" ++#include "ldmain.h" ++#include "ldmisc.h" ++#include "ldexp.h" ++#include "ldlang.h" ++#include "ldfile.h" ++#include "ldemul.h" ++#include <ldgram.h> ++#include "elf/common.h" ++#include "elf-bfd.h" ++#include "filenames.h" ++ ++/* Declare functions used by various EXTRA_EM_FILEs. */ ++static void gld${EMULATION_NAME}_before_parse (void); ++static void gld${EMULATION_NAME}_after_open (void); ++static void gld${EMULATION_NAME}_before_allocation (void); ++static void gld${EMULATION_NAME}_after_allocation (void); ++static lang_output_section_statement_type *gld${EMULATION_NAME}_place_orphan ++ (asection *, const char *, int); ++EOF ++ ++if [ "x${USE_LIBPATH}" = xyes ] ; then ++ case ${target} in ++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) ++ fragment <<EOF ++#ifdef HAVE_GLOB ++#include <glob.h> ++#endif ++EOF ++ ;; ++ esac ++fi ++ ++# Import any needed special functions and/or overrides. ++# ++source_em ${srcdir}/emultempl/elf-generic.em ++if test -n "$EXTRA_EM_FILE" ; then ++ source_em ${srcdir}/emultempl/${EXTRA_EM_FILE}.em ++fi ++ ++# Functions in this file can be overridden by setting the LDEMUL_* shell ++# variables. If the name of the overriding function is the same as is ++# defined in this file, then don't output this file's version. ++# If a different overriding name is given then output the standard function ++# as presumably it is called from the overriding function. ++# ++if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then ++fragment <<EOF ++ ++static void ++gld${EMULATION_NAME}_before_parse (void) ++{ ++ ldfile_set_output_arch ("${OUTPUT_ARCH}", bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`); ++ input_flags.dynamic = ${DYNAMIC_LINK-TRUE}; ++ config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`; ++ config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then echo TRUE ; else echo FALSE ; fi`; ++} ++ ++EOF ++fi ++ ++if test x"$LDEMUL_RECOGNIZED_FILE" != xgld"${EMULATION_NAME}"_load_symbols; then ++fragment <<EOF ++/* Handle the generation of DT_NEEDED tags. */ ++ ++static bfd_boolean ++gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry) ++{ ++ int link_class = 0; ++ ++ /* Tell the ELF linker that we don't want the output file to have a ++ DT_NEEDED entry for this file, unless it is used to resolve ++ references in a regular object. */ ++ if (entry->flags.add_DT_NEEDED_for_regular) ++ link_class = DYN_AS_NEEDED; ++ ++ /* Tell the ELF linker that we don't want the output file to have a ++ DT_NEEDED entry for any dynamic library in DT_NEEDED tags from ++ this file at all. */ ++ if (!entry->flags.add_DT_NEEDED_for_dynamic) ++ link_class |= DYN_NO_ADD_NEEDED; ++ ++ if (entry->flags.just_syms ++ && (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) != 0) ++ einfo (_("%P%F: --just-symbols may not be used on DSO: %B\n"), ++ entry->the_bfd); ++ ++ if (link_class == 0 ++ || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0) ++ return FALSE; ++ ++ bfd_elf_set_dyn_lib_class (entry->the_bfd, ++ (enum dynamic_lib_link_class) link_class); ++ ++ /* Continue on with normal load_symbols processing. */ ++ return FALSE; ++} ++EOF ++fi ++ ++fragment <<EOF ++ ++/* These variables are required to pass information back and forth ++ between after_open and check_needed and stat_needed and vercheck. */ ++ ++static struct bfd_link_needed_list *global_needed; ++static struct stat global_stat; ++static lang_input_statement_type *global_found; ++static struct bfd_link_needed_list *global_vercheck_needed; ++static bfd_boolean global_vercheck_failed; ++ ++/* These variables are used to implement target options */ ++ ++static char *audit; /* colon (typically) separated list of libs */ ++static char *depaudit; /* colon (typically) separated list of libs */ ++ ++/* On Linux, it's possible to have different versions of the same ++ shared library linked against different versions of libc. The ++ dynamic linker somehow tags which libc version to use in ++ /etc/ld.so.cache, and, based on the libc that it sees in the ++ executable, chooses which version of the shared library to use. ++ ++ We try to do a similar check here by checking whether this shared ++ library needs any other shared libraries which may conflict with ++ libraries we have already included in the link. If it does, we ++ skip it, and try to find another shared library farther on down the ++ link path. ++ ++ This is called via lang_for_each_input_file. ++ GLOBAL_VERCHECK_NEEDED is the list of objects needed by the object ++ which we are checking. This sets GLOBAL_VERCHECK_FAILED if we find ++ a conflicting version. */ ++ ++static void ++gld${EMULATION_NAME}_vercheck (lang_input_statement_type *s) ++{ ++ const char *soname; ++ struct bfd_link_needed_list *l; ++ ++ if (global_vercheck_failed) ++ return; ++ if (s->the_bfd == NULL ++ || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0) ++ return; ++ ++ soname = bfd_elf_get_dt_soname (s->the_bfd); ++ if (soname == NULL) ++ soname = lbasename (bfd_get_filename (s->the_bfd)); ++ ++ for (l = global_vercheck_needed; l != NULL; l = l->next) ++ { ++ const char *suffix; ++ ++ if (filename_cmp (soname, l->name) == 0) ++ { ++ /* Probably can't happen, but it's an easy check. */ ++ continue; ++ } ++ ++ if (strchr (l->name, '/') != NULL) ++ continue; ++ ++ suffix = strstr (l->name, ".so."); ++ if (suffix == NULL) ++ continue; ++ ++ suffix += sizeof ".so." - 1; ++ ++ if (filename_ncmp (soname, l->name, suffix - l->name) == 0) ++ { ++ /* Here we know that S is a dynamic object FOO.SO.VER1, and ++ the object we are considering needs a dynamic object ++ FOO.SO.VER2, and VER1 and VER2 are different. This ++ appears to be a version mismatch, so we tell the caller ++ to try a different version of this library. */ ++ global_vercheck_failed = TRUE; ++ return; ++ } ++ } ++} ++ ++ ++/* See if an input file matches a DT_NEEDED entry by running stat on ++ the file. */ ++ ++static void ++gld${EMULATION_NAME}_stat_needed (lang_input_statement_type *s) ++{ ++ struct stat st; ++ const char *suffix; ++ const char *soname; ++ ++ if (global_found != NULL) ++ return; ++ if (s->the_bfd == NULL) ++ return; ++ ++ /* If this input file was an as-needed entry, and wasn't found to be ++ needed at the stage it was linked, then don't say we have loaded it. */ ++ if ((bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0) ++ return; ++ ++ if (bfd_stat (s->the_bfd, &st) != 0) ++ { ++ einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd); ++ return; ++ } ++ ++ /* Some operating systems, e.g. Windows, do not provide a meaningful ++ st_ino; they always set it to zero. (Windows does provide a ++ meaningful st_dev.) Do not indicate a duplicate library in that ++ case. While there is no guarantee that a system that provides ++ meaningful inode numbers will never set st_ino to zero, this is ++ merely an optimization, so we do not need to worry about false ++ negatives. */ ++ if (st.st_dev == global_stat.st_dev ++ && st.st_ino == global_stat.st_ino ++ && st.st_ino != 0) ++ { ++ global_found = s; ++ return; ++ } ++ ++ /* We issue a warning if it looks like we are including two ++ different versions of the same shared library. For example, ++ there may be a problem if -lc picks up libc.so.6 but some other ++ shared library has a DT_NEEDED entry of libc.so.5. This is a ++ heuristic test, and it will only work if the name looks like ++ NAME.so.VERSION. FIXME: Depending on file names is error-prone. ++ If we really want to issue warnings about mixing version numbers ++ of shared libraries, we need to find a better way. */ ++ ++ if (strchr (global_needed->name, '/') != NULL) ++ return; ++ suffix = strstr (global_needed->name, ".so."); ++ if (suffix == NULL) ++ return; ++ suffix += sizeof ".so." - 1; ++ ++ soname = bfd_elf_get_dt_soname (s->the_bfd); ++ if (soname == NULL) ++ soname = lbasename (s->filename); ++ ++ if (filename_ncmp (soname, global_needed->name, suffix - global_needed->name) == 0) ++ einfo ("%P: warning: %s, needed by %B, may conflict with %s\n", ++ global_needed->name, global_needed->by, soname); ++} ++ ++struct dt_needed ++{ ++ bfd *by; ++ const char *name; ++}; ++ ++/* This function is called for each possible name for a dynamic object ++ named by a DT_NEEDED entry. The FORCE parameter indicates whether ++ to skip the check for a conflicting version. */ ++ ++static bfd_boolean ++gld${EMULATION_NAME}_try_needed (struct dt_needed *needed, ++ int force) ++{ ++ bfd *abfd; ++ const char *name = needed->name; ++ const char *soname; ++ int link_class; ++ ++ abfd = bfd_openr (name, bfd_get_target (link_info.output_bfd)); ++ if (abfd == NULL) ++ return FALSE; ++ ++ /* Linker needs to decompress sections. */ ++ abfd->flags |= BFD_DECOMPRESS; ++ ++ if (! bfd_check_format (abfd, bfd_object)) ++ { ++ bfd_close (abfd); ++ return FALSE; ++ } ++ if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0) ++ { ++ bfd_close (abfd); ++ return FALSE; ++ } ++ ++ /* For DT_NEEDED, they have to match. */ ++ if (abfd->xvec != link_info.output_bfd->xvec) ++ { ++ bfd_close (abfd); ++ return FALSE; ++ } ++ ++ /* Check whether this object would include any conflicting library ++ versions. If FORCE is set, then we skip this check; we use this ++ the second time around, if we couldn't find any compatible ++ instance of the shared library. */ ++ ++ if (! force) ++ { ++ struct bfd_link_needed_list *needs; ++ ++ if (! bfd_elf_get_bfd_needed_list (abfd, &needs)) ++ einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd); ++ ++ if (needs != NULL) ++ { ++ global_vercheck_needed = needs; ++ global_vercheck_failed = FALSE; ++ lang_for_each_input_file (gld${EMULATION_NAME}_vercheck); ++ if (global_vercheck_failed) ++ { ++ bfd_close (abfd); ++ /* Return FALSE to force the caller to move on to try ++ another file on the search path. */ ++ return FALSE; ++ } ++ ++ /* But wait! It gets much worse. On Linux, if a shared ++ library does not use libc at all, we are supposed to skip ++ it the first time around in case we encounter a shared ++ library later on with the same name which does use the ++ version of libc that we want. This is much too horrible ++ to use on any system other than Linux. */ ++ ++EOF ++case ${target} in ++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) ++ fragment <<EOF ++ { ++ struct bfd_link_needed_list *l; ++ ++ for (l = needs; l != NULL; l = l->next) ++ if (CONST_STRNEQ (l->name, "libc.so")) ++ break; ++ if (l == NULL) ++ { ++ bfd_close (abfd); ++ return FALSE; ++ } ++ } ++ ++EOF ++ ;; ++esac ++fragment <<EOF ++ } ++ } ++ ++ /* We've found a dynamic object matching the DT_NEEDED entry. */ ++ ++ /* We have already checked that there is no other input file of the ++ same name. We must now check again that we are not including the ++ same file twice. We need to do this because on many systems ++ libc.so is a symlink to, e.g., libc.so.1. The SONAME entry will ++ reference libc.so.1. If we have already included libc.so, we ++ don't want to include libc.so.1 if they are the same file, and we ++ can only check that using stat. */ ++ ++ if (bfd_stat (abfd, &global_stat) != 0) ++ einfo ("%F%P:%B: bfd_stat failed: %E\n", abfd); ++ ++ /* First strip off everything before the last '/'. */ ++ soname = lbasename (abfd->filename); ++ ++ if (verbose) ++ info_msg (_("found %s at %s\n"), soname, name); ++ ++ global_found = NULL; ++ lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed); ++ if (global_found != NULL) ++ { ++ /* Return TRUE to indicate that we found the file, even though ++ we aren't going to do anything with it. */ ++ return TRUE; ++ } ++ ++ /* Specify the soname to use. */ ++ bfd_elf_set_dt_needed_name (abfd, soname); ++ ++ /* Tell the ELF linker that we don't want the output file to have a ++ DT_NEEDED entry for this file, unless it is used to resolve ++ references in a regular object. */ ++ link_class = DYN_DT_NEEDED; ++ ++ /* Tell the ELF linker that we don't want the output file to have a ++ DT_NEEDED entry for this file at all if the entry is from a file ++ with DYN_NO_ADD_NEEDED. */ ++ if (needed->by != NULL ++ && (bfd_elf_get_dyn_lib_class (needed->by) & DYN_NO_ADD_NEEDED) != 0) ++ link_class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED; ++ ++ bfd_elf_set_dyn_lib_class (abfd, (enum dynamic_lib_link_class) link_class); ++ ++ /* Add this file into the symbol table. */ ++ if (! bfd_link_add_symbols (abfd, &link_info)) ++ einfo ("%F%B: could not read symbols: %E\n", abfd); ++ ++ return TRUE; ++} ++ ++ ++/* Search for a needed file in a path. */ ++ ++static bfd_boolean ++gld${EMULATION_NAME}_search_needed (const char *path, ++ struct dt_needed *n, int force) ++{ ++ const char *s; ++ const char *name = n->name; ++ size_t len; ++ struct dt_needed needed; ++ ++ if (name[0] == '/') ++ return gld${EMULATION_NAME}_try_needed (n, force); ++ ++ if (path == NULL || *path == '\0') ++ return FALSE; ++ ++ needed.by = n->by; ++ needed.name = n->name; ++ ++ len = strlen (name); ++ while (1) ++ { ++ char *filename, *sset; ++ ++ s = strchr (path, config.rpath_separator); ++ if (s == NULL) ++ s = path + strlen (path); ++ ++#if HAVE_DOS_BASED_FILE_SYSTEM ++ /* Assume a match on the second char is part of drive specifier. */ ++ else if (config.rpath_separator == ':' ++ && s == path + 1 ++ && ISALPHA (*path)) ++ { ++ s = strchr (s + 1, config.rpath_separator); ++ if (s == NULL) ++ s = path + strlen (path); ++ } ++#endif ++ filename = (char *) xmalloc (s - path + len + 2); ++ if (s == path) ++ sset = filename; ++ else ++ { ++ memcpy (filename, path, s - path); ++ filename[s - path] = '/'; ++ sset = filename + (s - path) + 1; ++ } ++ strcpy (sset, name); ++ ++ needed.name = filename; ++ if (gld${EMULATION_NAME}_try_needed (&needed, force)) ++ return TRUE; ++ ++ free (filename); ++ ++ if (*s == '\0') ++ break; ++ path = s + 1; ++ } ++ ++ return FALSE; ++} ++ ++EOF ++if [ "x${USE_LIBPATH}" = xyes ] ; then ++ fragment <<EOF ++ ++/* Add the sysroot to every entry in a path separated by ++ config.rpath_separator. */ ++ ++static char * ++gld${EMULATION_NAME}_add_sysroot (const char *path) ++{ ++ int len, colons, i; ++ char *ret, *p; ++ ++ len = strlen (path); ++ colons = 0; ++ i = 0; ++ while (path[i]) ++ if (path[i++] == config.rpath_separator) ++ colons++; ++ ++ if (path[i]) ++ colons++; ++ ++ len = len + (colons + 1) * strlen (ld_sysroot); ++ ret = xmalloc (len + 1); ++ strcpy (ret, ld_sysroot); ++ p = ret + strlen (ret); ++ i = 0; ++ while (path[i]) ++ if (path[i] == config.rpath_separator) ++ { ++ *p++ = path[i++]; ++ strcpy (p, ld_sysroot); ++ p = p + strlen (p); ++ } ++ else ++ *p++ = path[i++]; ++ ++ *p = 0; ++ return ret; ++} ++ ++EOF ++ case ${target} in ++ *-*-freebsd* | *-*-dragonfly*) ++ fragment <<EOF ++/* Read the system search path the FreeBSD way rather than the Linux way. */ ++#ifdef HAVE_ELF_HINTS_H ++#include <elf-hints.h> ++#else ++#include "elf-hints-local.h" ++#endif ++ ++static bfd_boolean ++gld${EMULATION_NAME}_check_ld_elf_hints (const struct bfd_link_needed_list *l, ++ int force) ++{ ++ static bfd_boolean initialized; ++ static char *ld_elf_hints; ++ struct dt_needed needed; ++ ++ if (!initialized) ++ { ++ FILE *f; ++ char *tmppath; ++ ++ tmppath = concat (ld_sysroot, _PATH_ELF_HINTS, (const char *) NULL); ++ f = fopen (tmppath, FOPEN_RB); ++ free (tmppath); ++ if (f != NULL) ++ { ++ struct elfhints_hdr hdr; ++ ++ if (fread (&hdr, 1, sizeof (hdr), f) == sizeof (hdr) ++ && hdr.magic == ELFHINTS_MAGIC ++ && hdr.version == 1) ++ { ++ if (fseek (f, hdr.strtab + hdr.dirlist, SEEK_SET) != -1) ++ { ++ char *b; ++ ++ b = xmalloc (hdr.dirlistlen + 1); ++ if (fread (b, 1, hdr.dirlistlen + 1, f) == ++ hdr.dirlistlen + 1) ++ ld_elf_hints = gld${EMULATION_NAME}_add_sysroot (b); ++ ++ free (b); ++ } ++ } ++ fclose (f); ++ } ++ ++ initialized = TRUE; ++ } ++ ++ if (ld_elf_hints == NULL) ++ return FALSE; ++ ++ needed.by = l->by; ++ needed.name = l->name; ++ return gld${EMULATION_NAME}_search_needed (ld_elf_hints, &needed, force); ++} ++EOF ++ # FreeBSD ++ ;; ++ ++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) ++ fragment <<EOF ++/* For a native linker, check the file /etc/ld.so.conf for directories ++ in which we may find shared libraries. /etc/ld.so.conf is really ++ only meaningful on Linux. */ ++ ++struct gld${EMULATION_NAME}_ld_so_conf ++{ ++ char *path; ++ size_t len, alloc; ++}; ++ ++static bfd_boolean ++gld${EMULATION_NAME}_parse_ld_so_conf ++ (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename); ++ ++static void ++gld${EMULATION_NAME}_parse_ld_so_conf_include ++ (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename, ++ const char *pattern) ++{ ++ char *newp = NULL; ++#ifdef HAVE_GLOB ++ glob_t gl; ++#endif ++ ++ if (pattern[0] != '/') ++ { ++ char *p = strrchr (filename, '/'); ++ size_t patlen = strlen (pattern) + 1; ++ ++ newp = xmalloc (p - filename + 1 + patlen); ++ memcpy (newp, filename, p - filename + 1); ++ memcpy (newp + (p - filename + 1), pattern, patlen); ++ pattern = newp; ++ } ++ ++#ifdef HAVE_GLOB ++ if (glob (pattern, 0, NULL, &gl) == 0) ++ { ++ size_t i; ++ ++ for (i = 0; i < gl.gl_pathc; ++i) ++ gld${EMULATION_NAME}_parse_ld_so_conf (info, gl.gl_pathv[i]); ++ globfree (&gl); ++ } ++#else ++ /* If we do not have glob, treat the pattern as a literal filename. */ ++ gld${EMULATION_NAME}_parse_ld_so_conf (info, pattern); ++#endif ++ ++ if (newp) ++ free (newp); ++} ++ ++static bfd_boolean ++gld${EMULATION_NAME}_parse_ld_so_conf ++ (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename) ++{ ++ FILE *f = fopen (filename, FOPEN_RT); ++ char *line; ++ size_t linelen; ++ ++ if (f == NULL) ++ return FALSE; ++ ++ linelen = 256; ++ line = xmalloc (linelen); ++ do ++ { ++ char *p = line, *q; ++ ++ /* Normally this would use getline(3), but we need to be portable. */ ++ while ((q = fgets (p, linelen - (p - line), f)) != NULL ++ && strlen (q) == linelen - (p - line) - 1 ++ && line[linelen - 2] != '\n') ++ { ++ line = xrealloc (line, 2 * linelen); ++ p = line + linelen - 1; ++ linelen += linelen; ++ } ++ ++ if (q == NULL && p == line) ++ break; ++ ++ p = strchr (line, '\n'); ++ if (p) ++ *p = '\0'; ++ ++ /* Because the file format does not know any form of quoting we ++ can search forward for the next '#' character and if found ++ make it terminating the line. */ ++ p = strchr (line, '#'); ++ if (p) ++ *p = '\0'; ++ ++ /* Remove leading whitespace. NUL is no whitespace character. */ ++ p = line; ++ while (*p == ' ' || *p == '\f' || *p == '\r' || *p == '\t' || *p == '\v') ++ ++p; ++ ++ /* If the line is blank it is ignored. */ ++ if (p[0] == '\0') ++ continue; ++ ++ if (CONST_STRNEQ (p, "include") && (p[7] == ' ' || p[7] == '\t')) ++ { ++ char *dir, c; ++ p += 8; ++ do ++ { ++ while (*p == ' ' || *p == '\t') ++ ++p; ++ ++ if (*p == '\0') ++ break; ++ ++ dir = p; ++ ++ while (*p != ' ' && *p != '\t' && *p) ++ ++p; ++ ++ c = *p; ++ *p++ = '\0'; ++ if (dir[0] != '\0') ++ gld${EMULATION_NAME}_parse_ld_so_conf_include (info, filename, ++ dir); ++ } ++ while (c != '\0'); ++ } ++ else ++ { ++ char *dir = p; ++ while (*p && *p != '=' && *p != ' ' && *p != '\t' && *p != '\f' ++ && *p != '\r' && *p != '\v') ++ ++p; ++ ++ while (p != dir && p[-1] == '/') ++ --p; ++ if (info->path == NULL) ++ { ++ info->alloc = p - dir + 1 + 256; ++ info->path = xmalloc (info->alloc); ++ info->len = 0; ++ } ++ else ++ { ++ if (info->len + 1 + (p - dir) >= info->alloc) ++ { ++ info->alloc += p - dir + 256; ++ info->path = xrealloc (info->path, info->alloc); ++ } ++ info->path[info->len++] = config.rpath_separator; ++ } ++ memcpy (info->path + info->len, dir, p - dir); ++ info->len += p - dir; ++ info->path[info->len] = '\0'; ++ } ++ } ++ while (! feof (f)); ++ free (line); ++ fclose (f); ++ return TRUE; ++} ++ ++static bfd_boolean ++gld${EMULATION_NAME}_check_ld_so_conf (const struct bfd_link_needed_list *l, ++ int force) ++{ ++ static bfd_boolean initialized; ++ static char *ld_so_conf; ++ struct dt_needed needed; ++ ++ if (! initialized) ++ { ++ char *tmppath; ++ struct gld${EMULATION_NAME}_ld_so_conf info; ++ ++ info.path = NULL; ++ info.len = info.alloc = 0; ++ tmppath = concat (ld_sysroot, "${prefix}/etc/ld.so.conf", ++ (const char *) NULL); ++ if (!gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath)) ++ { ++ free (tmppath); ++ tmppath = concat (ld_sysroot, "/etc/ld.so.conf", ++ (const char *) NULL); ++ gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath); ++ } ++ free (tmppath); ++ ++ if (info.path) ++ { ++ char *d = gld${EMULATION_NAME}_add_sysroot (info.path); ++ free (info.path); ++ ld_so_conf = d; ++ } ++ initialized = TRUE; ++ } ++ ++ if (ld_so_conf == NULL) ++ return FALSE; ++ ++ ++ needed.by = l->by; ++ needed.name = l->name; ++ return gld${EMULATION_NAME}_search_needed (ld_so_conf, &needed, force); ++} ++ ++EOF ++ # Linux ++ ;; ++ esac ++fi ++fragment <<EOF ++ ++/* See if an input file matches a DT_NEEDED entry by name. */ ++ ++static void ++gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s) ++{ ++ const char *soname; ++ ++ /* Stop looking if we've found a loaded lib. */ ++ if (global_found != NULL ++ && (bfd_elf_get_dyn_lib_class (global_found->the_bfd) ++ & DYN_AS_NEEDED) == 0) ++ return; ++ ++ if (s->filename == NULL || s->the_bfd == NULL) ++ return; ++ ++ /* Don't look for a second non-loaded as-needed lib. */ ++ if (global_found != NULL ++ && (bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0) ++ return; ++ ++ if (filename_cmp (s->filename, global_needed->name) == 0) ++ { ++ global_found = s; ++ return; ++ } ++ ++ if (s->flags.search_dirs) ++ { ++ const char *f = strrchr (s->filename, '/'); ++ if (f != NULL ++ && filename_cmp (f + 1, global_needed->name) == 0) ++ { ++ global_found = s; ++ return; ++ } ++ } ++ ++ soname = bfd_elf_get_dt_soname (s->the_bfd); ++ if (soname != NULL ++ && filename_cmp (soname, global_needed->name) == 0) ++ { ++ global_found = s; ++ return; ++ } ++} ++ ++EOF ++ ++if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then ++fragment <<EOF ++ ++static bfd_size_type ++gld${EMULATION_NAME}_id_note_section_size (bfd *abfd, ++ struct bfd_link_info *linfo) ++{ ++ const char *style = linfo->emit_note_gnu_build_id; ++ bfd_size_type size; ++ ++ abfd = abfd; ++ ++ size = offsetof (Elf_External_Note, name[sizeof "GNU"]); ++ size = (size + 3) & -(bfd_size_type) 4; ++ ++ if (!strcmp (style, "md5") || !strcmp (style, "uuid")) ++ size += 128 / 8; ++ else if (!strcmp (style, "sha1")) ++ size += 160 / 8; ++ else if (!strncmp (style, "0x", 2)) ++ { ++ /* ID is in string form (hex). Convert to bits. */ ++ const char *id = style + 2; ++ do ++ { ++ if (ISXDIGIT (id[0]) && ISXDIGIT (id[1])) ++ { ++ ++size; ++ id += 2; ++ } ++ else if (*id == '-' || *id == ':') ++ ++id; ++ else ++ { ++ size = 0; ++ break; ++ } ++ } while (*id != '\0'); ++ } ++ else ++ size = 0; ++ ++ return size; ++} ++ ++static unsigned char ++read_hex (const char xdigit) ++{ ++ if (ISDIGIT (xdigit)) ++ return xdigit - '0'; ++ if (ISUPPER (xdigit)) ++ return xdigit - 'A' + 0xa; ++ if (ISLOWER (xdigit)) ++ return xdigit - 'a' + 0xa; ++ abort (); ++ return 0; ++} ++ ++struct build_id_info ++{ ++ const char *style; ++ asection *sec; ++}; ++ ++static bfd_boolean ++gld${EMULATION_NAME}_write_build_id_section (bfd *abfd) ++{ ++ const struct elf_backend_data *bed = get_elf_backend_data (abfd); ++ struct build_id_info *info = (struct build_id_info *) ++ elf_tdata (abfd)->after_write_object_contents_info; ++ asection *asec; ++ Elf_Internal_Shdr *i_shdr; ++ unsigned char *contents, *id_bits; ++ bfd_size_type size; ++ Elf_External_Note *e_note; ++ ++ asec = info->sec; ++ if (bfd_is_abs_section (asec->output_section)) ++ { ++ einfo (_("%P: warning: .note.gnu.build-id section discarded," ++ " --build-id ignored.\n")); ++ return TRUE; ++ } ++ i_shdr = &elf_section_data (asec->output_section)->this_hdr; ++ ++ if (i_shdr->contents == NULL) ++ { ++ if (asec->contents == NULL) ++ asec->contents = (unsigned char *) xmalloc (asec->size); ++ contents = asec->contents; ++ } ++ else ++ contents = i_shdr->contents + asec->output_offset; ++ ++ e_note = (Elf_External_Note *) contents; ++ size = offsetof (Elf_External_Note, name[sizeof "GNU"]); ++ size = (size + 3) & -(bfd_size_type) 4; ++ id_bits = contents + size; ++ size = asec->size - size; ++ ++ bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz); ++ bfd_h_put_32 (abfd, size, &e_note->descsz); ++ bfd_h_put_32 (abfd, NT_GNU_BUILD_ID, &e_note->type); ++ memcpy (e_note->name, "GNU", sizeof "GNU"); ++ ++ if (!strcmp (info->style, "md5")) ++ { ++ struct md5_ctx ctx; ++ md5_init_ctx (&ctx); ++ if (bed->s->checksum_contents (abfd, ++ (void (*) (const void *, size_t, void *)) ++ &md5_process_bytes, ++ &ctx)) ++ md5_finish_ctx (&ctx, id_bits); ++ else ++ return FALSE; ++ } ++ else if (!strcmp (info->style, "sha1")) ++ { ++ struct sha1_ctx ctx; ++ sha1_init_ctx (&ctx); ++ if (bed->s->checksum_contents (abfd, ++ (void (*) (const void *, size_t, void *)) ++ &sha1_process_bytes, ++ &ctx)) ++ sha1_finish_ctx (&ctx, id_bits); ++ else ++ return FALSE; ++ } ++ else if (!strcmp (info->style, "uuid")) ++ { ++ int n; ++ int fd = open ("/dev/urandom", O_RDONLY); ++ if (fd < 0) ++ return FALSE; ++ n = read (fd, id_bits, size); ++ close (fd); ++ if (n < (int) size) ++ return FALSE; ++ } ++ else if (!strncmp (info->style, "0x", 2)) ++ { ++ /* ID is in string form (hex). Convert to bits. */ ++ const char *id = info->style + 2; ++ size_t n = 0; ++ do ++ { ++ if (ISXDIGIT (id[0]) && ISXDIGIT (id[1])) ++ { ++ id_bits[n] = read_hex (*id++) << 4; ++ id_bits[n++] |= read_hex (*id++); ++ } ++ else if (*id == '-' || *id == ':') ++ ++id; ++ else ++ abort (); /* Should have been validated earlier. */ ++ } while (*id != '\0'); ++ } ++ else ++ abort (); /* Should have been validated earlier. */ ++ ++ size = asec->size; ++ return (bfd_seek (abfd, ++ i_shdr->sh_offset + asec->output_offset, SEEK_SET) == 0 ++ && bfd_bwrite (contents, size, abfd) == size); ++} ++ ++ ++/* This is called after all the input files have been opened. */ ++ ++static void ++gld${EMULATION_NAME}_after_open (void) ++{ ++ struct bfd_link_needed_list *needed, *l; ++ struct elf_link_hash_table *htab; ++ ++ after_open_default (); ++ ++ htab = elf_hash_table (&link_info); ++ if (!is_elf_hash_table (htab)) ++ return; ++ ++ if (link_info.emit_note_gnu_build_id) ++ { ++ bfd *abfd; ++ asection *s; ++ bfd_size_type size; ++ ++ /* Find an ELF input. */ ++ for (abfd = link_info.input_bfds; ++ abfd != (bfd *) NULL; abfd = abfd->link_next) ++ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) ++ break; ++ ++ if (abfd == NULL) ++ { ++ /* PR 10555: If there are no input files do not ++ try to create a .note.gnu-build-id section. */ ++ free (link_info.emit_note_gnu_build_id); ++ link_info.emit_note_gnu_build_id = NULL; ++ } ++ else ++ { ++ size = gld${EMULATION_NAME}_id_note_section_size (abfd, &link_info); ++ if (size == 0) ++ { ++ einfo ("%P: warning: unrecognized --build-id style ignored.\n"); ++ free (link_info.emit_note_gnu_build_id); ++ link_info.emit_note_gnu_build_id = NULL; ++ } ++ else ++ { ++ s = bfd_make_section_with_flags (abfd, ".note.gnu.build-id", ++ SEC_ALLOC | SEC_LOAD ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED ++ | SEC_READONLY | SEC_DATA); ++ if (s != NULL && bfd_set_section_alignment (abfd, s, 2)) ++ { ++ struct elf_obj_tdata *t = elf_tdata (link_info.output_bfd); ++ struct build_id_info *b = ++ (struct build_id_info *) xmalloc (sizeof *b); ++ ++ b->style = link_info.emit_note_gnu_build_id; ++ b->sec = s; ++ elf_section_type (s) = SHT_NOTE; ++ s->size = size; ++ t->after_write_object_contents ++ = &gld${EMULATION_NAME}_write_build_id_section; ++ t->after_write_object_contents_info = b; ++ } ++ else ++ { ++ einfo ("%P: warning: Cannot create .note.gnu.build-id section," ++ " --build-id ignored.\n"); ++ free (link_info.emit_note_gnu_build_id); ++ link_info.emit_note_gnu_build_id = NULL; ++ } ++ } ++ } ++ } ++ ++ if (link_info.relocatable) ++ return; ++ ++ if (link_info.eh_frame_hdr ++ && !link_info.traditional_format) ++ { ++ bfd *abfd, *elfbfd = NULL; ++ bfd_boolean warn_eh_frame = FALSE; ++ asection *s; ++ ++ for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next) ++ { ++ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) ++ elfbfd = abfd; ++ if (!warn_eh_frame) ++ { ++ s = bfd_get_section_by_name (abfd, ".eh_frame"); ++ while (s != NULL ++ && (s->size <= 8 ++ || bfd_is_abs_section (s->output_section))) ++ s = bfd_get_next_section_by_name (s); ++ warn_eh_frame = s != NULL; ++ } ++ if (elfbfd && warn_eh_frame) ++ break; ++ } ++ if (elfbfd) ++ { ++ const struct elf_backend_data *bed; ++ ++ bed = get_elf_backend_data (elfbfd); ++ s = bfd_make_section_with_flags (elfbfd, ".eh_frame_hdr", ++ bed->dynamic_sec_flags ++ | SEC_READONLY); ++ if (s != NULL ++ && bfd_set_section_alignment (elfbfd, s, 2)) ++ { ++ htab->eh_info.hdr_sec = s; ++ warn_eh_frame = FALSE; ++ } ++ } ++ if (warn_eh_frame) ++ einfo ("%P: warning: Cannot create .eh_frame_hdr section," ++ " --eh-frame-hdr ignored.\n"); ++ } ++ ++ /* Get the list of files which appear in DT_NEEDED entries in ++ dynamic objects included in the link (often there will be none). ++ For each such file, we want to track down the corresponding ++ library, and include the symbol table in the link. This is what ++ the runtime dynamic linker will do. Tracking the files down here ++ permits one dynamic object to include another without requiring ++ special action by the person doing the link. Note that the ++ needed list can actually grow while we are stepping through this ++ loop. */ ++ needed = bfd_elf_get_needed_list (link_info.output_bfd, &link_info); ++ for (l = needed; l != NULL; l = l->next) ++ { ++ struct bfd_link_needed_list *ll; ++ struct dt_needed n, nn; ++ int force; ++ ++ /* If the lib that needs this one was --as-needed and wasn't ++ found to be needed, then this lib isn't needed either. Skip ++ the lib when creating a shared object unless we are copying ++ DT_NEEDED entres. */ ++ if (l->by != NULL ++ && ((bfd_elf_get_dyn_lib_class (l->by) & DYN_AS_NEEDED) != 0 ++ || (!link_info.executable ++ && bfd_elf_get_dyn_lib_class (l->by) & DYN_NO_ADD_NEEDED) != 0)) ++ continue; ++ ++ /* If we've already seen this file, skip it. */ ++ for (ll = needed; ll != l; ll = ll->next) ++ if ((ll->by == NULL ++ || (bfd_elf_get_dyn_lib_class (ll->by) & DYN_AS_NEEDED) == 0) ++ && strcmp (ll->name, l->name) == 0) ++ break; ++ if (ll != l) ++ continue; ++ ++ /* See if this file was included in the link explicitly. */ ++ global_needed = l; ++ global_found = NULL; ++ lang_for_each_input_file (gld${EMULATION_NAME}_check_needed); ++ if (global_found != NULL ++ && (bfd_elf_get_dyn_lib_class (global_found->the_bfd) ++ & DYN_AS_NEEDED) == 0) ++ continue; ++ ++ n.by = l->by; ++ n.name = l->name; ++ nn.by = l->by; ++ if (verbose) ++ info_msg (_("%s needed by %B\n"), l->name, l->by); ++ ++ /* As-needed libs specified on the command line (or linker script) ++ take priority over libs found in search dirs. */ ++ if (global_found != NULL) ++ { ++ nn.name = global_found->filename; ++ if (gld${EMULATION_NAME}_try_needed (&nn, TRUE)) ++ continue; ++ } ++ ++ /* We need to find this file and include the symbol table. We ++ want to search for the file in the same way that the dynamic ++ linker will search. That means that we want to use ++ rpath_link, rpath, then the environment variable ++ LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH ++ entries (native only), then the linker script LIB_SEARCH_DIRS. ++ We do not search using the -L arguments. ++ ++ We search twice. The first time, we skip objects which may ++ introduce version mismatches. The second time, we force ++ their use. See gld${EMULATION_NAME}_vercheck comment. */ ++ for (force = 0; force < 2; force++) ++ { ++ size_t len; ++ search_dirs_type *search; ++EOF ++if [ "x${NATIVE}" = xyes ] ; then ++fragment <<EOF ++ const char *lib_path; ++EOF ++fi ++if [ "x${USE_LIBPATH}" = xyes ] ; then ++fragment <<EOF ++ struct bfd_link_needed_list *rp; ++ int found; ++EOF ++fi ++fragment <<EOF ++ ++ if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link, ++ &n, force)) ++ break; ++EOF ++if [ "x${USE_LIBPATH}" = xyes ] ; then ++fragment <<EOF ++ if (gld${EMULATION_NAME}_search_needed (command_line.rpath, ++ &n, force)) ++ break; ++EOF ++fi ++if [ "x${NATIVE}" = xyes ] ; then ++fragment <<EOF ++ if (command_line.rpath_link == NULL ++ && command_line.rpath == NULL) ++ { ++ lib_path = (const char *) getenv ("LD_RUN_PATH"); ++ if (gld${EMULATION_NAME}_search_needed (lib_path, &n, ++ force)) ++ break; ++ } ++ lib_path = (const char *) getenv ("LD_LIBRARY_PATH"); ++ if (gld${EMULATION_NAME}_search_needed (lib_path, &n, force)) ++ break; ++EOF ++fi ++if [ "x${USE_LIBPATH}" = xyes ] ; then ++fragment <<EOF ++ found = 0; ++ rp = bfd_elf_get_runpath_list (link_info.output_bfd, &link_info); ++ for (; !found && rp != NULL; rp = rp->next) ++ { ++ char *tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name); ++ found = (rp->by == l->by ++ && gld${EMULATION_NAME}_search_needed (tmpname, ++ &n, ++ force)); ++ free (tmpname); ++ } ++ if (found) ++ break; ++ ++EOF ++fi ++if [ "x${USE_LIBPATH}" = xyes ] ; then ++ case ${target} in ++ *-*-freebsd* | *-*-dragonfly*) ++ fragment <<EOF ++ if (gld${EMULATION_NAME}_check_ld_elf_hints (l, force)) ++ break; ++EOF ++ # FreeBSD ++ ;; ++ ++ *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) ++ # Linux ++ fragment <<EOF ++ if (gld${EMULATION_NAME}_check_ld_so_conf (l, force)) ++ break; ++ ++EOF ++ ;; ++ esac ++fi ++fragment <<EOF ++ len = strlen (l->name); ++ for (search = search_head; search != NULL; search = search->next) ++ { ++ char *filename; ++ ++ if (search->cmdline) ++ continue; ++ filename = (char *) xmalloc (strlen (search->name) + len + 2); ++ sprintf (filename, "%s/%s", search->name, l->name); ++ nn.name = filename; ++ if (gld${EMULATION_NAME}_try_needed (&nn, force)) ++ break; ++ free (filename); ++ } ++ if (search != NULL) ++ break; ++EOF ++fragment <<EOF ++ } ++ ++ if (force < 2) ++ continue; ++ ++ einfo ("%P: warning: %s, needed by %B, not found (try using -rpath or -rpath-link)\n", ++ l->name, l->by); ++ } ++} ++ ++EOF ++fi ++ ++fragment <<EOF ++ ++/* Look through an expression for an assignment statement. */ ++ ++static void ++gld${EMULATION_NAME}_find_exp_assignment (etree_type *exp) ++{ ++ bfd_boolean provide = FALSE; ++ ++ switch (exp->type.node_class) ++ { ++ case etree_provide: ++ case etree_provided: ++ provide = TRUE; ++ /* Fall thru */ ++ case etree_assign: ++ /* We call record_link_assignment even if the symbol is defined. ++ This is because if it is defined by a dynamic object, we ++ actually want to use the value defined by the linker script, ++ not the value from the dynamic object (because we are setting ++ symbols like etext). If the symbol is defined by a regular ++ object, then, as it happens, calling record_link_assignment ++ will do no harm. */ ++ if (strcmp (exp->assign.dst, ".") != 0) ++ { ++ if (!bfd_elf_record_link_assignment (link_info.output_bfd, ++ &link_info, ++ exp->assign.dst, provide, ++ exp->assign.hidden)) ++ einfo ("%P%F: failed to record assignment to %s: %E\n", ++ exp->assign.dst); ++ } ++ gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src); ++ break; ++ ++ case etree_binary: ++ gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs); ++ gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs); ++ break; ++ ++ case etree_trinary: ++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond); ++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); ++ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs); ++ break; ++ ++ case etree_unary: ++ gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++ ++/* This is called by the before_allocation routine via ++ lang_for_each_statement. It locates any assignment statements, and ++ tells the ELF backend about them, in case they are assignments to ++ symbols which are referred to by dynamic objects. */ ++ ++static void ++gld${EMULATION_NAME}_find_statement_assignment (lang_statement_union_type *s) ++{ ++ if (s->header.type == lang_assignment_statement_enum) ++ gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp); ++} ++ ++EOF ++ ++if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then ++ if test x"${ELF_INTERPRETER_NAME+set}" = xset; then ++ ELF_INTERPRETER_SET_DEFAULT=" ++ if (sinterp != NULL) ++ { ++ sinterp->contents = (unsigned char *) ${ELF_INTERPRETER_NAME}; ++ sinterp->size = strlen ((char *) sinterp->contents) + 1; ++ } ++ ++" ++ else ++ ELF_INTERPRETER_SET_DEFAULT= ++ fi ++fragment <<EOF ++ ++/* used by before_allocation and handle_option. */ ++static void ++gld${EMULATION_NAME}_append_to_separated_string (char **to, char *op_arg) ++{ ++ if (*to == NULL) ++ *to = xstrdup (op_arg); ++ else ++ { ++ size_t to_len = strlen (*to); ++ size_t op_arg_len = strlen (op_arg); ++ char *buf; ++ char *cp = *to; ++ ++ /* First see whether OPTARG is already in the path. */ ++ do ++ { ++ if (strncmp (op_arg, cp, op_arg_len) == 0 ++ && (cp[op_arg_len] == 0 ++ || cp[op_arg_len] == config.rpath_separator)) ++ /* We found it. */ ++ break; ++ ++ /* Not yet found. */ ++ cp = strchr (cp, config.rpath_separator); ++ if (cp != NULL) ++ ++cp; ++ } ++ while (cp != NULL); ++ ++ if (cp == NULL) ++ { ++ buf = xmalloc (to_len + op_arg_len + 2); ++ sprintf (buf, "%s%c%s", *to, ++ config.rpath_separator, op_arg); ++ free (*to); ++ *to = buf; ++ } ++ } ++} ++ ++/* This is called after the sections have been attached to output ++ sections, but before any sizes or addresses have been set. */ ++ ++static void ++gld${EMULATION_NAME}_before_allocation (void) ++{ ++ const char *rpath; ++ asection *sinterp; ++ bfd *abfd; ++ ++ if (link_info.hash->type == bfd_link_elf_hash_table) ++ _bfd_elf_tls_setup (link_info.output_bfd, &link_info); ++ ++ /* If we are going to make any variable assignments, we need to let ++ the ELF backend know about them in case the variables are ++ referred to by dynamic objects. */ ++ lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment); ++ ++ /* Let the ELF backend work out the sizes of any sections required ++ by dynamic linking. */ ++ rpath = command_line.rpath; ++ if (rpath == NULL) ++ rpath = (const char *) getenv ("LD_RUN_PATH"); ++ ++ for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next) ++ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) ++ { ++ const char *audit_libs = elf_dt_audit (abfd); ++ ++ /* If the input bfd contains an audit entry, we need to add it as ++ a dep audit entry. */ ++ if (audit_libs && *audit_libs != '\0') ++ { ++ char *cp = xstrdup (audit_libs); ++ do ++ { ++ int more = 0; ++ char *cp2 = strchr (cp, config.rpath_separator); ++ ++ if (cp2) ++ { ++ *cp2 = '\0'; ++ more = 1; ++ } ++ ++ if (cp != NULL && *cp != '\0') ++ gld${EMULATION_NAME}_append_to_separated_string (&depaudit, cp); ++ ++ cp = more ? ++cp2 : NULL; ++ } ++ while (cp != NULL); ++ } ++ } ++ ++ if (! (bfd_elf_size_dynamic_sections ++ (link_info.output_bfd, command_line.soname, rpath, ++ command_line.filter_shlib, audit, depaudit, ++ (const char * const *) command_line.auxiliary_filters, ++ &link_info, &sinterp))) ++ einfo ("%P%F: failed to set dynamic section sizes: %E\n"); ++ ++${ELF_INTERPRETER_SET_DEFAULT} ++ /* Let the user override the dynamic linker we are using. */ ++ if (command_line.interpreter != NULL ++ && sinterp != NULL) ++ { ++ sinterp->contents = (bfd_byte *) command_line.interpreter; ++ sinterp->size = strlen (command_line.interpreter) + 1; ++ } ++ ++ /* Look for any sections named .gnu.warning. As a GNU extensions, ++ we treat such sections as containing warning messages. We print ++ out the warning message, and then zero out the section size so ++ that it does not get copied into the output file. */ ++ ++ { ++ LANG_FOR_EACH_INPUT_STATEMENT (is) ++ { ++ asection *s; ++ bfd_size_type sz; ++ char *msg; ++ bfd_boolean ret; ++ ++ if (is->flags.just_syms) ++ continue; ++ ++ s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning"); ++ if (s == NULL) ++ continue; ++ ++ sz = s->size; ++ msg = (char *) xmalloc ((size_t) (sz + 1)); ++ if (! bfd_get_section_contents (is->the_bfd, s, msg, ++ (file_ptr) 0, sz)) ++ einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n", ++ is->the_bfd); ++ msg[sz] = '\0'; ++ ret = link_info.callbacks->warning (&link_info, msg, ++ (const char *) NULL, ++ is->the_bfd, (asection *) NULL, ++ (bfd_vma) 0); ++ ASSERT (ret); ++ free (msg); ++ ++ /* Clobber the section size, so that we don't waste space ++ copying the warning into the output file. If we've already ++ sized the output section, adjust its size. The adjustment ++ is on rawsize because targets that size sections early will ++ have called lang_reset_memory_regions after sizing. */ ++ if (s->output_section != NULL ++ && s->output_section->rawsize >= s->size) ++ s->output_section->rawsize -= s->size; ++ ++ s->size = 0; ++ ++ /* Also set SEC_EXCLUDE, so that local symbols defined in the ++ warning section don't get copied to the output. */ ++ s->flags |= SEC_EXCLUDE | SEC_KEEP; ++ } ++ } ++ ++ before_allocation_default (); ++ ++ if (!bfd_elf_size_dynsym_hash_dynstr (link_info.output_bfd, &link_info)) ++ einfo ("%P%F: failed to set dynamic section sizes: %E\n"); ++} ++ ++EOF ++fi ++ ++if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then ++fragment <<EOF ++ ++/* Try to open a dynamic archive. This is where we know that ELF ++ dynamic libraries have an extension of .so (or .sl on oddball systems ++ like hpux). */ ++ ++static bfd_boolean ++gld${EMULATION_NAME}_open_dynamic_archive ++ (const char *arch, search_dirs_type *search, lang_input_statement_type *entry) ++{ ++ const char *filename; ++ char *string; ++ ++ if (! entry->flags.maybe_archive) ++ return FALSE; ++ ++ filename = entry->filename; ++ ++ /* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION ++ is defined, but it does not seem worth the headache to optimize ++ away those two bytes of space. */ ++ string = (char *) xmalloc (strlen (search->name) ++ + strlen (filename) ++ + strlen (arch) ++#ifdef EXTRA_SHLIB_EXTENSION ++ + strlen (EXTRA_SHLIB_EXTENSION) ++#endif ++ + sizeof "/lib.so"); ++ ++ sprintf (string, "%s/lib%s%s.so", search->name, filename, arch); ++ ++#ifdef EXTRA_SHLIB_EXTENSION ++ /* Try the .so extension first. If that fails build a new filename ++ using EXTRA_SHLIB_EXTENSION. */ ++ if (! ldfile_try_open_bfd (string, entry)) ++ { ++ sprintf (string, "%s/lib%s%s%s", search->name, ++ filename, arch, EXTRA_SHLIB_EXTENSION); ++#endif ++ ++ if (! ldfile_try_open_bfd (string, entry)) ++ { ++ free (string); ++ return FALSE; ++ } ++#ifdef EXTRA_SHLIB_EXTENSION ++ } ++#endif ++ ++ entry->filename = string; ++ ++ /* We have found a dynamic object to include in the link. The ELF ++ backend linker will create a DT_NEEDED entry in the .dynamic ++ section naming this file. If this file includes a DT_SONAME ++ entry, it will be used. Otherwise, the ELF linker will just use ++ the name of the file. For an archive found by searching, like ++ this one, the DT_NEEDED entry should consist of just the name of ++ the file, without the path information used to find it. Note ++ that we only need to do this if we have a dynamic object; an ++ archive will never be referenced by a DT_NEEDED entry. ++ ++ FIXME: This approach--using bfd_elf_set_dt_needed_name--is not ++ very pretty. I haven't been able to think of anything that is ++ pretty, though. */ ++ if (bfd_check_format (entry->the_bfd, bfd_object) ++ && (entry->the_bfd->flags & DYNAMIC) != 0) ++ { ++ ASSERT (entry->flags.maybe_archive && entry->flags.search_dirs); ++ ++ /* Rather than duplicating the logic above. Just use the ++ filename we recorded earlier. */ ++ ++ filename = lbasename (entry->filename); ++ bfd_elf_set_dt_needed_name (entry->the_bfd, filename); ++ } ++ ++ return TRUE; ++} ++ ++EOF ++fi ++ ++if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then ++fragment <<EOF ++ ++/* A variant of lang_output_section_find used by place_orphan. */ ++ ++static lang_output_section_statement_type * ++output_rel_find (asection *sec, int isdyn) ++{ ++ lang_output_section_statement_type *lookup; ++ lang_output_section_statement_type *last = NULL; ++ lang_output_section_statement_type *last_alloc = NULL; ++ lang_output_section_statement_type *last_ro_alloc = NULL; ++ lang_output_section_statement_type *last_rel = NULL; ++ lang_output_section_statement_type *last_rel_alloc = NULL; ++ int rela = sec->name[4] == 'a'; ++ ++ for (lookup = &lang_output_section_statement.head->output_section_statement; ++ lookup != NULL; ++ lookup = lookup->next) ++ { ++ if (lookup->constraint >= 0 ++ && CONST_STRNEQ (lookup->name, ".rel")) ++ { ++ int lookrela = lookup->name[4] == 'a'; ++ ++ /* .rel.dyn must come before all other reloc sections, to suit ++ GNU ld.so. */ ++ if (isdyn) ++ break; ++ ++ /* Don't place after .rel.plt as doing so results in wrong ++ dynamic tags. */ ++ if (strcmp (".plt", lookup->name + 4 + lookrela) == 0) ++ break; ++ ++ if (rela == lookrela || last_rel == NULL) ++ last_rel = lookup; ++ if ((rela == lookrela || last_rel_alloc == NULL) ++ && lookup->bfd_section != NULL ++ && (lookup->bfd_section->flags & SEC_ALLOC) != 0) ++ last_rel_alloc = lookup; ++ } ++ ++ last = lookup; ++ if (lookup->bfd_section != NULL ++ && (lookup->bfd_section->flags & SEC_ALLOC) != 0) ++ { ++ last_alloc = lookup; ++ if ((lookup->bfd_section->flags & SEC_READONLY) != 0) ++ last_ro_alloc = lookup; ++ } ++ } ++ ++ if (last_rel_alloc) ++ return last_rel_alloc; ++ ++ if (last_rel) ++ return last_rel; ++ ++ if (last_ro_alloc) ++ return last_ro_alloc; ++ ++ if (last_alloc) ++ return last_alloc; ++ ++ return last; ++} ++ ++/* Place an orphan section. We use this to put random SHF_ALLOC ++ sections in the right segment. */ ++ ++static lang_output_section_statement_type * ++gld${EMULATION_NAME}_place_orphan (asection *s, ++ const char *secname, ++ int constraint) ++{ ++ static struct orphan_save hold[] = ++ { ++ { ".text", ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, ++ 0, 0, 0, 0 }, ++ { ".rodata", ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, ++ 0, 0, 0, 0 }, ++ { ".data", ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, ++ 0, 0, 0, 0 }, ++ { ".bss", ++ SEC_ALLOC, ++ 0, 0, 0, 0 }, ++ { 0, ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, ++ 0, 0, 0, 0 }, ++ { ".interp", ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, ++ 0, 0, 0, 0 }, ++ { ".sdata", ++ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA, ++ 0, 0, 0, 0 }, ++ { ".comment", ++ SEC_HAS_CONTENTS, ++ 0, 0, 0, 0 }, ++ }; ++ enum orphan_save_index ++ { ++ orphan_text = 0, ++ orphan_rodata, ++ orphan_data, ++ orphan_bss, ++ orphan_rel, ++ orphan_interp, ++ orphan_sdata, ++ orphan_nonalloc ++ }; ++ static int orphan_init_done = 0; ++ struct orphan_save *place; ++ lang_output_section_statement_type *after; ++ lang_output_section_statement_type *os; ++ lang_output_section_statement_type *match_by_name = NULL; ++ int isdyn = 0; ++ int iself = s->owner->xvec->flavour == bfd_target_elf_flavour; ++ unsigned int sh_type = iself ? elf_section_type (s) : SHT_NULL; ++ ++ if (! link_info.relocatable ++ && link_info.combreloc ++ && (s->flags & SEC_ALLOC)) ++ { ++ if (iself) ++ switch (sh_type) ++ { ++ case SHT_RELA: ++ secname = ".rela.dyn"; ++ isdyn = 1; ++ break; ++ case SHT_REL: ++ secname = ".rel.dyn"; ++ isdyn = 1; ++ break; ++ default: ++ break; ++ } ++ else if (CONST_STRNEQ (secname, ".rel")) ++ { ++ secname = secname[4] == 'a' ? ".rela.dyn" : ".rel.dyn"; ++ isdyn = 1; ++ } ++ } ++ ++ /* Look through the script to see where to place this section. */ ++ if (constraint == 0) ++ for (os = lang_output_section_find (secname); ++ os != NULL; ++ os = next_matching_output_section_statement (os, 0)) ++ { ++ /* If we don't match an existing output section, tell ++ lang_insert_orphan to create a new output section. */ ++ constraint = SPECIAL; ++ ++ if (os->bfd_section != NULL ++ && (os->bfd_section->flags == 0 ++ || (_bfd_elf_match_sections_by_type (link_info.output_bfd, ++ os->bfd_section, ++ s->owner, s) ++ && ((s->flags ^ os->bfd_section->flags) ++ & (SEC_LOAD | SEC_ALLOC)) == 0))) ++ { ++ /* We already have an output section statement with this ++ name, and its bfd section has compatible flags. ++ If the section already exists but does not have any flags ++ set, then it has been created by the linker, probably as a ++ result of a --section-start command line switch. */ ++ lang_add_section (&os->children, s, NULL, os); ++ return os; ++ } ++ ++ /* Save unused output sections in case we can match them ++ against orphans later. */ ++ if (os->bfd_section == NULL) ++ match_by_name = os; ++ } ++ ++ /* If we didn't match an active output section, see if we matched an ++ unused one and use that. */ ++ if (match_by_name) ++ { ++ lang_add_section (&match_by_name->children, s, NULL, match_by_name); ++ return match_by_name; ++ } ++ ++ if (!orphan_init_done) ++ { ++ struct orphan_save *ho; ++ ++ for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho) ++ if (ho->name != NULL) ++ { ++ ho->os = lang_output_section_find (ho->name); ++ if (ho->os != NULL && ho->os->flags == 0) ++ ho->os->flags = ho->flags; ++ } ++ orphan_init_done = 1; ++ } ++ ++ /* If this is a final link, then always put .gnu.warning.SYMBOL ++ sections into the .text section to get them out of the way. */ ++ if (link_info.executable ++ && ! link_info.relocatable ++ && CONST_STRNEQ (s->name, ".gnu.warning.") ++ && hold[orphan_text].os != NULL) ++ { ++ os = hold[orphan_text].os; ++ lang_add_section (&os->children, s, NULL, os); ++ return os; ++ } ++ ++ /* Decide which segment the section should go in based on the ++ section name and section flags. We put loadable .note sections ++ right after the .interp section, so that the PT_NOTE segment is ++ stored right after the program headers where the OS can read it ++ in the first page. */ ++ ++ place = NULL; ++ if ((s->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0) ++ place = &hold[orphan_nonalloc]; ++ else if ((s->flags & SEC_ALLOC) == 0) ++ ; ++ else if ((s->flags & SEC_LOAD) != 0 ++ && ((iself && sh_type == SHT_NOTE) ++ || (!iself && CONST_STRNEQ (secname, ".note")))) ++ place = &hold[orphan_interp]; ++ else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) == 0) ++ place = &hold[orphan_bss]; ++ else if ((s->flags & SEC_SMALL_DATA) != 0) ++ place = &hold[orphan_sdata]; ++ else if ((s->flags & SEC_READONLY) == 0) ++ place = &hold[orphan_data]; ++ else if (((iself && (sh_type == SHT_RELA || sh_type == SHT_REL)) ++ || (!iself && CONST_STRNEQ (secname, ".rel"))) ++ && (s->flags & SEC_LOAD) != 0) ++ place = &hold[orphan_rel]; ++ else if ((s->flags & SEC_CODE) == 0) ++ place = &hold[orphan_rodata]; ++ else ++ place = &hold[orphan_text]; ++ ++ after = NULL; ++ if (place != NULL) ++ { ++ if (place->os == NULL) ++ { ++ if (place->name != NULL) ++ place->os = lang_output_section_find (place->name); ++ else ++ place->os = output_rel_find (s, isdyn); ++ } ++ after = place->os; ++ if (after == NULL) ++ after = lang_output_section_find_by_flags ++ (s, &place->os, _bfd_elf_match_sections_by_type); ++ if (after == NULL) ++ /* *ABS* is always the first output section statement. */ ++ after = &lang_output_section_statement.head->output_section_statement; ++ } ++ ++ return lang_insert_orphan (s, secname, constraint, after, place, NULL, NULL); ++} ++EOF ++fi ++ ++if test x"$LDEMUL_AFTER_ALLOCATION" != xgld"$EMULATION_NAME"_after_allocation; then ++fragment <<EOF ++ ++static void ++gld${EMULATION_NAME}_after_allocation (void) ++{ ++ bfd_boolean need_layout = bfd_elf_discard_info (link_info.output_bfd, ++ &link_info); ++ gld${EMULATION_NAME}_map_segments (need_layout); ++} ++EOF ++fi ++ ++if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then ++fragment <<EOF ++ ++static char * ++gld${EMULATION_NAME}_get_script (int *isfile) ++EOF ++ ++if test -n "$COMPILE_IN" ++then ++# Scripts compiled in. ++ ++# sed commands to quote an ld script as a C string. ++sc="-f stringify.sed" ++ ++fragment <<EOF ++{ ++ *isfile = 0; ++ ++ if (link_info.relocatable && config.build_constructors) ++ return ++EOF ++sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c ++echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c ++if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else ++echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c ++fi ++if test -n "$GENERATE_PIE_SCRIPT" ; then ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++echo ' ; else if (link_info.pie && link_info.combreloc' >> e${EMULATION_NAME}.c ++echo ' && link_info.relro' >> e${EMULATION_NAME}.c ++echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.pie && link_info.combreloc) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c ++fi ++echo ' ; else if (link_info.pie) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xd >> e${EMULATION_NAME}.c ++fi ++if test -n "$GENERATE_SHLIB_SCRIPT" ; then ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++echo ' ; else if (link_info.shared && link_info.combreloc' >> e${EMULATION_NAME}.c ++echo ' && link_info.relro' >> e${EMULATION_NAME}.c ++echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c ++fi ++echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c ++fi ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++echo ' ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c ++echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c ++echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c ++fi ++echo ' ; else return' >> e${EMULATION_NAME}.c ++sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c ++echo '; }' >> e${EMULATION_NAME}.c ++ ++else ++# Scripts read from the filesystem. ++ ++fragment <<EOF ++{ ++ *isfile = 1; ++ ++ if (link_info.relocatable && config.build_constructors) ++ return "ldscripts/${EMULATION_NAME}.xu"; ++ else if (link_info.relocatable) ++ return "ldscripts/${EMULATION_NAME}.xr"; ++ else if (!config.text_read_only) ++ return "ldscripts/${EMULATION_NAME}.xbn"; ++EOF ++if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ++else ++fragment <<EOF ++ else if (!config.magic_demand_paged) ++ return "ldscripts/${EMULATION_NAME}.xn"; ++EOF ++fi ++if test -n "$GENERATE_PIE_SCRIPT" ; then ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++fragment <<EOF ++ else if (link_info.pie && link_info.combreloc ++ && link_info.relro && (link_info.flags & DF_BIND_NOW)) ++ return "ldscripts/${EMULATION_NAME}.xdw"; ++ else if (link_info.pie && link_info.combreloc) ++ return "ldscripts/${EMULATION_NAME}.xdc"; ++EOF ++fi ++fragment <<EOF ++ else if (link_info.pie) ++ return "ldscripts/${EMULATION_NAME}.xd"; ++EOF ++fi ++if test -n "$GENERATE_SHLIB_SCRIPT" ; then ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++fragment <<EOF ++ else if (link_info.shared && link_info.combreloc ++ && link_info.relro && (link_info.flags & DF_BIND_NOW)) ++ return "ldscripts/${EMULATION_NAME}.xsw"; ++ else if (link_info.shared && link_info.combreloc) ++ return "ldscripts/${EMULATION_NAME}.xsc"; ++EOF ++fi ++fragment <<EOF ++ else if (link_info.shared) ++ return "ldscripts/${EMULATION_NAME}.xs"; ++EOF ++fi ++if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then ++fragment <<EOF ++ else if (link_info.combreloc && link_info.relro ++ && (link_info.flags & DF_BIND_NOW)) ++ return "ldscripts/${EMULATION_NAME}.xw"; ++ else if (link_info.combreloc) ++ return "ldscripts/${EMULATION_NAME}.xc"; ++EOF ++fi ++fragment <<EOF ++ else ++ return "ldscripts/${EMULATION_NAME}.x"; ++} ++ ++EOF ++fi ++fi ++ ++if test -n "$PARSE_AND_LIST_PROLOGUE" ; then ++fragment <<EOF ++ $PARSE_AND_LIST_PROLOGUE ++EOF ++fi ++ ++fragment <<EOF ++ ++#define OPTION_DISABLE_NEW_DTAGS (400) ++#define OPTION_ENABLE_NEW_DTAGS (OPTION_DISABLE_NEW_DTAGS + 1) ++#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1) ++#define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1) ++#define OPTION_EXCLUDE_LIBS (OPTION_EH_FRAME_HDR + 1) ++#define OPTION_HASH_STYLE (OPTION_EXCLUDE_LIBS + 1) ++#define OPTION_BUILD_ID (OPTION_HASH_STYLE + 1) ++#define OPTION_AUDIT (OPTION_BUILD_ID + 1) ++ ++static void ++gld${EMULATION_NAME}_add_options ++ (int ns, char **shortopts, int nl, struct option **longopts, ++ int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED) ++{ ++EOF ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++fragment <<EOF ++ static const char xtra_short[] = "${PARSE_AND_LIST_SHORTOPTS}z:P:"; ++EOF ++else ++fragment <<EOF ++ static const char xtra_short[] = "${PARSE_AND_LIST_SHORTOPTS}z:"; ++EOF ++fi ++fragment <<EOF ++ static const struct option xtra_long[] = { ++EOF ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++fragment <<EOF ++ {"audit", required_argument, NULL, OPTION_AUDIT}, ++ {"Bgroup", no_argument, NULL, OPTION_GROUP}, ++EOF ++fi ++fragment <<EOF ++ {"build-id", optional_argument, NULL, OPTION_BUILD_ID}, ++EOF ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++fragment <<EOF ++ {"depaudit", required_argument, NULL, 'P'}, ++ {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS}, ++ {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS}, ++ {"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR}, ++ {"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS}, ++ {"hash-style", required_argument, NULL, OPTION_HASH_STYLE}, ++EOF ++fi ++if test -n "$PARSE_AND_LIST_LONGOPTS" ; then ++fragment <<EOF ++ $PARSE_AND_LIST_LONGOPTS ++EOF ++fi ++fragment <<EOF ++ {NULL, no_argument, NULL, 0} ++ }; ++ ++ *shortopts = (char *) xrealloc (*shortopts, ns + sizeof (xtra_short)); ++ memcpy (*shortopts + ns, &xtra_short, sizeof (xtra_short)); ++ *longopts = (struct option *) ++ xrealloc (*longopts, nl * sizeof (struct option) + sizeof (xtra_long)); ++ memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long)); ++} ++ ++#define DEFAULT_BUILD_ID_STYLE "sha1" ++ ++static bfd_boolean ++gld${EMULATION_NAME}_handle_option (int optc) ++{ ++ switch (optc) ++ { ++ default: ++ return FALSE; ++ ++ case OPTION_BUILD_ID: ++ if (link_info.emit_note_gnu_build_id != NULL) ++ { ++ free (link_info.emit_note_gnu_build_id); ++ link_info.emit_note_gnu_build_id = NULL; ++ } ++ if (optarg == NULL) ++ optarg = DEFAULT_BUILD_ID_STYLE; ++ if (strcmp (optarg, "none")) ++ link_info.emit_note_gnu_build_id = xstrdup (optarg); ++ break; ++ ++EOF ++ ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++fragment <<EOF ++ case OPTION_AUDIT: ++ gld${EMULATION_NAME}_append_to_separated_string (&audit, optarg); ++ break; ++ ++ case 'P': ++ gld${EMULATION_NAME}_append_to_separated_string (&depaudit, optarg); ++ break; ++ ++ case OPTION_DISABLE_NEW_DTAGS: ++ link_info.new_dtags = FALSE; ++ break; ++ ++ case OPTION_ENABLE_NEW_DTAGS: ++ link_info.new_dtags = TRUE; ++ break; ++ ++ case OPTION_EH_FRAME_HDR: ++ link_info.eh_frame_hdr = TRUE; ++ break; ++ ++ case OPTION_GROUP: ++ link_info.flags_1 |= (bfd_vma) DF_1_GROUP; ++ /* Groups must be self-contained. */ ++ link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR; ++ link_info.unresolved_syms_in_shared_libs = RM_GENERATE_ERROR; ++ break; ++ ++ case OPTION_EXCLUDE_LIBS: ++ add_excluded_libs (optarg); ++ break; ++ ++ case OPTION_HASH_STYLE: ++ link_info.emit_hash = FALSE; ++ link_info.emit_gnu_hash = FALSE; ++ if (strcmp (optarg, "sysv") == 0) ++ link_info.emit_hash = TRUE; ++ else if (strcmp (optarg, "gnu") == 0) ++ link_info.emit_gnu_hash = TRUE; ++ else if (strcmp (optarg, "both") == 0) ++ { ++ link_info.emit_hash = TRUE; ++ link_info.emit_gnu_hash = TRUE; ++ } ++ else ++ einfo (_("%P%F: invalid hash style \`%s'\n"), optarg); ++ break; ++ ++EOF ++fi ++fragment <<EOF ++ case 'z': ++ if (strcmp (optarg, "defs") == 0) ++ link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR; ++ else if (strcmp (optarg, "muldefs") == 0) ++ link_info.allow_multiple_definition = TRUE; ++ else if (CONST_STRNEQ (optarg, "max-page-size=")) ++ { ++ char *end; ++ ++ config.maxpagesize = strtoul (optarg + 14, &end, 0); ++ if (*end || (config.maxpagesize & (config.maxpagesize - 1)) != 0) ++ einfo (_("%P%F: invalid maxium page size \`%s'\n"), ++ optarg + 14); ++ } ++ else if (CONST_STRNEQ (optarg, "common-page-size=")) ++ { ++ char *end; ++ config.commonpagesize = strtoul (optarg + 17, &end, 0); ++ if (*end ++ || (config.commonpagesize & (config.commonpagesize - 1)) != 0) ++ einfo (_("%P%F: invalid common page size \`%s'\n"), ++ optarg + 17); ++ } ++ else if (strcmp (optarg, "execstack") == 0) ++ { ++ link_info.execstack = TRUE; ++ link_info.noexecstack = FALSE; ++ } ++ else if (strcmp (optarg, "noexecstack") == 0) ++ { ++ link_info.noexecstack = TRUE; ++ link_info.execstack = FALSE; ++ } ++EOF ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++fragment <<EOF ++ else if (strcmp (optarg, "initfirst") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST; ++ else if (strcmp (optarg, "interpose") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_INTERPOSE; ++ else if (strcmp (optarg, "loadfltr") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_LOADFLTR; ++ else if (strcmp (optarg, "nodefaultlib") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NODEFLIB; ++ else if (strcmp (optarg, "nodelete") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NODELETE; ++ else if (strcmp (optarg, "nodlopen") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NOOPEN; ++ else if (strcmp (optarg, "nodump") == 0) ++ link_info.flags_1 |= (bfd_vma) DF_1_NODUMP; ++ else if (strcmp (optarg, "now") == 0) ++ { ++ link_info.flags |= (bfd_vma) DF_BIND_NOW; ++ link_info.flags_1 |= (bfd_vma) DF_1_NOW; ++ } ++ else if (strcmp (optarg, "lazy") == 0) ++ { ++ link_info.flags &= ~(bfd_vma) DF_BIND_NOW; ++ link_info.flags_1 &= ~(bfd_vma) DF_1_NOW; ++ } ++ else if (strcmp (optarg, "origin") == 0) ++ { ++ link_info.flags |= (bfd_vma) DF_ORIGIN; ++ link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN; ++ } ++ else if (strcmp (optarg, "combreloc") == 0) ++ link_info.combreloc = TRUE; ++ else if (strcmp (optarg, "nocombreloc") == 0) ++ link_info.combreloc = FALSE; ++ else if (strcmp (optarg, "nocopyreloc") == 0) ++ link_info.nocopyreloc = TRUE; ++ else if (strcmp (optarg, "relro") == 0) ++ link_info.relro = TRUE; ++ else if (strcmp (optarg, "norelro") == 0) ++ link_info.relro = FALSE; ++ else if (strcmp (optarg, "text") == 0) ++ link_info.error_textrel = TRUE; ++ else if (strcmp (optarg, "notext") == 0) ++ link_info.error_textrel = FALSE; ++ else if (strcmp (optarg, "textoff") == 0) ++ link_info.error_textrel = FALSE; ++EOF ++fi ++ ++fragment <<EOF ++ else ++ einfo (_("%P: warning: -z %s ignored.\n"), optarg); ++ break; ++EOF ++ ++if test -n "$PARSE_AND_LIST_ARGS_CASES" ; then ++fragment <<EOF ++ $PARSE_AND_LIST_ARGS_CASES ++EOF ++fi ++ ++fragment <<EOF ++ } ++ ++ return TRUE; ++} ++ ++EOF ++ ++if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then ++fragment <<EOF ++ ++static void ++gld${EMULATION_NAME}_list_options (FILE * file) ++{ ++EOF ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++fragment <<EOF ++ fprintf (file, _("\ ++ --audit=AUDITLIB Specify a library to use for auditing\n")); ++ fprintf (file, _("\ ++ -Bgroup Selects group name lookup rules for DSO\n")); ++EOF ++fi ++fragment <<EOF ++ fprintf (file, _("\ ++ --build-id[=STYLE] Generate build ID note\n")); ++EOF ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++fragment <<EOF ++ fprintf (file, _("\ ++ -P AUDITLIB, --depaudit=AUDITLIB\n" "\ ++ Specify a library to use for auditing dependencies\n")); ++ fprintf (file, _("\ ++ --disable-new-dtags Disable new dynamic tags\n")); ++ fprintf (file, _("\ ++ --enable-new-dtags Enable new dynamic tags\n")); ++ fprintf (file, _("\ ++ --eh-frame-hdr Create .eh_frame_hdr section\n")); ++ fprintf (file, _("\ ++ --exclude-libs=LIBS Make all symbols in LIBS hidden\n")); ++ fprintf (file, _("\ ++ --hash-style=STYLE Set hash style to sysv, gnu or both\n")); ++ fprintf (file, _("\ ++ -z combreloc Merge dynamic relocs into one section and sort\n")); ++EOF ++fi ++ ++fragment <<EOF ++ fprintf (file, _("\ ++ -z common-page-size=SIZE Set common page size to SIZE\n")); ++ fprintf (file, _("\ ++ -z defs Report unresolved symbols in object files.\n")); ++ fprintf (file, _("\ ++ -z execstack Mark executable as requiring executable stack\n")); ++EOF ++ ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++fragment <<EOF ++ fprintf (file, _("\ ++ -z initfirst Mark DSO to be initialized first at runtime\n")); ++ fprintf (file, _("\ ++ -z interpose Mark object to interpose all DSOs but executable\n")); ++ fprintf (file, _("\ ++ -z lazy Mark object lazy runtime binding (default)\n")); ++ fprintf (file, _("\ ++ -z loadfltr Mark object requiring immediate process\n")); ++EOF ++fi ++ ++fragment <<EOF ++ fprintf (file, _("\ ++ -z max-page-size=SIZE Set maximum page size to SIZE\n")); ++ fprintf (file, _("\ ++ -z muldefs Allow multiple definitions\n")); ++EOF ++ ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++fragment <<EOF ++ fprintf (file, _("\ ++ -z nocombreloc Don't merge dynamic relocs into one section\n")); ++ fprintf (file, _("\ ++ -z nocopyreloc Don't create copy relocs\n")); ++ fprintf (file, _("\ ++ -z nodefaultlib Mark object not to use default search paths\n")); ++ fprintf (file, _("\ ++ -z nodelete Mark DSO non-deletable at runtime\n")); ++ fprintf (file, _("\ ++ -z nodlopen Mark DSO not available to dlopen\n")); ++ fprintf (file, _("\ ++ -z nodump Mark DSO not available to dldump\n")); ++EOF ++fi ++fragment <<EOF ++ fprintf (file, _("\ ++ -z noexecstack Mark executable as not requiring executable stack\n")); ++EOF ++if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then ++fragment <<EOF ++ fprintf (file, _("\ ++ -z norelro Don't create RELRO program header\n")); ++ fprintf (file, _("\ ++ -z now Mark object non-lazy runtime binding\n")); ++ fprintf (file, _("\ ++ -z origin Mark object requiring immediate \$ORIGIN\n\ ++ processing at runtime\n")); ++ fprintf (file, _("\ ++ -z relro Create RELRO program header\n")); ++EOF ++fi ++ ++if test -n "$PARSE_AND_LIST_OPTIONS" ; then ++fragment <<EOF ++ $PARSE_AND_LIST_OPTIONS ++EOF ++fi ++ ++fragment <<EOF ++} ++EOF ++ ++if test -n "$PARSE_AND_LIST_EPILOGUE" ; then ++fragment <<EOF ++ $PARSE_AND_LIST_EPILOGUE ++EOF ++fi ++fi ++ ++fragment <<EOF ++ ++struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = ++{ ++ ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse}, ++ ${LDEMUL_SYSLIB-syslib_default}, ++ ${LDEMUL_HLL-hll_default}, ++ ${LDEMUL_AFTER_PARSE-after_parse_default}, ++ ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open}, ++ ${LDEMUL_AFTER_ALLOCATION-gld${EMULATION_NAME}_after_allocation}, ++ ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default}, ++ ${LDEMUL_CHOOSE_TARGET-ldemul_default_target}, ++ ${LDEMUL_BEFORE_ALLOCATION-gld${EMULATION_NAME}_before_allocation}, ++ ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script}, ++ "${EMULATION_NAME}", ++ "${OUTPUT_FORMAT}", ++ ${LDEMUL_FINISH-finish_default}, ++ ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL}, ++ ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-gld${EMULATION_NAME}_open_dynamic_archive}, ++ ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan}, ++ ${LDEMUL_SET_SYMBOLS-NULL}, ++ ${LDEMUL_PARSE_ARGS-NULL}, ++ gld${EMULATION_NAME}_add_options, ++ gld${EMULATION_NAME}_handle_option, ++ ${LDEMUL_UNRECOGNIZED_FILE-NULL}, ++ ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options}, ++ ${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols}, ++ ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL}, ++ ${LDEMUL_NEW_VERS_PATTERN-NULL} ++}; ++EOF +--- /dev/null 2015-09-06 08:42:34.091999986 +0100 ++++ ld/scripttempl/amigaos.sc 2016-01-03 01:46:50.663001071 +0000 +@@ -0,0 +1,527 @@ ++# ++# Unusual variables checked by this code: ++# NOP - four byte opcode for no-op (defaults to 0) ++# NO_SMALL_DATA - no .sbss/.sbss2/.sdata/.sdata2 sections if not ++# empty. ++# SMALL_DATA_CTOR - .ctors contains small data. ++# SMALL_DATA_DTOR - .dtors contains small data. ++# DATA_ADDR - if end-of-text-plus-one-page isn't right for data start ++# INITIAL_READONLY_SECTIONS - at start of text segment ++# OTHER_READONLY_SECTIONS - other than .text .init .rodata ... ++# (e.g., .PARISC.milli) ++# OTHER_TEXT_SECTIONS - these get put in .text when relocating ++# OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ... ++# (e.g., .PARISC.global) ++# OTHER_RELRO_SECTIONS - other than .data.rel.ro ... ++# (e.g. PPC32 .fixup, .got[12]) ++# OTHER_BSS_SECTIONS - other than .bss .sbss ... ++# ATTRS_SECTIONS - at the end ++# OTHER_SECTIONS - at the end ++# EXECUTABLE_SYMBOLS - symbols that must be defined for an ++# executable (e.g., _DYNAMIC_LINK) ++# TEXT_START_ADDR - the first byte of the text segment, after any ++# headers. ++# TEXT_BASE_ADDRESS - the first byte of the text segment. ++# TEXT_START_SYMBOLS - symbols that appear at the start of the ++# .text section. ++# DATA_START_SYMBOLS - symbols that appear at the start of the ++# .data section. ++# DATA_END_SYMBOLS - symbols that appear at the end of the ++# writeable data sections. ++# OTHER_GOT_SYMBOLS - symbols defined just before .got. ++# OTHER_GOT_SECTIONS - sections just after .got. ++# OTHER_SDATA_SECTIONS - sections just after .sdata. ++# OTHER_BSS_SYMBOLS - symbols that appear at the start of the ++# .bss section besides __bss_start. ++# DATA_PLT - .plt should be in data segment, not text segment. ++# PLT_BEFORE_GOT - .plt just before .got when .plt is in data segement. ++# BSS_PLT - .plt should be in bss segment ++# TEXT_DYNAMIC - .dynamic in text segment, not data segment. ++# EMBEDDED - whether this is for an embedded system. ++# SHLIB_TEXT_START_ADDR - if set, add to SIZEOF_HEADERS to set ++# start address of shared library. ++# INPUT_FILES - INPUT command of files to always include ++# WRITABLE_RODATA - if set, the .rodata section should be writable ++# INIT_START, INIT_END - statements just before and just after ++# combination of .init sections. ++# FINI_START, FINI_END - statements just before and just after ++# combination of .fini sections. ++# STACK_ADDR - start of a .stack section. ++# OTHER_SYMBOLS - symbols to place right at the end of the script. ++# ETEXT_NAME - name of a symbol for the end of the text section, ++# normally etext. ++# SEPARATE_GOTPLT - if set, .got.plt should be separate output section, ++# so that .got can be in the RELRO area. It should be set to ++# the number of bytes in the beginning of .got.plt which can be ++# in the RELRO area as well. ++# USER_LABEL_PREFIX - prefix to add to user-visible symbols. ++# ++# When adding sections, do note that the names of some sections are used ++# when specifying the start address of the next. ++# ++ ++# Many sections come in three flavours. There is the 'real' section, ++# like ".data". Then there are the per-procedure or per-variable ++# sections, generated by -ffunction-sections and -fdata-sections in GCC, ++# and useful for --gc-sections, which for a variable "foo" might be ++# ".data.foo". Then there are the linkonce sections, for which the linker ++# eliminates duplicates, which are named like ".gnu.linkonce.d.foo". ++# The exact correspondences are: ++# ++# Section Linkonce section ++# .text .gnu.linkonce.t.foo ++# .rodata .gnu.linkonce.r.foo ++# .data .gnu.linkonce.d.foo ++# .bss .gnu.linkonce.b.foo ++# .sdata .gnu.linkonce.s.foo ++# .sbss .gnu.linkonce.sb.foo ++# .sdata2 .gnu.linkonce.s2.foo ++# .sbss2 .gnu.linkonce.sb2.foo ++# .debug_info .gnu.linkonce.wi.foo ++# .tdata .gnu.linkonce.td.foo ++# .tbss .gnu.linkonce.tb.foo ++# .lrodata .gnu.linkonce.lr.foo ++# .ldata .gnu.linkonce.l.foo ++# .lbss .gnu.linkonce.lb.foo ++# ++# Each of these can also have corresponding .rel.* and .rela.* sections. ++ ++test -z "$ENTRY" && ENTRY=_start ++test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT} ++test -z "${LITTLE_OUTPUT_FORMAT}" && LITTLE_OUTPUT_FORMAT=${OUTPUT_FORMAT} ++if [ -z "$MACHINE" ]; then OUTPUT_ARCH=${ARCH}; else OUTPUT_ARCH=${ARCH}:${MACHINE}; fi ++test -z "${ELFSIZE}" && ELFSIZE=32 ++test -z "${ALIGNMENT}" && ALIGNMENT="${ELFSIZE} / 8" ++test "$LD_FLAG" = "N" && DATA_ADDR=. ++test -z "${ETEXT_NAME}" && ETEXT_NAME=etext ++test -n "$CREATE_SHLIB$CREATE_PIE" && test -n "$SHLIB_DATA_ADDR" && COMMONPAGESIZE="" ++test -z "$CREATE_SHLIB$CREATE_PIE" && test -n "$DATA_ADDR" && COMMONPAGESIZE="" ++test -n "$RELRO_NOW" && unset SEPARATE_GOTPLT ++test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }" ++DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE})" ++#DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))" ++DATA_SEGMENT_RELRO_END="" ++DATA_SEGMENT_END="" ++if test -n "${COMMONPAGESIZE}"; then ++ DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})" ++ DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);" ++ DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT-0}, .);" ++fi ++if test -z "${INITIAL_READONLY_SECTIONS}${CREATE_SHLIB}"; then ++ INITIAL_READONLY_SECTIONS=".interp ${RELOCATING-0} : { *(.interp) }" ++fi ++if test -z "$PLT"; then ++ PLT=".plt ${RELOCATING-0} : { *(.plt) }" ++fi ++test -n "${DATA_PLT-${BSS_PLT-text}}" && TEXT_PLT=yes ++if test -z "$GOT"; then ++ if test -z "$SEPARATE_GOTPLT"; then ++ GOT=".got ${RELOCATING-0} : { *(.got.plt) *(.got) }" ++ else ++ GOT=".got ${RELOCATING-0} : { *(.got) }" ++ GOTPLT=".got.plt ${RELOCATING-0} : { *(.got.plt) }" ++ fi ++fi ++DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }" ++RODATA=".rodata ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }" ++DATARELRO=".data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }" ++DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) }" ++if test -z "${NO_SMALL_DATA}"; then ++ SBSS=".sbss ${RELOCATING-0} : ++ { ++ ${RELOCATING+${SBSS_START_SYMBOLS}} ++ ${CREATE_SHLIB+*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)} ++ *(.dynsbss) ++ *(.sbss${RELOCATING+ .sbss.* .gnu.linkonce.sb.*}) ++ *(.scommon) ++ ${RELOCATING+${SBSS_END_SYMBOLS}} ++ }" ++ SBSS2=".sbss2 ${RELOCATING-0} : { *(.sbss2${RELOCATING+ .sbss2.* .gnu.linkonce.sb2.*}) }" ++ SDATA="/* We want the small data sections together, so single-instruction offsets ++ can access them all, and initialized data all before uninitialized, so ++ we can shorten the on-disk segment size. */ ++ .sdata ${RELOCATING-0} : ++ { ++ ${RELOCATING+${SDATA_START_SYMBOLS}} ++ ${CREATE_SHLIB+*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)} ++ *(.sdata${RELOCATING+ .sdata.* .gnu.linkonce.s.*}) ++ }" ++ SDATA2=".sdata2 ${RELOCATING-0} : ++ { ++ ${RELOCATING+${SDATA2_START_SYMBOLS}} ++ *(.sdata2${RELOCATING+ .sdata2.* .gnu.linkonce.s2.*}) ++ }" ++ REL_SDATA=".rel.sdata ${RELOCATING-0} : { *(.rel.sdata${RELOCATING+ .rel.sdata.* .rel.gnu.linkonce.s.*}) } ++ .rela.sdata ${RELOCATING-0} : { *(.rela.sdata${RELOCATING+ .rela.sdata.* .rela.gnu.linkonce.s.*}) }" ++ REL_SBSS=".rel.sbss ${RELOCATING-0} : { *(.rel.sbss${RELOCATING+ .rel.sbss.* .rel.gnu.linkonce.sb.*}) } ++ .rela.sbss ${RELOCATING-0} : { *(.rela.sbss${RELOCATING+ .rela.sbss.* .rela.gnu.linkonce.sb.*}) }" ++ REL_SDATA2=".rel.sdata2 ${RELOCATING-0} : { *(.rel.sdata2${RELOCATING+ .rel.sdata2.* .rel.gnu.linkonce.s2.*}) } ++ .rela.sdata2 ${RELOCATING-0} : { *(.rela.sdata2${RELOCATING+ .rela.sdata2.* .rela.gnu.linkonce.s2.*}) }" ++ REL_SBSS2=".rel.sbss2 ${RELOCATING-0} : { *(.rel.sbss2${RELOCATING+ .rel.sbss2.* .rel.gnu.linkonce.sb2.*}) } ++ .rela.sbss2 ${RELOCATING-0} : { *(.rela.sbss2${RELOCATING+ .rela.sbss2.* .rela.gnu.linkonce.sb2.*}) }" ++else ++ NO_SMALL_DATA=" " ++fi ++if test -z "${DATA_GOT}"; then ++ if test -n "${NO_SMALL_DATA}"; then ++ DATA_GOT=" " ++ fi ++fi ++if test -z "${SDATA_GOT}"; then ++ if test -z "${NO_SMALL_DATA}"; then ++ SDATA_GOT=" " ++ fi ++fi ++test -n "$SEPARATE_GOTPLT" && SEPARATE_GOTPLT=" " ++test "${LARGE_SECTIONS}" = "yes" && REL_LARGE=" ++ .rel.ldata ${RELOCATING-0} : { *(.rel.ldata${RELOCATING+ .rel.ldata.* .rel.gnu.linkonce.l.*}) } ++ .rela.ldata ${RELOCATING-0} : { *(.rela.ldata${RELOCATING+ .rela.ldata.* .rela.gnu.linkonce.l.*}) } ++ .rel.lbss ${RELOCATING-0} : { *(.rel.lbss${RELOCATING+ .rel.lbss.* .rel.gnu.linkonce.lb.*}) } ++ .rela.lbss ${RELOCATING-0} : { *(.rela.lbss${RELOCATING+ .rela.lbss.* .rela.gnu.linkonce.lb.*}) } ++ .rel.lrodata ${RELOCATING-0} : { *(.rel.lrodata${RELOCATING+ .rel.lrodata.* .rel.gnu.linkonce.lr.*}) } ++ .rela.lrodata ${RELOCATING-0} : { *(.rela.lrodata${RELOCATING+ .rela.lrodata.* .rela.gnu.linkonce.lr.*}) }" ++test "${LARGE_SECTIONS}" = "yes" && OTHER_BSS_SECTIONS=" ++ ${OTHER_BSS_SECTIONS} ++ .lbss ${RELOCATING-0} : ++ { ++ *(.dynlbss) ++ *(.lbss${RELOCATING+ .lbss.* .gnu.linkonce.lb.*}) ++ *(LARGE_COMMON) ++ }" ++test "${LARGE_SECTIONS}" = "yes" && LARGE_SECTIONS=" ++ .lrodata ${RELOCATING-0} ${RELOCATING+ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))} : ++ { ++ *(.lrodata${RELOCATING+ .lrodata.* .gnu.linkonce.lr.*}) ++ } ++ .ldata ${RELOCATING-0} ${RELOCATING+ALIGN(${MAXPAGESIZE}) + (. & (${MAXPAGESIZE} - 1))} : ++ { ++ *(.ldata${RELOCATING+ .ldata.* .gnu.linkonce.l.*}) ++ ${RELOCATING+. = ALIGN(. != 0 ? ${ALIGNMENT} : 1);} ++ }" ++CTOR=".ctors ${CONSTRUCTING-0} : ++ { ++ ${CONSTRUCTING+${CTOR_START}} ++ /* gcc uses crtbegin.o to find the start of ++ the constructors, so we make sure it is ++ first. Because this is a wildcard, it ++ doesn't matter if the user does not ++ actually link against crtbegin.o; the ++ linker won't look for a file to match a ++ wildcard. The wildcard also means that it ++ doesn't matter which directory crtbegin.o ++ is in. */ ++ ++ KEEP (*crtbegin.o(.ctors)) ++ KEEP (*crtbegin?.o(.ctors)) ++ ++ /* We don't want to include the .ctor section from ++ the crtend.o file until after the sorted ctors. ++ The .ctor section from the crtend file contains the ++ end of ctors marker and it must be last */ ++ ++ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o $OTHER_EXCLUDE_FILES) .ctors)) ++ KEEP (*(SORT(.ctors.*))) ++ KEEP (*(.ctors)) ++ ${CONSTRUCTING+${CTOR_END}} ++ }" ++DTOR=".dtors ${CONSTRUCTING-0} : ++ { ++ ${CONSTRUCTING+${DTOR_START}} ++ KEEP (*crtbegin.o(.dtors)) ++ KEEP (*crtbegin?.o(.dtors)) ++ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o $OTHER_EXCLUDE_FILES) .dtors)) ++ KEEP (*(SORT(.dtors.*))) ++ KEEP (*(.dtors)) ++ ${CONSTRUCTING+${DTOR_END}} ++ }" ++STACK=" .stack ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} : ++ { ++ ${RELOCATING+_stack = .;} ++ *(.stack) ++ }" ++ ++# if this is for an embedded system, don't add SIZEOF_HEADERS. ++if [ -z "$EMBEDDED" ]; then ++ test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR} + SIZEOF_HEADERS" ++else ++ test -z "${TEXT_BASE_ADDRESS}" && TEXT_BASE_ADDRESS="${TEXT_START_ADDR}" ++fi ++ ++cat <<EOF ++OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}", ++ "${LITTLE_OUTPUT_FORMAT}") ++OUTPUT_ARCH(${OUTPUT_ARCH}) ++ENTRY(${ENTRY}) ++ ++${RELOCATING+${LIB_SEARCH_DIRS}} ++${RELOCATING+${EXECUTABLE_SYMBOLS}} ++${RELOCATING+${INPUT_FILES}} ++${RELOCATING- /* For some reason, the Solaris linker makes bad executables ++ if gld -r is used and the intermediate file has sections starting ++ at non-zero addresses. Could be a Solaris ld bug, could be a GNU ld ++ bug. But for now assigning the zero vmas works. */} ++ ++SECTIONS ++{ ++ /* Read-only sections, merged into text segment: */ ++ ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+PROVIDE (__executable_start = ${TEXT_START_ADDR}); . = ${TEXT_BASE_ADDRESS};}}} ++ ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}} ++ ${CREATE_PIE+${RELOCATING+. = ${SHLIB_TEXT_START_ADDR:-0} + SIZEOF_HEADERS;}} ++ ${INITIAL_READONLY_SECTIONS} ++ .note.gnu.build-id : { *(.note.gnu.build-id) } ++ ${TEXT_DYNAMIC+${DYNAMIC}} ++ .hash ${RELOCATING-0} : { *(.hash) } ++ .gnu.hash ${RELOCATING-0} : { *(.gnu.hash) } ++ .dynsym ${RELOCATING-0} : { *(.dynsym) } ++ .dynstr ${RELOCATING-0} : { *(.dynstr) } ++ .gnu.version ${RELOCATING-0} : { *(.gnu.version) } ++ .gnu.version_d ${RELOCATING-0}: { *(.gnu.version_d) } ++ .gnu.version_r ${RELOCATING-0}: { *(.gnu.version_r) } ++ ++EOF ++if [ "x$COMBRELOC" = x ]; then ++ COMBRELOCCAT=cat ++else ++ COMBRELOCCAT="cat > $COMBRELOC" ++fi ++eval $COMBRELOCCAT <<EOF ++ .rel.init ${RELOCATING-0} : { *(.rel.init) } ++ .rela.init ${RELOCATING-0} : { *(.rela.init) } ++ .rel.text ${RELOCATING-0} : { *(.rel.text${RELOCATING+ .rel.text.* .rel.gnu.linkonce.t.*}) } ++ .rela.text ${RELOCATING-0} : { *(.rela.text${RELOCATING+ .rela.text.* .rela.gnu.linkonce.t.*}) } ++ .rel.fini ${RELOCATING-0} : { *(.rel.fini) } ++ .rela.fini ${RELOCATING-0} : { *(.rela.fini) } ++ .rel.rodata ${RELOCATING-0} : { *(.rel.rodata${RELOCATING+ .rel.rodata.* .rel.gnu.linkonce.r.*}) } ++ .rela.rodata ${RELOCATING-0} : { *(.rela.rodata${RELOCATING+ .rela.rodata.* .rela.gnu.linkonce.r.*}) } ++ ${OTHER_READONLY_RELOC_SECTIONS} ++ .rel.data.rel.ro ${RELOCATING-0} : { *(.rel.data.rel.ro${RELOCATING+* .rel.gnu.linkonce.d.rel.ro.*}) } ++ .rela.data.rel.ro ${RELOCATING-0} : { *(.rela.data.rel.ro${RELOCATING+* .rela.gnu.linkonce.d.rel.ro.*}) } ++ .rel.data ${RELOCATING-0} : { *(.rel.data${RELOCATING+ .rel.data.* .rel.gnu.linkonce.d.*}) } ++ .rela.data ${RELOCATING-0} : { *(.rela.data${RELOCATING+ .rela.data.* .rela.gnu.linkonce.d.*}) } ++ .rel.tdata ${RELOCATING-0} : { *(.rel.tdata${RELOCATING+ .rel.tdata.* .rel.gnu.linkonce.td.*}) } ++ .rela.tdata ${RELOCATING-0} : { *(.rela.tdata${RELOCATING+ .rela.tdata.* .rela.gnu.linkonce.td.*}) } ++ .rel.tbss ${RELOCATING-0} : { *(.rel.tbss${RELOCATING+ .rel.tbss.* .rel.gnu.linkonce.tb.*}) } ++ .rela.tbss ${RELOCATING-0} : { *(.rela.tbss${RELOCATING+ .rela.tbss.* .rela.gnu.linkonce.tb.*}) } ++ .rel.ctors ${RELOCATING-0} : { *(.rel.ctors) } ++ .rela.ctors ${RELOCATING-0} : { *(.rela.ctors) } ++ .rel.dtors ${RELOCATING-0} : { *(.rel.dtors) } ++ .rela.dtors ${RELOCATING-0} : { *(.rela.dtors) } ++ .rel.got ${RELOCATING-0} : { *(.rel.got) } ++ .rela.got ${RELOCATING-0} : { *(.rela.got) } ++ ${OTHER_GOT_RELOC_SECTIONS} ++ ${REL_SDATA} ++ ${REL_SBSS} ++ ${REL_SDATA2} ++ ${REL_SBSS2} ++ .rel.bss ${RELOCATING-0} : { *(.rel.bss${RELOCATING+ .rel.bss.* .rel.gnu.linkonce.b.*}) } ++ .rela.bss ${RELOCATING-0} : { *(.rela.bss${RELOCATING+ .rela.bss.* .rela.gnu.linkonce.b.*}) } ++ ${REL_LARGE} ++EOF ++if [ -n "$COMBRELOC" ]; then ++cat <<EOF ++ .rel.dyn ${RELOCATING-0} : ++ { ++EOF ++sed -e '/^[ ]*[{}][ ]*$/d;/:[ ]*$/d;/\.rela\./d;s/^.*: { *\(.*\)}$/ \1/' $COMBRELOC ++cat <<EOF ++ } ++ .rela.dyn ${RELOCATING-0} : ++ { ++EOF ++sed -e '/^[ ]*[{}][ ]*$/d;/:[ ]*$/d;/\.rel\./d;s/^.*: { *\(.*\)}/ \1/' $COMBRELOC ++cat <<EOF ++ } ++EOF ++fi ++cat <<EOF ++ .rel.plt ${RELOCATING-0} : { *(.rel.plt) } ++ .rela.plt ${RELOCATING-0} : { *(.rela.plt) } ++ ${OTHER_PLT_RELOC_SECTIONS} ++ ++ .init ${RELOCATING-0} : ++ { ++ ${RELOCATING+${INIT_START}} ++ KEEP (*(.init)) ++ ${RELOCATING+${INIT_END}} ++ } =${NOP-0} ++ ++ ${TINY_READONLY_SECTION} ++ .text ${RELOCATING-0} : ++ { ++ ${RELOCATING+${TEXT_START_SYMBOLS}} ++ *(.text .stub${RELOCATING+ .text.* .gnu.linkonce.t.*}) ++ KEEP (*(.text.*personality*)) ++ /* .gnu.warning sections are handled specially by elf32.em. */ ++ *(.gnu.warning) ++ ${RELOCATING+${OTHER_TEXT_SECTIONS}} ++ } =${NOP-0} ++ . = ALIGN(4096); ++ ${TEXT_PLT+${PLT}} ++ . = ALIGN(4096); ++ .fini ${RELOCATING-0} : ++ { ++ ${RELOCATING+${FINI_START}} ++ KEEP (*(.fini)) ++ ${RELOCATING+${FINI_END}} ++ } =${NOP-0} ++ ${RELOCATING+PROVIDE (__${ETEXT_NAME} = .);} ++ ${RELOCATING+PROVIDE (_${ETEXT_NAME} = .);} ++ ${RELOCATING+PROVIDE (${ETEXT_NAME} = .);} ++ ${WRITABLE_RODATA-${RODATA}} ++ .rodata1 ${RELOCATING-0} : { *(.rodata1) } ++ ${CREATE_SHLIB-${SDATA2}} ++ ${CREATE_SHLIB-${SBSS2}} ++ ${OTHER_READONLY_SECTIONS} ++ .eh_frame_hdr : { *(.eh_frame_hdr) } ++ .eh_frame ${RELOCATING-0} : ONLY_IF_RO { KEEP (*(.eh_frame)) } ++ .gcc_except_table ${RELOCATING-0} : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } ++ ++ /* Adjust the address for the data segment. We want to adjust up to ++ the same address within the page on the next page up. */ ++ ${CREATE_SHLIB-${CREATE_PIE-${RELOCATING+. = ${DATA_ADDR-${DATA_SEGMENT_ALIGN}};}}} ++ ${CREATE_SHLIB+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}} ++ ${CREATE_PIE+${RELOCATING+. = ${SHLIB_DATA_ADDR-${DATA_SEGMENT_ALIGN}};}} ++ ++ /* Exception handling */ ++ .eh_frame ${RELOCATING-0} : ONLY_IF_RW { KEEP (*(.eh_frame)) } ++ .gcc_except_table ${RELOCATING-0} : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } ++ ++ /* Thread Local Storage sections */ ++ .tdata ${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) } ++ .tbss ${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} } ++ ++ .preinit_array ${RELOCATING-0} : ++ { ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__preinit_array_start = .);}} ++ KEEP (*(.preinit_array)) ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__preinit_array_end = .);}} ++ } ++ .init_array ${RELOCATING-0} : ++ { ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__init_array_start = .);}} ++ KEEP (*(SORT(.init_array.*))) ++ KEEP (*(.init_array)) ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__init_array_end = .);}} ++ } ++ .fini_array ${RELOCATING-0} : ++ { ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_start = .);}} ++ KEEP (*(.fini_array)) ++ KEEP (*(SORT(.fini_array.*))) ++ ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_end = .);}} ++ } ++ ${SMALL_DATA_CTOR-${RELOCATING+${CTOR}}} ++ ${SMALL_DATA_DTOR-${RELOCATING+${DTOR}}} ++ .jcr ${RELOCATING-0} : { KEEP (*(.jcr)) } ++ ++ ${RELOCATING+${DATARELRO}} ++ ${OTHER_RELRO_SECTIONS} ++ ${TEXT_DYNAMIC-${DYNAMIC}} ++ ${DATA_GOT+${RELRO_NOW+${GOT}}} ++ ${DATA_GOT+${RELRO_NOW+${GOTPLT}}} ++ ${DATA_GOT+${RELRO_NOW-${SEPARATE_GOTPLT+${GOT}}}} ++ ${RELOCATING+${DATA_SEGMENT_RELRO_END}} ++ ${DATA_GOT+${RELRO_NOW-${SEPARATE_GOTPLT-${GOT}}}} ++ ${DATA_GOT+${RELRO_NOW-${GOTPLT}}} ++ ++ ${DATA_PLT+${PLT_BEFORE_GOT-${PLT}}} ++ ++ .data ${RELOCATING-0} : ++ { ++ ${RELOCATING+${DATA_START_SYMBOLS}} ++ *(.data${RELOCATING+ .data.* .gnu.linkonce.d.*}) ++ ${RELOCATING+KEEP (*(.gnu.linkonce.d.*personality*))} ++ ${CONSTRUCTING+SORT(CONSTRUCTORS)} ++ } ++ .data1 ${RELOCATING-0} : { *(.data1) } ++ ${WRITABLE_RODATA+${RODATA}} ++ ${OTHER_READWRITE_SECTIONS} ++ ${SMALL_DATA_CTOR+${RELOCATING+${CTOR}}} ++ ${SMALL_DATA_DTOR+${RELOCATING+${DTOR}}} ++ ${DATA_PLT+${PLT_BEFORE_GOT+${PLT}}} ++ ${SDATA_GOT+${RELOCATING+${OTHER_GOT_SYMBOLS}}} ++ ${SDATA_GOT+${GOT}} ++ ${SDATA_GOT+${OTHER_GOT_SECTIONS}} ++ ${SDATA} ++ ${OTHER_SDATA_SECTIONS} ++ ${RELOCATING+${DATA_END_SYMBOLS-${USER_LABEL_PREFIX}_edata = .; PROVIDE (${USER_LABEL_PREFIX}edata = .);}} ++ ${RELOCATING+__bss_start = .;} ++ ${RELOCATING+${OTHER_BSS_SYMBOLS}} ++ ${SBSS} ++ ${BSS_PLT+${PLT}} ++ .bss ${RELOCATING-0} : ++ { ++ *(.dynbss) ++ *(.bss${RELOCATING+ .bss.* .gnu.linkonce.b.*}) ++ *(COMMON) ++ /* Align here to ensure that the .bss section occupies space up to ++ _end. Align after .bss to ensure correct alignment even if the ++ .bss section disappears because there are no input sections. ++ FIXME: Why do we need it? When there is no .bss section, we don't ++ pad the .data section. */ ++ ${RELOCATING+. = ALIGN(. != 0 ? ${ALIGNMENT} : 1);} ++ } ++ ${OTHER_BSS_SECTIONS} ++ ${RELOCATING+${OTHER_BSS_END_SYMBOLS}} ++ ${RELOCATING+. = ALIGN(${ALIGNMENT});} ++ ${LARGE_SECTIONS} ++ ${RELOCATING+. = ALIGN(${ALIGNMENT});} ++ ${RELOCATING+${OTHER_END_SYMBOLS}} ++ ${RELOCATING+${END_SYMBOLS-${USER_LABEL_PREFIX}_end = .; PROVIDE (${USER_LABEL_PREFIX}end = .);}} ++ ${RELOCATING+${DATA_SEGMENT_END}} ++ ++ /* Stabs debugging sections. */ ++ .stab 0 : { *(.stab) } ++ .stabstr 0 : { *(.stabstr) } ++ .stab.excl 0 : { *(.stab.excl) } ++ .stab.exclstr 0 : { *(.stab.exclstr) } ++ .stab.index 0 : { *(.stab.index) } ++ .stab.indexstr 0 : { *(.stab.indexstr) } ++ ++ .comment 0 : { *(.comment) } ++ ++ /* DWARF debug sections. ++ Symbols in the DWARF debugging sections are relative to the beginning ++ of the section so we begin them at 0. */ ++ ++ /* DWARF 1 */ ++ .debug 0 : { *(.debug) } ++ .line 0 : { *(.line) } ++ ++ /* GNU DWARF 1 extensions */ ++ .debug_srcinfo 0 : { *(.debug_srcinfo) } ++ .debug_sfnames 0 : { *(.debug_sfnames) } ++ ++ /* DWARF 1.1 and DWARF 2 */ ++ .debug_aranges 0 : { *(.debug_aranges) } ++ .debug_pubnames 0 : { *(.debug_pubnames) } ++ ++ /* DWARF 2 */ ++ .debug_info 0 : { *(.debug_info${RELOCATING+ .gnu.linkonce.wi.*}) } ++ .debug_abbrev 0 : { *(.debug_abbrev) } ++ .debug_line 0 : { *(.debug_line) } ++ .debug_frame 0 : { *(.debug_frame) } ++ .debug_str 0 : { *(.debug_str) } ++ .debug_loc 0 : { *(.debug_loc) } ++ .debug_macinfo 0 : { *(.debug_macinfo) } ++ ++ /* SGI/MIPS DWARF 2 extensions */ ++ .debug_weaknames 0 : { *(.debug_weaknames) } ++ .debug_funcnames 0 : { *(.debug_funcnames) } ++ .debug_typenames 0 : { *(.debug_typenames) } ++ .debug_varnames 0 : { *(.debug_varnames) } ++ ++ /* DWARF 3 */ ++ .debug_pubtypes 0 : { *(.debug_pubtypes) } ++ .debug_ranges 0 : { *(.debug_ranges) } ++ ++ ${TINY_DATA_SECTION} ++ ${TINY_BSS_SECTION} ++ ++ ${STACK_ADDR+${STACK}} ++ ${ATTRS_SECTIONS} ++ ${OTHER_SECTIONS} ++ ${RELOCATING+${OTHER_SYMBOLS}} ++ ${RELOCATING+${DISCARDED}} ++} ++EOF diff --git a/ppc-amigaos/recipes/patches/binutils/remove_unused.p b/ppc-amigaos/recipes/patches/binutils/remove_unused.p deleted file mode 100644 index dea60e9..0000000 --- a/ppc-amigaos/recipes/patches/binutils/remove_unused.p +++ /dev/null @@ -1,406 +0,0 @@ ---- bfd/elf32-ppc.c.old 2014-01-04 16:37:47.404630311 +0000 -+++ bfd/elf32-ppc.c 2014-01-04 16:38:30.333547584 +0000 -@@ -4147,7 +4147,6 @@ - } - else - { -- Elf_Internal_Sym *sym; - bfd_signed_vma *lgot_refs; - char *lgot_masks; - -@@ -4165,7 +4164,6 @@ - return FALSE; - } - } -- sym = locsyms + r_symndx; - lgot_refs = elf_local_got_refcounts (ibfd); - if (lgot_refs == NULL) - abort (); ---- bfd/elf.c.old 2014-01-04 16:30:59.089704808 +0000 -+++ bfd/elf.c 2014-01-04 16:34:48.929678864 +0000 -@@ -4649,13 +4649,10 @@ - prep_headers (bfd *abfd) - { - Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ -- Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */ -- Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */ - struct elf_strtab_hash *shstrtab; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - i_ehdrp = elf_elfheader (abfd); -- i_shdrp = elf_elfsections (abfd); - - shstrtab = _bfd_elf_strtab_init (); - if (shstrtab == NULL) -@@ -4719,7 +4716,6 @@ - else - { - i_ehdrp->e_phentsize = 0; -- i_phdrp = 0; - i_ehdrp->e_phoff = 0; - } - -@@ -4767,7 +4763,6 @@ - _bfd_elf_write_object_contents (bfd *abfd) - { - const struct elf_backend_data *bed = get_elf_backend_data (abfd); -- Elf_Internal_Ehdr *i_ehdrp; - Elf_Internal_Shdr **i_shdrp; - bfd_boolean failed; - unsigned int count, num_sec; -@@ -4777,7 +4772,6 @@ - return FALSE; - - i_shdrp = elf_elfsections (abfd); -- i_ehdrp = elf_elfheader (abfd); - - failed = FALSE; - bfd_map_over_sections (abfd, bed->s->write_relocs, &failed); ---- binutils/dwarf.c.old 2014-01-04 16:44:22.393068874 +0000 -+++ binutils/dwarf.c 2014-01-04 16:45:12.317387306 +0000 -@@ -1589,7 +1589,6 @@ - { - DWARF2_Internal_CompUnit compunit; - unsigned char *hdrptr; -- unsigned char *cu_abbrev_offset_ptr; - unsigned char *tags; - int level; - unsigned long cu_offset; -@@ -1619,7 +1618,6 @@ - - cu_offset = start - section_begin; - -- cu_abbrev_offset_ptr = hdrptr; - compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size); - hdrptr += offset_size; - -@@ -2655,7 +2653,6 @@ - void *file ATTRIBUTE_UNUSED) - { - unsigned char *start = section->start; -- unsigned char *section_end; - unsigned long bytes; - unsigned char *section_begin = start; - unsigned int num_range_list = 0; -@@ -2668,7 +2665,6 @@ - unsigned char *next; - - bytes = section->size; -- section_end = start + bytes; - - if (bytes == 0) - { ---- binutils/ieee.c.old 2014-01-04 17:04:36.896761373 +0000 -+++ binutils/ieee.c 2014-01-04 17:05:14.355010533 +0000 -@@ -4815,7 +4815,6 @@ - const char *backslash; - #endif - char *c, *s; -- unsigned int nindx; - - if (info->filename != NULL) - { -@@ -4863,7 +4862,6 @@ - || ! ieee_write_id (info, info->modname)) - return FALSE; - -- nindx = info->name_indx; - ++info->name_indx; - if (! ieee_change_buffer (info, &info->vars) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) -@@ -5679,11 +5677,6 @@ - static bfd_boolean - ieee_offset_type (void *p) - { -- struct ieee_handle *info = (struct ieee_handle *) p; -- unsigned int targetindx, baseindx; -- -- targetindx = ieee_pop_type (info); -- baseindx = ieee_pop_type (info); - - /* FIXME: The MRI C++ compiler does not appear to generate any - useful type information about an offset type. It just records a ---- binutils/objdump.c.old 2014-01-04 16:41:33.090584888 +0000 -+++ binutils/objdump.c 2014-01-04 16:42:05.046153323 +0000 -@@ -1315,7 +1315,6 @@ - struct objdump_disasm_info *aux; - asection *section; - int octets_per_line; -- bfd_boolean done_dot; - int skip_addr_chars; - bfd_vma addr_offset; - unsigned int opb = info->octets_per_byte; -@@ -1361,7 +1360,6 @@ - - info->insn_info_valid = 0; - -- done_dot = FALSE; - addr_offset = start_offset; - while (addr_offset < stop_offset) - { -@@ -1402,8 +1400,6 @@ - int bpc = 0; - int pb = 0; - -- done_dot = FALSE; -- - if (with_line_numbers || with_source_code) - show_line (aux->abfd, section, addr_offset); - ---- binutils/rddbg.c.old 2014-01-04 16:48:10.560218033 +0000 -+++ binutils/rddbg.c 2014-01-04 16:48:33.511437185 +0000 -@@ -163,7 +163,6 @@ - { - unsigned int strx; - int type; -- int other; - int desc; - bfd_vma value; - -@@ -171,7 +170,6 @@ - - strx = bfd_get_32 (abfd, stab); - type = bfd_get_8 (abfd, stab + 4); -- other = bfd_get_8 (abfd, stab + 5); - desc = bfd_get_16 (abfd, stab + 6); - value = bfd_get_32 (abfd, stab + 8); - ---- binutils/stabs.c.old 2014-01-04 16:51:23.478216204 +0000 -+++ binutils/stabs.c 2014-01-04 16:54:20.752581129 +0000 -@@ -685,7 +685,7 @@ - debug_type dtype; - bfd_boolean synonym; - bfd_boolean self_crossref; -- unsigned int lineno; - debug_type *slot; -+ (void) desc; - - p = strchr (string, ':'); -@@ -703,14 +703,6 @@ - } - } - -- /* GCC 2.x puts the line number in desc. SunOS apparently puts in -- the number of bytes occupied by a type or object, which we -- ignore. */ -- if (info->gcc_compiled >= 2) -- lineno = desc; -- else -- lineno = 0; -- - /* FIXME: Sometimes the special C++ names start with '.'. */ - name = NULL; - if (string[0] == '$') -@@ -2006,7 +1998,6 @@ - const char *tagname, const char **pp, - bfd_boolean structp, const int *typenums) - { -- const char *orig; - bfd_vma size; - debug_baseclass *baseclasses; - debug_field *fields; -@@ -2015,8 +2006,6 @@ - debug_type vptrbase; - bfd_boolean ownvptr; - -- orig = *pp; -- - /* Get the size. */ - size = parse_number (pp, (bfd_boolean *) NULL); - -@@ -4645,7 +4634,7 @@ - case 'M': - case 'O': - { -- bfd_boolean memberp, constp, volatilep; -+ bfd_boolean memberp; - debug_type class_type = DEBUG_TYPE_NULL; - debug_type *args; - bfd_boolean varargs; -@@ -4653,8 +4642,6 @@ - const char *name; - - memberp = **pp == 'M'; -- constp = FALSE; -- volatilep = FALSE; - args = NULL; - varargs = FALSE; - -@@ -4698,12 +4685,10 @@ - { - if (**pp == 'C') - { -- constp = TRUE; - ++*pp; - } - else if (**pp == 'V') - { -- volatilep = TRUE; - ++*pp; - } - if (**pp != 'F') -@@ -4764,9 +4749,6 @@ - - case 'Q': - { -- const char *hold; -- -- hold = *pp; - if (! stab_demangle_qualified (minfo, pp, ptype)) - return FALSE; - } ---- gas/as.c.old 2014-01-04 17:13:31.225076310 +0000 -+++ gas/as.c 2014-01-04 17:18:37.674379984 +0000 -@@ -1060,7 +1060,6 @@ - { - segT s; - char *p; -- addressT addr; - offsetT size; - const char *name; - -@@ -1074,7 +1073,6 @@ - elf_section_type (s) - = get_elf_backend_data (stdoutput)->obj_attrs_section_type; - bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA); -- addr = frag_now_fix (); - p = frag_more (size); - bfd_elf_set_obj_attr_contents (stdoutput, (bfd_byte *)p, size); - } ---- gas/listing.c.old 2014-01-04 17:21:13.406248415 +0000 -+++ gas/listing.c 2014-01-04 17:21:51.156643142 +0000 -@@ -937,7 +937,6 @@ - { - list_info_type *list = head; - file_info_type *current_hll_file = (file_info_type *) NULL; -- char *message; - char *buffer; - char *p; - int show_listing = 1; -@@ -1002,8 +1001,6 @@ - { - /* Scan down the list and print all the stuff which can be done - with this line (or lines). */ -- message = 0; -- - if (list->hll_file) - current_hll_file = list->hll_file; - ---- gas/read.c.old 2014-01-04 17:24:32.839414940 +0000 -+++ gas/read.c 2014-01-04 17:46:41.158558836 +0000 -@@ -2575,10 +2575,15 @@ - void - s_mri (int ignore ATTRIBUTE_UNUSED) - { -- int on, old_flag; -+ int on; -+#ifdef MRI_MODE_CHANGE -+ int old_flag; -+#endif - - on = get_absolute_expression (); -+#ifdef MRI_MODE_CHANGE - old_flag = flag_mri; -+#endif - if (on != 0) - { - flag_mri = 1; -@@ -4683,11 +4688,9 @@ - sizeof_uleb128 (valueT value) - { - register int size = 0; -- register unsigned byte; - - do - { -- byte = (value & 0x7f); - value >>= 7; - size += 1; - } -@@ -5644,16 +5647,15 @@ - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { -- int res; - if (default_prefix) -- res = asprintf (&label, "%s%s", default_prefix, name); -+ (void) asprintf (&label, "%s%s", default_prefix, name); - else - { - char leading_char = bfd_get_symbol_leading_char (stdoutput); - /* Missing entry point, use function's name with the leading - char prepended. */ - if (leading_char) -- res = asprintf (&label, "%c%s", leading_char, name); -+ (void) asprintf (&label, "%c%s", leading_char, name); - else - label = name; - } ---- gas/stabs.c.old 2014-01-04 17:59:17.491017224 +0000 -+++ gas/stabs.c 2014-01-04 18:00:01.744605487 +0000 -@@ -658,7 +658,6 @@ - char *buf; - char *file; - unsigned int lineno; -- int res; - - if (! void_emitted_p) - { -@@ -668,7 +667,7 @@ - } - - as_where (&file, &lineno); -- res = asprintf (&buf, "\"%s:F1\",%d,0,%d,%s", -+ (void) asprintf (&buf, "\"%s:F1\",%d,0,%d,%s", - funcname, N_FUN, lineno + 1, startlabname); - input_line_pointer = buf; - s_stab ('s'); -@@ -689,13 +688,12 @@ - char *hold = input_line_pointer; - char *buf; - char sym[30]; -- int res; - - sprintf (sym, "%sendfunc%d", FAKE_LABEL_NAME, label_count); - ++label_count; - colon (sym); - -- res = asprintf (&buf, "\"\",%d,0,0,%s-%s", N_FUN, sym, startlabname); -+ (void) asprintf (&buf, "\"\",%d,0,0,%s-%s", N_FUN, sym, startlabname); - input_line_pointer = buf; - s_stab ('s'); - free (buf); ---- include/elf/ppc.h.old 2014-01-04 16:07:28.062263958 +0000 -+++ include/elf/ppc.h 2014-01-04 16:08:56.781487163 +0000 -@@ -133,10 +133,10 @@ - RELOC_NUMBER (R_PPC_AMIGAOS_BREL_HA, 213) - - /* Fake relocations for branch stubs, only used internally by ld. */ --#define R_PPC_RELAX32 245 --#define R_PPC_RELAX32PC 246 --#define R_PPC_RELAX32_PLT 247 --#define R_PPC_RELAX32PC_PLT 248 -+ FAKE_RELOC(R_PPC_RELAX32, 245) -+ FAKE_RELOC(R_PPC_RELAX32PC, 246) -+ FAKE_RELOC(R_PPC_RELAX32_PLT, 247) -+ FAKE_RELOC(R_PPC_RELAX32PC_PLT, 248) - - /* These are GNU extensions used in PIC code sequences. */ - RELOC_NUMBER (R_PPC_REL16, 249) ---- ld/ldlang.c.old 2014-01-04 18:03:19.264793435 +0000 -+++ ld/ldlang.c 2014-01-04 18:04:28.794701467 +0000 -@@ -2141,14 +2141,12 @@ - lang_input_statement_type *file, - asection *section) - { -- const char *section_name; - lang_statement_union_type *l; - - if (!wild->filenames_sorted - && (sec == NULL || sec->spec.sorted == none)) - return NULL; - -- section_name = bfd_get_section_name (file->the_bfd, section); - for (l = wild->children.head; l != NULL; l = l->header.next) - { - lang_input_section_type *ls; diff --git a/ppc-amigaos/recipes/patches/gcc/0001-Changes-for-AmigaOS-version-of-gcc.p b/ppc-amigaos/recipes/patches/gcc/0001-Changes-for-AmigaOS-version-of-gcc.p new file mode 100644 index 0000000..98441d3 --- /dev/null +++ b/ppc-amigaos/recipes/patches/gcc/0001-Changes-for-AmigaOS-version-of-gcc.p @@ -0,0 +1,5166 @@ +From eecb39df390b5b8cd36a8a417f61d4afba24c187 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Tue, 17 Feb 2015 20:25:55 +0100 +Subject: [PATCH 1/6] Changes for AmigaOS version of gcc. + +--- + fixincludes/configure | 1 + + fixincludes/configure.ac | 1 + + gcc/Makefile.in | 1 + + gcc/c-family/c-common.c | 26 + + gcc/c/c-typeck.c | 25 + + gcc/config.gcc | 8 + + gcc/config.host | 6 + + gcc/config/rs6000/amigaos-protos.h | 41 + + gcc/config/rs6000/amigaos.c | 466 +++++++++ + gcc/config/rs6000/amigaos.h | 431 ++++++++ + gcc/config/rs6000/amigaos.opt | 37 + + gcc/config/rs6000/rs6000-builtin.def | 7 + + gcc/config/rs6000/rs6000.c | 176 +++- + gcc/config/rs6000/rs6000.h | 3 + + gcc/config/rs6000/rs6000.md | 27 +- + gcc/config/rs6000/t-amigaos | 20 + + gcc/cp/typeck.c | 16 + + gcc/doc/extend.texi | 167 +++ + gcc/doc/invoke.texi | 136 +++ + gcc/expr.c | 1 - + gcc/gcc.c | 12 +- + gcc/prefix.c | 2 +- + intl/dcigettext.c | 2 + + libcpp/line-map.c | 3 + + libgcc/config.host | 3 + + libgcc/config/rs6000/t-amigaos | 45 + + libiberty/Makefile.in | 9 + + libiberty/basename.c | 21 +- + libiberty/configure | 1 + + libiberty/configure.ac | 1 + + libiberty/lrealpath.c | 3 +- + libiberty/make-relative-prefix.c | 37 +- + libiberty/make-temp-file.c | 27 +- + libiberty/pex-amigaos.c | 325 ++++++ + libstdc++-v3/configure | 1852 ++++++++++++++++++++++++++++++++- + libstdc++-v3/configure.ac | 3 + + libstdc++-v3/crossconfig.m4 | 8 + + libstdc++-v3/include/c_global/cstddef | 3 + + libstdc++-v3/include/c_std/cstddef | 3 + + 39 files changed, 3879 insertions(+), 77 deletions(-) + create mode 100644 gcc/config/rs6000/amigaos-protos.h + create mode 100644 gcc/config/rs6000/amigaos.c + create mode 100644 gcc/config/rs6000/amigaos.h + create mode 100644 gcc/config/rs6000/amigaos.opt + create mode 100644 gcc/config/rs6000/t-amigaos + create mode 100644 libgcc/config/rs6000/t-amigaos + create mode 100644 libiberty/pex-amigaos.c + +diff --git a/fixincludes/configure b/fixincludes/configure +index 4836cd886537e9cdf73ef2bb064bfa581fc1068a..6bee1a37ee30a1c12a8f41f05c21d956d1be1a09 100755 +--- fixincludes/configure ++++ fixincludes/configure +@@ -4712,12 +4712,13 @@ else + fi + else + case $host in + i?86-*-msdosdjgpp* | \ + i?86-*-mingw32* | \ + x86_64-*-mingw32* | \ ++ *-*-amigaos* | \ + *-*-beos* | \ + *-*-*vms*) + TARGET=twoprocess + ;; + + * ) +diff --git a/fixincludes/configure.ac b/fixincludes/configure.ac +index f8f352fb7153445782727eb3311d4305f33fa260..66a501d80528fdd50b4cd2f9f3282e3c562bf2e2 100644 +--- fixincludes/configure.ac ++++ fixincludes/configure.ac +@@ -50,12 +50,13 @@ else + TARGET=oneprocess + fi], + [case $host in + i?86-*-msdosdjgpp* | \ + i?86-*-mingw32* | \ + x86_64-*-mingw32* | \ ++ *-*-amigaos* | \ + *-*-beos* | \ + *-*-*vms*) + TARGET=twoprocess + ;; + + * ) +diff --git a/gcc/Makefile.in b/gcc/Makefile.in +index 07c6f0af71749b653c16ef7843a191e0bd9aa95d..c464690a51e62c8ba92fa3543dccb70488bd12f9 100644 +--- gcc/Makefile.in ++++ gcc/Makefile.in +@@ -1972,12 +1972,13 @@ default-c.o: config/default-c.c + CFLAGS-prefix.o += -DPREFIX=\"$(prefix)\" -DBASEVER=$(BASEVER_s) + prefix.o: $(BASEVER) + + # Language-independent files. + + DRIVER_DEFINES = \ ++ -DEXEC_PREFIX=\"$(exec_prefix)/\" \ + -DSTANDARD_STARTFILE_PREFIX=\"$(unlibsubdir)/\" \ + -DSTANDARD_EXEC_PREFIX=\"$(libdir)/gcc/\" \ + -DSTANDARD_LIBEXEC_PREFIX=\"$(libexecdir)/gcc/\" \ + -DDEFAULT_TARGET_VERSION=\"$(version)\" \ + -DDEFAULT_REAL_TARGET_MACHINE=\"$(real_target_noncanonical)\" \ + -DDEFAULT_TARGET_MACHINE=\"$(target_noncanonical)\" \ +diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c +index 117f89c023842aa8ea10a6a94088f4095246d9e3..4e1bbf417e6b774bdaa6c01dccef933fc73505ea 100644 +--- gcc/c-family/c-common.c ++++ gcc/c-family/c-common.c +@@ -381,12 +381,13 @@ static tree handle_vector_size_attribute (tree *, tree, tree, int, + bool *); + static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); + static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); + static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *); + static tree handle_warn_unused_result_attribute (tree *, tree, tree, int, + bool *); ++static tree handle_libcall_attribute (tree *, tree, tree, int, bool *); + static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); + static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); + static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *); + static tree handle_alloc_align_attribute (tree *, tree, tree, int, bool *); + static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *); + static tree handle_target_attribute (tree *, tree, tree, int, bool *); +@@ -755,12 +756,17 @@ const struct attribute_spec c_common_attribute_table[] = + handle_nothrow_attribute, false }, + { "may_alias", 0, 0, false, true, false, NULL, false }, + { "cleanup", 1, 1, true, false, false, + handle_cleanup_attribute, false }, + { "warn_unused_result", 0, 0, false, true, true, + handle_warn_unused_result_attribute, false }, ++ { "libcall", 0, 0, false, true, true, ++ handle_libcall_attribute, false }, ++ /* Similiar to libcall but doesn't imply linearvarargs. Can be handled as libcall here. */ ++ { "libcall2", 0, 0, false, true, true, ++ handle_libcall_attribute, false }, + { "sentinel", 0, 1, false, true, true, + handle_sentinel_attribute, false }, + /* For internal use (marking of builtins) only. The name contains space + to prevent its usage in source code. */ + { "type generic", 0, 0, false, true, true, + handle_type_generic_attribute, false }, +@@ -9218,12 +9224,32 @@ handle_warn_unused_result_attribute (tree *node, tree name, + *no_add_attrs = true; + } + + return NULL_TREE; + } + ++/* Handle a "libcall" attribute. No special handling. */ ++ ++static tree ++handle_libcall_attribute (tree *node, tree name, ++ tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, ++ bool *no_add_attrs) ++{ ++ if (TREE_CODE (*node) != FUNCTION_TYPE ++ && TREE_CODE (*node) != METHOD_TYPE ++ && TREE_CODE (*node) != FIELD_DECL ++ && TREE_CODE (*node) != TYPE_DECL) ++ { ++ warning (OPT_Wattributes,"%qs attribute only applies to functions", ++ IDENTIFIER_POINTER (name)); ++ *no_add_attrs = true; ++ } ++ ++ return NULL_TREE; ++} ++ + /* Handle a "sentinel" attribute. */ + + static tree + handle_sentinel_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) + { +diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c +index ffba66bb6c4cf935bc86fc3896fadcc5e40023a7..a98622b16f546b88eb7fdce9ca7631c3ca37470a 100644 +--- gcc/c/c-typeck.c ++++ gcc/c/c-typeck.c +@@ -2888,12 +2888,14 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, + tree fntype, fundecl = 0; + tree name = NULL_TREE, result; + tree tem; + int nargs; + tree *argarray; + ++ vec<tree, va_gc> *new_params = NULL; ++ vec<tree, va_gc> *new_origtypes = NULL; + + /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (function); + + /* Convert anything with function type to a pointer-to-function. */ + if (TREE_CODE (function) == FUNCTION_DECL) +@@ -2950,12 +2952,35 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, + if (fundecl && TREE_THIS_VOLATILE (fundecl)) + current_function_returns_abnormally = 1; + + /* fntype now gets the type of function pointed to. */ + fntype = TREE_TYPE (fntype); + ++ if (lookup_attribute ("libcall", TYPE_ATTRIBUTES (fntype)) || ++ lookup_attribute ("libcall2", TYPE_ATTRIBUTES (fntype))) ++ { ++ if (TREE_CODE (function) == COMPONENT_REF && lvalue_p (function)) ++ { ++ /* We copy the involved vectors here, as adding an element may ++ * free the original pointer, but we are not the owner of those. ++ * ++ * FIXME: At the moment, we don't free the memory allocated here ++ * If it is freed at the exit of the function via VEC_free() in ++ * some cases a segfault occurs */ ++ params = new_params = vec_safe_copy(params); ++ origtypes = new_origtypes = vec_safe_copy(origtypes); ++ ++ /* Type of 0 operand of a component ref is always a dereferenced object but ++ * we need to pass the address of this object */ ++ vec_safe_insert(params,0, ++ build1(ADDR_EXPR, build_pointer_type (TREE_TYPE (TREE_OPERAND (function, 0))), ++ TREE_OPERAND (function, 0))); ++ vec_safe_insert(origtypes,0,(tree)NULL); ++ } ++ } ++ + /* Convert the parameters to the types declared in the + function prototype, or apply default promotions. */ + + nargs = convert_arguments (loc, arg_loc, TYPE_ARG_TYPES (fntype), params, + origtypes, function, fundecl); + if (nargs < 0) +diff --git a/gcc/config.gcc b/gcc/config.gcc +index c835734128b0aef5a0b558ccd7ad24fd17bb9bee..6fcd952f5235f04160e5de45aff781993bf120a1 100644 +--- gcc/config.gcc ++++ gcc/config.gcc +@@ -2245,12 +2245,20 @@ nvptx-*) + fi + ;; + pdp11-*-*) + tm_file="${tm_file} newlib-stdint.h" + use_gcc_stdint=wrap + ;; ++powerpc-*-amigaos*) ++ tm_file="${tm_file} dbxelf.h elfos.h rs6000/sysv4.h rs6000/amigaos.h" ++ tm_p_file="${tm_p_file} rs6000/amigaos-protos.h" ++ extra_options="${extra_options} rs6000/sysv4.opt rs6000/amigaos.opt" ++ tmake_file="rs6000/t-amigaos" ++ extra_objs=amigaos.o ++ use_collect2=no ++ ;; + # port not yet contributed + #powerpc-*-openbsd*) + # tmake_file="${tmake_file} rs6000/t-fprules" + # extra_headers= + # ;; + powerpc-*-darwin*) +diff --git a/gcc/config.host b/gcc/config.host +index b0f5940c26379ebc75e0ca462cbb2cb01dabd2fa..51675e166b9833d327ec43fcca67d6a2b3560068 100644 +--- gcc/config.host ++++ gcc/config.host +@@ -242,12 +242,18 @@ case ${host} in + exit 1 + ;; + i[34567]86-*-darwin* | x86_64-*-darwin*) + out_host_hook_obj="${out_host_hook_obj} host-i386-darwin.o" + host_xmake_file="${host_xmake_file} i386/x-darwin" + ;; ++ powerpc-*-amigaos*) # AmigaOS 4 ++ prefix=/gcc ++ local_prefix=/gcc ++ host_can_use_collect2=no ++ host_xm_defines=HOST_LACKS_INODE_NUMBERS ++ ;; + powerpc-*-beos*) + host_can_use_collect2=no + ;; + powerpc-*-darwin*) + out_host_hook_obj="${out_host_hook_obj} host-ppc-darwin.o" + host_xmake_file="${host_xmake_file} rs6000/x-darwin" +diff --git a/gcc/config/rs6000/amigaos-protos.h b/gcc/config/rs6000/amigaos-protos.h +new file mode 100644 +index 0000000000000000000000000000000000000000..eb5f8fc5f3d546b8d8e1cdd8118a3085079df50e +--- /dev/null ++++ gcc/config/rs6000/amigaos-protos.h +@@ -0,0 +1,41 @@ ++/* Prototypes. ++ Copyright (C) 2003 Free Software Foundation, Inc. ++ ++ This file is part of GCC. ++ ++ GCC is free software; you can redistribute it and/or modify it ++ under the terms of the GNU General Public License as published ++ by the Free Software Foundation; either version 2, or (at your ++ option) any later version. ++ ++ GCC is distributed in the hope that it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public ++ License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with GCC; see the file COPYING. If not, write to the ++ Free Software Foundation, 59 Temple Place - Suite 330, Boston, ++ MA 02111-1307, USA. */ ++ ++ ++//#ifdef RTX_CODE ++//#ifdef TREE_CODE ++ ++extern void amigaos_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, int, int); ++extern void amigaos_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern struct rtx_def *amigaos_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern void amigaos_expand_builtin_va_start (tree valist, rtx nextarg); ++extern struct rtx_def *amigaos_expand_builtin_saveregs (void); ++extern void amigaos_init_builtins (void); ++extern rtx amigaos_expand_builtin (tree, rtx, rtx, enum machine_mode, int, bool*); ++extern tree amigaos_handle_linearvarargs_attribute (tree *, tree, tree, int, bool*); ++extern tree amigaos_handle_baserel_restore_attribute (tree *, tree, tree, int, bool*); ++extern tree amigaos_handle_force_no_baserel_attribute (tree *, tree, tree, int, bool*); ++extern tree amigaos_handle_check68kfuncptr_attribute (tree *, tree, tree, int, bool*); ++extern rtx amigaos_legitimize_baserel_address (rtx addr); ++extern int amigaos_baserel_operand(rtx x); ++extern int amigaos_not_baserel_tree_p(tree decl); ++ ++//#endif /* TREE_CODE */ ++//#endif /* RTX_CODE */ +diff --git a/gcc/config/rs6000/amigaos.c b/gcc/config/rs6000/amigaos.c +new file mode 100644 +index 0000000000000000000000000000000000000000..0f575a38e4dc4aac0b454c56bf62f625c0f7eb9c +--- /dev/null ++++ gcc/config/rs6000/amigaos.c +@@ -0,0 +1,466 @@ ++/* Subroutines used for code generation on Amiga OS 4 ++ Copyright (C) 2003 Free Software Foundation, Inc. ++ Contributed by Thomas Frieden (ThomasF@hyperion-entertainment.com) ++ ++ This file is part of GCC. ++ ++ GCC is free software; you can redistribute it and/or modify it ++ under the terms of the GNU General Public License as published ++ by the Free Software Foundation; either version 2, or (at your ++ option) any later version. ++ ++ GCC is distributed in the hope that it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public ++ License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with GCC; see the file COPYING. If not, write to the ++ Free Software Foundation, 59 Temple Place - Suite 330, Boston, ++ MA 02111-1307, USA. */ ++ ++ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "diagnostic-core.h" ++#include "tm.h" ++#include "hash-set.h" ++#include "inchash.h" ++#include "rtl.h" ++#include "regs.h" ++#include "hard-reg-set.h" ++#include "real.h" ++#include "insn-config.h" ++#include "conditions.h" ++#include "insn-flags.h" ++#include "insn-attr.h" ++#include "flags.h" ++#include "recog.h" ++#include "obstack.h" ++#include "symtab.h" ++#include "tree.h" ++#include "expr.h" ++#include "optabs.h" ++#include "except.h" ++#include "function.h" ++#include "output.h" ++#include "tm_p.h" ++#include "fold-const.h" ++#include "langhooks.h" ++#include "explow.h" ++ ++#undef DEBUG ++#ifdef DEBUG ++#define dprintf(...) \ ++printf("%s: ", __PRETTY_FUNCTION__); \ ++printf(__VA_ARGS__) ++#else ++#define dprintf(...) /* __VA_ARGS__ */ ++#endif ++ ++#undef TARGET_EXPAND_BUILTIN_SAVEREGS ++#define TARGET_EXPAND_BUILTIN_SAVEREGS() \ ++ amigaos_expand_builtin_saveregs () ++ ++#ifdef __amigaos4__ ++static const char * __attribute__((used)) amigaos_stack_cookie = "$STACK:768000"; ++#endif /* __amigaos4__ */ ++ ++#if 0 ++const char *amigaos_crt_string; ++#endif ++ ++/* Initialize a variable CUM of type CUMULATIVE_ARGS ++ for a call to a function whose data type is FNTYPE. ++ For a library call, FNTYPE is 0. ++ ++ Most of the work is delegated to init_cumulative_args() in rs6000.c, ++ here we just check for special attributes and update call_cookie ++ accordingly. */ ++#if 0 ++void ++amigaos_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, ++ rtx libname ATTRIBUTE_UNUSED, int incoming, ++ int n_named_args) ++{ ++ dprintf ("enter(cum=%p,fntype=%p)\n",cum,fntype); ++ init_cumulative_args (cum, fntype, libname, incoming, FALSE, n_named_args); ++ ++ /* Check if either libcall or linear varargs, set appropriate cookie */ ++ if (fntype && (lookup_attribute ("libcall", TYPE_ATTRIBUTES (fntype)))) ++ cum->call_cookie |= CALL_LINEARVARARGS; ++ ++ if (fntype && (lookup_attribute ("linearvarargs", TYPE_ATTRIBUTES (fntype)))) ++ cum->call_cookie |= CALL_LINEARVARARGS; ++ ++ dprintf ("exit\n"); ++} ++ ++/* Update the data in CUM to advance over an argument ++ of mode MODE and data type TYPE. ++ (TYPE is null for libcalls where that information may not be available.) ++ ++ If the function has the linearvarargs attribute and this argument ++ to advance over is the last non-vararg argument, then advance over ++ all registers, so that the overflow area is hit immediately. ++ Otherwise, just let function_arg_advance () from rs6000.c do its ++ thing. */ ++ ++void ++amigaos_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type, int named) ++{ ++ dprintf ("enter\n"); ++ function_arg_advance (cum, mode, type, named, 0); ++ ++ if (cum->call_cookie & CALL_LINEARVARARGS && cum->nargs_prototype <= 0) ++ { ++ cum->sysv_gregno = GP_ARG_MAX_REG + 1; ++ cum->fregno = FP_ARG_V4_MAX_REG + 1; ++ } ++ dprintf ("exit\n"); ++} ++ ++ ++/* Determine where to put an argument to a function. ++ ++ Linearvarargs should always go to the stack, apart from that ++ any decision made by function_arg () in rs6000.c will be OK. */ ++ ++struct rtx_def * ++amigaos_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type, int named) ++{ ++ struct rtx_def *res = 0; ++ ++ dprintf ("enter\n"); ++ if (mode == VOIDmode && cum->call_cookie & CALL_LINEARVARARGS) ++ res = GEN_INT (cum->call_cookie); ++ else ++ res = function_arg (cum, mode, type, named); ++ ++ dprintf ("exit\n"); ++ ++ return res; ++} ++#endif ++ ++/* Implement va_start. ++ ++ For linearvarargs functions, immediately increase the fpr ++ and gpr count to the maximum value, so that va_arg will look ++ only at the stack. */ ++#if 0 ++void ++amigaos_expand_builtin_va_start (tree valist, rtx nextarg) ++{ ++printf("amigaos_expand_builtin_va_start()\n"); ++ rs6000_va_start (valist, nextarg); ++ ++ if (crtl->args.info.call_cookie & CALL_LINEARVARARGS) ++ { ++ tree f_gpr, f_fpr; ++ tree gpr, fpr, t; ++ ++ f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); ++ f_fpr = TREE_CHAIN (f_gpr); ++ ++ valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist); ++ gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); ++ fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); ++ ++ /* Set gpr use count to 8, forcing the overflow area to be used */ ++ t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_cst (NULL_TREE, 8)); ++ TREE_SIDE_EFFECTS (t) = 1; ++ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); ++ ++ /* Likewise for floating point arguments */ ++ t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_cst (NULL_TREE, 8)); ++ TREE_SIDE_EFFECTS (t) = 1; ++ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); ++ } ++} ++#endif ++ ++/* Implement __builtin_saveregs for linearvarargs functions. */ ++#if 0 ++struct rtx_def * ++amigaos_expand_builtin_saveregs (void) ++{ ++ rtx block, mem_gpr_fpr, mem_overflow, tmp; ++ tree fntype; ++ int stdarg_p; ++ HOST_WIDE_INT words, gpr; ++ struct rtx_def *res; ++ ++ dprintf ("enter\n"); ++ ++ if (crtl->args.info.call_cookie & CALL_LINEARVARARGS) ++ { ++ HOST_WIDE_INT bits; ++ ++ fntype = TREE_TYPE (current_function_decl); ++ stdarg_p = (TYPE_ARG_TYPES (fntype) != 0 ++ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) ++ != void_type_node)); ++ ++ /* Allocate the va_list constructor. */ ++ block = assign_stack_local (BLKmode, 3 * UNITS_PER_WORD, BITS_PER_WORD); ++ MEM_READONLY_P (block) = 1; ++ MEM_READONLY_P (XEXP (block, 0)) = 1; ++ ++ mem_gpr_fpr = change_address (block, word_mode, XEXP (block, 0)); ++ mem_overflow = change_address (block, ptr_mode, ++ plus_constant (XEXP (block, 0), ++ UNITS_PER_WORD)); ++ /*mem_reg_save_area = change_address (block, ptr_mode, ++ plus_constant (XEXP (block, 0), ++ 2 * UNITS_PER_WORD));*/ ++ ++ /* Construct the two characters of `gpr' and `fpr' as a unit. */ ++ words = crtl->args.info.words; ++ gpr = crtl->args.info.sysv_gregno - GP_ARG_MIN_REG; ++ ++ /* Varargs has the va_dcl argument, but we don't count it. */ ++ if (!stdarg_p) ++ { ++ if (gpr > GP_ARG_NUM_REG) ++ words -= 1; ++ } ++ ++ bits = (GP_ARG_MAX_REG - GP_ARG_MIN_REG + 1) << 8 ++ | (FP_ARG_MAX_REG - FP_ARG_MIN_REG + 1); ++ if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD) ++ tmp = GEN_INT (bits << (BITS_PER_WORD - 16)); ++ else ++ { ++ bits <<= BITS_PER_WORD - HOST_BITS_PER_WIDE_INT - 16; ++ tmp = immed_double_const (0, bits, word_mode); ++ } ++ ++ emit_move_insn (mem_gpr_fpr, tmp); ++ ++ /* Find the overflow area. */ ++ tmp = expand_binop (Pmode, add_optab, virtual_incoming_args_rtx, ++ GEN_INT (words * UNITS_PER_WORD), ++ mem_overflow, 0, OPTAB_WIDEN); ++ if (tmp != mem_overflow) ++ emit_move_insn (mem_overflow, tmp); ++ ++ /*tmp = expand_binop (Pmode, add_optab, virtual_stack_vars_rtx, ++ GEN_INT (-RS6000_VARARGS_SIZE), ++ mem_reg_save_area, 0, OPTAB_WIDEN); ++ if (tmp != mem_reg_save_area) ++ emit_move_insn (mem_reg_save_area, tmp);*/ ++ ++ /* Return the address of the va_list constructor. */ ++ res = XEXP (block, 0); ++ } ++ else ++ { ++ res = expand_builtin_saveregs (); ++ } ++ ++ dprintf ("exit\n"); ++ return res; ++} ++#endif ++ ++/* Define subtarget builtins */ ++ ++void ++amigaos_init_builtins (void) ++{ ++ tree ftype; ++ ftype = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, ++ build_pointer_type (TREE_TYPE (va_list_type_node)), ++ void_list_node)); ++ ++ add_builtin_function ("__builtin_getlinearva", ++ ftype, ++ AMIGAOS_BUILTIN_GETLINEARVA, ++ BUILT_IN_MD, NULL, NULL_TREE); ++} ++ ++ ++/* Expand builtins */ ++rtx ++amigaos_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED, bool *success) ++{ ++ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); ++ tree f_gpr, f_fpr, f_res, f_ovf; ++ tree arg0, valist, ovf; ++ ++ unsigned int fcode = DECL_FUNCTION_CODE (fndecl); ++ ++// debug_tree(exp); ++// debug_tree(fndecl); ++ if (fcode != AMIGAOS_BUILTIN_GETLINEARVA) ++ { ++ *success = 0; ++ return NULL_RTX; ++ } ++ ++ if (! (crtl->args.info.call_cookie & CALL_LINEARVARARGS)) ++ { ++ /* TODO: This probably should be a fatal, but then the generated executable can't be linked. */ ++ error ("__builtin_getlinearva can only be used in a linearvarargs function"); ++ *success = 1; ++ return 0; ++ } ++ ++ arg0 = CALL_EXPR_ARG (exp, 0); ++ if (arg0 == error_mark_node) ++ return const0_rtx; ++ ++ f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); ++ f_fpr = TREE_CHAIN (f_gpr); ++ f_res = TREE_CHAIN (f_fpr); ++ f_ovf = TREE_CHAIN (f_res); ++ target = const0_rtx; ++ valist = build_simple_mem_ref(arg0);//build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (arg0)), arg0); ++ ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); ++ target = copy_to_reg (expand_expr (ovf, NULL_RTX, Pmode, EXPAND_NORMAL)); ++ *success = 1; ++ return target; ++} ++ ++/* Handle a "linearvarargs" attribute. */ ++tree ++amigaos_handle_linearvarargs_attribute (tree *node, tree name, ++ tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, ++ bool *no_add_attrs) ++{ ++ if (TREE_CODE (*node) != FUNCTION_TYPE ++ && TREE_CODE (*node) != METHOD_TYPE ++ && TREE_CODE (*node) != FIELD_DECL ++ && TREE_CODE (*node) != TYPE_DECL) ++ { ++ warning (0, "%s attribute only applies to functions", ++ IDENTIFIER_POINTER (name)); ++ *no_add_attrs = true; ++ } ++ ++ return NULL_TREE; ++} ++ ++ ++/* Generate code for base relative access */ ++ ++rtx ++amigaos_legitimize_baserel_address (rtx addr) ++{ ++ rtx dest = gen_reg_rtx (Pmode); ++ ++ emit_insn (gen_elf_base_high (dest, gen_rtx_REG (Pmode, 2), addr)); ++ emit_insn (gen_elf_base_low (dest, dest, addr)); ++ ++ return dest; ++} ++ ++int ++amigaos_not_baserel_tree_p(tree decl) ++{ ++ return(TREE_READONLY(decl) ++ || TREE_CONSTANT(decl) ++ || (DECL_ATTRIBUTES(decl) ++ && lookup_attribute("force_no_baserel", DECL_ATTRIBUTES(decl)))); ++} ++ ++int ++amigaos_baserel_operand(rtx x) ++{ ++ tree decl; ++ int ret = 0; ++ ++ if (GET_CODE(x) == SYMBOL_REF) ++ { ++ decl = SYMBOL_REF_DECL(x); ++ ++ if (decl) ++ { ++ if (SYMBOL_REF_FUNCTION_P(x) || amigaos_not_baserel_tree_p(decl)) ++ ret = 0; ++ else ++ ret = 1; ++ } ++ } ++ else if (GET_CODE(x) == CONST ++ && GET_CODE(XEXP(x, 0)) == PLUS ++ && GET_CODE(XEXP(XEXP(x, 0), 0)) == SYMBOL_REF ++ && GET_CODE(XEXP(XEXP(x, 0), 1)) == CONST_INT) ++ ret = amigaos_baserel_operand(XEXP(XEXP(x, 0), 0)); ++ else if (GET_CODE(x) == LO_SUM) ++ ret = amigaos_baserel_operand(XEXP(x, 1)); ++ ++ return ret; ++} ++ ++void amigaos_function_end_prologue(FILE *file); ++void amigaos_function_end_prologue(FILE *file) ++{ ++ if (TARGET_BASEREL ++ && current_function_decl ++ && lookup_attribute ("baserel_restore", TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))) ++ { ++ fprintf( file, "\tbl __baserel_get_addr\n"); ++ } ++} ++ ++ ++tree ++amigaos_handle_baserel_restore_attribute (tree *node, tree name, ++ tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, ++ bool *no_add_attrs) ++{ ++ if (TREE_CODE (*node) != FUNCTION_TYPE ++ && TREE_CODE (*node) != METHOD_TYPE ++ && TREE_CODE (*node) != FIELD_DECL ++ && TREE_CODE (*node) != TYPE_DECL) ++ { ++ warning (0, "%s attribute only applies to functions", ++ IDENTIFIER_POINTER (name)); ++ *no_add_attrs = true; ++ } ++ ++ return NULL_TREE; ++} ++ ++tree ++amigaos_handle_force_no_baserel_attribute (tree *node, tree name, ++ tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, ++ bool *no_add_attrs) ++{ ++ if (TREE_CODE (*node) != VAR_DECL) ++ { ++ warning (0, "%s attribute only applies to variables", ++ IDENTIFIER_POINTER (name)); ++ *no_add_attrs = true; ++ } ++ ++ return NULL_TREE; ++} ++ ++/* Handle a "check68kfuncptr" attribute. */ ++ ++tree ++amigaos_handle_check68kfuncptr_attribute (tree *node, tree name, ++ tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, ++ bool *no_add_attrs) ++{ ++ if (TREE_CODE (*node) != FUNCTION_TYPE ++ && TREE_CODE (*node) != METHOD_TYPE ++ && TREE_CODE (*node) != FIELD_DECL ++ && TREE_CODE (*node) != TYPE_DECL) ++ { ++ warning (0, "%s attribute only applies to functions", ++ IDENTIFIER_POINTER (name)); ++ *no_add_attrs = true; ++ } ++ ++ return NULL_TREE; ++} +diff --git a/gcc/config/rs6000/amigaos.h b/gcc/config/rs6000/amigaos.h +new file mode 100644 +index 0000000000000000000000000000000000000000..4556163c22a8fadc51c9ed7401c7e6c414e58c0e +--- /dev/null ++++ gcc/config/rs6000/amigaos.h +@@ -0,0 +1,431 @@ ++/* Definitions of target machine for GNU compiler, for AmigaOS. ++ Copyright (C) 1997, 2003, 2005 Free Software Foundation, Inc. ++ ++ This file is part of GCC. ++ ++ GCC is free software; you can redistribute it and/or modify it ++ under the terms of the GNU General Public License as published ++ by the Free Software Foundation; either version 2, or (at your ++ option) any later version. ++ ++ GCC is distributed in the hope that it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public ++ License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with GCC; see the file COPYING. If not, write to the ++ Free Software Foundation, 59 Temple Place - Suite 330, Boston, ++ MA 02111-1307, USA. */ ++ ++ ++/* Don't assume anything about the header files. */ ++#define NO_IMPLICIT_EXTERN_C ++ ++#undef MD_EXEC_PREFIX ++#undef MD_STARTFILE_PREFIX ++ ++/* Make CPU default to 604e. FIXME: Make this 750 later */ ++#undef PROCESSOR_DEFAULT ++#define PROCESSOR_DEFAULT PROCESSOR_PPC604e ++ ++#undef DEFAULT_ABI ++#define DEFAULT_ABI ABI_V4 ++ ++#undef ASM_CPU_SPEC ++#define ASM_CPU_SPEC \ ++"%{!mcpu*: \ ++ %{mpower: %{!mpower2: -mpwr}} \ ++ %{mpower2: -mpwrx} \ ++ %{mpowerpc64*: -mppc64} \ ++ %{!mpowerpc64*: %{mpowerpc*: -mppc}} \ ++ %{mno-power: %{!mpowerpc*: -mcom}} \ ++ %{!mno-power: %{!mpower*: %(asm_default)}}} \ ++%{mcpu=common: -mcom} \ ++%{mcpu=power: -mpwr} \ ++%{mcpu=power2: -mpwrx} \ ++%{mcpu=power3: -mppc64} \ ++%{mcpu=power4: -mpower4} \ ++%{mcpu=power5: -mpower4} \ ++%{mcpu=powerpc: -mppc} \ ++%{mcpu=rios: -mpwr} \ ++%{mcpu=rios1: -mpwr} \ ++%{mcpu=rios2: -mpwrx} \ ++%{mcpu=rsc: -mpwr} \ ++%{mcpu=rsc1: -mpwr} \ ++%{mcpu=rs64a: -mppc64} \ ++%{mcpu=401: -mppc} \ ++%{mcpu=403: -m403} \ ++%{mcpu=405: -m405} \ ++%{mcpu=405fp: -m405} \ ++%{mcpu=440: -m440} \ ++%{mcpu=440fp: -m440} \ ++%{mcpu=505: -mppc} \ ++%{mcpu=601: -m601} \ ++%{mcpu=602: -mppc} \ ++%{mcpu=603: -mppc} \ ++%{mcpu=603e: -mppc} \ ++%{mcpu=ec603e: -mppc} \ ++%{mcpu=604: -mppc} \ ++%{mcpu=604e: -mppc} \ ++%{mcpu=620: -mppc64} \ ++%{mcpu=630: -mppc64} \ ++%{mcpu=740: -mppc} \ ++%{mcpu=750: -mppc} \ ++%{mcpu=G3: -mppc} \ ++%{mcpu=7400: -mppc -maltivec} \ ++%{mcpu=7450: -mppc -maltivec} \ ++%{mcpu=G4: -mppc -maltivec} \ ++%{mcpu=801: -mppc} \ ++%{mcpu=821: -mppc} \ ++%{mcpu=823: -mppc} \ ++%{mcpu=860: -mppc} \ ++%{mcpu=970: -mpower4 -maltivec} \ ++%{mcpu=G5: -mpower4 -maltivec} \ ++%{mcpu=8540: -me500} \ ++%{maltivec: -maltivec}" ++ ++#define IS_MCRT(MCRTNAME) \ ++ (strcmp(amigaos_crt, MCRTNAME) == 0) ++ ++/* Make most of the definitions from other compilers available */ ++#undef TARGET_OS_CPP_BUILTINS ++#define TARGET_OS_CPP_BUILTINS() \ ++ do \ ++ { \ ++ builtin_define_std ("PPC"); \ ++ builtin_define_std ("powerpc"); \ ++ builtin_assert ("cpu=powerpc"); \ ++ builtin_assert ("machine=powerpc"); \ ++ builtin_define_std ("AMIGA"); \ ++ builtin_define_std ("AMIGAOS"); \ ++ builtin_define_std ("AMIGAOS4"); \ ++ builtin_define_std ("amiga"); \ ++ builtin_define_std ("amigaos"); \ ++ builtin_define_std ("amigaos4"); \ ++ builtin_assert ("system=amigaos"); \ ++ if (!amigaos_crt) \ ++ { \ ++ error ("no CRT specified"); \ ++ } \ ++ else if (IS_MCRT("clib2") || IS_MCRT("clib2-ts")) \ ++ { \ ++ builtin_define_std ("CLIB2"); \ ++ if (IS_MCRT("clib2-ts")) \ ++ builtin_define ("__THREAD_SAFE"); \ ++ } \ ++ else if (IS_MCRT("ixemul")) \ ++ { \ ++ builtin_define_std ("ixemul"); \ ++ builtin_define_std ("IXEMUL"); \ ++ } \ ++ else if (IS_MCRT("libnix")) \ ++ { \ ++ builtin_define_std ("libnix"); \ ++ builtin_define_std ("LIBNIX"); \ ++ } \ ++ else if (IS_MCRT("newlib")) \ ++ { \ ++ builtin_define_std ("NEWLIB"); \ ++ } \ ++ TARGET_OS_SYSV_CPP_BUILTINS (); \ ++ } \ ++ while (0) ++ ++#undef CPP_SPEC ++#define CPP_SPEC "%{posix: -D_POSIX_SOURCE} %(cpp_os_default)" ++ ++/*#define STANDARD_INCLUDE_DIR "/GCC/include"*/ ++/*#undef SYSTEM_INCLUDE_DIR *//* So that the include path order is the same in native and cross compilers */ ++#undef LOCAL_INCLUDE_DIR ++ ++#ifndef CROSS_DIRECTORY_STRUCTURE ++#define BASE_GCC_SPEC "/GCC/" ++#define BASE_SDK_SPEC "/SDK/" ++#else ++#define BASE_GCC_SPEC EXEC_PREFIX ++#define BASE_SDK_SPEC EXEC_PREFIX "ppc-amigaos/SDK/" ++#endif ++ ++#define LIB_SUBDIR_TYPE_SPEC "\ ++%{mbaserel:/baserel; msdata|msdata=default|msdata=sysv:/small-data}\ ++%{msoft-float:/soft-float}" ++ ++/* default linker specs */ ++#undef REAL_LIBGCC_SPEC ++#define REAL_LIBGCC_SPEC "\ ++%{static|static-libgcc: %{!use-dynld: -lgcc -lgcc_eh} %{use-dynld: -lgcc} }%{!static:%{!static-libgcc:%{!shared:%{!shared-libgcc: %{!use-dynld: -lgcc -lgcc_eh} %{use-dynld: -lgcc}}%{shared-libgcc:-lgcc}}%{shared:%{shared-libgcc:-lgcc}%{!shared-libgcc:-lgcc}}}}" ++ ++ ++/* make newlib the default */ ++#if 1 ++#define CPP_AMIGA_DEFAULT_SPEC "%{mcrt=default|!mcrt=*:%<mcrt=default -mcrt=newlib} %(cpp_newlib)" ++#define LINK_AMIGA_DEFAULT_SPEC "%(link_newlib)" ++#define STARTFILE_AMIGA_DEFAULT_SPEC "%(startfile_newlib)" ++#define ENDFILE_AMIGA_DEFAULT_SPEC "%(endfile_newlib)" ++#undef MULTILIB_DEFAULTS ++#define MULTILIB_DEFAULTS {"mcrt=newlib"} ++#else ++/* make clib2 the default */ ++#define CPP_AMIGA_DEFAULT_SPEC "%{mcrt=default|!mcrt=*:%<mcrt=default -mcrt=clib2} %(cpp_clib2)" ++#define LINK_AMIGA_DEFAULT_SPEC "%(link_clib2)" ++#define STARTFILE_AMIGA_DEFAULT_SPEC "%(startfile_clib2)" ++#define ENDFILE_AMIGA_DEFAULT_SPEC "%(endfile_clib2)" ++#undef MULTILIB_DEFAULTS ++#define MULTILIB_DEFAULTS {"mcrt=clib2"} ++#endif ++ ++/* clib2 */ ++ ++#define CPP_CLIB2_SPEC "\ ++-isystem %(base_sdk)clib2/include -isystem %(base_sdk)local/clib2/include" ++ ++#define LIB_SUBDIR_CLIB2_SPEC "%{mcrt=clib2-ts:lib.threadsafe; :lib}%(lib_subdir_type)" ++ ++#define LINK_CLIB2_SPEC "\ ++-L%(base_sdk)clib2/%(lib_subdir_clib2) \ ++-L%(base_gcc)lib/gcc/ppc-amigaos/%(version)/%{mcrt=clib2-ts:clib2-ts; :clib2}/lib%(lib_subdir_type) \ ++-L%(base_sdk)local/clib2/%(lib_subdir_clib2)" ++ ++#define STARTFILE_CLIB2_SPEC "\ ++%(base_sdk)clib2/%{mcrt=clib2-ts:lib.threadsafe; :lib}" \ ++ "%{!msoft-float:%(lib_subdir_type)}/crtbegin.o \ ++%(base_sdk)clib2/%{mcrt=clib2-ts:lib.threadsafe; :lib}" \ ++ "%{!msoft-float:%(lib_subdir_type)}/crt0.o" ++ ++#define ENDFILE_CLIB2_SPEC "\ ++%(base_sdk)clib2/%{mcrt=clib2-ts:lib.threadsafe; :lib}" \ ++ "%{!msoft-float:%(lib_subdir_type)}/crtend.o" ++ ++/* ixemul */ ++ ++#define CPP_IXEMUL_SPEC "\ ++-isystem %(base_sdk)ixemul/include -isystem %(base_sdk)local/ixemul/include" ++ ++#define LIB_SUBDIR_IXEMUL_SPEC "lib%(lib_subdir_type)" ++ ++#define LINK_IXEMUL_SPEC "\ ++-L%(base_sdk)ixemul/%(lib_subdir_ixemul) \ ++-L%(base_gcc)lib/gcc/ppc-amigaos/%(version)/ixemul/%(lib_subdir_ixemul) \ ++-L%(base_sdk)local/ixemul/%(lib_subdir_ixemul)" ++ ++/* ixemul startfile should work for all library flavours */ ++#define STARTFILE_IXEMUL_SPEC "%(base_sdk)ixemul/%(lib_subdir_ixemul)/crtbegin.o" ++#define ENDFILE_IXEMUL_SPEC "%(base_sdk)ixemul/%(lib_subdir_ixemul)/crtend.o" ++ ++/* libnix */ ++ ++#define CPP_LIBNIX_SPEC "\ ++-isystem %(base_sdk)libnix/include -isystem %(base_sdk)local/libnix/include" ++ ++#define LIB_SUBDIR_LIBNIX_SPEC "lib%(lib_subdir_type)" ++ ++#define LINK_LIBNIX_SPEC "\ ++-L%(base_sdk)libnix/%(lib_subdir_libnix) \ ++-L%(base_gcc)lib/gcc/ppc-amigaos/%(version)/libnix/%(lib_subdir_libnix) \ ++-L%(base_sdk)local/libnix/%(lib_subdir_libnix)" ++ ++#define STARTFILE_LIBNIX_SPEC "%(base_sdk)libnix/%(lib_subdir_libnix)/crtbegin.o" ++#define ENDFILE_LIBNIX_SPEC "%(base_sdk)libnix/%(lib_subdir_libnix)/crtend.o" ++ ++/* newlib */ ++ ++#define CPP_NEWLIB_SPEC "\ ++-isystem %(base_sdk)newlib/include -isystem %(base_sdk)local/newlib/include" ++ ++#define LIB_SUBDIR_NEWLIB_SPEC "lib%(lib_subdir_type)" ++ ++#define LINK_NEWLIB_SPEC "\ ++-L%(base_sdk)newlib/%(lib_subdir_newlib) \ ++-L%(base_gcc)lib/gcc/ppc-amigaos/%(version)/newlib/%(lib_subdir_newlib) \ ++-L%(base_sdk)local/newlib/%(lib_subdir_newlib)" ++ ++/* newlib startfile should work for all library flavours */ ++#define STARTFILE_NEWLIB_SPEC "\ ++%{shared: %(base_sdk)newlib/%(lib_subdir_newlib)/shcrtbegin.o} %{!shared: %(base_sdk)newlib/%(lib_subdir_newlib)/crtbegin.o}" ++ ++#define ENDFILE_NEWLIB_SPEC "\ ++%{shared: %(base_sdk)newlib/%(lib_subdir_newlib)/shcrtend.o} %{!shared: %(base_sdk)newlib/%(lib_subdir_newlib)/crtend.o}" ++ ++/* End clib specific */ ++ ++#undef CPP_OS_DEFAULT_SPEC ++#define CPP_OS_DEFAULT_SPEC "\ ++%{mcrt=clib2|mcrt=clib2-ts: %(cpp_clib2); \ ++mcrt=ixemul: %(cpp_ixemul); \ ++mcrt=libnix: %(cpp_libnix); \ ++mcrt=newlib: %(cpp_newlib); \ ++mcrt=default|!mcrt=*: %{mcrt=default|!nostdinc: %(cpp_amiga_default)}; \ ++: %eInvalid C runtime library} \ ++-isystem %(base_sdk)include/include_h \ ++-isystem %(base_sdk)include/netinclude \ ++-isystem %(base_sdk)local/common/include \ ++%{mbaserel: %{msdata|msdata=default|msdata=sysv: %e-mbaserel and -msdata options are incompatible}} \ ++%{newlib: %e-newlib is obsolete, use -mcrt=newlib instead}" ++ ++#undef LINK_SPEC ++#define LINK_SPEC "\ ++--defsym __amigaos4__=1 \ ++%{!shared: %{!use-dynld: -Bstatic}} \ ++-q -d %{h*} %{v:-V} %{G*} \ ++%{Wl,*:%*} %{YP,*} %{R*} \ ++%{Qy:} %{!Qn:-Qy} \ ++%(link_shlib) %(link_text) \ ++%{mbaserel: %{msdata|msdata=default|msdata=sysv: %e-mbaserel and -msdata options are incompatible}} \ ++%{mcrt=clib2|mcrt=clib2-ts: %(link_clib2); \ ++mcrt=ixemul: %(link_ixemul); \ ++mcrt=libnix: %(link_libnix); \ ++mcrt=newlib: %(link_newlib); \ ++mcrt=default|!mcrt=*: %(link_amiga_default); \ ++: %eInvalid C runtime library} \ ++-L%(base_sdk)local/common/lib%(lib_subdir_type) \ ++%{newlib: %e-newlib is obsolete, use -mcrt=newlib instead}" ++ ++/* FIXME: LINK_TEXT has been made empty now. Could we get rid of it? */ ++#if 0 ++#define LINK_TEXT "\ ++%{use-dynld: -Ttext=0x100000} %{!use-dynld: %{shared: -Ttext=0x100000} %{!shared: %{!Wl,-T*: %{!T*:-Ttext=0}}}}" ++#else ++#define LINK_TEXT "" ++#endif ++ ++#define LINK_SHLIB "\ ++%{shared:-shared -dy --defsym __dynld_version__=1} %{!shared: %{static:-static}} %{use-dynld: -dy}" ++ ++#undef STARTFILE_SPEC ++#define STARTFILE_SPEC "\ ++%{mcrt=clib2|mcrt=clib2-ts: %(startfile_clib2); \ ++mcrt=ixemul: %(startfile_ixemul); \ ++mcrt=libnix: %(startfile_libnix); \ ++mcrt=newlib: %(startfile_newlib); \ ++mcrt=default|!mcrt=*: %(startfile_amiga_default); \ ++: %eInvalid C runtime library}" ++ ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC "\ ++%{mcrt=clib2|mcrt=clib2-ts: %(endfile_clib2); \ ++mcrt=ixemul: %(endfile_ixemul); \ ++mcrt=libnix: %(endfile_libnix); \ ++mcrt=newlib: %(endfile_newlib); \ ++mcrt=default|!mcrt=*: %(endfile_amiga_default); \ ++: %eInvalid C runtime library}" ++ ++#undef LIB_SPEC ++#define LIB_SPEC "\ ++--start-group -lc --end-group" ++ ++#undef TARGET_DEFAULT ++#define TARGET_DEFAULT 0 ++ ++#undef SUBTARGET_EXTRA_SPECS ++#define SUBTARGET_EXTRA_SPECS \ ++ {"base_gcc", BASE_GCC_SPEC}, \ ++ {"base_sdk", BASE_SDK_SPEC}, \ ++ {"cpp_os_default", CPP_OS_DEFAULT_SPEC}, \ ++ {"lib_subdir_type", LIB_SUBDIR_TYPE_SPEC}, \ ++ /* default C runtime */ \ ++ {"cpp_amiga_default", CPP_AMIGA_DEFAULT_SPEC}, \ ++ {"link_amiga_default", LINK_AMIGA_DEFAULT_SPEC}, \ ++ {"startfile_amiga_default", STARTFILE_AMIGA_DEFAULT_SPEC}, \ ++ {"endfile_amiga_default", ENDFILE_AMIGA_DEFAULT_SPEC}, \ ++ /* clib2 */ \ ++ {"cpp_clib2", CPP_CLIB2_SPEC}, \ ++ {"lib_subdir_clib2", LIB_SUBDIR_CLIB2_SPEC}, \ ++ {"link_clib2", LINK_CLIB2_SPEC}, \ ++ {"startfile_clib2", STARTFILE_CLIB2_SPEC}, \ ++ {"endfile_clib2", ENDFILE_CLIB2_SPEC}, \ ++ /* ixemul */ \ ++ {"cpp_ixemul", CPP_IXEMUL_SPEC}, \ ++ {"lib_subdir_ixemul", LIB_SUBDIR_IXEMUL_SPEC}, \ ++ {"link_ixemul", LINK_IXEMUL_SPEC}, \ ++ {"startfile_ixemul", STARTFILE_IXEMUL_SPEC}, \ ++ {"endfile_ixemul", ENDFILE_IXEMUL_SPEC}, \ ++ /* libnix */ \ ++ {"cpp_libnix", CPP_LIBNIX_SPEC}, \ ++ {"lib_subdir_libnix", LIB_SUBDIR_LIBNIX_SPEC}, \ ++ {"link_libnix", LINK_LIBNIX_SPEC}, \ ++ {"startfile_libnix", STARTFILE_LIBNIX_SPEC}, \ ++ {"endfile_libnix", ENDFILE_LIBNIX_SPEC}, \ ++ /* newlib */ \ ++ {"cpp_newlib", CPP_NEWLIB_SPEC}, \ ++ {"lib_subdir_newlib", LIB_SUBDIR_NEWLIB_SPEC}, \ ++ {"link_newlib", LINK_NEWLIB_SPEC}, \ ++ {"startfile_newlib", STARTFILE_NEWLIB_SPEC}, \ ++ {"endfile_newlib", ENDFILE_NEWLIB_SPEC}, \ ++ /* used in link spec */ \ ++ {"link_text", LINK_TEXT}, \ ++ {"link_shlib", LINK_SHLIB}, ++ ++#undef DEFAULT_VTABLE_THUNKS ++#ifndef USE_GNULIBC_1 ++#define DEFAULT_VTABLE_THUNKS 1 ++#endif ++ ++#undef JUMP_TABLES_IN_TEXT_SECTION ++#define JUMP_TABLES_IN_TEXT_SECTION 0 ++ ++/* Used as cookie for linear vararg passing */ ++#define CALL_LINEARVARARGS 0x10000000 ++ ++/* AmigaOS specific options */ ++ ++/* Strings provided for own options management in rs6000.c */ ++/*extern const char *amigaos_crt_string;*/ ++ ++#define SUB3TARGET_OVERRIDE_OPTIONS \ ++do \ ++{ \ ++ if (TARGET_ALTIVEC) \ ++ { \ ++ rs6000_altivec_abi = 1; \ ++ TARGET_ALTIVEC_VRSAVE = 1; \ ++ } \ ++} while(0) ++ ++#undef SUBTARGET_EXPAND_BUILTIN ++#define SUBTARGET_EXPAND_BUILTIN(EXP, TARGET, SUBTARGET, MODE, IGNORE, SUCCESS) \ ++ amigaos_expand_builtin (EXP, TARGET, SUBTARGET, MODE, IGNORE, SUCCESS) ++ ++#undef SUBTARGET_INIT_BUILTINS ++#define SUBTARGET_INIT_BUILTINS \ ++ amigaos_init_builtins () ++ ++/* AmigaOS specific attribute */ ++#define SUBTARGET_ATTRIBUTE_TABLE \ ++ { "linearvarargs", 0, 0, false, true, true, amigaos_handle_linearvarargs_attribute, false}, \ ++ { "lineartags", 0, 0, false, true, true, amigaos_handle_lineartags_attribute, false}, \ ++ { "baserel_restore", 0, 0, false, true, true, amigaos_handle_baserel_restore_attribute, false }, \ ++ { "force_no_baserel", 0, 0, true, false, false, amigaos_handle_force_no_baserel_attribute, false }, \ ++ { "check68kfuncptr", 0, 0, false, true, true, amigaos_handle_check68kfuncptr_attribute, false } ++ ++/* Overrides */ ++/* ++#undef INIT_CUMULATIVE_ARGS ++#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \ ++ amigaos_init_cumulative_args (&CUM, FNTYPE, LIBNAME, FALSE, N_NAMED_ARGS) ++ ++#undef INIT_CUMULATIVE_INCOMING_ARGS ++#define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \ ++ amigaos_init_cumulative_args (&CUM, FNTYPE, LIBNAME, TRUE, 1000) ++ ++#undef FUNCTION_ARG_ADVANCE ++#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ ++ amigaos_function_arg_advance (&CUM, MODE, TYPE, NAMED) ++ ++#undef FUNCTION_ARG ++#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ ++ amigaos_function_arg (&CUM, MODE, TYPE, NAMED) ++*/ ++#undef EXPAND_BUILTIN_VA_START ++#define EXPAND_BUILTIN_VA_START(VALIST, NEXTARG) \ ++ amigaos_expand_builtin_va_start (VALIST, NEXTARG) ++ ++#undef SLOW_UNALIGNED_ACCESS ++#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) \ ++ (STRICT_ALIGNMENT \ ++ || (((MODE) == SFmode) && (ALIGN) < 32) \ ++ || (((MODE) == DFmode || (MODE) == TFmode || (MODE) == DImode) \ ++ && (ALIGN) < 64)) ++ ++/* This target uses the amigaos.opt file. */ ++#define TARGET_USES_AMIGAOS_OPT 1 +diff --git a/gcc/config/rs6000/amigaos.opt b/gcc/config/rs6000/amigaos.opt +new file mode 100644 +index 0000000000000000000000000000000000000000..93d74f10bea8c1b23c82a9650bb0c3c153464ba7 +--- /dev/null ++++ gcc/config/rs6000/amigaos.opt +@@ -0,0 +1,37 @@ ++; Options for the PowerPC AmigaOS port ++; ++; Copyright (C) 2005 Free Software Foundation, Inc. ++; Contributed by Jens Langner <Jens.Langner@light-speed.de> ++; ++; This file is part of GCC. ++; ++; GCC is free software; you can redistribute it and/or modify it under ++; the terms of the GNU General Public License as published by the Free ++; Software Foundation; either version 2, or (at your option) any later ++; version. ++; ++; GCC is distributed in the hope that it will be useful, but WITHOUT ++; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public ++; License for more details. ++; ++; You should have received a copy of the GNU General Public License ++; along with GCC; see the file COPYING. If not, write to the Free ++; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ++; 02110-1301, USA. ++ ++mcrt= ++Target RejectNegative Joined Var(amigaos_crt) Init("newlib") ++Select C runtime library ++ ++mbaserel ++Target Report Mask(BASEREL) ++Generate base relative data access ++ ++mcheck68kfuncptr ++Target Report Var(CHECK68KFUNCPTR) ++Generate target checking for function pointers ++ ++use-dynld ++Target Driver ++Generated binary employs the dynamic linker for shared objects. +diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def +index 7b79efcedb31000524ac8ac485a054bef70ff9c3..07ecb46ca445f2503529b61f1acecfd722b673ce 100644 +--- gcc/config/rs6000/rs6000-builtin.def ++++ gcc/config/rs6000/rs6000-builtin.def +@@ -1985,6 +1985,13 @@ RS6000_BUILTIN_X (RS6000_BUILTIN_MTFSF, "__builtin_mtfsf", + RS6000_BTC_MISC | RS6000_BTC_UNARY | RS6000_BTC_VOID, + CODE_FOR_rs6000_mtfsf) + + /* Darwin CfString builtin. */ + BU_SPECIAL_X (RS6000_BUILTIN_CFSTRING, "__builtin_cfstring", RS6000_BTM_ALWAYS, + RS6000_BTC_MISC) ++ ++/* AmigaOS specific builtin. */ ++RS6000_BUILTIN_2 (AMIGAOS_BUILTIN_GETLINEARVA, /* ENUM */ \ ++ "__builtin_getlinearva", /* NAME */ \ ++ RS6000_BTM_ALWAYS, /* MASK */ \ ++ RS6000_BTC_MISC, /* ATTR */ \ ++ CODE_FOR_nothing) /* ICODE */ +diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c +index f5c2d422a8076e6fa5da3b864ade636c54cd9af8..ee0ea2ffabb6b9c6fdcba687d88be1e1164374ee 100644 +--- gcc/config/rs6000/rs6000.c ++++ gcc/config/rs6000/rs6000.c +@@ -161,12 +161,18 @@ typedef struct rs6000_stack { + not in save_size */ + int spe_gp_size; /* size of 64-bit GPR save size for SPE */ + int spe_padding_size; + HOST_WIDE_INT total_size; /* total bytes allocated for stack */ + int spe_64bit_regs_used; + int savres_strategy; ++#ifdef TARGET_BASEREL ++ int baserel_save_p; /* true if the baserel register needs to be ++ saved */ ++ int baserel_save_offset; /* offset to save baserel register */ ++ int baserel_size; /* size of saved baserel register */ ++#endif + } rs6000_stack_t; + + /* A C structure for machine-specific, per-function data. + This is added to the cfun structure. */ + typedef struct GTY(()) machine_function + { +@@ -1426,12 +1432,18 @@ static const struct attribute_spec rs6000_attribute_table[] = + + #undef TARGET_ASM_FUNCTION_PROLOGUE + #define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue + #undef TARGET_ASM_FUNCTION_EPILOGUE + #define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue + ++#ifdef TARGET_BASEREL ++extern void amigaos_function_end_prologue(FILE *); ++#undef TARGET_ASM_FUNCTION_END_PROLOGUE ++#define TARGET_ASM_FUNCTION_END_PROLOGUE amigaos_function_end_prologue ++#endif ++ + #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA + #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA rs6000_output_addr_const_extra + + #undef TARGET_LEGITIMIZE_ADDRESS + #define TARGET_LEGITIMIZE_ADDRESS rs6000_legitimize_address + +@@ -6957,12 +6969,20 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, + { + enum tls_model model = SYMBOL_REF_TLS_MODEL (x); + if (model != 0) + return rs6000_legitimize_tls_address (x, model); + } + ++#ifdef TARGET_BASEREL ++ if (TARGET_BASEREL ++ && amigaos_baserel_operand(x)) ++ { ++ return amigaos_legitimize_baserel_address(x); ++ } ++#endif ++ + extra = 0; + switch (mode) + { + case TFmode: + case TDmode: + case TImode: +@@ -8549,12 +8569,21 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode mode) + tmp = gen_rtx_PLUS (mode, tmp, addend); + tmp = force_operand (tmp, operands[0]); + } + operands[1] = tmp; + } + ++#ifdef TARGET_BASEREL ++ if (/*GET_CODE (operands[1]) == SYMBOL_REF ++ && */TARGET_BASEREL ++ && amigaos_baserel_operand (operands[1])) ++ { ++ operands[1] = amigaos_legitimize_baserel_address (operands[1]); ++ } ++#endif ++ + /* Handle the case where reload calls us with an invalid address. */ + if (reload_in_progress && mode == Pmode + && (! general_operand (operands[1], mode) + || ! nonimmediate_operand (operands[0], mode))) + goto emit_set; + +@@ -8852,12 +8881,20 @@ rs6000_emit_move (rtx dest, rtx source, machine_mode mode) + #endif + emit_insn (gen_macho_high (target, operands[1])); + emit_insn (gen_macho_low (operands[0], target, operands[1])); + return; + } + ++#ifdef TARGET_BASEREL ++ if (TARGET_BASEREL && amigaos_baserel_operand(operands[1])) ++ { ++ emit_insn (gen_elf_base_high (target, gen_rtx_REG (Pmode, 2), operands[1])); ++ emit_insn (gen_elf_base_low (operands[0], target, operands[1])); ++ return; ++ } ++#endif + emit_insn (gen_elf_high (target, operands[1])); + emit_insn (gen_elf_low (operands[0], target, operands[1])); + return; + } + + /* If this is a SYMBOL_REF that refers to a constant pool entry, +@@ -9372,12 +9409,18 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, + if ((!fntype && rs6000_default_long_calls) + || (fntype + && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)) + && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))) + cum->call_cookie |= CALL_LONG; + ++ /* AmigaOS4: Check if either libcall or linear varargs, set appropriate cookie */ ++ if (fntype && (lookup_attribute ("libcall", TYPE_ATTRIBUTES (fntype)))) ++ cum->call_cookie |= CALL_LINEARVARARGS; ++ if (fntype && (lookup_attribute ("linearvarargs", TYPE_ATTRIBUTES (fntype)))) ++ cum->call_cookie |= CALL_LINEARVARARGS; ++ + if (TARGET_DEBUG_ARG) + { + fprintf (stderr, "\ninit_cumulative_args:"); + if (fntype) + { + tree ret_type = TREE_TYPE (fntype); +@@ -10023,12 +10066,21 @@ rs6000_function_arg_advance_1 (CUMULATIVE_ARGS *cum, machine_mode mode, + fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ", + cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode)); + fprintf (stderr, "named = %d, align = %d, depth = %d\n", + named, align_words - start_words, depth); + } + } ++ ++ /* If the function has the linearvarargs attribute and this argument ++ to advance over is the last non-vararg argument, then advance over ++ all registers, so that the overflow area is hit immediately. */ ++ if (cum->call_cookie & CALL_LINEARVARARGS && cum->nargs_prototype <= 0) ++ { ++ cum->sysv_gregno = GP_ARG_MAX_REG + 1; ++ cum->fregno = FP_ARG_V4_MAX_REG + 1; ++ } + } + + static void + rs6000_function_arg_advance (cumulative_args_t cum, machine_mode mode, + const_tree type, bool named) + { +@@ -11189,12 +11241,18 @@ setup_incoming_varargs (cumulative_args_t cum, machine_mode mode, + save_area = virtual_incoming_args_rtx; + + if (targetm.calls.must_pass_in_stack (mode, type)) + first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type); + } + ++#ifdef CALL_LINEARVARARGS ++ /* For AmigaOS: No need to save registers for linearvarargs functions */ ++ if (next_cum.call_cookie & CALL_LINEARVARARGS) ++ return; ++#endif ++ + set = get_varargs_alias_set (); + if (! no_rtl && first_reg_offset < GP_ARG_NUM_REG + && cfun->va_list_gpr_size) + { + int n_gpr, nregs = GP_ARG_NUM_REG - first_reg_offset; + +@@ -11316,13 +11374,13 @@ rs6000_build_builtin_va_list (void) + return build_array_type (record, build_index_type (size_zero_node)); + } + + /* Implement va_start. */ + + static void +-rs6000_va_start (tree valist, rtx nextarg) ++rs6000_va_start2 (tree valist, rtx nextarg) + { + HOST_WIDE_INT words, n_gpr, n_fpr; + tree f_gpr, f_fpr, f_res, f_ovf, f_sav; + tree gpr, fpr, ovf, sav, t; + + /* Only SVR4 needs something special. */ +@@ -11351,12 +11409,21 @@ rs6000_va_start (tree valist, rtx nextarg) + words = crtl->args.info.words; + n_gpr = MIN (crtl->args.info.sysv_gregno - GP_ARG_MIN_REG, + GP_ARG_NUM_REG); + n_fpr = MIN (crtl->args.info.fregno - FP_ARG_MIN_REG, + FP_ARG_NUM_REG); + ++ /* For linearvarargs functions, immediately increase the fpr ++ and gpr count to the maximum value, so that va_arg will look ++ only at the stack. */ ++ if (crtl->args.info.call_cookie & CALL_LINEARVARARGS) ++ { ++ n_gpr = GP_ARG_NUM_REG; ++ n_fpr = FP_ARG_NUM_REG; ++ } ++ + if (TARGET_DEBUG_ARG) + fprintf (stderr, "va_start: words = "HOST_WIDE_INT_PRINT_DEC", n_gpr = " + HOST_WIDE_INT_PRINT_DEC", n_fpr = "HOST_WIDE_INT_PRINT_DEC"\n", + words, n_gpr, n_fpr); + + if (cfun->va_list_gpr_size) +@@ -11402,12 +11469,18 @@ rs6000_va_start (tree valist, rtx nextarg) + t = fold_build_pointer_plus_hwi (t, cfun->machine->varargs_save_offset); + t = build2 (MODIFY_EXPR, TREE_TYPE (sav), sav, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + } + ++void ++rs6000_va_start (tree valist, rtx nextarg) ++{ ++ rs6000_va_start2(valist, nextarg); ++} ++ + /* Implement va_arg. */ + + static tree + rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, + gimple_seq *post_p) + { +@@ -14155,12 +14228,20 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, + size_t i; + rtx ret; + bool success; + HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask; + bool func_valid_p = ((rs6000_builtin_mask & mask) == mask); + ++ /* Try subtarget first */ ++#ifdef SUBTARGET_EXPAND_BUILTIN ++ ret = SUBTARGET_EXPAND_BUILTIN (exp, target, subtarget, mode, ignore, &success); ++ if (success) ++ return ret; ++#endif ++ ++ + if (TARGET_DEBUG_BUILTIN) + { + enum insn_code icode = rs6000_builtin_info[uns_fcode].icode; + const char *name1 = rs6000_builtin_info[uns_fcode].name; + const char *name2 = ((icode != CODE_FOR_nothing) + ? get_insn_name ((int)icode) +@@ -19214,13 +19295,22 @@ print_operand_address (FILE *file, rtx x) + #endif + #if TARGET_ELF + else if (GET_CODE (x) == LO_SUM && REG_P (XEXP (x, 0)) + && CONSTANT_P (XEXP (x, 1))) + { + output_addr_const (file, XEXP (x, 1)); ++#ifdef TARGET_BASEREL ++ if (TARGET_BASEREL && amigaos_baserel_operand(x)) ++ { ++ fprintf (file, "@brel@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]); ++ } ++ else ++ fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]); ++#else + fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]); ++#endif + } + #endif + else if (toc_relative_expr_p (x, false)) + { + /* This hack along with a corresponding hack in + rs6000_output_addr_const_extra arranges to output addends +@@ -21827,12 +21917,25 @@ rs6000_stack_info (void) + - info_ptr->first_altivec_reg_save); + + /* Does this function call anything? */ + info_ptr->calls_p = (! crtl->is_leaf + || cfun->machine->ra_needs_full_frame); + ++#ifdef TARGET_BASEREL ++ /* Check if the function wants to setup the baserel register (r2) */ ++ if (TARGET_BASEREL ++ && current_function_decl ++ && lookup_attribute ("baserel_restore", TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))) ++ { ++ info_ptr->baserel_save_p = 1; ++ info_ptr->baserel_size = reg_size; ++ df_set_regs_ever_live(2,true); ++ info_ptr->calls_p = 1; ++ } ++#endif /* TARGET_BASEREL */ ++ + /* Determine if we need to save the condition code registers. */ + if (df_regs_ever_live_p (CR2_REGNO) + || df_regs_ever_live_p (CR3_REGNO) + || df_regs_ever_live_p (CR4_REGNO)) + { + info_ptr->cr_save_p = 1; +@@ -21944,13 +22047,19 @@ rs6000_stack_info (void) + info_ptr->lr_save_offset = 2*reg_size; + break; + + case ABI_V4: + info_ptr->fp_save_offset = - info_ptr->fp_size; + info_ptr->gp_save_offset = info_ptr->fp_save_offset - info_ptr->gp_size; ++#ifdef TARGET_BASEREL ++ info_ptr->baserel_save_offset = info_ptr->gp_save_offset ++ - info_ptr->baserel_size; ++ info_ptr->cr_save_offset = info_ptr->baserel_save_offset - info_ptr->cr_size; ++#else + info_ptr->cr_save_offset = info_ptr->gp_save_offset - info_ptr->cr_size; ++#endif + + if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0) + { + /* Align stack so SPE GPR save area is aligned on a + double-word boundary. */ + if (info_ptr->spe_gp_size != 0 && info_ptr->cr_save_offset != 0) +@@ -22004,12 +22113,16 @@ rs6000_stack_info (void) + + ehrd_size + + ehcr_size + + info_ptr->cr_size + + info_ptr->vrsave_size, + save_align); + ++#ifdef TARGET_BASEREL ++ info_ptr->save_size += RS6000_ALIGN (info_ptr->baserel_size, save_align); ++#endif ++ + non_fixed_size = (info_ptr->vars_size + + info_ptr->parm_size + + info_ptr->save_size); + + info_ptr->total_size = RS6000_ALIGN (non_fixed_size + info_ptr->fixed_size, + ABI_STACK_BOUNDARY / BITS_PER_UNIT); +@@ -22188,12 +22301,17 @@ debug_stack_info (rs6000_stack_t *info) + if (info->lr_save_p) + fprintf (stderr, "\tlr_save_p = %5d\n", info->lr_save_p); + + if (info->cr_save_p) + fprintf (stderr, "\tcr_save_p = %5d\n", info->cr_save_p); + ++#ifdef TARGET_BASEREL ++ if (info->baserel_save_p) ++ fprintf (stderr, "\tbaserel_save_p = %5d\n", info->baserel_save_p); ++#endif ++ + if (info->vrsave_mask) + fprintf (stderr, "\tvrsave_mask = 0x%x\n", info->vrsave_mask); + + if (info->push_p) + fprintf (stderr, "\tpush_p = %5d\n", info->push_p); + +@@ -22224,12 +22342,17 @@ debug_stack_info (rs6000_stack_t *info) + if (info->cr_save_offset) + fprintf (stderr, "\tcr_save_offset = %5d\n", info->cr_save_offset); + + if (info->varargs_save_offset) + fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset); + ++#ifdef TARGET_BASEREL ++ if (info->baserel_save_offset && TARGET_BASEREL) ++ fprintf (stderr, "\tbaserel_save_offset = %5d\n", info->baserel_save_offset); ++#endif ++ + if (info->total_size) + fprintf (stderr, "\ttotal_size = "HOST_WIDE_INT_PRINT_DEC"\n", + info->total_size); + + if (info->vars_size) + fprintf (stderr, "\tvars_size = "HOST_WIDE_INT_PRINT_DEC"\n", +@@ -22253,12 +22376,17 @@ debug_stack_info (rs6000_stack_t *info) + if (info->altivec_size) + fprintf (stderr, "\taltivec_size = %5d\n", info->altivec_size); + + if (info->vrsave_size) + fprintf (stderr, "\tvrsave_size = %5d\n", info->vrsave_size); + ++#ifdef TARGET_BASEREL ++ if (info->baserel_size && TARGET_BASEREL) ++ fprintf (stderr, "\tbaserel_size = %5d\n", info->baserel_size); ++#endif ++ + if (info->altivec_padding_size) + fprintf (stderr, "\taltivec_padding_size= %5d\n", + info->altivec_padding_size); + + if (info->spe_padding_size) + fprintf (stderr, "\tspe_padding_size = %5d\n", +@@ -23989,12 +24117,28 @@ rs6000_emit_prologue (void) + emit_frame_save (frame_reg_rtx, reg_mode, + info->first_gp_reg_save + i, + info->gp_save_offset + frame_off + reg_size * i, + sp_off - frame_off); + } + ++#ifdef TARGET_BASEREL ++ if (info->baserel_save_p && TARGET_BASEREL) ++ { ++ /* Store r2 */ ++ rtx addr, reg, mem; ++ ++ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, ++ GEN_INT (info->baserel_save_offset + frame_off)); /* or sp_off? */ ++ mem = gen_frame_mem (reg_mode, addr); ++ ++ reg = gen_rtx_REG (reg_mode, 2); ++ insn = emit_move_insn (mem, reg); ++ rs6000_frame_related (insn, gen_rtx_REG (Pmode, 12), info->total_size, /* verify info->total_size */ ++ NULL_RTX, NULL_RTX); ++ } ++#endif + if (crtl->calls_eh_return) + { + unsigned int i; + rtvec p; + + for (i = 0; ; ++i) +@@ -24446,12 +24590,19 @@ rs6000_emit_prologue (void) + + if (!info->lr_save_p) + emit_move_insn (lr, gen_rtx_REG (Pmode, 0)); + } + #endif + ++#ifdef TARGET_BASEREL ++ /* Emit a blockage to prevent r2-dependant instructions from moving into ++ * the prologue. r2 is set up later in amigaos_function_end_prologue. */ ++ if (info->baserel_save_p && TARGET_BASEREL) ++ emit_insn (gen_blockage ()); ++#endif ++ + /* If we need to, save the TOC register after doing the stack setup. + Do not emit eh frame info for this save. The unwinder wants info, + conceptually attached to instructions in this function, about + register values in the caller of this function. This R2 may have + already been changed from the value in the caller. + We don't attempt to write accurate DWARF EH frame info for R2 +@@ -24502,12 +24653,17 @@ rs6000_output_savres_externs (FILE *file) + & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0; + int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0); + name = rs6000_savres_routine_name (info, regno, sel); + fprintf (file, "\t.extern %s\n", name); + } + } ++ ++#ifdef TARGET_BASEREL ++ if (info->baserel_save_p && TARGET_BASEREL) ++ fprintf (file, "\t.extern __baserel_get_addr\n"); ++#endif + } + + /* Write function prologue. */ + + static void + rs6000_output_function_prologue (FILE *file, +@@ -25319,12 +25475,30 @@ rs6000_emit_epilogue (int sibcall) + + reg_size * (int) i); + + emit_move_insn (gen_rtx_REG (reg_mode, regno), mem); + } + } + ++#ifdef TARGET_BASEREL ++ if (info->baserel_save_p && TARGET_BASEREL) ++ { ++ rtx addr, mem, reg; ++ ++ /* Restore r2 */ ++ addr = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 12), ++ GEN_INT (info->baserel_save_offset + frame_off)); /* or sp_off? */ ++ mem = gen_frame_mem (reg_mode, addr); ++ ++ reg = gen_rtx_REG (reg_mode, 2); ++ emit_move_insn (reg, mem); ++ ++ /* Mark register as used. */ ++ emit_insn (gen_rtx_USE (VOIDmode, reg)); ++ } ++#endif ++ + /* Restore GPRs. This is done as a PARALLEL if we are using + the load-multiple instructions. */ + if (TARGET_SPE_ABI + && info->spe_64bit_regs_used + && info->first_gp_reg_save != 32) + { +diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h +index 653c2c94e11a6f22d20fe3e33532e4d354c2be5e..99ad439bc53ba7194804bb9bcb47e5756e7175e2 100644 +--- gcc/config/rs6000/rs6000.h ++++ gcc/config/rs6000/rs6000.h +@@ -2771,6 +2771,9 @@ enum rs6000_builtin_type_index + #define void_type_internal_node (rs6000_builtin_types[RS6000_BTI_void]) + + extern GTY(()) tree rs6000_builtin_types[RS6000_BTI_MAX]; + extern GTY(()) tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT]; + + #define TARGET_SUPPORTS_WIDE_INT 1 ++ ++/* Used by amigaos port */ ++void rs6000_va_start (tree valist, rtx nextarg); +diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md +index 0e5883c7fc895a454d3677f0818c4f13b625c9ce..c8304a75b801c6c5fbe7617e0b42eb46ad15d050 100644 +--- gcc/config/rs6000/rs6000.md ++++ gcc/config/rs6000/rs6000.md +@@ -10950,12 +10950,37 @@ + "TARGET_TOC" + "la %0,%a1" + "&& TARGET_CMODEL != CMODEL_SMALL && reload_completed" + [(set (match_dup 0) (high:P (match_dup 1))) + (set (match_dup 0) (lo_sum:P (match_dup 0) (match_dup 1)))]) + ++;; This needs to be above elf_high/elf_low since elf_base_low and elf_low ++;; have the same instruction signature, so in some cases elf_low would be ++;; generated instead of elf_base_low. Since the requirements for elf_base_low ++;; are more restrictive than those for elf_low, there should be no problems ++;; when determining which instruction to use. Additionally, the elf_low function ++;; has now been guared against used accidently. ++(define_insn "elf_base_high" ++ [(set (match_operand:SI 0 "gpc_reg_operand" "=b") ++ (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b") ++ (high:SI (match_operand 2 "" ""))))] ++ "TARGET_ELF && ! TARGET_64BIT && TARGET_BASEREL" ++ "{cau|addis} %0,%1,%2@brel@ha" ++ [(set_attr "length" "4")]) ++ ++;; Nearly same as elf_low, but used base relative relocs. ++;; The second alternative has also been removed (as %K always ++;; uses normal relocs, see rs6000.c/print_operand()). ++(define_insn "elf_base_low" ++ [(set (match_operand:SI 0 "gpc_reg_operand" "=r") ++ (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b") ++ (match_operand 2 "" "")))] ++ "TARGET_ELF && ! TARGET_64BIT && TARGET_BASEREL && amigaos_baserel_operand(operands[2])" ++ "{cal|la} %0,%2@brel@l(%1)" ++ [(set_attr "length" "4")]) ++ + ;; Elf specific ways of loading addresses for non-PIC code. + ;; The output of this could be r0, but we make a very strong + ;; preference for a base register because it will usually + ;; be needed there. + (define_insn "elf_high" + [(set (match_operand:SI 0 "gpc_reg_operand" "=b*r") +@@ -10964,13 +10989,13 @@ + "lis %0,%1@ha") + + (define_insn "elf_low" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b") + (match_operand 2 "" "")))] +- "TARGET_ELF && ! TARGET_64BIT" ++ "TARGET_ELF && ! TARGET_64BIT && !(TARGET_BASEREL && amigaos_baserel_operand(operands[2]))" + "la %0,%2@l(%1)") + + ;; Call and call_value insns + (define_expand "call" + [(parallel [(call (mem:SI (match_operand 0 "address_operand" "")) + (match_operand 1 "" "")) +diff --git a/gcc/config/rs6000/t-amigaos b/gcc/config/rs6000/t-amigaos +new file mode 100644 +index 0000000000000000000000000000000000000000..15d9d3fd5a5f0c8109cd158242745fa52b19257e +--- /dev/null ++++ gcc/config/rs6000/t-amigaos +@@ -0,0 +1,20 @@ ++# Makefile fragment for AmigaOS/PPC target. ++ ++# Extra object file linked to the cc1* executables. ++amigaos.o: $(srcdir)/config/rs6000/amigaos.c $(CONFIG_H) ++ $(CXX) -c $(ALL_CXXFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) ++ ++# We always have limits.h. ++LIMITS_H_TEST = true ++ ++# Override defaults. ++# FIXME: This is only correct when building a native version natively. ++NATIVE_SYSTEM_HEADER_DIR=/gcc/include ++#OTHER_FIXINCLUDES_DIRS=${gcc_tooldir}/include ++ ++# Build the libraries for both newlib and clib2 ++# We do not build soft float flavours as none of the ++# libs support soft floats ++MULTILIB_OPTIONS = mcrt=newlib/mcrt=clib2 ++MULTILIB_DIRNAMES = newlib clib2 ++#MULTILIB_REUSE = =mcrt=newlib +diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c +index 22792556c2431d1875e36cee2304c91d709102ea..cd6a6f14e32a9ee078dd048f5d20965960ac4f44 100644 +--- gcc/cp/typeck.c ++++ gcc/cp/typeck.c +@@ -3525,12 +3525,28 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params, + + return error_mark_node; + } + + /* fntype now gets the type of function pointed to. */ + fntype = TREE_TYPE (fntype); ++ ++ if (lookup_attribute ("libcall", TYPE_ATTRIBUTES (fntype)) || ++ lookup_attribute ("libcall2", TYPE_ATTRIBUTES (fntype))) ++ { ++ if (TREE_CODE (function) == COMPONENT_REF && lvalue_p (function)) ++ { ++ /* Type of 0 operand of a component ref is always a dereferenced object but ++ * we need to pass the address of this object */ ++ ++ /* FIXME: param_types? */ ++ vec_safe_insert(*params,0, ++ build1(ADDR_EXPR, build_pointer_type (TREE_TYPE (TREE_OPERAND (function, 0))), ++ TREE_OPERAND (function, 0))); ++ } ++ } ++ + parm_types = TYPE_ARG_TYPES (fntype); + + if (params == NULL) + { + allocated = make_tree_vector (); + params = &allocated; +diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi +index 70a09032d433c2834f6d1458dcaee92763616570..f63512c1029aa2168a89824ce284844387121082 100644 +--- gcc/doc/extend.texi ++++ gcc/doc/extend.texi +@@ -4508,12 +4508,163 @@ The @code{weak} attribute causes the declaration to be emitted as a weak + symbol rather than a global. This is primarily useful in defining + library functions that can be overridden in user code, though it can + also be used with non-function declarations. Weak symbols are supported + for ELF targets, and also for a.out targets when using the GNU assembler + and linker. + ++@item libcall ++@cindex AmigaOS specific function attributes ++On AmigaOS, the @code{libcall} attribute is used to declare function ++pointers in an AmigaOS @emph{Interface}. When such a function pointer ++is invoked, a pointer to the Interface itself is passed as a hidden ++first argument, similar to @code{this} in C++. ++ ++ISO/IEC 9899:1999 Edits for Libcall functions ++ ++The following are a set of changes to ISO/IEC 9899:1999 (aka C99) ++that document the exact semantics of the language extension. ++ ++@itemize @bullet ++@item ++@cite{6.5.2.2 Function calls} ++ ++Change paragraph 3 to ++ ++@quotation ++[...] denotes the called function. The arguments to the function ++are specified by the implicit argument, if any, followed by the list ++of expressions. ++@end quotation ++ ++Add new paragraph before paragraph 4 ++ ++@quotation ++If the expression that denotes the called function is a structure or union ++member expression as defined in (6.5.2.3) (or such an expression enclosed ++in any number of parentheses expressions), is an lvalue, and has a type ++that includes the attribute @code{libcall}, then the function call has an ++implicit argument. In other cases there is no implicit argument. If there ++is an implicit argument, then this will be the first argument to the function, ++and the list of expressions will follow it. The type of the implicit ++argument is that of a pointer to the structure or union object of which the ++function expression designates a member. The value of the implicit argument ++is the address of this structure or union object. ++@end quotation ++@end itemize ++ ++@item linearvarargs ++@cindex AmigaOS specific function attributes ++On AmigaOS, the @code{linearvarargs} attribute causes all unprototyped ++arguments to a varargs function to be passed on the stack, and not in ++registers as the SVR4 ABI defines. Please note that @code{libcall} also ++implies @code{linearvarargs}. ++ ++@item baserel_restore ++@cindex AmigaOS specific function attributes ++On AmigaOS, when compiling with @option{-mbaserel} causes the compiler ++to create a call to @code{baserel_get_addr} function in the function prologue ++to set up register @code{r2}. The previous contents of register @code{r2} ++are restored in the function epilogue. See @option{-mbaserel} option for ++more details. ++ ++@item check68kfuncptr ++@cindex AmigaOS specific function attributes ++On AmigaOS, when calling a function using a function pointer causes ++the compiler to emit additional code to allow for function pointers ++to m68k functions. This is currently available only in the C front end. ++ ++The generated code will call @code{__amigaos4_check68k_check} function ++which expects one function pointer argument and returns an integer ++value. If the return value is non-zero, the function pointer will be ++used to perform the function call in the usual way, otherwise ++@code{__amigaos4_check68k_trampoline} function will be called to perform ++the call. The @code{__amigaos4_check68k_check} function should be provided ++by the user and will usually just return the result of ++@code{exec.library} @code{IsNative} call on its argument. ++ ++The @code{__amigaos4_check68k_trampoline} function is a @code{linearvarargs} ++function and should also be provided by the user. It will receive at ++least two arguments: the number of arguments to the function pointer and ++the function pointer itself. Additionally, the arguments to the function ++pointer will follow on the stack, each having one zero longword in front ++of it with one final zero longword after all the arguments. This makes it ++possible to create tag pairs and a terminating @code{TAG_DONE} for a ++call to @code{EmulateTags} in @code{exec.library}. The return code of ++@code{__amigaos4_check68k_trampoline} function will be used as a return ++code of the function pointer call. ++ ++The following example can be used for functions that have no more than ++13 arguments: ++ ++@smallexample ++static const UWORD trampoline_code[][6] = ++@{ ++ /* @r{JMP (A5)} */ ++ @{0X4ED5, 0, 0, 0, 0, 0@}, ++ /* @r{MOVEM.L D0, -(A7); JSR (A5); ADDQ.L #4,A7; RTS} */ ++ @{0X48E7, 0X8000, 0X4E95, 0X588F, 0X4E75, 0@}, ++ /* @r{MOVEM.L D0-D1, -(A7); JSR (A5); ADDQ.L #8, A7; RTS} */ ++ @{0X48E7, 0XC000, 0X4E95, 0X508F, 0X4E75, 0@}, ++ /* @r{MOVEM.L D0-D2, -(A7); JSR (A5); ADDA.W #0X000C, A7; RTS} */ ++ @{0X48E7, 0XE000, 0X4E95, 0XDEFC, 0X000C, 0X4E75@}, ++ /* @r{MOVEM.L D0-D3, -(A7); JSR (A5); ADDA.W #0X0010, A7; RTS} */ ++ @{0X48E7, 0XF000, 0X4E95, 0XDEFC, 0X0010, 0X4E75@}, ++ /* @r{MOVEM.L D0-D4, -(A7); JSR (A5); ADDA.W #0X0014, A7; RTS} */ ++ @{0X48E7, 0XF800, 0X4E95, 0XDEFC, 0X0014, 0X4E75@}, ++ /* @r{MOVEM.L D0-D5, -(A7); JSR (A5); ADDA.W #0X0018, A7; RTS} */ ++ @{0X48E7, 0XFC00, 0X4E95, 0XDEFC, 0X0018, 0X4E75@}, ++ /* @r{MOVEM.L D0-D6, -(A7); JSR (A5); ADDA.W #0X001C, A7; RTS} */ ++ @{0X48E7, 0XFE00, 0X4E95, 0XDEFC, 0X001C, 0X4E75@}, ++ /* @r{MOVEM.L D0-D7, -(A7); JSR (A5); ADDA.W #0X0020, A7; RTS} */ ++ @{0X48E7, 0XFF00, 0X4E95, 0XDEFC, 0X0020, 0X4E75@}, ++ /* @r{MOVEM.L D0-D7/A0, -(A7); JSR (A5); ADDA.W #0X0024, A7; RTS} */ ++ @{0X48E7, 0XFF80, 0X4E95, 0XDEFC, 0X0024, 0X4E75@}, ++ /* @r{MOVEM.L D0-D7/A0-A1, -(A7); JSR (A5); ADDA.W #0X0028, A7; RTS} */ ++ @{0X48E7, 0XFFC0, 0X4E95, 0XDEFC, 0X0028, 0X4E75@}, ++ /* @r{MOVEM.L D0-D7/A0-A2, -(A7); JSR (A5); ADDA.W #0X002C, A7; RTS} */ ++ @{0X48E7, 0XFFE0, 0X4E95, 0XDEFC, 0X002C, 0X4E75@}, ++ /* @r{MOVEM.L D0-D7/A0-A3, -(A7); JSR (A5); ADDA.W #0X0030, A7; RTS} */ ++ @{0X48E7, 0XFFF0, 0X4E95, 0XDEFC, 0X0030, 0X4E75@}, ++ /* @r{MOVEM.L D0-D7/A0-A3, -(A7); JSR (A5); ADDA.W #0X0034, A7; RTS} */ ++ @{0X48E7, 0XFFF8, 0X4E95, 0XDEFC, 0X0034, 0X4E75@} ++@}; ++ ++int VARARGS68K __amigaos4_check68k_trampoline(int num_args, ++ int func, ++ ...) ++@{ ++ int result, i; ++ va_list args; ++ long *stack; ++ ++ va_startlinear(args, func); ++ stack = va_getlinearva(args, long *); ++ ++ /* @r{Replace 0's with tag id's} */ ++ for(i = 0; i < 8 && i < num_args; i++) ++ stack[i * 2] = ET_RegisterD0 + i; ++ ++ while(i < num_args) ++ @{ ++ stack[i * 2] = ET_RegisterA0 + i - 8; ++ i++; ++ @} ++ ++ if (num_args < sizeof(trampoline_code) ++ / sizeof(trampoline_code[0])) ++ result = IExec->EmulateTags(trampoline_code[num_args], ++ ET_SaveRegs, TRUE, ++ ET_RegisterA5, func, ++ TAG_MORE, stack); ++ ++ va_end(args); ++ ++ return(result); ++@} ++@end smallexample ++ + @item weakref + @itemx weakref ("@var{target}") + @cindex @code{weakref} function attribute + The @code{weakref} attribute marks a declaration as a weak reference. + Without arguments, it should be accompanied by an @code{alias} attribute + naming the target symbol. Optionally, the @var{target} may be given as +@@ -5698,12 +5849,28 @@ struct + + @noindent + Here, @code{t5} takes up 2 bytes. + @end enumerate + @end table + ++@subsection AmigaOS PPC Variable Attributes ++ ++One attribute is currently defined for AmigaOS PPC. ++ ++@table @code ++@item force_no_baserel ++@cindex forcing a variable not to be addressed base relative ++ ++This attribute forces access to a variable in code compiled with ++@option{-mbaserel} option not to be base relative. If necessary, the ++access should be protected with some sort of arbitration. See ++documentation on @option{-mbaserel} option for more details about this ++attribute. ++ ++@end table ++ + @subsection Xstormy16 Variable Attributes + + One attribute is currently defined for xstormy16 configurations: + @code{below100}. + + @table @code +diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi +index d3be5899c57fa2147893f27c7c7bddac98bd4ff4..68ecbffa0f2f92f5ecc7331e8e855240134dbcdf 100644 +--- gcc/doc/invoke.texi ++++ gcc/doc/invoke.texi +@@ -1109,12 +1109,16 @@ See RS/6000 and PowerPC Options. + -mtarget-align -mno-target-align @gol + -mlongcalls -mno-longcalls} + + @emph{zSeries Options} + See S/390 and zSeries Options. + ++@emph{AmigaOS PPC options} ++@gccoptlist{-mcrt=@var{crt} -mbaserel -mno-baserel @gol ++-mcheck68kfuncptr} ++ + @item Code Generation Options + @xref{Code Gen Options,,Options for Code Generation Conventions}. + @gccoptlist{-fcall-saved-@var{reg} -fcall-used-@var{reg} @gol + -ffixed-@var{reg} -fexceptions @gol + -fnon-call-exceptions -fdelete-dead-exceptions -funwind-tables @gol + -fasynchronous-unwind-tables @gol +@@ -12227,12 +12231,13 @@ platform. + * VMS Options:: + * VxWorks Options:: + * x86 Options:: + * x86 Windows Options:: + * Xstormy16 Options:: + * Xtensa Options:: ++* AmigaOS PPC options:: + * zSeries Options:: + @end menu + + @node AArch64 Options + @subsection AArch64 Options + @cindex AArch64 Options +@@ -23178,12 +23183,143 @@ These options are defined for Xstormy16: + @table @gcctabopt + @item -msim + @opindex msim + Choose startup files and linker script suitable for the simulator. + @end table + ++@node AmigaOS PPC options ++@subsection AmigaOS PPC options ++@cindex AmigaOS PPC options ++ ++@table @gcctabopt ++ ++@item -mcrt=@var{crt} ++@opindex mcrt ++ ++Select the C runtime library to use. The same option must be used for ++both compiling and linking. Some of the possible values are @samp{default}, ++@samp{clib2}, @samp{clib2-ts} (thread-safe variant of clib2) and @samp{newlib}. ++Each option makes available an appropriate define, for example ++@code{__CLIB2__}, @code{__NEWLIB__} etc. Additionally, @samp{clib2-ts} option ++provides the @code{__THREAD_SAFE} define. ++ ++@item -mbaserel ++@opindex mbaserel ++ ++Generate code to access all non-constant data relative to register @code{r2}. ++The executable should also be linked with @option{-mbaserel} option. ++ ++This option is useful for creating shared libraries for which all ++openers have a separate copy of non-constant data but share the constant ++data. A better way to do this is by using interface cloning, but ++sometimes this is not possible, for example when some package is being ++ported in form of shared library. ++ ++This option can also be used to create residentable programs with ++special startup code. ++ ++The startup code or the appropriate interface setup method should use ++@code{CopyDataSegment} function from @samp{elf.library} v51.8 or later to ++copy and relocate the data segment that each instance should have a copy of ++and then set up @code{r2} (and/or @code{EnvironmentVector} interface field ++for libraries) appropriately: ++ ++@smallexample ++Elf32_Handle handle = NULL; ++BPTR seg = IDOS->GetProcSegList(NULL); ++ ++if (seg) ++@{ ++ IDOS->GetSegListInfoTags(seg, GSLI_ElfHandle, &handle, TAG_DONE); ++ ++ if (handle ++ && (handle = IElf->OpenElfTags(OET_ElfHandle, handle, TAG_DONE))) ++ @{ ++ uint32 offset; ++ uint8 *data = IElf->CopyDataSegment(handle, &offset); ++ ++ if (data) ++ @{ ++ /* @r{Store @code{data} somewhere since it will be required} ++ * @r{in the cleanup stage} ++ */ ++ ++ CurrentInterface->Data.EnvironmentVector = data + offset; ++ ++ /* @r{Optionally, set r2 to the same value as @code{EnvironmentVector}} if the ++ * @r{current method will call functions access instance local data. This is} ++ * @r{not necessary if the current method will only call interface methods} ++ * @r{which have @code{baserel_restore} attribute (see below).} ++ */ ++ ++ IElf->CloseElfTags(handle, CET_ReClose, TRUE, TAG_DONE); ++ @} ++ else ++ /* Data was not allocated */; ++ @} ++ else ++ /* ELF handle couldn't be obtained */; ++@} ++else ++ /* Process segment list was not retrieved */; ++ ++@end smallexample ++ ++The copied data segment should be freed in the cleanup stage using the ++same procedure to obtain the ELF handle and then @code{FreeDataSegmentCopy} ++should be called with the value @code{CopyDataSegment} returned (@emph{not} ++with the value that @code{EnvironmentVector} contains). ++ ++Interface methods should include @code{baserel_restore} attribute in their ++definition. When this attribute is present, the compiler will call ++@code{__baserel_get_addr} function in the function prologue. This function ++should set up @code{r2} register and must not modify any other registers ++except @code{r2}. Since it will be called in function prologue, register ++@code{r3} will contain the the first argument of the function. For ++interfaces, this is the interface pointer through which ++@code{EnvironmentVector} field can be accessed. Previous contents ++of register @code{r2} will be restored in the function epilogue. ++ ++One possible implementation of @code{__baserel_get_addr} function: ++ ++@smallexample ++asm("\n\ ++ text\n\ ++ globl __baserel_get_addr\n\ ++ ++__baserel_get_addr:\n\ ++ lwz 2, 48(3) /* @r{Fetch EnvironmentVector from struct Interface *} */\n\ ++ blr\n\ ++"); ++@end smallexample ++ ++If some non-constant variable needs to be shared by all instances, it ++can be declared with @code{force_no_baserel} attribute. The variable will ++still be present in instance local data area that was created on ++startup, but the compiler will generate code to access it in the ++original data section for all instances. Because of that, the ++declaration of the variable with this attribute must be available to the ++compiler whenever the variable is accessed, otherwise it will generate ++code to access instance local copy of that variable which is probably ++not the desired behaviour. Additionally, some sort of access arbitration ++is probably required. ++ ++@item -mno-baserel ++@opindex mno-baserel ++ ++Generate absolute data access. This is the default. ++ ++@item -mcheck68kfuncptr ++@opindex mcheck68kfuncptr ++ ++Causes each function call through a function pointer to be performed as ++if the function pointer was declared with the @samp{check68kfuncptr} ++function attribute. @xref{Function Attributes}. ++ ++@end table ++ + @node Xtensa Options + @subsection Xtensa Options + @cindex Xtensa Options + + These options are supported for Xtensa targets: + +diff --git a/gcc/expr.c b/gcc/expr.c +index 5c095507f4a303b1c4ab3519d165735be5a37d07..fb57de6652c4bd9dd39300eaaf6c3b2b8aad5fb8 100644 +--- gcc/expr.c ++++ gcc/expr.c +@@ -8134,13 +8134,12 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, + tree treeop0, treeop1, treeop2; + #define REDUCE_BIT_FIELD(expr) (reduce_bit_field \ + ? reduce_to_bit_field_precision ((expr), \ + target, \ + type) \ + : (expr)) +- + type = ops->type; + mode = TYPE_MODE (type); + unsignedp = TYPE_UNSIGNED (type); + + treeop0 = ops->op0; + treeop1 = ops->op1; +diff --git a/gcc/gcc.c b/gcc/gcc.c +index d956c36b151eea45681aa650c39c522f85be359f..d4d061080ba1166fb14069094556246b32265da4 100644 +--- gcc/gcc.c ++++ gcc/gcc.c +@@ -2730,13 +2730,13 @@ execute (void) + commands[0].argv[0] = (string) ? string : commands[0].argv[0]; + } + + for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++) + if (arg && strcmp (arg, "|") == 0) + { /* each command. */ +-#if defined (__MSDOS__) || defined (OS2) || defined (VMS) ++#if defined (__MSDOS__) || defined (OS2) || defined (VMS) || defined(AMIGA) + fatal_error (input_location, "-pipe not supported"); + #endif + argbuf[i] = 0; /* Termination of + command args. */ + commands[n_commands].prog = argbuf[i + 1]; + commands[n_commands].argv +@@ -4261,13 +4261,12 @@ process_command (unsigned int decoded_options_count, + add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS", + PREFIX_PRIORITY_LAST, 2, 0); + #endif + add_prefix (&startfile_prefixes, standard_exec_prefix, "BINUTILS", + PREFIX_PRIORITY_LAST, 1, 0); + } +- + gcc_assert (!IS_ABSOLUTE_PATH (tooldir_base_prefix)); + tooldir_prefix2 = concat (tooldir_base_prefix, spec_host_machine, + dir_separator_str, NULL); + + /* Look for tools relative to the location from which the driver is + running, or, if that is not available, the configured prefix. */ +@@ -6312,12 +6311,17 @@ give_switch (int switchnum, int omit_first_word) + if (dot) + (CONST_CAST (char *, arg))[length] = '.'; + do_spec_1 (suffix_subst, 1, NULL); + } + else + do_spec_1 (arg, 1, NULL); ++ ++#ifdef __amigaos__ ++ /* Don't lose args which happen to be the empty string */ ++ arg_going = 1; ++#endif /* __amigaos__ */ + } + } + + do_spec_1 (" ", 0, NULL); + switches[switchnum].validated = true; + } +@@ -6702,13 +6706,15 @@ is_directory (const char *path1, bool linker) + len1 = strlen (path1); + path = (char *) alloca (3 + len1); + memcpy (path, path1, len1); + cp = path + len1; + if (!IS_DIR_SEPARATOR (cp[-1])) + *cp++ = DIR_SEPARATOR; ++#ifndef __amigaos__ + *cp++ = '.'; ++#endif + *cp = '\0'; + + /* Exclude directories that the linker is known to search. */ + if (linker + && IS_DIR_SEPARATOR (path[0]) + && ((cp - path == 6 +@@ -7223,22 +7229,24 @@ driver::set_up_specs () const + ? gcc_exec_prefix : standard_exec_prefix, + machine_suffix, + standard_startfile_prefix, NULL), + NULL, PREFIX_PRIORITY_LAST, 0, 1); + } + ++#ifndef __amigaos__ + /* Sysrooted prefixes are relocated because target_system_root is + also relocated by gcc_exec_prefix. */ + if (*standard_startfile_prefix_1) + add_sysrooted_prefix (&startfile_prefixes, + standard_startfile_prefix_1, "BINUTILS", + PREFIX_PRIORITY_LAST, 0, 1); + if (*standard_startfile_prefix_2) + add_sysrooted_prefix (&startfile_prefixes, + standard_startfile_prefix_2, "BINUTILS", + PREFIX_PRIORITY_LAST, 0, 1); ++#endif + } + + /* Process any user specified specs in the order given on the command + line. */ + for (struct user_specs *uptr = user_specs_head; uptr; uptr = uptr->next) + { +diff --git a/gcc/prefix.c b/gcc/prefix.c +index 3d7532380d5ea5b6a56fd89688cbd76a5d01df57..4ce2ce2e576ca3ad7e9ffee2a2ddc0d25620b3b9 100644 +--- gcc/prefix.c ++++ gcc/prefix.c +@@ -326,13 +326,13 @@ update_path (const char *path, const char *key) + + #ifdef UPDATE_PATH_HOST_CANONICALIZE + /* Perform host dependent canonicalization when needed. */ + UPDATE_PATH_HOST_CANONICALIZE (result); + #endif + +-#ifdef DIR_SEPARATOR_2 ++#if defined (DIR_SEPARATOR_2) && !defined (__amigaos__) + /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR. */ + if (DIR_SEPARATOR_2 != DIR_SEPARATOR) + tr (result, DIR_SEPARATOR_2, DIR_SEPARATOR); + #endif + + #if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2) +diff --git a/intl/dcigettext.c b/intl/dcigettext.c +index a8d4a14d273b153b117b507ec76356635ccd876e..a9cc1066050e10b539149027a5c159f21accfaca 100644 +--- intl/dcigettext.c ++++ intl/dcigettext.c +@@ -145,13 +145,15 @@ extern int errno; + # define tfind __tfind + #else + # if !defined HAVE_GETCWD + char *getwd (); + # define getcwd(buf, max) getwd (buf) + # else ++# if !defined getcwd + char *getcwd (); ++# endif + # endif + # ifndef HAVE_STPCPY + static char *stpcpy PARAMS ((char *dest, const char *src)); + # endif + # ifndef HAVE_MEMPCPY + static void *mempcpy PARAMS ((void *dest, const void *src, size_t n)); +diff --git a/libcpp/line-map.c b/libcpp/line-map.c +index f9260d00008988a5b5f6b23e03f8f9abd61edd16..b48616406c55ca77e0ebfaa795f83bc661445f3e 100644 +--- libcpp/line-map.c ++++ libcpp/line-map.c +@@ -717,12 +717,15 @@ linemap_ordinary_map_lookup (struct line_maps *set, source_location line) + + mn = LINEMAPS_ORDINARY_CACHE (set); + mx = LINEMAPS_ORDINARY_USED (set); + + cached = LINEMAPS_ORDINARY_MAP_AT (set, mn); + /* We should get a segfault if no line_maps have been added yet. */ ++#ifdef __amigaos4__ ++ linemap_assert(cached != 0); ++#endif + if (line >= MAP_START_LOCATION (cached)) + { + if (mn + 1 == mx || line < MAP_START_LOCATION (&cached[1])) + return cached; + } + else +diff --git a/libgcc/config.host b/libgcc/config.host +index 4329891fb986fee1c1e01ee367df18c927a7a4b8..9b5c8e2c189ad14dbadbd8e982b6e25113a41fa5 100644 +--- libgcc/config.host ++++ libgcc/config.host +@@ -956,12 +956,15 @@ nios2-*-*) + tmake_file="$tmake_file nios2/t-nios2 t-softfp-sfdf t-softfp-excl t-softfp" + extra_parts="$extra_parts crti.o crtn.o" + ;; + pdp11-*-*) + tmake_file="pdp11/t-pdp11 t-fdpbit" + ;; ++powerpc-*-amigaos*) ++ tmake_file="${tmake_file} rs6000/t-savresfgpr rs6000/t-amigaos" ++ ;; + powerpc-*-darwin*) + case ${host} in + *-*-darwin9* | *-*-darwin[12][0-9]*) + # libSystem contains unwind information for signal frames since + # Darwin 9. + ;; +diff --git a/libgcc/config/rs6000/t-amigaos b/libgcc/config/rs6000/t-amigaos +new file mode 100644 +index 0000000000000000000000000000000000000000..da1e303eed7e60df883971a610e8904db0df3e23 +--- /dev/null ++++ libgcc/config/rs6000/t-amigaos +@@ -0,0 +1,45 @@ ++# We need to enable the altivec in the assembler as ++# crtsavevr.S needs it. Not sure how this is handled ++# on other platforms or if this is a limitiation ++# of our binutils. ++HOST_LIBGCC2_CFLAGS += -Wa,-maltivec ++ ++# The shared library needs to be compiled with -fPIC ++ ++gcc_s_compile += -fPIC ++ ++ ++# We want fine grained libraries, so use the new code to build the ++# floating point emulation libraries. ++FPBIT = fp-bit.c ++DPBIT = dp-bit.c ++ ++dp-bit.c: $(srcdir)/config/fp-bit.c ++ cat $(srcdir)/config/fp-bit.c > dp-bit.c ++ ++fp-bit.c: $(srcdir)/config/fp-bit.c ++ echo '#define FLOAT' > fp-bit.c ++ cat $(srcdir)/config/fp-bit.c >> fp-bit.c ++ ++# Build a shared libgcc library. ++# Note that this also builds clib2 shared lib which is not useable at ++# this writing ++# ++# We don't set LIBGCC2_CFLAGS += -fPIC here as this will also ++# produce a position independend static library. The -fPIC is ++# ensured in the special libgcc t-amigaos file. ++# ++SHLIB_DIR = @multilib_dir@ ++SHLIB_SLIBDIR_QUAL = @shlib_slibdir_qual@ ++SHLIB_OBJS = @shlib_objs@ ++SHLIB_EXT = .so ++SHLIB_SONAME = @shlib_base_name@$(SHLIB_EXT) ++SHLIB_LINK = $(GCC_FOR_TARGET) -shared $(SHLIB_OBJS) -nodefaultlibs $(LIBGCC2_CFLAGS) \ ++ -Wl,--soname=libgcc$(SHLIB_EXT) \ ++ -o $(SHLIB_DIR)/$(SHLIB_SONAME) @multilib_flags@ $(SHLIB_LC) ++ ++# Install the shared libgcc library, but ensure that the name is libgcc.so ++SHLIB_INSTALL = \ ++ $(mkinstalldirs) $(DESTDIR)$(inst_libdir); \ ++ $(INSTALL_DATA) $(SHLIB_DIR)/$(SHLIB_SONAME) \ ++ $(DESTDIR)$(inst_libdir)/libgcc$(SHLIB_EXT); +diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in +index f06cc69a973bcf39235febce84a2d7fad7130eed..a3d556b812465e04f339b04bfee766aaaa8eb65b 100644 +--- libiberty/Makefile.in ++++ libiberty/Makefile.in +@@ -140,12 +140,13 @@ CFILES = alloca.c argv.c asprintf.c atexit.c \ + make-temp-file.c md5.c memchr.c memcmp.c memcpy.c memmem.c \ + memmove.c mempcpy.c memset.c mkstemps.c \ + objalloc.c obstack.c \ + partition.c pexecute.c \ + pex-common.c pex-djgpp.c pex-msdos.c pex-one.c \ + pex-unix.c pex-win32.c \ ++ pex-amigaos.c \ + physmem.c putenv.c \ + random.c regex.c rename.c rindex.c \ + safe-ctype.c setenv.c setproctitle.c sha1.c sigsetmask.c \ + simple-object.c simple-object-coff.c simple-object-elf.c \ + simple-object-mach-o.c simple-object-xcoff.c \ + snprintf.c sort.c \ +@@ -207,12 +208,13 @@ CONFIGURED_OFILES = ./asprintf.$(objext) ./atexit.$(objext) \ + ./getcwd.$(objext) ./getpagesize.$(objext) \ + ./gettimeofday.$(objext) \ + ./index.$(objext) ./insque.$(objext) \ + ./memchr.$(objext) ./memcmp.$(objext) ./memcpy.$(objext) \ + ./memmem.$(objext) ./memmove.$(objext) \ + ./mempcpy.$(objext) ./memset.$(objext) ./mkstemps.$(objext) \ ++ ./pex-amigaos.$(objext) \ + ./pex-djgpp.$(objext) ./pex-msdos.$(objext) \ + ./pex-unix.$(objext) ./pex-win32.$(objext) \ + ./putenv.$(objext) \ + ./random.$(objext) ./rename.$(objext) ./rindex.$(objext) \ + ./setenv.$(objext) \ + ./setproctitle.$(objext) \ +@@ -1120,12 +1122,19 @@ $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir + else true; fi + if [ x"$(NOASANFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(NOASANFLAG) $(srcdir)/pex-win32.c -o noasan/$@; \ + else true; fi + $(COMPILE.c) $(srcdir)/pex-win32.c $(OUTPUT_OPTION) + ++./pex-amigaos.$(objext): $(srcdir)/pex-amigaos.c config.h $(INCDIR)/ansidecl.h \ ++ $(INCDIR)/libiberty.h $(srcdir)/pex-common.h ++ if [ x"$(PICFLAG)" != x ]; then \ ++ $(COMPILE.c) $(PICFLAG) $(srcdir)/pex-amigaos.c -o pic/$@; \ ++ else true; fi ++ $(COMPILE.c) $(srcdir)/pex-amigaos.c $(OUTPUT_OPTION) ++ + ./pexecute.$(objext): $(srcdir)/pexecute.c config.h $(INCDIR)/ansidecl.h \ + $(INCDIR)/libiberty.h + if [ x"$(PICFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(srcdir)/pexecute.c -o pic/$@; \ + else true; fi + if [ x"$(NOASANFLAG)" != x ]; then \ +diff --git a/libiberty/basename.c b/libiberty/basename.c +index 0f2c069f0ccf5a7d91e4913548e068c247e12efb..6ba5c4aa4f814fbc28f03127d22e91253c980c1b 100644 +--- libiberty/basename.c ++++ libiberty/basename.c +@@ -15,32 +15,13 @@ Behavior is undefined if the pathname ends in a directory separator. + #ifdef HAVE_CONFIG_H + #include "config.h" + #endif + #include "ansidecl.h" + #include "libiberty.h" + #include "safe-ctype.h" +- +-#ifndef DIR_SEPARATOR +-#define DIR_SEPARATOR '/' +-#endif +- +-#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ +- defined (__OS2__) +-#define HAVE_DOS_BASED_FILE_SYSTEM +-#ifndef DIR_SEPARATOR_2 +-#define DIR_SEPARATOR_2 '\\' +-#endif +-#endif +- +-/* Define IS_DIR_SEPARATOR. */ +-#ifndef DIR_SEPARATOR_2 +-# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +-#else /* DIR_SEPARATOR_2 */ +-# define IS_DIR_SEPARATOR(ch) \ +- (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +-#endif /* DIR_SEPARATOR_2 */ ++#include "filenames.h" + + char * + basename (const char *name) + { + const char *base; + +diff --git a/libiberty/configure b/libiberty/configure +index b06cab24efa57a9bc6aff387d47833188b796e53..645595a1fdbe34c8387fd19ad78dc1132b4760e3 100755 +--- libiberty/configure ++++ libiberty/configure +@@ -6809,12 +6809,13 @@ fi + + # Figure out which version of pexecute to use. + case "${host}" in + *-*-mingw* | *-*-winnt*) pexecute=pex-win32 ;; + *-*-msdosdjgpp*) pexecute=pex-djgpp ;; + *-*-msdos*) pexecute=pex-msdos ;; ++ *-*-amigaos*) pexecute=pex-amigaos;; + *) pexecute=pex-unix ;; + esac + + + if test x$gcc_no_link = xyes; then + if test "x${ac_cv_func_mmap_fixed_mapped+set}" != xset; then +diff --git a/libiberty/configure.ac b/libiberty/configure.ac +index 922aa86e9b03719135b2b12ee5aad1c0cbd74342..1c5704ff8cf09fc7446aea2d17e163c9589af542 100644 +--- libiberty/configure.ac ++++ libiberty/configure.ac +@@ -685,12 +685,13 @@ fi + + # Figure out which version of pexecute to use. + case "${host}" in + *-*-mingw* | *-*-winnt*) pexecute=pex-win32 ;; + *-*-msdosdjgpp*) pexecute=pex-djgpp ;; + *-*-msdos*) pexecute=pex-msdos ;; ++ *-*-amigaos*) pexecute=pex-amigaos ;; + *) pexecute=pex-unix ;; + esac + AC_SUBST(pexecute) + + libiberty_AC_FUNC_STRNCMP + +diff --git a/libiberty/lrealpath.c b/libiberty/lrealpath.c +index b27c8de990e974c7294dfc4024ef44fbd3844a52..1491511553f865caaf8effc67a3ea42319edd3cf 100644 +--- libiberty/lrealpath.c ++++ libiberty/lrealpath.c +@@ -46,12 +46,13 @@ components will be simplified. The returned value will be allocated using + #ifdef HAVE_UNISTD_H + #include <unistd.h> + #endif + #ifdef HAVE_STRING_H + #include <string.h> + #endif ++#include <stdio.h> /* for MAXPATHLEN */ + + /* On GNU libc systems the declaration is only visible with _GNU_SOURCE. */ + #if defined(HAVE_CANONICALIZE_FILE_NAME) \ + && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME) + extern char *canonicalize_file_name (const char *); + #endif +@@ -106,13 +107,13 @@ lrealpath (const char *filename) + compile time buffer size and no alternative function. Query the + OS, using pathconf(), for the buffer limit. Care is needed + though, some systems do not limit PATH_MAX (return -1 for + pathconf()) making it impossible to pass a correctly sized buffer + to realpath() (it could always overflow). On those systems, we + skip this. */ +-#if defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H) ++#if !defined (REALPATH_LIMIT) && defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H) + { + /* Find out the max path size. */ + long path_max = pathconf ("/", _PC_PATH_MAX); + if (path_max > 0) + { + /* PATH_MAX is bounded. */ +diff --git a/libiberty/make-relative-prefix.c b/libiberty/make-relative-prefix.c +index fe639d18bd2815a5ec33aef28720386725ab1bd5..0b5691adc3f6ed9013472568d9d001495205673b 100644 +--- libiberty/make-relative-prefix.c ++++ libiberty/make-relative-prefix.c +@@ -63,44 +63,43 @@ relative prefix can be found, return @code{NULL}. + #endif + + #include <string.h> + + #include "ansidecl.h" + #include "libiberty.h" ++#include "filenames.h" + + #ifndef R_OK + #define R_OK 4 + #define W_OK 2 + #define X_OK 1 + #endif + +-#ifndef DIR_SEPARATOR +-# define DIR_SEPARATOR '/' +-#endif +- + #if defined (_WIN32) || defined (__MSDOS__) \ + || defined (__DJGPP__) || defined (__OS2__) +-# define HAVE_DOS_BASED_FILE_SYSTEM +-# define HAVE_HOST_EXECUTABLE_SUFFIX +-# define HOST_EXECUTABLE_SUFFIX ".exe" +-# ifndef DIR_SEPARATOR_2 +-# define DIR_SEPARATOR_2 '\\' +-# endif +-# define PATH_SEPARATOR ';' +-#else +-# define PATH_SEPARATOR ':' ++# define HAVE_HOST_EXECUTABLE_SUFFIX ++# define HOST_EXECUTABLE_SUFFIX ".exe" ++# define PATH_SEPARATOR ';' ++#endif ++ ++#ifdef __amigaos__ ++# define PATH_SEPARATOR ':' ++# define DIR_UP ".." + #endif + +-#ifndef DIR_SEPARATOR_2 +-# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +-#else +-# define IS_DIR_SEPARATOR(ch) \ +- (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) ++#ifndef PATH_SEPARATOR ++# define PATH_SEPARATOR ':' + #endif + +-#define DIR_UP ".." ++#ifndef DIR_UP ++# define DIR_UP ".." ++#endif ++ ++#ifndef DIR_SEPARATOR ++# define DIR_SEPARATOR '/' ++#endif + + static char *save_string (const char *, int); + static char **split_directories (const char *, int *); + static void free_split_directories (char **); + + static char * +diff --git a/libiberty/make-temp-file.c b/libiberty/make-temp-file.c +index 244cc23c5090e1c0d227820dc703adbc8022f8d5..5edcd153410bcd459a0546fd9d3cef6ee91a29af 100644 +--- libiberty/make-temp-file.c ++++ libiberty/make-temp-file.c +@@ -38,25 +38,26 @@ Boston, MA 02110-1301, USA. */ + #include <sys/file.h> /* May get R_OK, etc. on some systems. */ + #endif + #if defined(_WIN32) && !defined(__CYGWIN__) + #include <windows.h> + #endif + ++#ifndef DIR_SEPARATOR ++#define DIR_SEPARATOR '/' ++#endif ++ + #ifndef R_OK + #define R_OK 4 + #define W_OK 2 + #define X_OK 1 + #endif + + #include "libiberty.h" +-extern int mkstemps (char *, int); ++#include "filenames.h" + +-/* '/' works just fine on MS-DOS based systems. */ +-#ifndef DIR_SEPARATOR +-#define DIR_SEPARATOR '/' +-#endif ++extern int mkstemps (char *, int); + + /* Name of temporary file. + mktemp requires 6 trailing X's. */ + #define TEMP_FILE "ccXXXXXX" + #define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1) + +@@ -78,17 +79,19 @@ try_dir (const char *dir, const char *base) + if (dir != 0 + && access (dir, R_OK | W_OK | X_OK) == 0) + return dir; + return 0; + } + ++#ifndef __amigaos__ + static const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 }; + static const char usrtmp[] = + { DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 }; + static const char vartmp[] = + { DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 }; ++#endif /* __amigaos__ */ + + #endif + + static char *memoized_tmpdir; + + /* +@@ -127,27 +130,37 @@ choose_tmpdir (void) + if (strcmp (P_tmpdir, "\\") == 0) + base = try_dir ("\\.", base); + else + base = try_dir (P_tmpdir, base); + #endif + ++#ifndef __amigaos__ + /* Try /var/tmp, /usr/tmp, then /tmp. */ + base = try_dir (vartmp, base); + base = try_dir (usrtmp, base); + base = try_dir (tmp, base); ++#else ++ base = try_dir ("T:", base); ++#endif + + /* If all else fails, use the current directory! */ + if (base == 0) + base = "."; + /* Append DIR_SEPARATOR to the directory we've chosen + and return it. */ + len = strlen (base); + tmpdir = XNEWVEC (char, len + 2); + strcpy (tmpdir, base); +- tmpdir[len] = DIR_SEPARATOR; +- tmpdir[len+1] = '\0'; ++ ++ /* Don't add DIR_SEPARATOR if base already ends with a dir separator, ++ it's unneeded and can cause ill effects on e.g. AmigaOS. */ ++ if (!IS_DIR_SEPARATOR(base[len-1])) ++ { ++ tmpdir[len] = DIR_SEPARATOR; ++ tmpdir[len+1] = '\0'; ++ } + memoized_tmpdir = tmpdir; + #else /* defined(_WIN32) && !defined(__CYGWIN__) */ + DWORD len; + + /* Figure out how much space we need. */ + len = GetTempPath(0, NULL); +diff --git a/libiberty/pex-amigaos.c b/libiberty/pex-amigaos.c +new file mode 100644 +index 0000000000000000000000000000000000000000..0c61a108764c8501f8a2e9552c7c07499f402b1a +--- /dev/null ++++ libiberty/pex-amigaos.c +@@ -0,0 +1,325 @@ ++/* Utilities to execute a program in a subprocess (possibly linked by pipes ++ with other subprocesses), and wait for it. Generic AMIGAOS specialization. ++ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005 ++ Free Software Foundation, Inc. ++ ++This file is part of the libiberty library. ++Libiberty is free software; you can redistribute it and/or ++modify it under the terms of the GNU Library General Public ++License as published by the Free Software Foundation; either ++version 2 of the License, or (at your option) any later version. ++ ++Libiberty is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++Library General Public License for more details. ++ ++You should have received a copy of the GNU Library General Public ++License along with libiberty; see the file COPYING.LIB. If not, ++write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, ++Boston, MA 02110-1301, USA. */ ++ ++#include "pex-common.h" ++ ++#include <stdio.h> ++#include <errno.h> ++#ifdef NEED_DECLARATION_ERRNO ++extern int errno; ++#endif ++#ifdef HAVE_STDLIB_H ++#include <stdlib.h> ++#endif ++#include <string.h> ++#include <fcntl.h> ++#include <unistd.h> ++#include <sys/stat.h> ++#include <ctype.h> ++ ++/* Use ECHILD if available, otherwise use EINVAL. */ ++#ifdef ECHILD ++#define PWAIT_ERROR ECHILD ++#else ++#define PWAIT_ERROR EINVAL ++#endif ++ ++#if !defined(FD_CLOEXEC) ++#define FD_CLOEXEC 1 ++#endif ++ ++static int pex_amiga_open_read (struct pex_obj *, const char *, int); ++static int pex_amiga_open_write (struct pex_obj *, const char *, int); ++static pid_t pex_amiga_exec_child (struct pex_obj *, int, const char *, ++ char * const *, char * const *, ++ int, int, int, int, ++ const char **, int *); ++static int pex_amiga_close (struct pex_obj *, int); ++static int pex_amiga_wait (struct pex_obj *, long, int *, struct pex_time *, ++ int, const char **, int *); ++static FILE *pex_amiga_fdopenr (struct pex_obj *, int, int); ++static FILE *pex_amiga_fdopenw (struct pex_obj *, int, int); ++ ++/* The list of functions we pass to the common routines. */ ++ ++const struct pex_funcs funcs = ++{ ++ pex_amiga_open_read, ++ pex_amiga_open_write, ++ pex_amiga_exec_child, ++ pex_amiga_close, ++ pex_amiga_wait, ++ NULL, /* pipe */ ++ pex_amiga_fdopenr, ++ pex_amiga_fdopenw, ++ NULL, /* cleanup */ ++}; ++ ++/* Return a newly initialized pex_obj structure. */ ++ ++struct pex_obj * ++pex_init (int flags, const char *pname, const char *tempbase) ++{ ++ /* AMIGAOS does not support pipes. */ ++ flags &= ~ PEX_USE_PIPES; ++ return pex_init_common (flags, pname, tempbase, &funcs); ++} ++ ++/* Open a file for reading. */ ++ ++static int ++pex_amiga_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, ++ int binary ATTRIBUTE_UNUSED) ++{ ++ return open (name, O_RDONLY); ++} ++ ++/* Open a file for writing. */ ++ ++static int ++pex_amiga_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, ++ int binary ATTRIBUTE_UNUSED) ++{ ++ /* Note that we can't use O_EXCL here because gcc may have already ++ created the temporary file via make_temp_file. */ ++ return open (name, O_WRONLY | O_CREAT | O_TRUNC); ++} ++ ++/* Close a file. */ ++ ++static int ++pex_amiga_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) ++{ ++ return close (fd); ++} ++ ++/* Execute a child. */ ++ ++const unsigned char __shell_escape_character = '\\'; ++ ++static pid_t ++pex_amiga_exec_child (struct pex_obj *obj, int flags ATTRIBUTE_UNUSED, const char *executable ATTRIBUTE_UNUSED, ++ char * const * argv, char * const * env ATTRIBUTE_UNUSED, ++ int in ATTRIBUTE_UNUSED, int out ATTRIBUTE_UNUSED, int errdes ATTRIBUTE_UNUSED, ++ int toclose ATTRIBUTE_UNUSED, const char **errmsg, int *err) ++{ ++ int rc; ++ char *scmd,*s; ++ int i,j,c,len,arglen; ++ int need_quote; ++ int already_have_quote; ++ int escaped; ++ int *statuses; ++ ++ len = 0; ++ ++ for(i = 0 ; argv[i] != NULL ; i++) ++ { ++ arglen = strlen(argv[i]); ++ ++ len += 1 + arglen; ++ ++ need_quote = already_have_quote = 0; ++ ++ /* Check if this parameter is already surrounded by double quotes. ++ What counts is that the first character is a double quote. We ++ hope that the last character is an unescaped double quote, but ++ don't check for it. */ ++ if(argv[i][0] == '\"') ++ { ++ already_have_quote = 1; ++ } ++ else ++ { ++ /* Check if there's a blank space in the argument. If so, we will ++ need to add double quote characters. */ ++ for (j = 0 ; j < arglen ; j++) ++ { ++ c = argv[i][j]; ++ ++ if (isspace(c)) ++ { ++ need_quote = 1; ++ break; ++ } ++ } ++ ++ /* Make room for the double quote characters that we will have to add. */ ++ if(need_quote) ++ len += 2; ++ } ++ ++ /* Check if there are " or * characters in the quoted string which ++ may have to be escaped. */ ++ if (need_quote || already_have_quote) ++ { ++ for (j = 0 ; j < arglen ; j++) ++ { ++ c = argv[i][j]; ++ ++ /* We just might have to add an escape character in front of these two. */ ++ if (c == '\"' || c == '*') ++ len++; ++ } ++ } ++ } ++ ++ s = scmd = (char *) xmalloc (len+1); ++ ++ for(i = 0 ; argv[i] != NULL ; i++) ++ { ++ arglen = strlen(argv[i]); ++ ++ need_quote = already_have_quote = 0; ++ ++ if (argv[i][0] == '\"') ++ { ++ already_have_quote = 1; ++ } ++ else ++ { ++ for (j = 0 ; j < arglen ; j++) ++ { ++ c = argv[i][j]; ++ ++ if (isspace(c)) ++ { ++ need_quote = 1; ++ break; ++ } ++ } ++ } ++ ++ if(s != scmd) ++ (*s++) = ' '; ++ ++ if(need_quote) ++ (*s++) = '\"'; ++ ++ escaped = 0; ++ ++ for(j = 0 ; j < arglen ; j++) ++ { ++ c = argv[i][j]; ++ ++ /* If this is a " or * and the parameter is quoted, try to ++ add an escape character in front of it. */ ++ if((c == '\"' || c == '*') && (need_quote || already_have_quote)) ++ { ++ /* Careful, don't escape the first double ++ quote character by mistake. */ ++ if(!already_have_quote || j > 0) ++ { ++ /* Don't add an escape character here if the previous character ++ already was an escape character. */ ++ if(!escaped) ++ (*s++) = '*'; ++ } ++ } ++ ++ (*s++) = c; ++ ++ /* Remember if the last character read was an escape character. */ ++ if (escaped) ++ escaped = 0; ++ else ++ escaped = (c == __shell_escape_character && c != '*'); ++ } ++ ++ if(need_quote) ++ (*s++) = '\"'; ++ } ++ ++ (*s) = '\0'; ++ ++ rc = system (scmd); ++ ++ free (scmd); ++ ++ if (rc == -1) ++ { ++ *err = errno; ++ *errmsg = install_error_msg; ++ return -1; ++ } ++ ++ /* Save the exit status for later. When we are called, obj->count ++ is the number of children which have executed before this ++ one. */ ++ statuses = (int *) obj->sysdep; ++ statuses = XRESIZEVEC (int, statuses, obj->count + 1); ++ statuses[obj->count] = (rc << 8); /* Tuck the status away for pwait */ ++ obj->sysdep = (void *) statuses; ++ ++ return obj->count; ++} ++ ++/* Create a pipe. */ ++/* ++static int ++pex_amiga_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p, ++ int binary ATTRIBUTE_UNUSED) ++{ ++ return pipe (p); ++} ++*/ ++ ++/* Get a FILE pointer to read from a file descriptor. */ ++ ++static FILE * ++pex_amiga_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, ++ int binary ATTRIBUTE_UNUSED) ++{ ++ return fdopen (fd, "r"); ++} ++ ++/* Get a FILE pointer to write to a file descriptor. */ ++ ++static FILE * ++pex_amiga_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, ++ int binary ATTRIBUTE_UNUSED) ++{ ++ if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) ++ return NULL; ++ return fdopen (fd, "w"); ++} ++ ++ ++/* Wait for a child process to complete. Actually the child process ++ has already completed, and we just need to return the exit ++ status. */ ++ ++static int ++pex_amiga_wait (struct pex_obj *obj, long pid, int *status, ++ struct pex_time *time, int done ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED, ++ int *err ATTRIBUTE_UNUSED) ++{ ++ int *statuses; ++ ++ if (time != NULL) ++ memset (time, 0, sizeof (struct pex_time)); ++ ++ statuses = (int *) obj->sysdep; ++ *status = statuses[pid]; ++ ++ return 0; ++} +diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure +index 8cd4c76e70d82a9913c45f26b99e386ad659a3a0..b14ada402280cf8afa221731680d82b794a83352 100755 +--- libstdc++-v3/configure ++++ libstdc++-v3/configure +@@ -77229,12 +77229,171 @@ done + + $as_echo "#define HAVE_TANF 1" >>confdefs.h + + $as_echo "#define HAVE_TANHF 1" >>confdefs.h + + ;; ++ *-amigaos*) ++ for ac_header in nan.h ieeefp.h endian.h sys/isa_defs.h \ ++ machine/endian.h machine/param.h sys/machine.h sys/types.h \ ++ fp.h locale.h float.h inttypes.h ++do : ++ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ++ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" ++eval as_val=\$$as_ac_Header ++ if test "x$as_val" = x""yes; then : ++ cat >>confdefs.h <<_ACEOF ++#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 ++_ACEOF ++ ++fi ++ ++done ++ ++ SECTION_FLAGS='-ffunction-sections -fdata-sections' ++ ++ ++ # If we're not using GNU ld, then there's no point in even trying these ++ # tests. Check for that first. We should have already tested for gld ++ # by now (in libtool), but require it now just to be safe... ++ test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' ++ test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' ++ ++ ++ ++ # The name set by libtool depends on the version of libtool. Shame on us ++ # for depending on an impl detail, but c'est la vie. Older versions used ++ # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on ++ # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually ++ # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't ++ # set (hence we're using an older libtool), then set it. ++ if test x${with_gnu_ld+set} != xset; then ++ if test x${ac_cv_prog_gnu_ld+set} != xset; then ++ # We got through "ac_require(ac_prog_ld)" and still not set? Huh? ++ with_gnu_ld=no ++ else ++ with_gnu_ld=$ac_cv_prog_gnu_ld ++ fi ++ fi ++ ++ # Start by getting the version number. I think the libtool test already ++ # does some of this, but throws away the result. ++ glibcxx_ld_is_gold=no ++ if test x"$with_gnu_ld" = x"yes"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld version" >&5 ++$as_echo_n "checking for ld version... " >&6; } ++ ++ if $LD --version 2>/dev/null | grep 'GNU gold' >/dev/null 2>&1; then ++ glibcxx_ld_is_gold=yes ++ fi ++ ldver=`$LD --version 2>/dev/null | ++ sed -e 's/GNU gold /GNU ld /;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` ++ ++ glibcxx_gnu_ld_version=`echo $ldver | \ ++ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_gnu_ld_version" >&5 ++$as_echo "$glibcxx_gnu_ld_version" >&6; } ++ fi ++ ++ # Set --gc-sections. ++ glibcxx_have_gc_sections=no ++ if test "$glibcxx_ld_is_gold" = "yes"; then ++ if $LD --help 2>/dev/null | grep gc-sections >/dev/null 2>&1; then ++ glibcxx_have_gc_sections=yes ++ fi ++ else ++ glibcxx_gcsections_min_ld=21602 ++ if test x"$with_gnu_ld" = x"yes" && ++ test $glibcxx_gnu_ld_version -gt $glibcxx_gcsections_min_ld ; then ++ glibcxx_have_gc_sections=yes ++ fi ++ fi ++ if test "$glibcxx_have_gc_sections" = "yes"; then ++ # Sufficiently young GNU ld it is! Joy and bunny rabbits! ++ # NB: This flag only works reliably after 2.16.1. Configure tests ++ # for this are difficult, so hard wire a value that should work. ++ ++ ac_test_CFLAGS="${CFLAGS+set}" ++ ac_save_CFLAGS="$CFLAGS" ++ CFLAGS='-Wl,--gc-sections' ++ ++ # Check for -Wl,--gc-sections ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,--gc-sections" >&5 ++$as_echo_n "checking for ld that supports -Wl,--gc-sections... " >&6; } ++ if test x$gcc_no_link = xyes; then ++ as_fn_error "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 ++fi ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ int one(void) { return 1; } ++ int two(void) { return 2; } ++ ++int ++main () ++{ ++ two(); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_gcsections=yes ++else ++ ac_gcsections=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++ if test "$ac_gcsections" = "yes"; then ++ rm -f conftest.c ++ touch conftest.c ++ if $CC -c conftest.c; then ++ if $LD --gc-sections -o conftest conftest.o 2>&1 | \ ++ grep "Warning: gc-sections option ignored" > /dev/null; then ++ ac_gcsections=no ++ fi ++ fi ++ rm -f conftest.c conftest.o conftest ++ fi ++ if test "$ac_gcsections" = "yes"; then ++ SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" ++ fi ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_gcsections" >&5 ++$as_echo "$ac_gcsections" >&6; } ++ ++ if test "$ac_test_CFLAGS" = set; then ++ CFLAGS="$ac_save_CFLAGS" ++ else ++ # this is the suspicious part ++ CFLAGS='' ++ fi ++ fi ++ ++ # Set -z,relro. ++ # Note this is only for shared objects. ++ ac_ld_relro=no ++ if test x"$with_gnu_ld" = x"yes"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld that supports -Wl,-z,relro" >&5 ++$as_echo_n "checking for ld that supports -Wl,-z,relro... " >&6; } ++ cxx_z_relo=`$LD -v --help 2>/dev/null | grep "z relro"` ++ if test -n "$cxx_z_relo"; then ++ OPT_LDFLAGS="-Wl,-z,relro" ++ ac_ld_relro=yes ++ fi ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ld_relro" >&5 ++$as_echo "$ac_ld_relro" >&6; } ++ fi ++ ++ # Set linker optimization flags. ++ if test x"$with_gnu_ld" = x"yes"; then ++ OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" ++ fi ++ ++ ++ ++ ++ ;; + *) + as_fn_error "No support for this host/target combination." "$LINENO" 5 + ;; + esac + + fi +@@ -80295,43 +80454,1687 @@ $as_echo "$gxx_include_dir" >&6; } + + + WARN_FLAGS='-Wall -Wextra -Wwrite-strings -Wcast-qual -Wabi' + + + +-ac_config_files="$ac_config_files Makefile" +- +-ac_config_files="$ac_config_files scripts/testsuite_flags" +- +-ac_config_files="$ac_config_files scripts/extract_symvers" ++# create libtool - libtool > 2.0: ++: ${CONFIG_LT=./config.lt} ++{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_LT" >&5 ++$as_echo "$as_me: creating $CONFIG_LT" >&6;} ++as_write_fail=0 ++cat >"$CONFIG_LT" <<_ASEOF || as_write_fail=1 ++#! $SHELL ++# Generated by $as_me. ++# Run this file to recreate a libtool stub with the current configuration. ++SHELL=\${CONFIG_SHELL-$SHELL} ++export SHELL ++_ASEOF ++cat >>"$CONFIG_LT" <<\_ASEOF || as_write_fail=1 ++## -------------------- ## ++## M4sh Initialization. ## ++## -------------------- ## + +-ac_config_files="$ac_config_files doc/xsl/customization.xsl" ++# Be more Bourne compatible ++DUALCASE=1; export DUALCASE # for MKS sh ++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : ++ emulate sh ++ NULLCMD=: ++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which ++ # is contrary to our usage. Disable this feature. ++ alias -g '${1+"$@"}'='"$@"' ++ setopt NO_GLOB_SUBST ++else ++ case `(set -o) 2>/dev/null` in #( ++ *posix*) : ++ set -o posix ;; #( ++ *) : ++ ;; ++esac ++fi + + +-# Multilibs need MULTISUBDIR defined correctly in certain makefiles so +-# that multilib installs will end up installed in the correct place. +-# The testsuite needs it for multilib-aware ABI baseline files. +-# To work around this not being passed down from config-ml.in -> +-# srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually +-# append it here. Only modify Makefiles that have just been created. +-# +-# Also, get rid of this simulated-VPATH thing that automake does. +-ac_config_files="$ac_config_files include/Makefile libsupc++/Makefile src/Makefile src/c++98/Makefile src/c++11/Makefile src/filesystem/Makefile doc/Makefile po/Makefile testsuite/Makefile python/Makefile" ++as_nl=' ++' ++export as_nl ++# Printing a long string crashes Solaris 7 /usr/bin/printf. ++as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo ++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo ++# Prefer a ksh shell builtin over an external printf program on Solaris, ++# but without wasting forks for bash or zsh. ++if test -z "$BASH_VERSION$ZSH_VERSION" \ ++ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then ++ as_echo='print -r --' ++ as_echo_n='print -rn --' ++elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then ++ as_echo='printf %s\n' ++ as_echo_n='printf %s' ++else ++ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then ++ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' ++ as_echo_n='/usr/ucb/echo -n' ++ else ++ as_echo_body='eval expr "X$1" : "X\\(.*\\)"' ++ as_echo_n_body='eval ++ arg=$1; ++ case $arg in #( ++ *"$as_nl"*) ++ expr "X$arg" : "X\\(.*\\)$as_nl"; ++ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; ++ esac; ++ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ++ ' ++ export as_echo_n_body ++ as_echo_n='sh -c $as_echo_n_body as_echo' ++ fi ++ export as_echo_body ++ as_echo='sh -c $as_echo_body as_echo' ++fi + ++# The user is always right. ++if test "${PATH_SEPARATOR+set}" != set; then ++ PATH_SEPARATOR=: ++ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { ++ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || ++ PATH_SEPARATOR=';' ++ } ++fi + +-ac_config_commands="$ac_config_commands generate-headers" + ++# IFS ++# We need space, tab and new line, in precisely that order. Quoting is ++# there to prevent editors from complaining about space-tab. ++# (If _AS_PATH_WALK were called with IFS unset, it would disable word ++# splitting by setting IFS to empty value.) ++IFS=" "" $as_nl" + +-cat >confcache <<\_ACEOF +-# This file is a shell script that caches the results of configure +-# tests run on this system so they can be shared between configure +-# scripts and configure runs, see configure's option --config-cache. +-# It is not useful on other systems. If it contains results you don't +-# want to keep, you may remove or edit it. +-# +-# config.status only pays attention to the cache file if you give it ++# Find who we are. Look in the path if we contain no directory separator. ++case $0 in #(( ++ *[\\/]* ) as_myself=$0 ;; ++ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break ++ done ++IFS=$as_save_IFS ++ ++ ;; ++esac ++# We did not find ourselves, most probably we were run as `sh COMMAND' ++# in which case we are not to be found in the path. ++if test "x$as_myself" = x; then ++ as_myself=$0 ++fi ++if test ! -f "$as_myself"; then ++ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 ++ exit 1 ++fi ++ ++# Unset variables that we do not need and which cause bugs (e.g. in ++# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" ++# suppresses any "Segmentation fault" message there. '((' could ++# trigger a bug in pdksh 5.2.14. ++for as_var in BASH_ENV ENV MAIL MAILPATH ++do eval test x\${$as_var+set} = xset \ ++ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : ++done ++PS1='$ ' ++PS2='> ' ++PS4='+ ' ++ ++# NLS nuisances. ++LC_ALL=C ++export LC_ALL ++LANGUAGE=C ++export LANGUAGE ++ ++# CDPATH. ++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH ++ ++ ++# as_fn_error ERROR [LINENO LOG_FD] ++# --------------------------------- ++# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are ++# provided, also output the error to LOG_FD, referencing LINENO. Then exit the ++# script with status $?, using 1 if that was 0. ++as_fn_error () ++{ ++ as_status=$?; test $as_status -eq 0 && as_status=1 ++ if test "$3"; then ++ as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 ++ fi ++ $as_echo "$as_me: error: $1" >&2 ++ as_fn_exit $as_status ++} # as_fn_error ++ ++ ++# as_fn_set_status STATUS ++# ----------------------- ++# Set $? to STATUS, without forking. ++as_fn_set_status () ++{ ++ return $1 ++} # as_fn_set_status ++ ++# as_fn_exit STATUS ++# ----------------- ++# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. ++as_fn_exit () ++{ ++ set +e ++ as_fn_set_status $1 ++ exit $1 ++} # as_fn_exit ++ ++# as_fn_unset VAR ++# --------------- ++# Portably unset VAR. ++as_fn_unset () ++{ ++ { eval $1=; unset $1;} ++} ++as_unset=as_fn_unset ++# as_fn_append VAR VALUE ++# ---------------------- ++# Append the text in VALUE to the end of the definition contained in VAR. Take ++# advantage of any shell optimizations that allow amortized linear growth over ++# repeated appends, instead of the typical quadratic growth present in naive ++# implementations. ++if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : ++ eval 'as_fn_append () ++ { ++ eval $1+=\$2 ++ }' ++else ++ as_fn_append () ++ { ++ eval $1=\$$1\$2 ++ } ++fi # as_fn_append ++ ++# as_fn_arith ARG... ++# ------------------ ++# Perform arithmetic evaluation on the ARGs, and store the result in the ++# global $as_val. Take advantage of shells that can avoid forks. The arguments ++# must be portable across $(()) and expr. ++if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : ++ eval 'as_fn_arith () ++ { ++ as_val=$(( $* )) ++ }' ++else ++ as_fn_arith () ++ { ++ as_val=`expr "$@" || test $? -eq 1` ++ } ++fi # as_fn_arith ++ ++ ++if expr a : '\(a\)' >/dev/null 2>&1 && ++ test "X`expr 00001 : '.*\(...\)'`" = X001; then ++ as_expr=expr ++else ++ as_expr=false ++fi ++ ++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then ++ as_basename=basename ++else ++ as_basename=false ++fi ++ ++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then ++ as_dirname=dirname ++else ++ as_dirname=false ++fi ++ ++as_me=`$as_basename -- "$0" || ++$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ ++ X"$0" : 'X\(//\)$' \| \ ++ X"$0" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X/"$0" | ++ sed '/^.*\/\([^/][^/]*\)\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ ++# Avoid depending upon Character Ranges. ++as_cr_letters='abcdefghijklmnopqrstuvwxyz' ++as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' ++as_cr_Letters=$as_cr_letters$as_cr_LETTERS ++as_cr_digits='0123456789' ++as_cr_alnum=$as_cr_Letters$as_cr_digits ++ ++ECHO_C= ECHO_N= ECHO_T= ++case `echo -n x` in #((((( ++-n*) ++ case `echo 'xy\c'` in ++ *c*) ECHO_T=' ';; # ECHO_T is single tab character. ++ xy) ECHO_C='\c';; ++ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ++ ECHO_T=' ';; ++ esac;; ++*) ++ ECHO_N='-n';; ++esac ++ ++rm -f conf$$ conf$$.exe conf$$.file ++if test -d conf$$.dir; then ++ rm -f conf$$.dir/conf$$.file ++else ++ rm -f conf$$.dir ++ mkdir conf$$.dir 2>/dev/null ++fi ++if (echo >conf$$.file) 2>/dev/null; then ++ if ln -s conf$$.file conf$$ 2>/dev/null; then ++ as_ln_s='ln -s' ++ # ... but there are two gotchas: ++ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. ++ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. ++ # In both cases, we have to default to `cp -p'. ++ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || ++ as_ln_s='cp -p' ++ elif ln conf$$.file conf$$ 2>/dev/null; then ++ as_ln_s=ln ++ else ++ as_ln_s='cp -p' ++ fi ++else ++ as_ln_s='cp -p' ++fi ++rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file ++rmdir conf$$.dir 2>/dev/null ++ ++ ++# as_fn_mkdir_p ++# ------------- ++# Create "$as_dir" as a directory, including parents if necessary. ++as_fn_mkdir_p () ++{ ++ ++ case $as_dir in #( ++ -*) as_dir=./$as_dir;; ++ esac ++ test -d "$as_dir" || eval $as_mkdir_p || { ++ as_dirs= ++ while :; do ++ case $as_dir in #( ++ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( ++ *) as_qdir=$as_dir;; ++ esac ++ as_dirs="'$as_qdir' $as_dirs" ++ as_dir=`$as_dirname -- "$as_dir" || ++$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ++ X"$as_dir" : 'X\(//\)[^/]' \| \ ++ X"$as_dir" : 'X\(//\)$' \| \ ++ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X"$as_dir" | ++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)[^/].*/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ test -d "$as_dir" && break ++ done ++ test -z "$as_dirs" || eval "mkdir $as_dirs" ++ } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" ++ ++ ++} # as_fn_mkdir_p ++if mkdir -p . 2>/dev/null; then ++ as_mkdir_p='mkdir -p "$as_dir"' ++else ++ test -d ./-p && rmdir ./-p ++ as_mkdir_p=false ++fi ++ ++if test -x / >/dev/null 2>&1; then ++ as_test_x='test -x' ++else ++ if ls -dL / >/dev/null 2>&1; then ++ as_ls_L_option=L ++ else ++ as_ls_L_option= ++ fi ++ as_test_x=' ++ eval sh -c '\'' ++ if test -d "$1"; then ++ test -d "$1/."; ++ else ++ case $1 in #( ++ -*)set "./$1";; ++ esac; ++ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ++ ???[sx]*):;;*)false;;esac;fi ++ '\'' sh ++ ' ++fi ++as_executable_p=$as_test_x ++ ++# Sed expression to map a string onto a valid CPP name. ++as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" ++ ++# Sed expression to map a string onto a valid variable name. ++as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" ++ ++ ++exec 6>&1 ++## --------------------------------- ## ++## Main body of "$CONFIG_LT" script. ## ++## --------------------------------- ## ++_ASEOF ++test $as_write_fail = 0 && chmod +x "$CONFIG_LT" ++ ++cat >>"$CONFIG_LT" <<\_LTEOF ++lt_cl_silent=false ++exec 5>>config.log ++{ ++ echo ++ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ++## Running $as_me. ## ++_ASBOX ++} >&5 ++ ++lt_cl_help="\ ++\`$as_me' creates a local libtool stub from the current configuration, ++for use in further configure time tests before the real libtool is ++generated. ++ ++Usage: $0 [OPTIONS] ++ ++ -h, --help print this help, then exit ++ -V, --version print version number, then exit ++ -q, --quiet do not print progress messages ++ -d, --debug don't remove temporary files ++ ++Report bugs to <bug-libtool@gnu.org>." ++ ++lt_cl_version="\ ++package-unused config.lt version-unused ++configured by $0, generated by GNU Autoconf 2.64. ++ ++Copyright (C) 2009 Free Software Foundation, Inc. ++This config.lt script is free software; the Free Software Foundation ++gives unlimited permision to copy, distribute and modify it." ++ ++while test $# != 0 ++do ++ case $1 in ++ --version | --v* | -V ) ++ echo "$lt_cl_version"; exit 0 ;; ++ --help | --h* | -h ) ++ echo "$lt_cl_help"; exit 0 ;; ++ --debug | --d* | -d ) ++ debug=: ;; ++ --quiet | --q* | --silent | --s* | -q ) ++ lt_cl_silent=: ;; ++ ++ -*) as_fn_error "unrecognized option: $1 ++Try \`$0 --help' for more information." "$LINENO" 5 ;; ++ ++ *) as_fn_error "unrecognized argument: $1 ++Try \`$0 --help' for more information." "$LINENO" 5 ;; ++ esac ++ shift ++done ++ ++if $lt_cl_silent; then ++ exec 6>/dev/null ++fi ++_LTEOF ++ ++cat >>"$CONFIG_LT" <<_LTEOF ++ ++ ++# The HP-UX ksh and POSIX shell print the target directory to stdout ++# if CDPATH is set. ++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH ++ ++sed_quote_subst='$sed_quote_subst' ++double_quote_subst='$double_quote_subst' ++delay_variable_subst='$delay_variable_subst' ++macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' ++macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' ++enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' ++enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' ++pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' ++enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' ++SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ++ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' ++host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' ++host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' ++host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' ++build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' ++build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' ++build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' ++SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' ++Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' ++GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' ++EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' ++FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' ++LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' ++NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' ++LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' ++max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ++ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' ++exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' ++lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' ++lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' ++lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' ++reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' ++reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' ++OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' ++deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' ++file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' ++AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' ++AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' ++STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' ++RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' ++old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' ++old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' ++old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' ++lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' ++CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' ++CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' ++compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' ++GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' ++lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' ++lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' ++lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' ++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' ++objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' ++MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' ++lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' ++need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' ++DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' ++NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' ++LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' ++OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' ++OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' ++libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' ++shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' ++extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' ++archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' ++enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' ++export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' ++whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' ++compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' ++old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' ++old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' ++archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' ++archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' ++module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' ++module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' ++with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' ++allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' ++no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' ++hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' ++hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' ++hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' ++hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' ++hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' ++inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' ++link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' ++fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`' ++always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' ++export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' ++exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' ++include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' ++prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' ++file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' ++variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' ++need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' ++need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' ++version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' ++runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' ++shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' ++shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' ++libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' ++library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' ++soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' ++install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' ++postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' ++postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' ++finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' ++finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' ++hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' ++sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' ++sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' ++hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' ++enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' ++enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' ++enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' ++old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' ++striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' ++compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' ++predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' ++postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' ++predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' ++postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' ++compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' ++LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' ++reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' ++reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' ++GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' ++lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' ++archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' ++enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' ++export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' ++whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' ++compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' ++old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' ++allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' ++no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_flag_spec_ld_CXX='`$ECHO "$hardcode_libdir_flag_spec_ld_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' ++inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' ++link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' ++fix_srcfile_path_CXX='`$ECHO "$fix_srcfile_path_CXX" | $SED "$delay_single_quote_subst"`' ++always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' ++export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' ++include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' ++prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' ++compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' ++predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' ++postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' ++predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' ++postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' ++compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' ++ ++LTCC='$LTCC' ++LTCFLAGS='$LTCFLAGS' ++compiler='$compiler_DEFAULT' ++ ++# A function that is used when there is no print builtin or printf. ++func_fallback_echo () ++{ ++ eval 'cat <<_LTECHO_EOF ++\$1 ++_LTECHO_EOF' ++} ++ ++# Quote evaled strings. ++for var in SHELL \ ++ECHO \ ++SED \ ++GREP \ ++EGREP \ ++FGREP \ ++LD \ ++NM \ ++LN_S \ ++lt_SP2NL \ ++lt_NL2SP \ ++reload_flag \ ++OBJDUMP \ ++deplibs_check_method \ ++file_magic_cmd \ ++AR \ ++AR_FLAGS \ ++STRIP \ ++RANLIB \ ++CC \ ++CFLAGS \ ++compiler \ ++lt_cv_sys_global_symbol_pipe \ ++lt_cv_sys_global_symbol_to_cdecl \ ++lt_cv_sys_global_symbol_to_c_name_address \ ++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ ++lt_prog_compiler_no_builtin_flag \ ++lt_prog_compiler_wl \ ++lt_prog_compiler_pic \ ++lt_prog_compiler_static \ ++lt_cv_prog_compiler_c_o \ ++need_locks \ ++DSYMUTIL \ ++NMEDIT \ ++LIPO \ ++OTOOL \ ++OTOOL64 \ ++shrext_cmds \ ++export_dynamic_flag_spec \ ++whole_archive_flag_spec \ ++compiler_needs_object \ ++with_gnu_ld \ ++allow_undefined_flag \ ++no_undefined_flag \ ++hardcode_libdir_flag_spec \ ++hardcode_libdir_flag_spec_ld \ ++hardcode_libdir_separator \ ++fix_srcfile_path \ ++exclude_expsyms \ ++include_expsyms \ ++file_list_spec \ ++variables_saved_for_relink \ ++libname_spec \ ++library_names_spec \ ++soname_spec \ ++install_override_mode \ ++finish_eval \ ++old_striplib \ ++striplib \ ++compiler_lib_search_dirs \ ++predep_objects \ ++postdep_objects \ ++predeps \ ++postdeps \ ++compiler_lib_search_path \ ++LD_CXX \ ++reload_flag_CXX \ ++compiler_CXX \ ++lt_prog_compiler_no_builtin_flag_CXX \ ++lt_prog_compiler_wl_CXX \ ++lt_prog_compiler_pic_CXX \ ++lt_prog_compiler_static_CXX \ ++lt_cv_prog_compiler_c_o_CXX \ ++export_dynamic_flag_spec_CXX \ ++whole_archive_flag_spec_CXX \ ++compiler_needs_object_CXX \ ++with_gnu_ld_CXX \ ++allow_undefined_flag_CXX \ ++no_undefined_flag_CXX \ ++hardcode_libdir_flag_spec_CXX \ ++hardcode_libdir_flag_spec_ld_CXX \ ++hardcode_libdir_separator_CXX \ ++fix_srcfile_path_CXX \ ++exclude_expsyms_CXX \ ++include_expsyms_CXX \ ++file_list_spec_CXX \ ++compiler_lib_search_dirs_CXX \ ++predep_objects_CXX \ ++postdep_objects_CXX \ ++predeps_CXX \ ++postdeps_CXX \ ++compiler_lib_search_path_CXX; do ++ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in ++ *[\\\\\\\`\\"\\\$]*) ++ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ++ ;; ++ *) ++ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ++ ;; ++ esac ++done ++ ++# Double-quote double-evaled strings. ++for var in reload_cmds \ ++old_postinstall_cmds \ ++old_postuninstall_cmds \ ++old_archive_cmds \ ++extract_expsyms_cmds \ ++old_archive_from_new_cmds \ ++old_archive_from_expsyms_cmds \ ++archive_cmds \ ++archive_expsym_cmds \ ++module_cmds \ ++module_expsym_cmds \ ++export_symbols_cmds \ ++prelink_cmds \ ++postinstall_cmds \ ++postuninstall_cmds \ ++finish_cmds \ ++sys_lib_search_path_spec \ ++sys_lib_dlsearch_path_spec \ ++reload_cmds_CXX \ ++old_archive_cmds_CXX \ ++old_archive_from_new_cmds_CXX \ ++old_archive_from_expsyms_cmds_CXX \ ++archive_cmds_CXX \ ++archive_expsym_cmds_CXX \ ++module_cmds_CXX \ ++module_expsym_cmds_CXX \ ++export_symbols_cmds_CXX \ ++prelink_cmds_CXX; do ++ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in ++ *[\\\\\\\`\\"\\\$]*) ++ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ++ ;; ++ *) ++ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ++ ;; ++ esac ++done ++ ++ac_aux_dir='$ac_aux_dir' ++xsi_shell='$xsi_shell' ++lt_shell_append='$lt_shell_append' ++ ++# See if we are running on zsh, and set the options which allow our ++# commands through without removal of \ escapes INIT. ++if test -n "\${ZSH_VERSION+set}" ; then ++ setopt NO_GLOB_SUBST ++fi ++ ++ ++ PACKAGE='$PACKAGE' ++ VERSION='$VERSION' ++ TIMESTAMP='$TIMESTAMP' ++ RM='$RM' ++ ofile='$ofile' ++ ++ ++ ++ ++ ++_LTEOF ++ ++cat >>"$CONFIG_LT" <<\_LTEOF ++{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $ofile" >&5 ++$as_echo "$as_me: creating $ofile" >&6;} ++ ++ ++ # See if we are running on zsh, and set the options which allow our ++ # commands through without removal of \ escapes. ++ if test -n "${ZSH_VERSION+set}" ; then ++ setopt NO_GLOB_SUBST ++ fi ++ ++ cfgfile="${ofile}T" ++ trap "$RM \"$cfgfile\"; exit 1" 1 2 15 ++ $RM "$cfgfile" ++ ++ cat <<_LT_EOF >> "$cfgfile" ++#! $SHELL ++ ++# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. ++# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION ++# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: ++# NOTE: Changes made to this file will be lost: look at ltmain.sh. ++# ++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, ++# 2006, 2007, 2008, 2009 Free Software Foundation, Inc. ++# Written by Gordon Matzigkeit, 1996 ++# ++# This file is part of GNU Libtool. ++# ++# GNU Libtool is free software; you can redistribute it and/or ++# modify it under the terms of the GNU General Public License as ++# published by the Free Software Foundation; either version 2 of ++# the License, or (at your option) any later version. ++# ++# As a special exception to the GNU General Public License, ++# if you distribute this file as part of a program or library that ++# is built using GNU Libtool, you may include this file under the ++# same distribution terms that you use for the rest of that program. ++# ++# GNU Libtool is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GNU Libtool; see the file COPYING. If not, a copy ++# can be downloaded from http://www.gnu.org/licenses/gpl.html, or ++# obtained by writing to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ ++ ++# The names of the tagged configurations supported by this script. ++available_tags="CXX " ++ ++# ### BEGIN LIBTOOL CONFIG ++ ++# Which release of libtool.m4 was used? ++macro_version=$macro_version ++macro_revision=$macro_revision ++ ++# Whether or not to build shared libraries. ++build_libtool_libs=$enable_shared ++ ++# Whether or not to build static libraries. ++build_old_libs=$enable_static ++ ++# What type of objects to build. ++pic_mode=$pic_mode ++ ++# Whether or not to optimize for fast installation. ++fast_install=$enable_fast_install ++ ++# Shell to use when invoking shell scripts. ++SHELL=$lt_SHELL ++ ++# An echo program that protects backslashes. ++ECHO=$lt_ECHO ++ ++# The host system. ++host_alias=$host_alias ++host=$host ++host_os=$host_os ++ ++# The build system. ++build_alias=$build_alias ++build=$build ++build_os=$build_os ++ ++# A sed program that does not truncate output. ++SED=$lt_SED ++ ++# Sed that helps us avoid accidentally triggering echo(1) options like -n. ++Xsed="\$SED -e 1s/^X//" ++ ++# A grep program that handles long lines. ++GREP=$lt_GREP ++ ++# An ERE matcher. ++EGREP=$lt_EGREP ++ ++# A literal string matcher. ++FGREP=$lt_FGREP ++ ++# A BSD- or MS-compatible name lister. ++NM=$lt_NM ++ ++# Whether we need soft or hard links. ++LN_S=$lt_LN_S ++ ++# What is the maximum length of a command? ++max_cmd_len=$max_cmd_len ++ ++# Object file suffix (normally "o"). ++objext=$ac_objext ++ ++# Executable file suffix (normally ""). ++exeext=$exeext ++ ++# whether the shell understands "unset". ++lt_unset=$lt_unset ++ ++# turn spaces into newlines. ++SP2NL=$lt_lt_SP2NL ++ ++# turn newlines into spaces. ++NL2SP=$lt_lt_NL2SP ++ ++# An object symbol dumper. ++OBJDUMP=$lt_OBJDUMP ++ ++# Method to check whether dependent libraries are shared objects. ++deplibs_check_method=$lt_deplibs_check_method ++ ++# Command to use when deplibs_check_method == "file_magic". ++file_magic_cmd=$lt_file_magic_cmd ++ ++# The archiver. ++AR=$lt_AR ++AR_FLAGS=$lt_AR_FLAGS ++ ++# A symbol stripping program. ++STRIP=$lt_STRIP ++ ++# Commands used to install an old-style archive. ++RANLIB=$lt_RANLIB ++old_postinstall_cmds=$lt_old_postinstall_cmds ++old_postuninstall_cmds=$lt_old_postuninstall_cmds ++ ++# Whether to use a lock for old archive extraction. ++lock_old_archive_extraction=$lock_old_archive_extraction ++ ++# A C compiler. ++LTCC=$lt_CC ++ ++# LTCC compiler flags. ++LTCFLAGS=$lt_CFLAGS ++ ++# Take the output of nm and produce a listing of raw symbols and C names. ++global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe ++ ++# Transform the output of nm in a proper C declaration. ++global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl ++ ++# Transform the output of nm in a C name address pair. ++global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address ++ ++# Transform the output of nm in a C name address pair when lib prefix is needed. ++global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix ++ ++# The name of the directory that contains temporary libtool files. ++objdir=$objdir ++ ++# Used to examine libraries when file_magic_cmd begins with "file". ++MAGIC_CMD=$MAGIC_CMD ++ ++# Must we lock files when doing compilation? ++need_locks=$lt_need_locks ++ ++# Tool to manipulate archived DWARF debug symbol files on Mac OS X. ++DSYMUTIL=$lt_DSYMUTIL ++ ++# Tool to change global to local symbols on Mac OS X. ++NMEDIT=$lt_NMEDIT ++ ++# Tool to manipulate fat objects and archives on Mac OS X. ++LIPO=$lt_LIPO ++ ++# ldd/readelf like tool for Mach-O binaries on Mac OS X. ++OTOOL=$lt_OTOOL ++ ++# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. ++OTOOL64=$lt_OTOOL64 ++ ++# Old archive suffix (normally "a"). ++libext=$libext ++ ++# Shared library suffix (normally ".so"). ++shrext_cmds=$lt_shrext_cmds ++ ++# The commands to extract the exported symbol list from a shared archive. ++extract_expsyms_cmds=$lt_extract_expsyms_cmds ++ ++# Variables whose values should be saved in libtool wrapper scripts and ++# restored at link time. ++variables_saved_for_relink=$lt_variables_saved_for_relink ++ ++# Do we need the "lib" prefix for modules? ++need_lib_prefix=$need_lib_prefix ++ ++# Do we need a version for libraries? ++need_version=$need_version ++ ++# Library versioning type. ++version_type=$version_type ++ ++# Shared library runtime path variable. ++runpath_var=$runpath_var ++ ++# Shared library path variable. ++shlibpath_var=$shlibpath_var ++ ++# Is shlibpath searched before the hard-coded library search path? ++shlibpath_overrides_runpath=$shlibpath_overrides_runpath ++ ++# Format of library name prefix. ++libname_spec=$lt_libname_spec ++ ++# List of archive names. First name is the real one, the rest are links. ++# The last name is the one that the linker finds with -lNAME ++library_names_spec=$lt_library_names_spec ++ ++# The coded name of the library, if different from the real name. ++soname_spec=$lt_soname_spec ++ ++# Permission mode override for installation of shared libraries. ++install_override_mode=$lt_install_override_mode ++ ++# Command to use after installation of a shared archive. ++postinstall_cmds=$lt_postinstall_cmds ++ ++# Command to use after uninstallation of a shared archive. ++postuninstall_cmds=$lt_postuninstall_cmds ++ ++# Commands used to finish a libtool library installation in a directory. ++finish_cmds=$lt_finish_cmds ++ ++# As "finish_cmds", except a single script fragment to be evaled but ++# not shown. ++finish_eval=$lt_finish_eval ++ ++# Whether we should hardcode library paths into libraries. ++hardcode_into_libs=$hardcode_into_libs ++ ++# Compile-time system search path for libraries. ++sys_lib_search_path_spec=$lt_sys_lib_search_path_spec ++ ++# Run-time system search path for libraries. ++sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec ++ ++# Whether dlopen is supported. ++dlopen_support=$enable_dlopen ++ ++# Whether dlopen of programs is supported. ++dlopen_self=$enable_dlopen_self ++ ++# Whether dlopen of statically linked programs is supported. ++dlopen_self_static=$enable_dlopen_self_static ++ ++# Commands to strip libraries. ++old_striplib=$lt_old_striplib ++striplib=$lt_striplib ++ ++ ++# The linker used to build libraries. ++LD=$lt_LD ++ ++# How to create reloadable object files. ++reload_flag=$lt_reload_flag ++reload_cmds=$lt_reload_cmds ++ ++# Commands used to build an old-style archive. ++old_archive_cmds=$lt_old_archive_cmds ++ ++# A language specific compiler. ++CC=$lt_compiler ++ ++# Is the compiler the GNU compiler? ++with_gcc=$GCC ++ ++# Compiler flag to turn off builtin functions. ++no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag ++ ++# How to pass a linker flag through the compiler. ++wl=$lt_lt_prog_compiler_wl ++ ++# Additional compiler flags for building library objects. ++pic_flag=$lt_lt_prog_compiler_pic ++ ++# Compiler flag to prevent dynamic linking. ++link_static_flag=$lt_lt_prog_compiler_static ++ ++# Does compiler simultaneously support -c and -o options? ++compiler_c_o=$lt_lt_cv_prog_compiler_c_o ++ ++# Whether or not to add -lc for building shared libraries. ++build_libtool_need_lc=$archive_cmds_need_lc ++ ++# Whether or not to disallow shared libs when runtime libs are static. ++allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes ++ ++# Compiler flag to allow reflexive dlopens. ++export_dynamic_flag_spec=$lt_export_dynamic_flag_spec ++ ++# Compiler flag to generate shared objects directly from archives. ++whole_archive_flag_spec=$lt_whole_archive_flag_spec ++ ++# Whether the compiler copes with passing no objects directly. ++compiler_needs_object=$lt_compiler_needs_object ++ ++# Create an old-style archive from a shared archive. ++old_archive_from_new_cmds=$lt_old_archive_from_new_cmds ++ ++# Create a temporary old-style archive to link instead of a shared archive. ++old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds ++ ++# Commands used to build a shared archive. ++archive_cmds=$lt_archive_cmds ++archive_expsym_cmds=$lt_archive_expsym_cmds ++ ++# Commands used to build a loadable module if different from building ++# a shared archive. ++module_cmds=$lt_module_cmds ++module_expsym_cmds=$lt_module_expsym_cmds ++ ++# Whether we are building with GNU ld or not. ++with_gnu_ld=$lt_with_gnu_ld ++ ++# Flag that allows shared libraries with undefined symbols to be built. ++allow_undefined_flag=$lt_allow_undefined_flag ++ ++# Flag that enforces no undefined symbols. ++no_undefined_flag=$lt_no_undefined_flag ++ ++# Flag to hardcode \$libdir into a binary during linking. ++# This must work even if \$libdir does not exist ++hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec ++ ++# If ld is used when linking, flag to hardcode \$libdir into a binary ++# during linking. This must work even if \$libdir does not exist. ++hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld ++ ++# Whether we need a single "-rpath" flag with a separated argument. ++hardcode_libdir_separator=$lt_hardcode_libdir_separator ++ ++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes ++# DIR into the resulting binary. ++hardcode_direct=$hardcode_direct ++ ++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes ++# DIR into the resulting binary and the resulting library dependency is ++# "absolute",i.e impossible to change by setting \${shlibpath_var} if the ++# library is relocated. ++hardcode_direct_absolute=$hardcode_direct_absolute ++ ++# Set to "yes" if using the -LDIR flag during linking hardcodes DIR ++# into the resulting binary. ++hardcode_minus_L=$hardcode_minus_L ++ ++# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR ++# into the resulting binary. ++hardcode_shlibpath_var=$hardcode_shlibpath_var ++ ++# Set to "yes" if building a shared library automatically hardcodes DIR ++# into the library and all subsequent libraries and executables linked ++# against it. ++hardcode_automatic=$hardcode_automatic ++ ++# Set to yes if linker adds runtime paths of dependent libraries ++# to runtime path list. ++inherit_rpath=$inherit_rpath ++ ++# Whether libtool must link a program against all its dependency libraries. ++link_all_deplibs=$link_all_deplibs ++ ++# Fix the shell variable \$srcfile for the compiler. ++fix_srcfile_path=$lt_fix_srcfile_path ++ ++# Set to "yes" if exported symbols are required. ++always_export_symbols=$always_export_symbols ++ ++# The commands to list exported symbols. ++export_symbols_cmds=$lt_export_symbols_cmds ++ ++# Symbols that should not be listed in the preloaded symbols. ++exclude_expsyms=$lt_exclude_expsyms ++ ++# Symbols that must always be exported. ++include_expsyms=$lt_include_expsyms ++ ++# Commands necessary for linking programs (against libraries) with templates. ++prelink_cmds=$lt_prelink_cmds ++ ++# Specify filename containing input files. ++file_list_spec=$lt_file_list_spec ++ ++# How to hardcode a shared library path into an executable. ++hardcode_action=$hardcode_action ++ ++# The directories searched by this compiler when creating a shared library. ++compiler_lib_search_dirs=$lt_compiler_lib_search_dirs ++ ++# Dependencies to place before and after the objects being linked to ++# create a shared library. ++predep_objects=$lt_predep_objects ++postdep_objects=$lt_postdep_objects ++predeps=$lt_predeps ++postdeps=$lt_postdeps ++ ++# The library search path used internally by the compiler when linking ++# a shared library. ++compiler_lib_search_path=$lt_compiler_lib_search_path ++ ++# ### END LIBTOOL CONFIG ++ ++_LT_EOF ++ ++ case $host_os in ++ aix3*) ++ cat <<\_LT_EOF >> "$cfgfile" ++# AIX sometimes has problems with the GCC collect2 program. For some ++# reason, if we set the COLLECT_NAMES environment variable, the problems ++# vanish in a puff of smoke. ++if test "X${COLLECT_NAMES+set}" != Xset; then ++ COLLECT_NAMES= ++ export COLLECT_NAMES ++fi ++_LT_EOF ++ ;; ++ esac ++ ++ ++ltmain="$ac_aux_dir/ltmain.sh" ++ ++ ++ # We use sed instead of cat because bash on DJGPP gets confused if ++ # if finds mixed CR/LF and LF-only lines. Since sed operates in ++ # text mode, it properly converts lines to CR/LF. This bash problem ++ # is reportedly fixed, but why not run on old versions too? ++ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ ++ || (rm -f "$cfgfile"; exit 1) ++ ++ case $xsi_shell in ++ yes) ++ cat << \_LT_EOF >> "$cfgfile" ++ ++# func_dirname file append nondir_replacement ++# Compute the dirname of FILE. If nonempty, add APPEND to the result, ++# otherwise set result to NONDIR_REPLACEMENT. ++func_dirname () ++{ ++ case ${1} in ++ */*) func_dirname_result="${1%/*}${2}" ;; ++ * ) func_dirname_result="${3}" ;; ++ esac ++} ++ ++# func_basename file ++func_basename () ++{ ++ func_basename_result="${1##*/}" ++} ++ ++# func_dirname_and_basename file append nondir_replacement ++# perform func_basename and func_dirname in a single function ++# call: ++# dirname: Compute the dirname of FILE. If nonempty, ++# add APPEND to the result, otherwise set result ++# to NONDIR_REPLACEMENT. ++# value returned in "$func_dirname_result" ++# basename: Compute filename of FILE. ++# value retuned in "$func_basename_result" ++# Implementation must be kept synchronized with func_dirname ++# and func_basename. For efficiency, we do not delegate to ++# those functions but instead duplicate the functionality here. ++func_dirname_and_basename () ++{ ++ case ${1} in ++ */*) func_dirname_result="${1%/*}${2}" ;; ++ * ) func_dirname_result="${3}" ;; ++ esac ++ func_basename_result="${1##*/}" ++} ++ ++# func_stripname prefix suffix name ++# strip PREFIX and SUFFIX off of NAME. ++# PREFIX and SUFFIX must not contain globbing or regex special ++# characters, hashes, percent signs, but SUFFIX may contain a leading ++# dot (in which case that matches only a dot). ++func_stripname () ++{ ++ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are ++ # positional parameters, so assign one to ordinary parameter first. ++ func_stripname_result=${3} ++ func_stripname_result=${func_stripname_result#"${1}"} ++ func_stripname_result=${func_stripname_result%"${2}"} ++} ++ ++# func_opt_split ++func_opt_split () ++{ ++ func_opt_split_opt=${1%%=*} ++ func_opt_split_arg=${1#*=} ++} ++ ++# func_lo2o object ++func_lo2o () ++{ ++ case ${1} in ++ *.lo) func_lo2o_result=${1%.lo}.${objext} ;; ++ *) func_lo2o_result=${1} ;; ++ esac ++} ++ ++# func_xform libobj-or-source ++func_xform () ++{ ++ func_xform_result=${1%.*}.lo ++} ++ ++# func_arith arithmetic-term... ++func_arith () ++{ ++ func_arith_result=$(( $* )) ++} ++ ++# func_len string ++# STRING may not start with a hyphen. ++func_len () ++{ ++ func_len_result=${#1} ++} ++ ++_LT_EOF ++ ;; ++ *) # Bourne compatible functions. ++ cat << \_LT_EOF >> "$cfgfile" ++ ++# func_dirname file append nondir_replacement ++# Compute the dirname of FILE. If nonempty, add APPEND to the result, ++# otherwise set result to NONDIR_REPLACEMENT. ++func_dirname () ++{ ++ # Extract subdirectory from the argument. ++ func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` ++ if test "X$func_dirname_result" = "X${1}"; then ++ func_dirname_result="${3}" ++ else ++ func_dirname_result="$func_dirname_result${2}" ++ fi ++} ++ ++# func_basename file ++func_basename () ++{ ++ func_basename_result=`$ECHO "${1}" | $SED "$basename"` ++} ++ ++ ++# func_stripname prefix suffix name ++# strip PREFIX and SUFFIX off of NAME. ++# PREFIX and SUFFIX must not contain globbing or regex special ++# characters, hashes, percent signs, but SUFFIX may contain a leading ++# dot (in which case that matches only a dot). ++# func_strip_suffix prefix name ++func_stripname () ++{ ++ case ${2} in ++ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; ++ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; ++ esac ++} ++ ++# sed scripts: ++my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' ++my_sed_long_arg='1s/^-[^=]*=//' ++ ++# func_opt_split ++func_opt_split () ++{ ++ func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"` ++ func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"` ++} ++ ++# func_lo2o object ++func_lo2o () ++{ ++ func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` ++} ++ ++# func_xform libobj-or-source ++func_xform () ++{ ++ func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` ++} ++ ++# func_arith arithmetic-term... ++func_arith () ++{ ++ func_arith_result=`expr "$@"` ++} ++ ++# func_len string ++# STRING may not start with a hyphen. ++func_len () ++{ ++ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` ++} ++ ++_LT_EOF ++esac ++ ++case $lt_shell_append in ++ yes) ++ cat << \_LT_EOF >> "$cfgfile" ++ ++# func_append var value ++# Append VALUE to the end of shell variable VAR. ++func_append () ++{ ++ eval "$1+=\$2" ++} ++_LT_EOF ++ ;; ++ *) ++ cat << \_LT_EOF >> "$cfgfile" ++ ++# func_append var value ++# Append VALUE to the end of shell variable VAR. ++func_append () ++{ ++ eval "$1=\$$1\$2" ++} ++ ++_LT_EOF ++ ;; ++ esac ++ ++ ++ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ ++ || (rm -f "$cfgfile"; exit 1) ++ ++ mv -f "$cfgfile" "$ofile" || ++ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") ++ chmod +x "$ofile" ++ ++ ++ cat <<_LT_EOF >> "$ofile" ++ ++# ### BEGIN LIBTOOL TAG CONFIG: CXX ++ ++# The linker used to build libraries. ++LD=$lt_LD_CXX ++ ++# How to create reloadable object files. ++reload_flag=$lt_reload_flag_CXX ++reload_cmds=$lt_reload_cmds_CXX ++ ++# Commands used to build an old-style archive. ++old_archive_cmds=$lt_old_archive_cmds_CXX ++ ++# A language specific compiler. ++CC=$lt_compiler_CXX ++ ++# Is the compiler the GNU compiler? ++with_gcc=$GCC_CXX ++ ++# Compiler flag to turn off builtin functions. ++no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX ++ ++# How to pass a linker flag through the compiler. ++wl=$lt_lt_prog_compiler_wl_CXX ++ ++# Additional compiler flags for building library objects. ++pic_flag=$lt_lt_prog_compiler_pic_CXX ++ ++# Compiler flag to prevent dynamic linking. ++link_static_flag=$lt_lt_prog_compiler_static_CXX ++ ++# Does compiler simultaneously support -c and -o options? ++compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX ++ ++# Whether or not to add -lc for building shared libraries. ++build_libtool_need_lc=$archive_cmds_need_lc_CXX ++ ++# Whether or not to disallow shared libs when runtime libs are static. ++allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX ++ ++# Compiler flag to allow reflexive dlopens. ++export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX ++ ++# Compiler flag to generate shared objects directly from archives. ++whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX ++ ++# Whether the compiler copes with passing no objects directly. ++compiler_needs_object=$lt_compiler_needs_object_CXX ++ ++# Create an old-style archive from a shared archive. ++old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX ++ ++# Create a temporary old-style archive to link instead of a shared archive. ++old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX ++ ++# Commands used to build a shared archive. ++archive_cmds=$lt_archive_cmds_CXX ++archive_expsym_cmds=$lt_archive_expsym_cmds_CXX ++ ++# Commands used to build a loadable module if different from building ++# a shared archive. ++module_cmds=$lt_module_cmds_CXX ++module_expsym_cmds=$lt_module_expsym_cmds_CXX ++ ++# Whether we are building with GNU ld or not. ++with_gnu_ld=$lt_with_gnu_ld_CXX ++ ++# Flag that allows shared libraries with undefined symbols to be built. ++allow_undefined_flag=$lt_allow_undefined_flag_CXX ++ ++# Flag that enforces no undefined symbols. ++no_undefined_flag=$lt_no_undefined_flag_CXX ++ ++# Flag to hardcode \$libdir into a binary during linking. ++# This must work even if \$libdir does not exist ++hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX ++ ++# If ld is used when linking, flag to hardcode \$libdir into a binary ++# during linking. This must work even if \$libdir does not exist. ++hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX ++ ++# Whether we need a single "-rpath" flag with a separated argument. ++hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX ++ ++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes ++# DIR into the resulting binary. ++hardcode_direct=$hardcode_direct_CXX ++ ++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes ++# DIR into the resulting binary and the resulting library dependency is ++# "absolute",i.e impossible to change by setting \${shlibpath_var} if the ++# library is relocated. ++hardcode_direct_absolute=$hardcode_direct_absolute_CXX ++ ++# Set to "yes" if using the -LDIR flag during linking hardcodes DIR ++# into the resulting binary. ++hardcode_minus_L=$hardcode_minus_L_CXX ++ ++# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR ++# into the resulting binary. ++hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX ++ ++# Set to "yes" if building a shared library automatically hardcodes DIR ++# into the library and all subsequent libraries and executables linked ++# against it. ++hardcode_automatic=$hardcode_automatic_CXX ++ ++# Set to yes if linker adds runtime paths of dependent libraries ++# to runtime path list. ++inherit_rpath=$inherit_rpath_CXX ++ ++# Whether libtool must link a program against all its dependency libraries. ++link_all_deplibs=$link_all_deplibs_CXX ++ ++# Fix the shell variable \$srcfile for the compiler. ++fix_srcfile_path=$lt_fix_srcfile_path_CXX ++ ++# Set to "yes" if exported symbols are required. ++always_export_symbols=$always_export_symbols_CXX ++ ++# The commands to list exported symbols. ++export_symbols_cmds=$lt_export_symbols_cmds_CXX ++ ++# Symbols that should not be listed in the preloaded symbols. ++exclude_expsyms=$lt_exclude_expsyms_CXX ++ ++# Symbols that must always be exported. ++include_expsyms=$lt_include_expsyms_CXX ++ ++# Commands necessary for linking programs (against libraries) with templates. ++prelink_cmds=$lt_prelink_cmds_CXX ++ ++# Specify filename containing input files. ++file_list_spec=$lt_file_list_spec_CXX ++ ++# How to hardcode a shared library path into an executable. ++hardcode_action=$hardcode_action_CXX ++ ++# The directories searched by this compiler when creating a shared library. ++compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX ++ ++# Dependencies to place before and after the objects being linked to ++# create a shared library. ++predep_objects=$lt_predep_objects_CXX ++postdep_objects=$lt_postdep_objects_CXX ++predeps=$lt_predeps_CXX ++postdeps=$lt_postdeps_CXX ++ ++# The library search path used internally by the compiler when linking ++# a shared library. ++compiler_lib_search_path=$lt_compiler_lib_search_path_CXX ++ ++# ### END LIBTOOL TAG CONFIG: CXX ++_LT_EOF ++ ++ ++as_fn_exit 0 ++_LTEOF ++chmod +x "$CONFIG_LT" ++ ++# configure is writing to config.log, but config.lt does its own redirection, ++# appending to config.log, which fails on DOS, as config.log is still kept ++# open by configure. Here we exec the FD to /dev/null, effectively closing ++# config.log, so it can be properly (re)opened and appended to by config.lt. ++lt_cl_success=: ++test "$silent" = yes && ++ lt_config_lt_args="$lt_config_lt_args --quiet" ++exec 5>/dev/null ++$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false ++exec 5>>config.log ++$lt_cl_success || as_fn_exit 1 ++ ++ ++ac_config_files="$ac_config_files Makefile" ++ ++ac_config_files="$ac_config_files scripts/testsuite_flags" ++ ++ac_config_files="$ac_config_files scripts/extract_symvers" ++ ++ac_config_files="$ac_config_files doc/xsl/customization.xsl" ++ ++ ++# Multilibs need MULTISUBDIR defined correctly in certain makefiles so ++# that multilib installs will end up installed in the correct place. ++# The testsuite needs it for multilib-aware ABI baseline files. ++# To work around this not being passed down from config-ml.in -> ++# srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually ++# append it here. Only modify Makefiles that have just been created. ++# ++# Also, get rid of this simulated-VPATH thing that automake does. ++ac_config_files="$ac_config_files include/Makefile libsupc++/Makefile src/Makefile src/c++98/Makefile src/c++11/Makefile src/filesystem/Makefile doc/Makefile po/Makefile testsuite/Makefile python/Makefile" ++ ++ ++ac_config_commands="$ac_config_commands generate-headers" ++ ++ ++cat >confcache <<\_ACEOF ++# This file is a shell script that caches the results of configure ++# tests run on this system so they can be shared between configure ++# scripts and configure runs, see configure's option --config-cache. ++# It is not useful on other systems. If it contains results you don't ++# want to keep, you may remove or edit it. ++# ++# config.status only pays attention to the cache file if you give it + # the --recheck option to rerun configure. + # + # `ac_cv_env_foo' variables (set or unset) will be overridden when + # loading this file, other *unset* `ac_cv_foo' will be assigned the + # following values. + +@@ -81494,12 +83297,13 @@ fi + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + ++ac_aux_dir='$ac_aux_dir' + + + + GCC="$GCC" + CC="$CC" + acx_cv_header_stdint="$acx_cv_header_stdint" +diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac +index 580fb8b2eb8ab25bed4872f1d071ba925cf3dcff..76ddbdae13f46336f68672e217e5dfa2fdffee97 100644 +--- libstdc++-v3/configure.ac ++++ libstdc++-v3/configure.ac +@@ -492,12 +492,15 @@ fi + GLIBCXX_EXPORT_INSTALL_INFO + + # Export all the include and flag information to Makefiles. + GLIBCXX_EXPORT_INCLUDES + GLIBCXX_EXPORT_FLAGS + ++# create libtool - libtool > 2.0: ++LT_OUTPUT ++ + dnl In autoconf 2.5x, AC_OUTPUT is replaced by four AC_CONFIG_* macros, + dnl which can all be called multiple times as needed, plus one (different) + dnl AC_OUTPUT macro. This one lists the files to be created: + AC_CONFIG_FILES(Makefile) + AC_CONFIG_FILES([scripts/testsuite_flags],[chmod +x scripts/testsuite_flags]) + AC_CONFIG_FILES([scripts/extract_symvers],[chmod +x scripts/extract_symvers]) +diff --git a/libstdc++-v3/crossconfig.m4 b/libstdc++-v3/crossconfig.m4 +index 10247f940b55ee77df940044c3889b08b51cfb4c..c7d1034f4870e92dfd502d25bc7cc858f6a19370 100644 +--- libstdc++-v3/crossconfig.m4 ++++ libstdc++-v3/crossconfig.m4 +@@ -266,11 +266,19 @@ case "${host}" in + AC_DEFINE(HAVE_SINF) + AC_DEFINE(HAVE_SINHF) + AC_DEFINE(HAVE_SQRTF) + AC_DEFINE(HAVE_TANF) + AC_DEFINE(HAVE_TANHF) + ;; ++ *-amigaos*) ++ AC_CHECK_HEADERS([nan.h ieeefp.h endian.h sys/isa_defs.h \ ++ machine/endian.h machine/param.h sys/machine.h sys/types.h \ ++ fp.h locale.h float.h inttypes.h]) ++ SECTION_FLAGS='-ffunction-sections -fdata-sections' ++ AC_SUBST(SECTION_FLAGS) ++ GLIBCXX_CHECK_LINKER_FEATURES ++ ;; + *) + AC_MSG_ERROR([No support for this host/target combination.]) + ;; + esac + ]) +diff --git a/libstdc++-v3/include/c_global/cstddef b/libstdc++-v3/include/c_global/cstddef +index 33f4f8f76bd497d345ec7440b9397427e26671eb..7c39a30d2bc41b4eb82b13c3d390cfce52854457 100644 +--- libstdc++-v3/include/c_global/cstddef ++++ libstdc++-v3/include/c_global/cstddef +@@ -44,12 +44,15 @@ + #include <bits/c++config.h> + #include <stddef.h> + + #if __cplusplus >= 201103L + namespace std + { ++/* Needed as clib2 on AmigaOS has no C11 support yet */ ++#if __STDC_VERSION__ >= 201112L + // We handle size_t, ptrdiff_t, and nullptr_t in c++config.h. + using ::max_align_t; ++#endif + } + #endif + + #endif // _GLIBCXX_CSTDDEF +diff --git a/libstdc++-v3/include/c_std/cstddef b/libstdc++-v3/include/c_std/cstddef +index d46a4ea16388d674917a74620c3f50d43de84bb6..9189ed063448a45439a265bf4a51cc36e0c731ed 100644 +--- libstdc++-v3/include/c_std/cstddef ++++ libstdc++-v3/include/c_std/cstddef +@@ -44,12 +44,15 @@ + #include <bits/c++config.h> + #include <stddef.h> + + #if __cplusplus >= 201103L + namespace std + { ++/* Needed as clib2 on AmigaOS has no C11 support yet */ ++#if __STDC_VERSION__ >= 201112L + // We handle size_t, ptrdiff_t, and nullptr_t in c++config.h. + using ::max_align_t; ++#endif + } + #endif + + #endif // _GLIBCXX_CSTDDEF +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/gcc/0002-Added-new-function-attribute-lineartags-and-pragma-a.p b/ppc-amigaos/recipes/patches/gcc/0002-Added-new-function-attribute-lineartags-and-pragma-a.p new file mode 100644 index 0000000..1eec43a --- /dev/null +++ b/ppc-amigaos/recipes/patches/gcc/0002-Added-new-function-attribute-lineartags-and-pragma-a.p @@ -0,0 +1,376 @@ +From c8d51b6ed56c643f9744d7a18fee3b13a76b98d3 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Fri, 14 Nov 2014 20:03:56 +0100 +Subject: [PATCH 2/6] Added new function attribute "lineartags" and pragma + "amigaos tagtype". + +Functions that have the lineartags attribute are assumed to be functions +with tags, in which case type checking is now enabled. That is, the value +that follow a specific tag is assumed to be a certain type. If this is +not the case, the compiler will warn. + +The compiler can be taught about that types via the new pragma +#pragma amigaos tagtype(TYPE) +which is written before an "enum" or a "static const int" that defines +the number of the tag. + +For instance: + +#pragma amigaos tagtype(struct Screen *) +static const int WA_CustomScreen = WA_Dummy + 0x0D; + + or + +#pragma amigaos tagtype(struct Screen *) +enum {WA_CustomScreen = WA_Dummy + 0x0D}; + +is possible now. + +It is not very robust yet wrt to catching misuses of the new feature. +For instance, no check is done that the attribute is applied to varargs +functions. +--- + gcc/c-family/c-pragma.c | 10 +++ + gcc/c/c-parser.c | 129 +++++++++++++++++++++++++++++++++++++ + gcc/c/c-typeck.c | 24 +++++++ + gcc/config/rs6000/amigaos-protos.h | 1 + + gcc/config/rs6000/amigaos.c | 7 ++ + 5 files changed, 171 insertions(+) + +diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c +index 6894f0e7c3d1ea932ff05f370680be3d18dfcf94..24278250901bfa75c9aae9be63a62351f33e390e 100644 +--- gcc/c-family/c-pragma.c ++++ gcc/c-family/c-pragma.c +@@ -1066,12 +1066,21 @@ handle_pragma_message (cpp_reader *ARG_UNUSED(dummy)) + warning (OPT_Wpragmas, "junk at end of %<#pragma message%>"); + + if (TREE_STRING_LENGTH (message) > 1) + inform (input_location, "#pragma message: %s", TREE_STRING_POINTER (message)); + } + ++/* This is queried by the invoker of the handler */ ++int was_tagtypepragma; ++/* Tagtype pragma */ ++static void ++handle_pragma_tagtype (cpp_reader *reader) ++{ ++ was_tagtypepragma = 1; ++} ++ + /* Mark whether the current location is valid for a STDC pragma. */ + + static bool valid_location_for_stdc_pragma; + + void + mark_valid_location_for_stdc_pragma (bool flag) +@@ -1483,12 +1492,13 @@ init_pragma (void) + + c_register_pragma_with_expansion (0, "redefine_extname", + handle_pragma_redefine_extname); + + c_register_pragma_with_expansion (0, "message", handle_pragma_message); + ++ c_register_pragma_with_expansion ("amigaos", "tagtype", handle_pragma_tagtype); + #ifdef REGISTER_TARGET_PRAGMAS + REGISTER_TARGET_PRAGMAS (); + #endif + + /* Allow plugins to register their own pragmas. */ + invoke_plugin_callbacks (PLUGIN_PRAGMAS, NULL); +diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c +index 86cbc404a4c10edac0ce2341ae0099f624ee36ea..cc77530b090576db35610468052d84763c3965fd 100644 +--- gcc/c/c-parser.c ++++ gcc/c/c-parser.c +@@ -80,12 +80,74 @@ along with GCC; see the file COPYING3. If not see + #include "cgraph.h" + #include "plugin.h" + #include "omp-low.h" + #include "builtins.h" + #include "gomp-constants.h" + ++static htab_t amigaos_tagdecl_to_type; ++ ++struct amigaos_hash_type ++{ ++ tree decl; ++ tree type; ++}; ++ ++static hashval_t ++amigaos_hash_descriptor (const void *p) ++{ ++ return htab_hash_pointer (((const amigaos_hash_type *)p)->decl); ++} ++ ++static int ++amigaos_eq_descriptor (const void *p1, const void *p2) ++{ ++ return ((const amigaos_hash_type *)p1)->decl == ((const amigaos_hash_type *)p2)->decl; ++} ++ ++/** ++ * Returns the tag type that is associated with the given type. ++ * ++ * @param type ++ * @return ++ */ ++tree amigaos_get_type_associated_tagtype(tree decl) ++{ ++ amigaos_hash_type aht = {decl, 0}; ++ amigaos_hash_type *faht; ++ ++ if (!amigaos_tagdecl_to_type) ++ return NULL; ++ ++ faht = (amigaos_hash_type *)htab_find(amigaos_tagdecl_to_type, &aht); ++ if (!faht) ++ return NULL; ++ return faht->type; ++} ++ ++static void amigaos_put_type_associated_tagtype(tree decl, tree type) ++{ ++ gcc_assert(decl); ++ ++ if (!amigaos_tagdecl_to_type) ++ amigaos_tagdecl_to_type = htab_create (10, amigaos_hash_descriptor, amigaos_eq_descriptor, NULL); ++ ++ amigaos_hash_type *aht = (amigaos_hash_type *)xmalloc(sizeof(*aht)); ++ aht->decl = decl; ++ aht->type = type; ++ ++ void **pentry = htab_find_slot (amigaos_tagdecl_to_type, aht, INSERT); ++ gcc_assert(pentry); ++ gcc_assert(*pentry == NULL); ++ *pentry = aht; ++} ++ ++/** ++ * Contains the tagtype that is currently processed or NULL_TREE ++ * if no tagtype is processed. ++ */ ++static tree amigaos_current_tagtype; + + /* Initialization routine for this file. */ + + void + c_parse_init (void) + { +@@ -2390,12 +2452,15 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, + goto out; + attrs_ok = true; + seen_type = true; + t = c_parser_enum_specifier (parser); + invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec); + declspecs_add_type (loc, specs, t); ++ /* Handle special tagtype enhanced enums */ ++ if (amigaos_current_tagtype != NULL_TREE && t.spec != NULL_TREE) ++ amigaos_put_type_associated_tagtype(t.spec, amigaos_current_tagtype); + break; + case RID_STRUCT: + case RID_UNION: + if (!typespec_ok) + goto out; + attrs_ok = true; +@@ -9590,12 +9655,32 @@ c_parser_objc_at_dynamic_declaration (c_parser *parser) + } + c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); + objc_add_dynamic_declaration (loc, list); + } + + ++/** ++ * This function is called whenever a declaration was finished that was preceded ++ * by a tagtype pragma. ++ * ++ * @param gcc_data will be the finished declaration ++ * @param user_data will be the parsed c type of the declaration (c_type_name *) ++ * that was specified ahead of the declaration via the pragma. ++ */ ++static void amigaos_tagtype_finish_decl_callback (void *gcc_data, void *user_data) ++{ ++ tree decl = (tree)gcc_data; ++ c_type_name *ctype = (c_type_name*)user_data; ++ tree type = groktypename (ctype, NULL, NULL); ++ ++ /* TODO: All sorts of checks */ ++ ++ /* Now put the association in our own hash table */ ++ amigaos_put_type_associated_tagtype(decl, type); ++} ++ + /* Handle pragmas. Some OpenMP pragmas are associated with, and therefore + should be considered, statements. ALLOW_STMT is true if we're within + the context of a function and such pragmas are to be allowed. Returns + true if we actually parsed such a pragma. */ + + static bool +@@ -9777,12 +9862,56 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) + break; + } + + c_parser_consume_pragma (parser); + c_invoke_pragma_handler (id); + ++ /* If was_tagtypepragma is set, the pragma was a tagtype one, ++ * which, at the moment, cannot easily handled outside of this ++ * file. ++ */ ++ extern int was_tagtypepragma; ++ if (was_tagtypepragma) ++ { ++ c_token *tok = c_parser_peek_token (the_parser); ++ enum cpp_ttype ret = tok->type; ++ c_parser_consume_token(parser); ++ ++ c_type_name *ctype = c_parser_type_name(parser); ++ tree ctypetree = groktypename (ctype, NULL, NULL); ++ ++ /* Make the parsed type available to all functions called from here on */ ++ amigaos_current_tagtype = ctypetree; ++ ++ tok = c_parser_peek_token (the_parser); ++ ret = tok->type; ++ c_parser_consume_token(parser); ++ c_parser_skip_to_pragma_eol(parser); ++ ++ tok = c_parser_peek_token (the_parser); ++ ret = tok->type; ++ ++ /* Parse the line that follows. We will register for a PLUGIN_FINISH_DECL event ++ * to minimize contermination ++ */ ++ bool old_flag_plugin_added = flag_plugin_added; ++ register_callback ("amigaos-tagtype", PLUGIN_FINISH_DECL, ++ amigaos_tagtype_finish_decl_callback, ++ ctype); ++ flag_plugin_added = 1; ++ c_parser_declaration_or_fndef(parser, false, false, true, false, true, NULL, vNULL); ++ unregister_callback ("amigaos-tagtype", PLUGIN_FINISH_DECL); ++ flag_plugin_added = old_flag_plugin_added; ++ /* Reset the variable that is set in the pragma handler */ ++ was_tagtypepragma = 0; ++ /* The tagtype has been processed */ ++ amigaos_current_tagtype = NULL_TREE; ++ return false; ++ } ++ ++ + /* Skip to EOL, but suppress any error message. Those will have been + generated by the handler routine through calling error, as opposed + to calling c_parser_error. */ + parser->error = true; + c_parser_skip_to_pragma_eol (parser); + +diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c +index a98622b16f546b88eb7fdce9ca7631c3ca37470a..2c03a10f1127c2bec5d9280ecc2f786fd5d13153 100644 +--- gcc/c/c-typeck.c ++++ gcc/c/c-typeck.c +@@ -3100,12 +3100,14 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, + unsigned int parmnum; + bool error_args = false; + const bool type_generic = fundecl + && lookup_attribute ("type generic", TYPE_ATTRIBUTES (TREE_TYPE (fundecl))); + bool type_generic_remove_excess_precision = false; + tree selector; ++ const bool lineartags = fundecl ++ && lookup_attribute ("lineartags", TYPE_ATTRIBUTES (TREE_TYPE (fundecl))); + + /* Change pointer to function to the function itself for + diagnostics. */ + if (TREE_CODE (function) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) + function = TREE_OPERAND (function, 0); +@@ -3139,12 +3141,14 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, + if (flag_cilkplus && fundecl && is_cilkplus_reduce_builtin (fundecl)) + return vec_safe_length (values); + + /* Scan the given expressions and types, producing individual + converted arguments. */ + ++ tree prev_tagtype = NULL_TREE; ++ + for (typetail = typelist, parmnum = 0; + values && values->iterate (parmnum, &val); + ++parmnum) + { + tree type = typetail ? TREE_VALUE (typetail) : 0; + tree valtype = TREE_TYPE (val); +@@ -3193,12 +3197,32 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist, + } + val = c_fully_fold (val, false, NULL); + STRIP_TYPE_NOPS (val); + + val = require_complete_type (val); + ++ /* If this is a function call with linear tags try to improve the expected ++ * type on base of recorded tag <-> type mapping. ++ */ ++ if (lineartags && type == 0) ++ { ++ extern tree amigaos_get_type_associated_tagtype(tree type); ++ ++ if (prev_tagtype) ++ { ++ type = prev_tagtype; ++ prev_tagtype = NULL_TREE; ++ } ++ else ++ { ++ prev_tagtype = amigaos_get_type_associated_tagtype(val); ++ if (!prev_tagtype) ++ prev_tagtype = amigaos_get_type_associated_tagtype((*origtypes)[parmnum]); ++ } ++ } ++ + if (type != 0) + { + /* Formal parm type is specified by a function prototype. */ + + if (type == error_mark_node || !COMPLETE_TYPE_P (type)) + { +diff --git a/gcc/config/rs6000/amigaos-protos.h b/gcc/config/rs6000/amigaos-protos.h +index eb5f8fc5f3d546b8d8e1cdd8118a3085079df50e..3b8c994cdbd192eaf7112c780f0106a4d96cbb90 100644 +--- gcc/config/rs6000/amigaos-protos.h ++++ gcc/config/rs6000/amigaos-protos.h +@@ -27,12 +27,13 @@ extern void amigaos_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, + extern struct rtx_def *amigaos_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int); + extern void amigaos_expand_builtin_va_start (tree valist, rtx nextarg); + extern struct rtx_def *amigaos_expand_builtin_saveregs (void); + extern void amigaos_init_builtins (void); + extern rtx amigaos_expand_builtin (tree, rtx, rtx, enum machine_mode, int, bool*); + extern tree amigaos_handle_linearvarargs_attribute (tree *, tree, tree, int, bool*); ++extern tree amigaos_handle_lineartags_attribute (tree *, tree, tree, int, bool*); + extern tree amigaos_handle_baserel_restore_attribute (tree *, tree, tree, int, bool*); + extern tree amigaos_handle_force_no_baserel_attribute (tree *, tree, tree, int, bool*); + extern tree amigaos_handle_check68kfuncptr_attribute (tree *, tree, tree, int, bool*); + extern rtx amigaos_legitimize_baserel_address (rtx addr); + extern int amigaos_baserel_operand(rtx x); + extern int amigaos_not_baserel_tree_p(tree decl); +diff --git a/gcc/config/rs6000/amigaos.c b/gcc/config/rs6000/amigaos.c +index 0f575a38e4dc4aac0b454c56bf62f625c0f7eb9c..ccf4f912cb66cd424a2398c6535e05fa493f39f1 100644 +--- gcc/config/rs6000/amigaos.c ++++ gcc/config/rs6000/amigaos.c +@@ -345,12 +345,19 @@ amigaos_handle_linearvarargs_attribute (tree *node, tree name, + *no_add_attrs = true; + } + + return NULL_TREE; + } + ++tree ++amigaos_handle_lineartags_attribute (tree *node, tree name, tree args, int flags, bool *no_add_attrs) ++{ ++ /* TODO: This function should applied only to functions or methods */ ++ return NULL_TREE; ++} ++ + + /* Generate code for base relative access */ + + rtx + amigaos_legitimize_baserel_address (rtx addr) + { +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/gcc/0003-Disable-.machine-directive-generation.p b/ppc-amigaos/recipes/patches/gcc/0003-Disable-.machine-directive-generation.p new file mode 100644 index 0000000..edadf9d --- /dev/null +++ b/ppc-amigaos/recipes/patches/gcc/0003-Disable-.machine-directive-generation.p @@ -0,0 +1,49 @@ +From 43dda55bb84a70181e84f496fd8417ed3c22db54 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Thu, 9 Jul 2015 06:54:37 +0200 +Subject: [PATCH 3/6] Disable .machine directive generation. + +It breaks manual args to the assembler with different flavor, +e.g., -Wa,-m440. This is probably not the right fix. + +This reverts parts of a commit from 2015-03-03. +--- + gcc/config/rs6000/rs6000.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c +index ee0ea2ffabb6b9c6fdcba687d88be1e1164374ee..19544afa364f7f7ab1a5c5a61ad7891218398f99 100644 +--- gcc/config/rs6000/rs6000.c ++++ gcc/config/rs6000/rs6000.c +@@ -5191,12 +5191,14 @@ rs6000_file_start (void) + } + + #ifdef USING_ELFOS_H + if (rs6000_default_cpu == 0 || rs6000_default_cpu[0] == '\0' + || !global_options_set.x_rs6000_cpu_index) + { ++ /* Temporarily disabled as it overrides e.g., -mcpu=440 */ ++#if 0 + fputs ("\t.machine ", asm_out_file); + if ((rs6000_isa_flags & OPTION_MASK_DIRECT_MOVE) != 0) + fputs ("power8\n", asm_out_file); + else if ((rs6000_isa_flags & OPTION_MASK_POPCNTD) != 0) + fputs ("power7\n", asm_out_file); + else if ((rs6000_isa_flags & OPTION_MASK_CMPB) != 0) +@@ -5206,12 +5208,13 @@ rs6000_file_start (void) + else if ((rs6000_isa_flags & OPTION_MASK_MFCRF) != 0) + fputs ("power4\n", asm_out_file); + else if ((rs6000_isa_flags & OPTION_MASK_POWERPC64) != 0) + fputs ("ppc64\n", asm_out_file); + else + fputs ("ppc\n", asm_out_file); ++#endif + } + #endif + + if (DEFAULT_ABI == ABI_ELFv2) + fprintf (file, "\t.abiversion 2\n"); + +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/gcc/0004-The-default-link-mode-is-static-for-AmigaOS.p b/ppc-amigaos/recipes/patches/gcc/0004-The-default-link-mode-is-static-for-AmigaOS.p new file mode 100644 index 0000000..5eeb4e5 --- /dev/null +++ b/ppc-amigaos/recipes/patches/gcc/0004-The-default-link-mode-is-static-for-AmigaOS.p @@ -0,0 +1,51 @@ +From 8eb1aa062283f82007d639e862278a750f314da5 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Wed, 2 Dec 2015 20:56:33 +0100 +Subject: [PATCH 4/6] The default link mode is static for AmigaOS. + +Changed the g++ driver to reflect this. +--- + gcc/cp/g++spec.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/gcc/cp/g++spec.c b/gcc/cp/g++spec.c +index 6536d7e776f861b4bd40277e96c80a635cbcc85e..ff1d77eaefc20039f7e5df48ffb849ee533b9797 100644 +--- gcc/cp/g++spec.c ++++ gcc/cp/g++spec.c +@@ -102,14 +102,14 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, + /* By default, we throw on the math library if we have one. */ + int need_math = (MATH_LIBRARY[0] != '\0'); + + /* By default, we throw on the time library if we have one. */ + int need_time = (TIME_LIBRARY[0] != '\0'); + +- /* True if we saw -static. */ +- int static_link = 0; ++ /* False if we saw -shared. */ ++ int static_link = 1; + + /* True if we should add -shared-libgcc to the command-line. */ + int shared_libgcc = 1; + + /* The total number of arguments with the new stuff. */ + unsigned int argc; +@@ -196,12 +196,16 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, + break; + + case OPT_static: + static_link = 1; + break; + ++ case OPT_shared: ++ static_link = 0; ++ break; ++ + case OPT_static_libgcc: + shared_libgcc = 0; + break; + + case OPT_static_libstdc__: + library = library >= 0 ? 2 : library; +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/gcc/0005-Disable-the-usage-of-dev-urandom-when-compiling-for-.p b/ppc-amigaos/recipes/patches/gcc/0005-Disable-the-usage-of-dev-urandom-when-compiling-for-.p new file mode 100644 index 0000000..99621d8 --- /dev/null +++ b/ppc-amigaos/recipes/patches/gcc/0005-Disable-the-usage-of-dev-urandom-when-compiling-for-.p @@ -0,0 +1,73 @@ +From c9b38a7315faed955e2f01e37f84d06ba32aa9b5 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Wed, 2 Dec 2015 21:39:42 +0100 +Subject: [PATCH 5/6] Disable the usage of /dev/urandom when compiling for + AmigaOS. + +--- + gcc/gcc.c | 3 +++ + gcc/toplev.c | 4 ++-- + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/gcc/gcc.c b/gcc/gcc.c +index d4d061080ba1166fb14069094556246b32265da4..8239a6b2152ac192498cd8a50b0d4b9c7db45c62 100644 +--- gcc/gcc.c ++++ gcc/gcc.c +@@ -9124,22 +9124,25 @@ print_asm_header_spec_function (int arg ATTRIBUTE_UNUSED, + /* Get a random number for -frandom-seed */ + + static unsigned HOST_WIDE_INT + get_random_number (void) + { + unsigned HOST_WIDE_INT ret = 0; ++ ++#ifndef __amigaos4__ + int fd; + + fd = open ("/dev/urandom", O_RDONLY); + if (fd >= 0) + { + read (fd, &ret, sizeof (HOST_WIDE_INT)); + close (fd); + if (ret) + return ret; + } ++#endif + + /* Get some more or less random data. */ + #ifdef HAVE_GETTIMEOFDAY + { + struct timeval tv; + +diff --git a/gcc/toplev.c b/gcc/toplev.c +index cb6c51739ffc40d19f83efafb02d7670e4da2915..3ba2210c953d2dde2ab919808b86ed3e7a4f4d1e 100644 +--- gcc/toplev.c ++++ gcc/toplev.c +@@ -288,22 +288,22 @@ static void + init_local_tick (void) + { + if (!flag_random_seed) + { + /* Try urandom first. Time of day is too likely to collide. + In case of any error we just use the local tick. */ +- ++#ifndef __amigaos4__ + int fd = open ("/dev/urandom", O_RDONLY); + if (fd >= 0) + { + if (read (fd, &random_seed, sizeof (random_seed)) + != sizeof (random_seed)) + random_seed = 0; + close (fd); + } +- ++#endif + /* Now get the tick anyways */ + #ifdef HAVE_GETTIMEOFDAY + { + struct timeval tv; + + gettimeofday (&tv, NULL); +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/gcc/0006-Expand-arg-zero-on-AmigaOS-using-the-PROGDIR-assign.p b/ppc-amigaos/recipes/patches/gcc/0006-Expand-arg-zero-on-AmigaOS-using-the-PROGDIR-assign.p new file mode 100644 index 0000000..6f15af2 --- /dev/null +++ b/ppc-amigaos/recipes/patches/gcc/0006-Expand-arg-zero-on-AmigaOS-using-the-PROGDIR-assign.p @@ -0,0 +1,41 @@ +From 85c5321c36040abb1c3b70cb1e0f9bf217178957 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Sat, 5 Dec 2015 13:17:26 +0100 +Subject: [PATCH 6/6] Expand arg zero on AmigaOS using the PROGDIR: assign. + +This should make sure that the proper relative paths are computed during +process_command(). +--- + gcc/gcc.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/gcc/gcc.c b/gcc/gcc.c +index 8239a6b2152ac192498cd8a50b0d4b9c7db45c62..f6f1ba3195a4ffc8e335d7abe797d4b006fc96d5 100644 +--- gcc/gcc.c ++++ gcc/gcc.c +@@ -6898,12 +6898,22 @@ compare_files (char *cmpfile[]) + int + driver::main (int argc, char **argv) + { + bool early_exit; + + set_progname (argv[0]); ++#ifdef __amigaos4__ ++ /* Expand the command name on AmigaOS */ ++ char *expanded_progdir = lrealpath("/progdir/"); ++ if (expanded_progdir) ++ { ++ char *expanded_argv0 = concat(expanded_progdir,"/",progname,NULL); ++ argv[0] = expanded_argv0; /* FIXME: Leak */ ++ free(expanded_progdir); ++ } ++#endif + expand_at_files (&argc, &argv); + decode_argv (argc, const_cast <const char **> (argv)); + global_initializations (); + build_multilib_strings (); + set_up_specs (); + putenv_COLLECT_GCC (argv[0]); +-- +2.1.4 + diff --git a/ppc-amigaos/recipes/patches/gcc/gmp-configure.p b/ppc-amigaos/recipes/patches/gcc/gmp-configure.p deleted file mode 100644 index a8ac807..0000000 --- a/ppc-amigaos/recipes/patches/gcc/gmp-configure.p +++ /dev/null @@ -1,11 +0,0 @@ ---- gmp/configure.orig 2012-08-17 18:03:57.000000000 +0100 -+++ gmp/configure 2012-08-17 18:04:17.000000000 +0100 -@@ -30006,8 +30006,6 @@ - echo "define(<M4WRAP_SPURIOUS>,<$gmp_cv_m4_m4wrap_spurious>)" >> $gmp_tmpconfigm4 - - --else -- M4=m4-not-needed - fi - - # Only do the GMP_ASM checks if there's a .S or .asm wanting them. |