diff options
author | Chris Young <chris@unsatisfactorysoftware.co.uk> | 2016-02-28 15:57:25 +0000 |
---|---|---|
committer | Chris Young <chris@unsatisfactorysoftware.co.uk> | 2016-02-28 15:57:25 +0000 |
commit | 84675cfd17dc1dd6c01f248cb9c94d9995b42f53 (patch) | |
tree | 16af7f02f61b0ca864d2020248a35764c045d0f2 /ppc-amigaos | |
parent | f704c927b5b8e365ff2fbd053c185306051e0123 (diff) | |
download | toolchains-84675cfd17dc1dd6c01f248cb9c94d9995b42f53.tar.gz toolchains-84675cfd17dc1dd6c01f248cb9c94d9995b42f53.tar.bz2 |
Import binutils patches from https://github.com/sba1/adtools/tree/master/binutils/2.23.2/patches
Diffstat (limited to 'ppc-amigaos')
8 files changed, 28206 insertions, 406 deletions
diff --git a/ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p b/ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p new file mode 100644 index 0000000..9ac09fe --- /dev/null +++ b/ppc-amigaos/recipes/patches/binutils/0001-Changes-for-various-Amiga-targets.p @@ -0,0 +1,27432 @@ +From 1678a95339b8893195b307a953a0053ceeca0133 Mon Sep 17 00:00:00 2001 +From: Sebastian Bauer <mail@sebastianbauer.info> +Date: Sat, 14 Feb 2015 14:54:44 +0100 +Subject: [PATCH 1/7] Changes for various Amiga targets. + +--- + bfd/ChangeLog-9697 | 64 + + bfd/ChangeLog-9899 | 5 + + bfd/Makefile.am | 18 +- + bfd/Makefile.in | 24 +- + bfd/amigaos.c | 3189 +++++++++ + bfd/amigaoslink.c | 1032 +++ + bfd/aout-amiga.c | 152 + + bfd/aoutx.h | 26 +- + bfd/bfd-in2.h | 12 + + bfd/bfd.c | 1 + + bfd/bfdio.c | 25 + + bfd/config.bfd | 28 +- + bfd/configure | 5 + + bfd/configure.host | 1 + + bfd/configure.in | 5 + + bfd/doc/Makefile.am | 15 +- + bfd/doc/Makefile.in | 15 +- + bfd/doc/bfd.texinfo | 9 +- + bfd/elf32-amiga.c | 3844 +++++++++++ + bfd/{elf32-ppc.c => elf32-amigaos.c} | 341 +- + bfd/elf32-i386-amithlon.c | 198 + + bfd/elf32-i386.c | 17 +- + bfd/elf32-morphos.c | 7137 +++++++++++++++++++++ + bfd/elf32-ppc.c | 4 + + bfd/hosts/amigaos.h | 5 + + bfd/hosts/morphos.h | 5 + + bfd/libamiga.h | 187 + + bfd/libbfd.h | 8 + + bfd/linker.c | 26 +- + bfd/reloc.c | 19 + + bfd/targets.c | 11 + + binutils/objcopy.c | 50 +- + binutils/readelf.c | 5 + + binutils/rename.c | 4 +- + config.sub | 11 +- + config/mh-amigaos | 13 + + config/mh-morphos | 13 + + configure | 6 + + configure.ac | 6 + + gas/ChangeLog-9697 | 12 + + gas/ChangeLog-9899 | 4 + + gas/Makefile.am | 5 +- + gas/Makefile.in | 20 +- + gas/as.c | 14 + + gas/config/m68k-parse.h | 3 + + gas/config/m68k-parse.y | 10 +- + gas/config/obj-amigahunk.c | 212 + + gas/config/obj-amigahunk.h | 54 + + gas/config/obj-elf.c | 4 +- + gas/config/tc-i386.h | 15 +- + gas/config/tc-m68k.c | 312 +- + gas/config/tc-m68k.h | 15 + + gas/config/tc-ppc.c | 36 +- + gas/config/tc-sh.c | 28 +- + gas/config/te-amiga.h | 24 + + gas/config/te-amigaos.h | 14 + + gas/config/{te-nbsd.h => te-amithlon.h} | 16 +- + gas/config/te-morphos.h | 14 + + gas/configure | 20 + + gas/configure.in | 18 + + gas/configure.tgt | 8 +- + gas/read.c | 21 +- + gas/read.h | 4 + + gas/write.c | 31 +- + gas/write.h | 4 +- + gprof/Makefile.am | 2 +- + gprof/Makefile.in | 2 +- + gprof/configure | 13 + + gprof/configure.in | 11 + + gprof/gconfig.in | 4 - + include/elf/amigaos.h | 27 + + include/elf/ppc.h | 12 + + include/libiberty.h | 2 +- + ld/ChangeLog-9197 | 15 + + ld/ChangeLog-9899 | 5 + + ld/Makefile.am | 38 + + ld/Makefile.in | 46 + + ld/configure.host | 4 + + ld/configure.tgt | 9 + + ld/emulparams/amiga.sh | 6 + + ld/emulparams/amiga_bss.sh | 6 + + ld/emulparams/amigaos.sh | 26 + + ld/emulparams/amithlon.sh | 11 + + ld/emulparams/morphos.sh | 6 + + ld/emulparams/morphos_baserel.sh | 6 + + ld/emulparams/ppcamiga.sh | 8 + + ld/emulparams/ppcamiga_bss.sh | 8 + + ld/emultempl/amiga.em | 288 + + ld/emultempl/{elf32.em => amigaos.em} | 0 + ld/emultempl/amithlon.em | 1698 +++++ + ld/emultempl/morphos.em | 1104 ++++ + ld/emultempl/ppc32elf.em | 12 + + ld/ldctor.c | 18 +- + ld/ldfile.c | 54 +- + ld/ldfile.h | 5 + + ld/ldlang.c | 7 + + ld/ldlang.h | 2 + + ld/ldlex.c | 127 +- + ld/ldmain.c | 7 + + ld/scripttempl/amiga.sc | 49 + + ld/scripttempl/amiga_bss.sc | 41 + + ld/scripttempl/{elf64hppa.sc => amigaos.sc} | 132 +- + ld/scripttempl/{mep.sc => amithlon.sc} | 145 +- + ld/scripttempl/{elfi370.sc => morphos.sc} | 57 +- + ld/scripttempl/{elfi370.sc => morphos_baserel.sc} | 108 +- + libiberty/config/mh-amigaos | 12 + + libiberty/config/mh-morphos | 12 + + libiberty/lrealpath.c | 6 + + opcodes/m68k-dis.c | 2 +- + 109 files changed, 20966 insertions(+), 641 deletions(-) + create mode 100644 bfd/amigaos.c + create mode 100644 bfd/amigaoslink.c + create mode 100644 bfd/aout-amiga.c + create mode 100644 bfd/elf32-amiga.c + copy bfd/{elf32-ppc.c => elf32-amigaos.c} (97%) + create mode 100644 bfd/elf32-i386-amithlon.c + create mode 100644 bfd/elf32-morphos.c + create mode 100644 bfd/hosts/amigaos.h + create mode 100644 bfd/hosts/morphos.h + create mode 100644 bfd/libamiga.h + create mode 100644 config/mh-amigaos + create mode 100644 config/mh-morphos + create mode 100644 gas/config/obj-amigahunk.c + create mode 100644 gas/config/obj-amigahunk.h + create mode 100644 gas/config/te-amiga.h + create mode 100644 gas/config/te-amigaos.h + copy gas/config/{te-nbsd.h => te-amithlon.h} (65%) + create mode 100644 gas/config/te-morphos.h + create mode 100644 include/elf/amigaos.h + create mode 100644 ld/emulparams/amiga.sh + create mode 100644 ld/emulparams/amiga_bss.sh + create mode 100644 ld/emulparams/amigaos.sh + create mode 100644 ld/emulparams/amithlon.sh + create mode 100644 ld/emulparams/morphos.sh + create mode 100644 ld/emulparams/morphos_baserel.sh + create mode 100644 ld/emulparams/ppcamiga.sh + create mode 100644 ld/emulparams/ppcamiga_bss.sh + create mode 100644 ld/emultempl/amiga.em + copy ld/emultempl/{elf32.em => amigaos.em} (100%) + create mode 100644 ld/emultempl/amithlon.em + create mode 100644 ld/emultempl/morphos.em + create mode 100644 ld/scripttempl/amiga.sc + create mode 100644 ld/scripttempl/amiga_bss.sc + copy ld/scripttempl/{elf64hppa.sc => amigaos.sc} (88%) + copy ld/scripttempl/{mep.sc => amithlon.sc} (76%) + copy ld/scripttempl/{elfi370.sc => morphos.sc} (88%) + copy ld/scripttempl/{elfi370.sc => morphos_baserel.sc} (69%) + create mode 100644 libiberty/config/mh-amigaos + create mode 100644 libiberty/config/mh-morphos + +diff --git a/bfd/ChangeLog-9697 b/bfd/ChangeLog-9697 +index e9a5c1d60a313aaf09d1a8add619022cfdf575fa..1c2bb3f3c91d32e8b95f8b0cf16b98c58cde454b 100644 +--- a/bfd/ChangeLog-9697 ++++ b/bfd/ChangeLog-9697 +@@ -46,12 +46,19 @@ Mon Dec 22 13:20:57 1997 Ian Lance Taylor <ian@cygnus.com> + + Mon Dec 22 13:04:33 1997 Joel Sherrill <joel@oarcorp.com> + + * config.bfd (i[3456]86*-go32-rtems*): Fix to be the same as + i[3456]86-go32. + ++Fri Dec 19 14:25:58 1997 Daniel Verite <daniel@brainstorm.fr> ++ ++ * amigaos.c (amiga_bfd_copy_private_section_data): Add return ++ value. ++ * amigaoslink.c (amiga_final_link): Update linker_mark fields for ++ input sections involved in the output. ++ + Thu Dec 18 16:01:25 1997 Doug Evans <devans@canuck.cygnus.com> + + * configure: Regenerate to get @SHELL@ substituted. + + Wed Dec 17 09:45:09 1997 Nick Clifton <nickc@cygnus.com> + +@@ -594,12 +601,22 @@ Tue Sep 23 19:03:13 1997 Ian Lance Taylor <ian@cygnus.com> + + * elf.c (map_sections_to_segments): Even if we are not demand + paged, don't put a loadable section after a nonloadable section. + (assign_file_positions_for_segments): Increment the file offset + for a section with contents, even if it is not loadable. + ++Tue Sep 23 09:46:10 1997 Fred Fish <fnf@ninemoons.com> ++ ++ * amigaos.c (alloca): Only declare if not defined as macro. ++ ++Mon Sep 22 10:15:30 1997 Fred Fish <fnf@ninemoons.com> ++ ++ * amigaos.c (sysdep.h): Relocate include to provided needed ++ <sys/types.h> file. ++ * amigaoslink.c (sysdep.h): Ditto, and remove <sys/types.h>. ++ + Sun Sep 21 11:03:24 1997 Nick Clifton <nickc@cygnus.com> + + * elf32-v850.c (v850_elf_final_link_relocate): Add return code + indicating that __ctbp could not be found. + + Thu Sep 18 15:04:57 1997 Nick Clifton <nickc@cygnus.com> +@@ -764,12 +781,18 @@ Tue Aug 26 17:26:51 1997 Ian Lance Taylor <ian@cygnus.com> + * doc/Makefile.am (MKDOC): Use EXEEXT_FOR_BUILD, not EXEEXT. + * aclocal.m4: Rebuild. + * configure: Rebuild. + * Makefile.in: Rebuild. + * doc/Makefile.in: Rebuild. + ++Mon Aug 25 16:32:00 1997 Steffen Opel <opel@rumms.uni-mannheim.de> ++ ++ * Makefile.in (guide, install-guide, clean-guide, bfd.guide): ++ New targets for AmigaGuide documentation. ++ (install): Add install-info and install-guide. ++ + Mon Aug 25 16:14:34 1997 Christopher Provenzano <proven@cygnus.com> + + * configure: Rebuild with latest devo autoconf for NT support + + Mon Aug 25 16:11:04 1997 Nick Clifton <nickc@cygnus.com> + +@@ -3764,12 +3787,18 @@ Fri Aug 30 11:49:19 1996 Ian Lance Taylor <ian@cygnus.com> + page before checking D_PAGED. + + * ihex.c (ihex_scan): Removed unnecessary extbase variable. + (ihex_write_object_contents): Remove extbase; always use segbase + instead. + ++Thu Aug 29 17:53:51 1996 Daniel Verite <daniel@brainstorm.eu.org> ++ ++ * amigaos.c (amiga_get_section_contents): Handle sections that ++ are larger than their disksize. ++ (amiga_make_unique_section): Remove infinite loop. ++ + Thu Aug 29 16:52:17 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * configure.in (i[345]86-*-*): Recognize i686 for pentium pro. + * configure.host (i[345]86-*-*): Ditto. + * config.bfd (i[345]86-*-*): Ditto. + * configure: Regenerate. +@@ -3989,12 +4018,19 @@ Mon Aug 5 13:42:41 1996 Ian Lance Taylor <ian@cygnus.com> + * elf.c (map_sections_to_segments): Rewrite tests for starting a + new segment to make them more comprehensible. If the relationship + between the LMA and the VMA changed, start a new segment. Don't + check dynsec when deciding whether to start a new segment for a + writeable section; -N will now handle this. + ++Sun Aug 4 22:15:56 1996 Fred Fish <fnf@ninemoons.com> ++ ++ * amigaoslink.c (sys/types.h): Include before genlink.h to get ++ definition for size_t which is used in genlink.h. This was not ++ getting defined during a cross compilation on alpha-dec-osf2.0 for ++ some reason. ++ + Thu Aug 1 22:43:08 1996 Jeffrey A Law (law@cygnus.com) + + * libhppa.h: Remove "esel" changes. Not the right approach. + * som.c: Corresponding changes. + (som_bfd_derive_misc_symbol_info): Use ST_DATA for symbols + which don't have a SOM symbol type associated with them. +@@ -4085,12 +4121,17 @@ Mon Jul 22 15:30:30 1996 Ian Lance Taylor <ian@cygnus.com> + + Fri Jul 19 18:15:51 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Fix test for whether a compiler has a 64 bit + type. From Jim Wilson <wilson@cygnus.com>. + ++Thu Jul 18 16:58:11 1996 Daniel Verite <daniel@brainstorm.eu.org> ++ ++ * amigaoslink.c (aout_perform_reloc): Fix baserel 16 bits relocs. ++ (my_add_to): Fix sign bug in extraction of 16 bits values. ++ + Thu Jul 18 15:39:10 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.host (mips-sgi-irix6*): New host. + + * configure.in: Set and substitute VERSION, BFD_HOST_64BIT_LONG + (replacing HOST_64BITLONG), BFD_HOST_64_BIT_DEFINED, +@@ -4214,12 +4255,17 @@ Mon Jul 8 16:18:03 1996 Ian Lance Taylor <ian@cygnus.com> + (mips_relhi_addr, mips_relhi_addend): Remove. + (mips_relhi_reloc): Maintain a list of unmatched RELHI relocs. + (mips_rello_reloc): Process mips_relhi_list. + (mips_relocate_section): Permit an arbitrary number of REFHI or + RELHI relocs before the associated REFLO or RELLO reloc. + ++Sun Jul 7 12:15:39 1996 Kamil Iskra <iskra@student.uci.agh.edu.pl> ++ ++ * amigaos.c (amiga_write_symbols): Fix Daniel's workaround for ++ outputting long symbol names. ++ + Fri Jul 5 19:27:49 1996 Ian Lance Taylor <ian@cygnus.com> + + * aout-target.h (MY(callback)): Set reloc_count fields. + + Thu Jul 4 12:00:37 1996 Ian Lance Taylor <ian@cygnus.com> + +@@ -4293,12 +4339,17 @@ Fri Jun 28 11:17:00 1996 Richard Henderson <rth@tamu.edu> + (elf64_alpha_link_hash_newfunc): Initialize flags field. + (elf64_alpha_check_relocs): Record types of LITUSE entries that + are found for LITERAL relocs. + (elf64_alpha_adjust_dynamic_symbol): If a symbol has its address + taken, we cannot generate a .plt entry for the symbol. + ++Thu Jun 27 17:35:32 1996 Daniel Verite <daniel@brainstorm.eu.org> ++ ++ * amigaos.c (amiga_write_object_contents): Don't output symbols ++ which are not attached to any section, such as indirect symbols. ++ + Thu Jun 27 11:24:29 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Add AC_ISC_POSIX, and check for setitimer and + sysconf functions (for gprof). + * configure, config.in: Rebuild. + +@@ -4522,12 +4573,25 @@ Wed Jun 12 11:16:37 1996 Ian Lance Taylor <ian@cygnus.com> + Tue Jun 11 15:24:48 1996 Ian Lance Taylor <ian@cygnus.com> + + * xcofflink.c (xcoff_build_ldsyms): Set XCOFF_DEF_REGULAR for a + common symbol defined by the linker. Don't export function code + even if export_defineds is set. + ++Tue Jun 11 12:52:10 1996 Daniel Verite <daniel@brainstorm.eu.org> ++ ++ * amigaoslink.c (mygeta4): Function removed. ++ (amiga_final_link): Search for ___a4_init symbol in the global hash ++ table and cache its value in the backend data. ++ ++ * amigaos.c (write_longs): Return a boolean instead of the ++ number of longs written. ++ (write_section_contents): Split reloc hunks at 0xffff entries. ++ (amiga_write_symbols): Cut the names in hunk symbols at 124 characters ++ (workaround for an amigaos bug). ++ (amiga_handle_rest): Added a sanity check in reloc hunks parsing. ++ + Mon Jun 10 11:57:27 1996 Jeffrey A Law (law@cygnus.com) + + * coff-h8300.c (howto_table): Add new entries for R_BCC_INV + and R_JMP_DEL. + (rtype2howto): Handle R_BCC_INV and R_JMP_DEL. + (h8300_symbol_address_p): New function. +diff --git a/bfd/ChangeLog-9899 b/bfd/ChangeLog-9899 +index 6d7f5cd616db22097b8238d8686f60484c9e6ee6..6e25901995a73646a13037d32c14563df20f74b3 100644 +--- a/bfd/ChangeLog-9899 ++++ b/bfd/ChangeLog-9899 +@@ -5570,12 +5570,17 @@ Wed Jan 21 21:16:06 1998 Manfred Hollstein <manfred@s-direktnet.de> + (GET_SCNDHR_NLNNO): Likewise. + + Mon Jan 19 12:49:52 1998 Ian Lance Taylor <ian@cygnus.com> + + * cpu-sh.c (arch_info_struct): Correct next field of sh3e. + ++Sun Jan 18 10:39:52 1998 Daniel Verite <daniel@brainstorm.fr> ++ ++ * amigaos.c (CAN_WRITE_OUTSYM): New macro. ++ (amiga_write_object_contents): Use CAN_WRITE_OUTSYM ++ + Wed Jan 14 17:23:27 1998 Nick Clifton <nickc@cygnus.com> + + * elf32-m32r.c: Add macros to handle NOP insertion. + + Wed Jan 14 16:15:22 1998 Richard Henderson <rth@cygnus.com> + +diff --git a/bfd/Makefile.am b/bfd/Makefile.am +index 9ab2aa947a0a96ba5a469652c579a4d181793646..c224a3cecc392df96a6bc20c8dc73eb81c677269 100644 +--- a/bfd/Makefile.am ++++ b/bfd/Makefile.am +@@ -232,13 +232,16 @@ ALL_MACHINES_CFILES = \ + cpu-z80.c \ + cpu-z8k.c + + # The .o files needed by all of the 32 bit vectors that are configured into + # target_vector in targets.c if configured with --enable-targets=all. + BFD32_BACKENDS = \ ++ amigaos.lo \ ++ amigaoslink.lo \ + aout-adobe.lo \ ++ aout-amiga.lo \ + aout-arm.lo \ + aout-cris.lo \ + aout-ns32k.lo \ + aout-sparcle.lo \ + aout-tic30.lo \ + aout0.lo \ +@@ -287,12 +290,13 @@ BFD32_BACKENDS = \ + elf-strtab.lo \ + elf-vxworks.lo \ + elf.lo \ + elf32-am33lin.lo \ + elf32-arc.lo \ + elf32-arm.lo \ ++ elf32-amigaos.lo \ + elf32-avr.lo \ + elf32-bfin.lo \ + elf32-cr16.lo \ + elf32-cr16c.lo \ + elf32-cris.lo \ + elf32-crx.lo \ +@@ -320,12 +324,13 @@ BFD32_BACKENDS = \ + elf32-m68k.lo \ + elf32-m88k.lo \ + elf32-mcore.lo \ + elf32-mep.lo \ + elf32-microblaze.lo \ + elf32-mips.lo \ ++ elf32-morphos.lo \ + elf32-moxie.lo \ + elf32-msp430.lo \ + elf32-mt.lo \ + elf32-openrisc.lo \ + elf32-or32.lo \ + elf32-pj.lo \ +@@ -420,13 +425,16 @@ BFD32_BACKENDS = \ + xcofflink.lo \ + xsym.lo \ + xtensa-isa.lo \ + xtensa-modules.lo + + BFD32_BACKENDS_CFILES = \ ++ amigaos.c \ ++ amigaoslink.c \ + aout-adobe.c \ ++ aout-amiga.c \ + aout-arm.c \ + aout-cris.c \ + aout-ns32k.c \ + aout-sparcle.c \ + aout-tic30.c \ + aout0.c \ +@@ -475,12 +483,13 @@ BFD32_BACKENDS_CFILES = \ + elf-strtab.c \ + elf-vxworks.c \ + elf.c \ + elf32-am33lin.c \ + elf32-arc.c \ + elf32-arm.c \ ++ elf32-amigaos.c \ + elf32-avr.c \ + elf32-bfin.c \ + elf32-cr16.c \ + elf32-cr16c.c \ + elf32-cris.c \ + elf32-crx.c \ +@@ -508,12 +517,13 @@ BFD32_BACKENDS_CFILES = \ + elf32-m68k.c \ + elf32-m88k.c \ + elf32-mcore.c \ + elf32-mep.c \ + elf32-microblaze.c \ + elf32-mips.c \ ++ elf32-morphos.c \ + elf32-moxie.c \ + elf32-msp430.c \ + elf32-mt.c \ + elf32-openrisc.c \ + elf32-or32.c \ + elf32-pj.c \ +@@ -745,13 +755,13 @@ CFILES = $(SOURCE_CFILES) $(BUILD_CFILES) + + ## This is a list of all .h files which are in the source tree. + SOURCE_HFILES = \ + aout-target.h aoutf1.h aoutx.h coffcode.h coffswap.h ecoffswap.h \ + elf-bfd.h elf-hppa.h elf32-hppa.h \ + elf64-hppa.h elfcode.h elfcore.h \ +- freebsd.h genlink.h go32stub.h \ ++ freebsd.h genlink.h go32stub.h libamiga.h \ + libaout.h libbfd.h libcoff.h libecoff.h libhppa.h libieee.h \ + libnlm.h liboasys.h libpei.h libxcoff.h mach-o.h \ + netbsd.h nlm-target.h nlmcode.h nlmswap.h ns32k.h \ + pef.h pef-traceback.h peicode.h som.h version.h \ + vms.h xsym.h + +@@ -1013,12 +1023,6 @@ coff-tic4x.lo: coff-tic4x.c + @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR) + @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo + @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< $(NO_WERROR) + +-coff-tic54x.lo: coff-tic54x.c +-@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR) +-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +-@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< $(NO_WERROR) +diff --git a/bfd/Makefile.in b/bfd/Makefile.in +index 99902757111d8011447cde1dda030e5a9c817ff2..bcdf435a15eb144bca66d8bfe04122a45e647446 100644 +--- a/bfd/Makefile.in ++++ b/bfd/Makefile.in +@@ -532,13 +532,16 @@ ALL_MACHINES_CFILES = \ + cpu-z8k.c + + + # The .o files needed by all of the 32 bit vectors that are configured into + # target_vector in targets.c if configured with --enable-targets=all. + BFD32_BACKENDS = \ ++ amigaos.lo \ ++ amigaoslink.lo \ + aout-adobe.lo \ ++ aout-amiga.lo \ + aout-arm.lo \ + aout-cris.lo \ + aout-ns32k.lo \ + aout-sparcle.lo \ + aout-tic30.lo \ + aout0.lo \ +@@ -587,12 +590,13 @@ BFD32_BACKENDS = \ + elf-strtab.lo \ + elf-vxworks.lo \ + elf.lo \ + elf32-am33lin.lo \ + elf32-arc.lo \ + elf32-arm.lo \ ++ elf32-amigaos.lo \ + elf32-avr.lo \ + elf32-bfin.lo \ + elf32-cr16.lo \ + elf32-cr16c.lo \ + elf32-cris.lo \ + elf32-crx.lo \ +@@ -620,12 +624,13 @@ BFD32_BACKENDS = \ + elf32-m68k.lo \ + elf32-m88k.lo \ + elf32-mcore.lo \ + elf32-mep.lo \ + elf32-microblaze.lo \ + elf32-mips.lo \ ++ elf32-morphos.lo \ + elf32-moxie.lo \ + elf32-msp430.lo \ + elf32-mt.lo \ + elf32-openrisc.lo \ + elf32-or32.lo \ + elf32-pj.lo \ +@@ -720,13 +725,16 @@ BFD32_BACKENDS = \ + xcofflink.lo \ + xsym.lo \ + xtensa-isa.lo \ + xtensa-modules.lo + + BFD32_BACKENDS_CFILES = \ ++ amigaos.c \ ++ amigaoslink.c \ + aout-adobe.c \ ++ aout-amiga.c \ + aout-arm.c \ + aout-cris.c \ + aout-ns32k.c \ + aout-sparcle.c \ + aout-tic30.c \ + aout0.c \ +@@ -775,12 +783,13 @@ BFD32_BACKENDS_CFILES = \ + elf-strtab.c \ + elf-vxworks.c \ + elf.c \ + elf32-am33lin.c \ + elf32-arc.c \ + elf32-arm.c \ ++ elf32-amigaos.c \ + elf32-avr.c \ + elf32-bfin.c \ + elf32-cr16.c \ + elf32-cr16c.c \ + elf32-cris.c \ + elf32-crx.c \ +@@ -808,12 +817,13 @@ BFD32_BACKENDS_CFILES = \ + elf32-m68k.c \ + elf32-m88k.c \ + elf32-mcore.c \ + elf32-mep.c \ + elf32-microblaze.c \ + elf32-mips.c \ ++ elf32-morphos.c \ + elf32-moxie.c \ + elf32-msp430.c \ + elf32-mt.c \ + elf32-openrisc.c \ + elf32-or32.c \ + elf32-pj.c \ +@@ -1046,13 +1056,13 @@ BUILD_CFILES = \ + + CFILES = $(SOURCE_CFILES) $(BUILD_CFILES) + SOURCE_HFILES = \ + aout-target.h aoutf1.h aoutx.h coffcode.h coffswap.h ecoffswap.h \ + elf-bfd.h elf-hppa.h elf32-hppa.h \ + elf64-hppa.h elfcode.h elfcore.h \ +- freebsd.h genlink.h go32stub.h \ ++ freebsd.h genlink.h go32stub.h libamiga.h \ + libaout.h libbfd.h libcoff.h libecoff.h libhppa.h libieee.h \ + libnlm.h liboasys.h libpei.h libxcoff.h mach-o.h \ + netbsd.h nlm-target.h nlmcode.h nlmswap.h ns32k.h \ + pef.h pef-traceback.h peicode.h som.h version.h \ + vms.h xsym.h + +@@ -1215,13 +1225,16 @@ mostlyclean-compile: + + distclean-compile: + -rm -f *.tab.c + + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix386-core.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix5ppc-core.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amigaos.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amigaoslink.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-adobe.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-amiga.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-arm.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-cris.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-ns32k.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-sparcle.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-tic30.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout0.Plo@am__quote@ +@@ -1365,12 +1378,13 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-m10300.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-nacl.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-strtab.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-vxworks.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-am33lin.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-amigaos.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-arc.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-arm.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-avr.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-bfin.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-cr16.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-cr16c.Plo@am__quote@ +@@ -1401,12 +1415,13 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68k.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m88k.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mcore.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mep.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-microblaze.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mips.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-morphos.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-moxie.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-msp430.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mt.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-openrisc.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-or32.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-pj.Plo@am__quote@ +@@ -2065,16 +2080,9 @@ coff-tic4x.lo: coff-tic4x.c + @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR) + @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo + @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< $(NO_WERROR) + +-coff-tic54x.lo: coff-tic54x.c +-@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR) +-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +-@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< $(NO_WERROR) +- + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: +diff --git a/bfd/amigaos.c b/bfd/amigaos.c +new file mode 100644 +index 0000000000000000000000000000000000000000..9d715d64d458e6599c19ed65fbb61c253d2ab208 +--- /dev/null ++++ b/bfd/amigaos.c +@@ -0,0 +1,3189 @@ ++/* BFD back-end for Commodore-Amiga AmigaOS binaries. ++ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 ++ Free Software Foundation, Inc. ++ Contributed by Leonard Norrgard. Partially based on the bout ++ and ieee BFD backends and Markus Wild's tool hunk2gcc. ++ Revised and updated by Stephan Thesing. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++ ++/* ++SECTION ++ amiga back end ++ ++This section describes the overall structure of the Amiga BFD back end. ++The linker stuff can be found in @xref{amigalink}. ++@menu ++@* implementation:: ++@* amigalink:: ++@end menu ++ ++INODE ++implementation, amigalink, amiga, amiga ++ ++SECTION ++ implementation ++ ++The need for a port of the bfd library for Amiga style object (hunk) files ++arose by the desire to port the GNU debugger gdb to the Amiga. ++Also, the linker ld should be updated to the current version (2.5.2). ++@@* ++This port bases on the work done by Leonard Norrgard, who started porting ++gdb. Raphael Luebbert, who supports the ixemul.library, has also worked on ++implementing the needed @code{ptrace()} system call and gas2.5. ++ ++@menu ++@* not supported:: ++@* Does it work?:: ++@* TODO:: ++@end menu ++ ++INODE ++not supported, Does it work?, implementation, implementation ++ ++SUBSECTION ++ not supported ++ ++Currently, the implementation does not support Amiga link library files, like ++e.g. amiga.lib. This may be added in a later version, if anyone starts work ++on it, or I find some time for it. ++ ++The handling of the symbols in hunk files is a little bit broken: ++ o The symbols in a load file are totally ignored at the moment, so gdb and gprof ++ do not work. ++ o The symbols of a object module (Hunk file, starting with HUNK_UNIT) are read in ++ correctly, but HUNK_SYMBOL hunks are also ignored. ++ ++The reason for this is the following: ++Amiga symbol hunks do not allow for much information. Only a name and a value are allowed. ++On the other hand, a.out format carries along much more information (see, e.g. the ++entry on set symbols in the ld manual). The old linker copied this information into ++a HUNK_DEBUG hunk. Now there is the choice: ++ o ignoring the debug hunk, read in only HUNK_SYMBOL definitions => extra info is lost. ++ o read in the debug hunk and use the information therein => How can clashs between the ++ information in the debug hunk and HUNK_SYMBOL or HUNK_EXT hunks be avoided? ++I haven't decided yet, what to do about this. ++ ++Although bfd allows to link together object modules of different flavours, ++producing a.out style executables does not work on Amiga :-) ++It should, however, be possible to create a.out files with the -r option of ld ++(incremental link). ++ ++INODE ++Does it work?, TODO, not supported, implementation ++ ++SUBSECTION ++ Does it work? ++ ++Currently, the following utilities work: ++ o objdump ++ o objcopy ++ o strip ++ o nm ++ o ar ++ o gas ++ ++INODE ++TODO, , Does it work?, implementation ++ ++SUBSECTION ++ TODO ++ ++ o fix FIXME:s ++ ++@* ++BFD: ++ o add flag to say if the format allows multiple sections with the ++ same name. Fix bfd_get_section_by_name() and bfd_make_section() ++ accordingly. ++ ++ o dumpobj.c: the disassembler: use relocation record data to find symbolic ++ names of addresses, when available. Needs new routine where one can ++ specify the source section of the symbol to be printed as well as some ++ rewrite of the disassemble functions. ++*/ ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "libbfd.h" ++#include "libamiga.h" ++ ++#define BYTES_IN_WORD 4 ++#include "aout/aout64.h" /* struct external_nlist */ ++ ++#ifndef alloca ++extern PTR alloca PARAMS ((size_t)); ++#endif ++ ++#define bfd_is_bfd_section(sec) \ ++ (bfd_is_abs_section(sec)||bfd_is_com_section(sec)||bfd_is_und_section(sec)||bfd_is_ind_section(sec)) ++ ++struct arch_syms { ++ unsigned long offset; /* disk offset in the archive */ ++ unsigned long size; /* size of the block of symbols */ ++ unsigned long unit_offset; /* start of unit on disk */ ++ struct arch_syms *next; /* linked list */ ++}; ++ ++typedef struct amiga_ardata_struct { ++ /* generic stuff */ ++ struct artdata generic; ++ /* amiga-specific stuff */ ++ unsigned long filesize; ++ struct arch_syms *defsyms; ++ unsigned long defsym_count; ++ unsigned long outnum; ++} amiga_ardata_type; ++ ++#define amiga_ardata(bfd) (*(amiga_ardata_type **)(void *)&(bfd)->tdata.aout_ar_data) ++ ++#define bfd_msg (*_bfd_error_handler) ++ ++#define GL(x) bfd_get_32 (abfd, (bfd_byte *) (x)) ++#define GW(x) bfd_get_16 (abfd, (bfd_byte *) (x)) ++#define LONGSIZE(l) (((l)+3) >> 2) ++ ++/* AmigaOS doesn't like HUNK_SYMBOL with symbol names longer than 124 characters */ ++#define MAX_NAME_SIZE 124 ++ ++static bfd_boolean get_long PARAMS ((bfd *, unsigned long *)); ++static const struct bfd_target *amiga_object_p PARAMS ((bfd *)); ++static sec_ptr amiga_get_section_by_hunk_number PARAMS ((bfd *, long)); ++static bfd_boolean amiga_add_reloc PARAMS ((bfd *, sec_ptr, bfd_size_type, ++ amiga_symbol_type *, reloc_howto_type *, long)); ++static sec_ptr amiga_make_unique_section PARAMS ((bfd *, const char *)); ++static bfd_boolean parse_archive_units PARAMS ((bfd *, int *, unsigned long, ++ bfd_boolean, struct arch_syms **, symindex *)); ++static bfd_boolean amiga_digest_file PARAMS ((bfd *)); ++static bfd_boolean amiga_read_unit PARAMS ((bfd *, unsigned long)); ++static bfd_boolean amiga_read_load PARAMS ((bfd *)); ++static bfd_boolean amiga_handle_cdb_hunk PARAMS ((bfd *, unsigned long, ++ unsigned long, unsigned long, unsigned long)); ++static bfd_boolean amiga_handle_rest PARAMS ((bfd *, sec_ptr, bfd_boolean)); ++static bfd_boolean amiga_mkobject PARAMS ((bfd *)); ++static bfd_boolean amiga_mkarchive PARAMS ((bfd *)); ++static bfd_boolean write_longs PARAMS ((const unsigned long *, unsigned long, ++ bfd *)); ++static long determine_datadata_relocs PARAMS ((bfd *, sec_ptr)); ++static void remove_section_index PARAMS ((sec_ptr, int *)); ++static bfd_boolean amiga_write_object_contents PARAMS ((bfd *)); ++static bfd_boolean write_name PARAMS ((bfd *, const char *, unsigned long)); ++static bfd_boolean amiga_write_archive_contents PARAMS ((bfd *)); ++static bfd_boolean amiga_write_armap PARAMS ((bfd *, unsigned int, ++ struct orl *, unsigned int, int)); ++static int determine_type PARAMS ((arelent *)); ++static bfd_boolean amiga_write_section_contents PARAMS ((bfd *, sec_ptr, ++ sec_ptr, unsigned long, int *, int)); ++static bfd_boolean amiga_write_symbols PARAMS ((bfd *, sec_ptr)); ++static bfd_boolean amiga_get_section_contents PARAMS ((bfd *, sec_ptr, PTR, ++ file_ptr, bfd_size_type)); ++static bfd_boolean amiga_new_section_hook PARAMS ((bfd *, sec_ptr)); ++static bfd_boolean amiga_slurp_symbol_table PARAMS ((bfd *)); ++static long amiga_get_symtab_upper_bound PARAMS ((bfd *)); ++static long amiga_get_symtab PARAMS ((bfd *, asymbol **)); ++static asymbol *amiga_make_empty_symbol PARAMS ((bfd *)); ++static void amiga_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *)); ++static void amiga_print_symbol PARAMS ((bfd *, PTR, asymbol *, ++ bfd_print_symbol_type)); ++static long amiga_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); ++static bfd_boolean read_raw_relocs PARAMS ((bfd *, sec_ptr, unsigned long, ++ unsigned long)); ++static bfd_boolean amiga_slurp_relocs PARAMS ((bfd *, sec_ptr, asymbol **)); ++static long amiga_canonicalize_reloc PARAMS ((bfd *, sec_ptr, arelent **, ++ asymbol **)); ++static bfd_boolean amiga_set_section_contents PARAMS ((bfd *, sec_ptr, PTR, ++ file_ptr, bfd_size_type)); ++static bfd_boolean amiga_set_arch_mach PARAMS ((bfd *, enum bfd_architecture, ++ unsigned long)); ++static int amiga_sizeof_headers PARAMS ((bfd *, bfd_boolean)); ++static bfd_boolean amiga_find_nearest_line PARAMS ((bfd *, sec_ptr, ++ asymbol **, bfd_vma, const char **, const char **, unsigned int *)); ++static reloc_howto_type *amiga_bfd_reloc_type_lookup PARAMS ((bfd *, ++ bfd_reloc_code_real_type)); ++static bfd_boolean amiga_bfd_copy_private_bfd_data PARAMS ((bfd *, bfd *)); ++static bfd_boolean amiga_bfd_copy_private_section_data PARAMS ((bfd *, ++ sec_ptr, bfd *, sec_ptr)); ++static bfd_boolean amiga_slurp_armap PARAMS ((bfd *)); ++static void amiga_truncate_arname PARAMS ((bfd *, const char *, char *)); ++static const struct bfd_target *amiga_archive_p PARAMS ((bfd *)); ++static bfd *amiga_openr_next_archived_file PARAMS ((bfd *, bfd *)); ++static PTR amiga_read_ar_hdr PARAMS ((bfd *)); ++static int amiga_generic_stat_arch_elt PARAMS ((bfd *, struct stat *)); ++ ++/*#define DEBUG_AMIGA 1*/ ++#if DEBUG_AMIGA ++#include <stdarg.h> ++static void ++error_print (const char *fmt, ...) ++{ ++ va_list args; ++ va_start (args, fmt); ++ vfprintf (stderr, fmt, args); ++ va_end (args); ++} ++#define DPRINT(L,x) if (L>=DEBUG_AMIGA) error_print x ++#else ++#define DPRINT(L,x) ++#endif ++ ++enum {R_ABS32=0,R_PC16,R_PC8,R_SD32,R_SD16,R_SD8,R_ABS32SHORT,R_PC26,R_PC32,R__MAX}; ++static reloc_howto_type howto_table[R__MAX] = ++{ ++ {H_ABS32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield,/* complain_on_overflow */ ++ 0, /* special_function */ ++ "RELOC32", /* textual name */ ++ FALSE, /* partial_inplace */ ++ 0xffffffff, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE}, /* pcrel_offset */ ++ {H_PC16, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0, "RELRELOC16", FALSE, 0x0000ffff, 0x0000ffff, TRUE}, ++ {H_PC8, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0, "RELRELOC8", FALSE, 0x000000ff, 0x000000ff, TRUE}, ++ {H_SD32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "DREL32", FALSE, 0xffffffff, 0xffffffff, FALSE}, ++ {H_SD16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "DREL16", FALSE, 0x0000ffff, 0x0000ffff, FALSE}, ++ {H_SD8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "DREL8", FALSE, 0x000000ff, 0x000000ff, FALSE}, ++ {H_ABS32SHORT, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "RELOC32SHORT", FALSE, 0x0000ffff, 0x0000ffff, FALSE}, ++ {H_PC26, 0, 2, 26, TRUE, 0, complain_overflow_signed, 0, "RELRELOC26", FALSE, 0x03fffffc, 0x03fffffc, TRUE}, ++ {H_PC32, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0, "RELRELOC32", FALSE, 0xffffffff, 0xffffffff, TRUE} ++}; ++ ++/* The following are gross hacks that need to be fixed. The problem is ++ that the linker unconditionally references these values without ++ going through any of bfd's standard interface. Thus they need to ++ be defined in a bfd module that is included in *all* configurations, ++ and are currently in bfd.c, otherwise linking the linker will fail ++ on non-Amiga target configurations. */ ++ ++/* This one is used by the linker and tells us, if a debug hunk should ++ be written out. */ ++extern int write_debug_hunk; ++ ++/* This is also used by the linker to set the attribute of sections. */ ++extern int amiga_attribute; ++ ++/* used with base-relative linking */ ++extern int amiga_base_relative; ++ ++/* used with -resident linking */ ++extern int amiga_resident; ++ ++static bfd_boolean ++get_long (abfd, n) ++ bfd *abfd; ++ unsigned long *n; ++{ ++ if (bfd_bread ((PTR)n, 4, abfd) != 4) ++ return FALSE; ++ *n = GL (n); ++ return TRUE; ++} ++ ++static const struct bfd_target * ++amiga_object_p (abfd) ++ bfd *abfd; ++{ ++ unsigned long x; ++ char buf[8]; ++ ++ /* An Amiga object file must be at least 8 bytes long. */ ++ if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf)) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return NULL; ++ } ++ ++ bfd_seek (abfd, 0, SEEK_SET); ++ ++ /* Does it look like an Amiga object file? */ ++ x = GL (&buf[0]); ++ if ((x != HUNK_UNIT) && (x != HUNK_HEADER)) ++ { ++ /* Not an Amiga file. */ ++ bfd_set_error (bfd_error_wrong_format); ++ return NULL; ++ } ++ ++ /* Can't fail and return (but must be declared bfd_boolean to suit ++ other bfd requirements). */ ++ (void) amiga_mkobject (abfd); ++ ++ AMIGA_DATA(abfd)->IsLoadFile = (x == HUNK_HEADER); ++ ++ if (!amiga_digest_file (abfd)) ++ { ++ /* Something went wrong. */ ++ DPRINT(20,("bfd parser stopped at offset 0x%lx\n",bfd_tell(abfd))); ++ return NULL; ++ } ++ ++ /* Set default architecture to m68k:68000. */ ++ /* So we can link on 68000 AMIGAs... */ ++ abfd->arch_info = bfd_scan_arch ("m68k:68000"); ++ ++ return abfd->xvec; ++} ++ ++static sec_ptr ++amiga_get_section_by_hunk_number (abfd, hunk_number) ++ bfd *abfd; ++ long hunk_number; ++{ ++ /* A cache, so we don't have to search the entire list every time. */ ++ static sec_ptr last_reference; ++ static bfd *last_bfd; ++ sec_ptr p; ++ ++ if (last_reference) ++ if (last_bfd == abfd && last_reference->target_index == hunk_number) ++ return last_reference; ++ for (p = abfd->sections; p != NULL; p = p->next) ++ if (p->target_index == hunk_number) ++ { ++ last_reference = p; ++ last_bfd = abfd; ++ return p; ++ } ++ BFD_FAIL (); ++ return NULL; ++} ++ ++static bfd_boolean ++amiga_add_reloc (abfd, section, offset, symbol, howto, target_hunk) ++ bfd *abfd; ++ sec_ptr section; ++ bfd_size_type offset; ++ amiga_symbol_type *symbol; ++ reloc_howto_type *howto; ++ long target_hunk; ++{ ++ amiga_reloc_type *reloc; ++ sec_ptr target_sec; ++ ++ reloc = (amiga_reloc_type *) bfd_alloc (abfd, sizeof (amiga_reloc_type)); ++ if (reloc == NULL) ++ return FALSE; ++ ++ abfd->flags |= HAS_RELOC; ++ section->flags |= SEC_RELOC; ++ ++ if (amiga_per_section(section)->reloc_tail) ++ amiga_per_section(section)->reloc_tail->next = reloc; ++ else ++ section->relocation = &reloc->relent; ++ amiga_per_section(section)->reloc_tail = reloc; ++ ++ reloc->relent.sym_ptr_ptr = &reloc->symbol; ++ reloc->relent.address = offset; ++ reloc->relent.addend = 0; ++ reloc->relent.howto = howto; ++ ++ reloc->next = NULL; ++ if (symbol==NULL) { /* relative to section */ ++ target_sec = amiga_get_section_by_hunk_number (abfd, target_hunk); ++ if (target_sec) ++ reloc->symbol = target_sec->symbol; ++ else ++ return FALSE; ++ } ++ else ++ reloc->symbol = &symbol->symbol; ++ ++ return TRUE; ++} ++ ++/* BFD doesn't currently allow multiple sections with the same ++ name, so we try a little harder to get a unique name. */ ++static sec_ptr ++amiga_make_unique_section (abfd, name) ++ bfd *abfd; ++ const char *name; ++{ ++ sec_ptr section; ++ ++ bfd_set_error (bfd_error_no_error); ++ section = bfd_make_section (abfd, name); ++ if ((section == NULL) && (bfd_get_error() == bfd_error_no_error)) ++ { ++#if 0 ++ char *new_name = bfd_alloc (abfd, strlen(name) + 4); ++ int i = 1; ++ ++ /* We try to come up with an original name (since BFD currently ++ requires all sections to have different names). */ ++ while (!section && (i<=99)) ++ { ++ sprintf (new_name, "%s_%u", name, i++); ++ section = bfd_make_section (abfd, new_name); ++ } ++#else ++ section = bfd_make_section_anyway (abfd, name); ++#endif ++ } ++ return section; ++} ++ ++#if DEBUG_AMIGA ++#define DPRINTHUNK(x) fprintf(stderr,"Processing %s hunk (0x%x)...",\ ++ (x) == HUNK_UNIT ? "HUNK_UNIT" :\ ++ (x) == HUNK_NAME ? "HUNK_NAME" :\ ++ (x) == HUNK_CODE ? "HUNK_CODE" :\ ++ (x) == HUNK_DATA ? "HUNK_DATA" :\ ++ (x) == HUNK_BSS ? "HUNK_BSS" :\ ++ (x) == HUNK_ABSRELOC32 ? "HUNK_RELOC32" :\ ++ (x) == HUNK_RELRELOC16 ? "HUNK_RELRELOC16" :\ ++ (x) == HUNK_RELRELOC8 ? "HUNK_RELRELOC8" :\ ++ (x) == HUNK_EXT ? "HUNK_EXT" :\ ++ (x) == HUNK_SYMBOL ? "HUNK_SYMBOL" :\ ++ (x) == HUNK_DEBUG ? "HUNK_DEBUG" :\ ++ (x) == HUNK_END ? "HUNK_END" :\ ++ (x) == HUNK_HEADER ? "HUNK_HEADER" :\ ++ (x) == HUNK_OVERLAY ? "HUNK_OVERLAY" :\ ++ (x) == HUNK_BREAK ? "HUNK_BREAK" :\ ++ (x) == HUNK_DREL32 ? "HUNK_DREL32" :\ ++ (x) == HUNK_DREL16 ? "HUNK_DREL16" :\ ++ (x) == HUNK_DREL8 ? "HUNK_DREL8" :\ ++ (x) == HUNK_LIB ? "HUNK_LIB" :\ ++ (x) == HUNK_INDEX ? "HUNK_INDEX" :\ ++ (x) == HUNK_RELOC32SHORT ? "HUNK_RELOC32SHORT" :\ ++ (x) == HUNK_RELRELOC32 ? "HUNK_RELRELOC32" :\ ++ (x) == HUNK_PPC_CODE ? "HUNK_PPC_CODE" :\ ++ (x) == HUNK_RELRELOC26 ? "HUNK_RELRELOC26" :\ ++ "*unknown*",(x)) ++#define DPRINTHUNKEND fprintf(stderr,"done\n") ++#else ++#define DPRINTHUNK(x) ++#define DPRINTHUNKEND ++#endif ++ ++static bfd_boolean ++parse_archive_units (abfd, n_units, filesize, one, syms, symcount) ++ bfd *abfd; ++ int *n_units; ++ unsigned long filesize; ++ bfd_boolean one; /* parse only the first unit? */ ++ struct arch_syms **syms; ++ symindex *symcount; ++{ ++ struct arch_syms *nsyms,*syms_tail=NULL; ++ unsigned long unit_offset,defsym_pos=0; ++ unsigned long hunk_type,type,len,no,n; ++ symindex defsymcount=0; ++ ++ *n_units = 0; ++ while (get_long (abfd, &hunk_type)) { ++ switch (hunk_type) { ++ case HUNK_END: ++ break; ++ case HUNK_UNIT: ++ unit_offset = bfd_tell (abfd) - 4; ++ (*n_units)++; ++ if (one && *n_units>1) { ++ bfd_seek (abfd, -4, SEEK_CUR); ++ return TRUE; ++ } ++ /* Fall through */ ++ case HUNK_NAME: ++ case HUNK_CODE: ++ case HUNK_DATA: ++ case HUNK_DEBUG: ++ case HUNK_PPC_CODE: ++ if (!get_long (abfd, &len) ++ || bfd_seek (abfd, HUNK_VALUE (len) << 2, SEEK_CUR)) ++ return FALSE; ++ break; ++ case HUNK_BSS: ++ if (!get_long (abfd, &len)) ++ return FALSE; ++ break; ++ case HUNK_ABSRELOC32: ++ case HUNK_RELRELOC16: ++ case HUNK_RELRELOC8: ++ case HUNK_SYMBOL: ++ case HUNK_DREL32: ++ case HUNK_DREL16: ++ case HUNK_DREL8: ++ for (;;) { ++ /* read offsets count */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (!no) ++ break; ++ /* skip hunk+offsets */ ++ if (bfd_seek (abfd, (no+1)<<2, SEEK_CUR)) ++ return FALSE; ++ } ++ break; ++ case HUNK_EXT: ++ defsym_pos = 0; ++ if (!get_long (abfd, &n)) ++ return FALSE; ++ while (n) { ++ len = n & 0xffffff; ++ type = (n>>24) & 0xff; ++ switch (type) { ++ case EXT_SYMB: ++ case EXT_DEF: ++ case EXT_ABS: ++ /* retain the positions of defined symbols for each object ++ in the archive. They'll be used later to build a ++ pseudo-armap, which _bfd_generic_link_add_archive_symbols ++ needs */ ++ if (defsym_pos==0) ++ defsym_pos = bfd_tell (abfd) - 4; ++ /* skip name & value */ ++ if (bfd_seek (abfd, (len+1)<<2, SEEK_CUR)) ++ return FALSE; ++ defsymcount++; ++ break; ++ ++ case EXT_ABSREF32: ++ case EXT_RELREF16: ++ case EXT_RELREF8: ++ case EXT_DEXT32: ++ case EXT_DEXT16: ++ case EXT_DEXT8: ++ case EXT_RELREF32: ++ case EXT_RELREF26: ++ /* skip name */ ++ if (bfd_seek (abfd, len<<2, SEEK_CUR)) ++ return FALSE; ++ /* skip references */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (no && bfd_seek (abfd, no<<2, SEEK_CUR)) ++ return FALSE; ++ break; ++ ++ case EXT_ABSCOMMON: ++ case EXT_DEXT32COMMON: ++ case EXT_DEXT16COMMON: ++ case EXT_DEXT8COMMON: ++ /* skip name & value */ ++ if (bfd_seek (abfd, (len+1)<<2, SEEK_CUR)) ++ return FALSE; ++ /* skip references */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (no && bfd_seek (abfd, no<<2, SEEK_CUR)) ++ return FALSE; ++ break; ++ ++ default: /* error */ ++ bfd_msg ("unexpected type %ld(0x%lx) in hunk_ext1 at offset 0x%lx", ++ type, type, bfd_tell (abfd)); ++ return FALSE; ++ } ++ ++ if (!get_long (abfd, &n)) ++ return FALSE; ++ } ++ if (defsym_pos != 0 && syms) { ++ /* there are some defined symbols, keep enough information on ++ them to simulate an armap later on */ ++ nsyms = (struct arch_syms *) bfd_alloc (abfd, sizeof (struct arch_syms)); ++ nsyms->next = NULL; ++ if (syms_tail) ++ syms_tail->next = nsyms; ++ else ++ *syms = nsyms; ++ syms_tail = nsyms; ++ nsyms->offset = defsym_pos; ++ nsyms->size = bfd_tell (abfd) - defsym_pos; ++ nsyms->unit_offset = unit_offset; ++ } ++ break; /* of HUNK_EXT */ ++ ++ default: ++#if 0 ++ bfd_msg ("unexpected hunk 0x%lx at offset 0x%lx", ++ hunk_type, bfd_tell (abfd)); ++#endif ++ return FALSE; ++ } ++ } ++ if (syms && symcount) ++ *symcount = defsymcount; ++ return (bfd_tell (abfd) == filesize); ++} ++ ++static bfd_boolean ++amiga_digest_file (abfd) ++ bfd *abfd; ++{ ++ struct stat stat_buffer; ++ unsigned long tmp; ++ ++ if (!get_long (abfd, &tmp)) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ ++ switch (HUNK_VALUE (tmp)) ++ { ++ case HUNK_UNIT: ++ /* Read the unit(s) */ ++ if (bfd_stat (abfd, &stat_buffer) < 0) ++ return FALSE; ++/* ++ while ((pos=bfd_tell (abfd)) < stat_buffer.st_size) ++ {*/ ++ if (!amiga_read_unit (abfd, stat_buffer.st_size - abfd->origin)) ++ return FALSE; ++ if (abfd->arelt_data) ++ arelt_size (abfd) = bfd_tell (abfd); ++/* }*/ ++ break; ++ ++ case HUNK_HEADER: ++ /* This is a load file */ ++ if (!amiga_read_load (abfd)) ++ return FALSE; ++ break; ++ } ++ ++ return TRUE; ++}/* of amiga_digest_file */ ++ ++ ++/* Read in Unit file */ ++/* file pointer is located after the HUNK_UNIT LW */ ++static bfd_boolean ++amiga_read_unit (abfd, size) ++ bfd *abfd; ++ unsigned long size; ++{ ++ unsigned long hunk_number=0,hunk_type,tmp; ++ ++ /* read LW length of unit's name */ ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ ++ /* and skip it (FIXME maybe) */ ++ if (bfd_seek (abfd, tmp<<2, SEEK_CUR)) ++ return FALSE; ++ ++ while (bfd_tell (abfd) < size) ++ { ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ ++ /* Now there may be CODE, DATA, BSS, SYMBOL, DEBUG, RELOC Hunks */ ++ hunk_type = HUNK_VALUE (tmp); ++ switch (hunk_type) ++ { ++ case HUNK_UNIT: ++ /* next unit, seek back and return */ ++ return (bfd_seek (abfd, -4, SEEK_CUR) == 0); ++ ++ case HUNK_DEBUG: ++ /* we don't parse hunk_debug at the moment */ ++ if (!get_long (abfd, &tmp) || bfd_seek (abfd, tmp<<2, SEEK_CUR)) ++ return FALSE; ++ break; ++ ++ case HUNK_NAME: ++ case HUNK_CODE: ++ case HUNK_DATA: ++ case HUNK_BSS: ++ case HUNK_PPC_CODE: ++ /* Handle this hunk, including relocs, etc. ++ The finishing HUNK_END is consumed by the routine */ ++ if (!amiga_handle_cdb_hunk (abfd, hunk_type, hunk_number++, 0, -1)) ++ return FALSE; ++ break; ++ ++ default: ++ /* Something very nasty happened: invalid hunk occured... */ ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ break; ++ }/* Of switch hunk_type */ ++ ++ /* Next hunk */ ++ } ++ return TRUE; ++} ++ ++ ++/* Read a load file */ ++static bfd_boolean ++amiga_read_load (abfd) ++ bfd *abfd; ++{ ++ unsigned long max_hunk_number,hunk_type,tmp,i; ++ unsigned long *hunk_attributes,*hunk_sizes; ++ char buf[16]; ++ ++ /* Read hunk lengths (and memory attributes...) */ ++ /* Read in each hunk */ ++ ++ if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf)) ++ return FALSE; ++ ++ /* If there are resident libs: abort (obsolete feature) */ ++ if (GL (&buf[0]) != 0) ++ return FALSE; ++ ++ max_hunk_number = GL (&buf[4]); ++ ++ /* Sanity */ ++ if (max_hunk_number<1) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ ++ AMIGA_DATA(abfd)->nb_hunks = max_hunk_number; ++ ++ /* Num of root hunk must be 0 */ ++ if (GL (&buf[8]) != 0) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ ++ /* Num of last hunk must be mhn-1 */ ++ if (GL (&buf[12]) != max_hunk_number-1) ++ { ++ bfd_msg ("Overlay loadfiles are not supported"); ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ ++ hunk_sizes = alloca (max_hunk_number * sizeof (unsigned long)); ++ hunk_attributes = alloca (max_hunk_number * sizeof (unsigned long)); ++ if (hunk_sizes == NULL || hunk_attributes == NULL) ++ { ++ bfd_set_error (bfd_error_no_memory); ++ return FALSE; ++ } ++ ++ /* Now, read in sizes and memory attributes */ ++ for (i=0; i<max_hunk_number; i++) ++ { ++ if (!get_long (abfd, &hunk_sizes[i])) ++ return FALSE; ++ switch (HUNK_ATTRIBUTE (hunk_sizes[i])) ++ { ++ case HUNK_ATTR_CHIP: ++ hunk_attributes[i] = MEMF_CHIP; ++ break; ++ case HUNK_ATTR_FAST: ++ hunk_attributes[i] = MEMF_FAST; ++ break; ++ case HUNK_ATTR_FOLLOWS: ++ if (!get_long (abfd, &hunk_attributes[i])) ++ return FALSE; ++ break; ++ default: ++ hunk_attributes[i] = 0; ++ break; ++ } ++ hunk_sizes[i] = HUNK_VALUE (hunk_sizes[i]) << 2; ++ } ++ ++ for (i=0; i<max_hunk_number; i++) ++ { ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ ++ /* This may be HUNK_NAME, CODE, DATA, BSS, DEBUG */ ++ hunk_type = HUNK_VALUE (tmp); ++ switch (hunk_type) ++ { ++ case HUNK_NAME: ++ case HUNK_CODE: ++ case HUNK_DATA: ++ case HUNK_BSS: ++ case HUNK_PPC_CODE: ++ if (!amiga_handle_cdb_hunk (abfd, hunk_type, i, ++ hunk_attributes[i], hunk_sizes[i])) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ break; ++ ++ case HUNK_DEBUG: ++ if (--i,!amiga_handle_cdb_hunk (abfd, hunk_type, -1, 0, 0)) ++ { ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ } ++ break; ++ ++ default: ++ /* invalid hunk */ ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ break; ++ }/* Of switch */ ++ } ++ ++ return TRUE; ++}/* Of amiga_read_load */ ++ ++ ++/* Handle NAME, CODE, DATA, BSS, DEBUG Hunks */ ++static bfd_boolean ++amiga_handle_cdb_hunk (abfd, hunk_type, hunk_number, hunk_attribute, ++ hunk_size) ++ bfd *abfd; ++ unsigned long hunk_type; ++ unsigned long hunk_number; ++ unsigned long hunk_attribute; ++ unsigned long hunk_size; ++/* If hunk_size==-1, then we are digesting a HUNK_UNIT */ ++{ ++ sec_ptr current_section; ++ char *sec_name,*current_name=NULL; ++ unsigned long len,tmp; ++ int secflags,is_load=(hunk_size!=(unsigned long)-1); ++ ++ if (hunk_type==HUNK_NAME) /* get name */ ++ { ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ ++ len = HUNK_VALUE (tmp) << 2; ++ if (len != 0) ++ { ++ current_name = bfd_alloc (abfd, len+1); ++ if (!current_name) ++ return FALSE; ++ ++ if (bfd_bread (current_name, len, abfd) != len) ++ return FALSE; ++ ++ current_name[len] = '\0'; ++ if (current_name[0] == '\0') ++ { ++ bfd_release (abfd, current_name); ++ current_name = NULL; ++ } ++ } ++ ++ if (!get_long (abfd, &hunk_type)) ++ return FALSE; ++ } ++ ++ /* file_pointer is now after hunk_type */ ++ secflags = 0; ++ switch (hunk_type) ++ { ++ case HUNK_CODE: ++ case HUNK_PPC_CODE: ++ secflags = SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS; ++ sec_name = ".text"; ++ goto do_section; ++ ++ case HUNK_DATA: ++ secflags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS; ++ sec_name = ".data"; ++ goto do_section; ++ ++ case HUNK_BSS: ++ secflags = SEC_ALLOC; ++ sec_name = ".bss"; ++ ++ do_section: ++ if (!current_name) ++ current_name = sec_name; ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ len = HUNK_VALUE (tmp) << 2; /* Length of section */ ++ if (!is_load) ++ { ++ hunk_attribute=HUNK_ATTRIBUTE (len); ++ hunk_attribute=(hunk_attribute==HUNK_ATTR_CHIP)?MEMF_CHIP: ++ (hunk_attribute==HUNK_ATTR_FAST)?MEMF_FAST:0; ++ } ++ ++ /* Make new section */ ++ current_section = amiga_make_unique_section (abfd, current_name); ++ if (!current_section) ++ return FALSE; ++ ++ current_section->filepos = bfd_tell (abfd); ++ /* For a loadfile, the section size in memory comes from the ++ hunk header. The size on disk may be smaller. */ ++ current_section->_cooked_size = current_section->_raw_size = ++ ((hunk_size==(unsigned long)-1) ? len : hunk_size); ++ current_section->target_index = hunk_number; ++ bfd_set_section_flags (abfd, current_section, secflags); ++ ++ amiga_per_section(current_section)->disk_size = len; /* size on disk */ ++ amiga_per_section(current_section)->attribute = hunk_attribute; ++ ++ /* skip the contents */ ++ if ((secflags & SEC_HAS_CONTENTS) && bfd_seek (abfd, len, SEEK_CUR)) ++ return FALSE; ++ ++ if (!amiga_handle_rest (abfd, current_section, is_load)) ++ return FALSE; ++ break; ++ ++ /* Currently, there is one debug hunk per executable, instead of one ++ per unit as it would with a "standard" AmigaOS implementation. So ++ the debug hunk is at the same level as code/data/bss. ++ This will change in the future */ ++ case HUNK_DEBUG: ++ /* format of gnu debug hunk is: ++ HUNK_DEBUG ++ N ++ ZMAGIC ++ symtabsize ++ strtabsize ++ symtabdata [length=symtabsize] ++ strtabdata [length=strtabsize] ++ [pad bytes] ++ */ ++ ++ /* read LW length */ ++ if (!get_long (abfd, &tmp)) ++ return FALSE; ++ len = tmp << 2; ++ if (len > 12) ++ { ++ char buf[12]; ++ if (bfd_bread (buf, sizeof(buf), abfd) != sizeof(buf)) ++ return FALSE; ++ if (GL (&buf[0]) == ZMAGIC) /* GNU DEBUG HUNK */ ++ { ++ amiga_data_type *amiga_data=AMIGA_DATA(abfd); ++ /* FIXME: we should add the symbols in the debug hunk to symtab... */ ++ amiga_data->symtab_size = GL (&buf[4]); ++ amiga_data->stringtab_size = GL (&buf[8]); ++ adata(abfd).sym_filepos = bfd_tell (abfd); ++ adata(abfd).str_filepos = adata(abfd).sym_filepos + ++ amiga_data->symtab_size; ++ } ++ len -= sizeof(buf); ++ } ++ if (bfd_seek (abfd, len, SEEK_CUR)) ++ return FALSE; ++ break; ++ ++ default: ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ break; ++ }/* switch (hunk_type) */ ++ ++ return TRUE; ++}/* Of amiga_handle_cdb_hunk */ ++ ++ ++/* Handle rest of a hunk ++ I.e.: Relocs, EXT, SYMBOLS... */ ++static bfd_boolean ++amiga_handle_rest (abfd, current_section, isload) ++ bfd *abfd; ++ sec_ptr current_section; ++ bfd_boolean isload; ++{ ++ amiga_per_section_type *asect=amiga_per_section(current_section); ++ unsigned long hunk_type,relno,type,len,no; ++ raw_reloc_type *relp; ++ ++ for (relno=0;;) ++ { ++ if (!get_long (abfd, &hunk_type)) ++ return FALSE; ++ switch (hunk_type) ++ { ++ case HUNK_END: ++ if (relno) ++ { ++ abfd->flags |= HAS_RELOC; ++ current_section->flags |= SEC_RELOC; ++ current_section->reloc_count = relno; ++ } ++ return TRUE; ++ break; ++ ++ case HUNK_DREL32: ++ if (isload) ++ hunk_type = HUNK_RELOC32SHORT; ++ case HUNK_ABSRELOC32: ++ case HUNK_RELRELOC16: ++ case HUNK_RELRELOC8: ++ case HUNK_DREL16: ++ case HUNK_DREL8: ++ case HUNK_RELOC32SHORT: ++ /* count and skip relocs */ ++ relp = (raw_reloc_type *) bfd_alloc (abfd, sizeof (*relp)); ++ relp->next = asect->relocs; ++ asect->relocs = relp; ++ relp->pos = bfd_tell (abfd) - 4; ++ relp->num = 0; ++ if (hunk_type != HUNK_RELOC32SHORT) { ++ for (;;) { ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (!no) ++ break; ++ relp->num += no; ++ if (bfd_seek (abfd, (no+1)<<2, SEEK_CUR)) ++ return FALSE; ++ } ++ } ++ else { ++ for (;;) { ++ char buf[2]; ++ if (bfd_bread (buf, 2, abfd) != 2) ++ return FALSE; ++ if (no=GW(buf),!no) ++ break; ++ relp->num += no; ++ if (bfd_seek (abfd, (no+1)<<1, SEEK_CUR)) ++ return FALSE; ++ } ++ if ((bfd_tell (abfd) & 2) && bfd_seek (abfd, 2, SEEK_CUR)) ++ return FALSE; ++ } ++ relno += relp->num; ++ break; ++ ++ case HUNK_SYMBOL: ++ /* In a unit, we ignore these, since all symbol information ++ comes with HUNK_EXT, in a load file, these are added */ ++ if (!isload) ++ { ++ asect->hunk_symbol_pos = bfd_tell (abfd); ++ for (;;) { ++ /* size of symbol */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (!no) ++ break; ++ /* skip the name */ ++ if (bfd_seek (abfd, (no+1)<<2, SEEK_CUR)) ++ return FALSE; ++ } ++ break; ++ } ++ /* We add these, by falling through... */ ++ ++ case HUNK_EXT: ++ /* We leave these alone, until they are requested by the user */ ++ asect->hunk_ext_pos = bfd_tell (abfd); ++ for (;;) ++ { ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (!no) ++ break; ++ ++ /* symbol type and length */ ++ type = (no>>24) & 0xff; ++ len = no & 0xffffff; ++ ++ /* skip symbol name */ ++ if (bfd_seek (abfd, len<<2, SEEK_CUR)) ++ return FALSE; ++ ++ /* We have symbols */ ++ abfd->flags |= HAS_SYMS; ++ abfd->symcount++; ++ ++ switch (type) ++ { ++ case EXT_SYMB: /* Symbol hunks are relative to hunk start... */ ++ case EXT_DEF: /* def relative to hunk */ ++ case EXT_ABS: /* def absolute */ ++ /* skip the value */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ break; ++ ++ case EXT_ABSCOMMON: /* Common ref/def */ ++ case EXT_DEXT32COMMON: ++ case EXT_DEXT16COMMON: ++ case EXT_DEXT8COMMON: ++ /* FIXME: skip the size of common block */ ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ ++ /* Fall through */ ++ ++ case EXT_ABSREF32: /* 32 bit ref */ ++ case EXT_RELREF16: /* 16 bit ref */ ++ case EXT_RELREF8: /* 8 bit ref */ ++ case EXT_DEXT32: /* 32 bit baserel */ ++ case EXT_DEXT16: /* 16 bit baserel */ ++ case EXT_DEXT8: /* 8 bit baserel */ ++ case EXT_RELREF32: ++ case EXT_RELREF26: ++ if (!get_long (abfd, &no)) ++ return FALSE; ++ if (no) ++ { ++ relno += no; ++ /* skip references */ ++ if (bfd_seek (abfd, no<<2, SEEK_CUR)) ++ return FALSE; ++ } ++ break; ++ ++ default: /* error */ ++ bfd_msg ("unexpected type %ld(0x%lx) in hunk_ext2 at offset 0x%lx", ++ type, type, bfd_tell (abfd)); ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ break; ++ }/* of switch type */ ++ } ++ break; ++ ++ case HUNK_DEBUG: ++ /* If a debug hunk is found at this position, the file has ++ been generated by a third party tool and the debug info ++ here are useless to us. Just skip the hunk, then. */ ++ if (!get_long (abfd, &no) || bfd_seek (abfd, no<<2, SEEK_CUR)) ++ return FALSE; ++ break; ++ ++ default: /* error */ ++ bfd_seek (abfd, -4, SEEK_CUR); ++ bfd_msg ("missing HUNK_END: unexpected hunktype %ld(0x%lx) at offset 0x%lx", ++ hunk_type, hunk_type, bfd_tell (abfd)); ++ hunk_type = HUNK_VALUE(hunk_type); ++ if (hunk_type == HUNK_CODE || hunk_type == HUNK_DATA || hunk_type == HUNK_BSS) ++ return TRUE; ++ bfd_set_error (bfd_error_wrong_format); ++ return FALSE; ++ break; ++ }/* Of switch */ ++ }/* Of for */ ++ return TRUE; ++}/* of amiga_handle_rest */ ++ ++static bfd_boolean ++amiga_mkobject (abfd) ++ bfd *abfd; ++{ ++ amiga_data_type *rawptr; ++ rawptr = (amiga_data_type *) bfd_zalloc (abfd, sizeof (*rawptr)); ++ abfd->tdata.amiga_data = rawptr; ++ return (rawptr!=NULL); ++} ++ ++static bfd_boolean ++amiga_mkarchive (abfd) ++ bfd *abfd; ++{ ++ amiga_ardata_type *ar; ++ ar = (amiga_ardata_type *) bfd_zalloc (abfd, sizeof (*ar)); ++ amiga_ardata (abfd) = ar; ++ return (ar!=NULL); ++} ++ ++/* write nb long words (possibly swapped out) to the output file */ ++static bfd_boolean ++write_longs (in, nb, abfd) ++ const unsigned long *in; ++ unsigned long nb; ++ bfd *abfd; ++{ ++ unsigned char out[10*4]; ++ unsigned long i; ++ ++ while (nb) ++ { ++ for (i=0; i<nb && i<10; in++,i++) ++ bfd_putb32 (in[0], &out[i*4]); ++ if (bfd_bwrite ((PTR)out, 4*i, abfd) != 4*i) ++ return FALSE; ++ nb -= i; ++ } ++ return TRUE; ++} ++ ++static long ++determine_datadata_relocs (abfd, section) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ sec_ptr section; ++{ ++ sec_ptr insection; ++ asymbol *sym_p; ++ unsigned int i; ++ long relocs=1; ++ ++ for (i=0;i<section->reloc_count;i++) ++ { ++ arelent *r=section->orelocation[i]; ++ if (r == NULL) ++ continue; ++ sym_p=*(r->sym_ptr_ptr); /* The symbol for this relocation */ ++ insection=sym_p->section; ++ ++ /* Is reloc relative to a special section? */ ++ if (bfd_is_bfd_section(insection)) ++ continue; /* Nothing to do, since this translates to HUNK_EXT */ ++ if (insection->output_section == section) ++ relocs++; ++ } ++ return relocs; ++} ++ ++/* Adjust the indices map when we decide not to output the section <sec> */ ++static void ++remove_section_index (sec, index_map) ++ sec_ptr sec; ++ int *index_map; ++{ ++ int i=sec->index; ++ for (sec=sec->next,index_map[i++]=-1; sec; sec=sec->next) ++ (index_map[i++])--; ++} ++ ++/* Write out the contents of a bfd */ ++static bfd_boolean ++amiga_write_object_contents (abfd) ++ bfd *abfd; ++{ ++ long datadata_relocs=0,bss_size=0,idx; ++ int *index_map,max_hunk=-1; ++ sec_ptr data_sec,p; ++ unsigned long i,n[5]; ++ ++ /* Distinguish UNITS, LOAD Files ++ Write out hunks+relocs+HUNK_EXT+HUNK_DEBUG (GNU format) */ ++ DPRINT(5,("Entering write_object_conts\n")); ++ ++ abfd->output_has_begun=TRUE; /* Output has begun */ ++ ++ index_map = bfd_alloc (abfd, abfd->section_count * sizeof (int)); ++ if (!index_map) ++ return FALSE; ++ ++ for (idx=0, p=abfd->sections; p!=NULL; p=p->next) ++ index_map[idx++] = p->index; ++ ++ /* Distinguish Load files and Unit files */ ++ if (AMIGA_DATA(abfd)->IsLoadFile) ++ { ++ DPRINT(5,("Writing load file\n")); ++ ++ if (amiga_base_relative) ++ BFD_ASSERT (abfd->section_count==3); ++ ++ /* Write out load file header */ ++ n[0] = HUNK_HEADER; ++ n[1] = n[2] = 0; ++ for (p=abfd->sections; p!=NULL; p=p->next) { ++ /* For baserel linking, don't remove empty sections, since they ++ may get some contents later on */ ++ if ((amiga_base_relative || p->_raw_size!=0 || p->_cooked_size!=0) && ++ !(amiga_base_relative && !strcmp (p->name, ".bss"))) ++ n[2]++; ++ else ++ remove_section_index (p, index_map); ++ } ++ n[3] = 0; ++ n[4] = n[2]-1; ++ if (!write_longs (n, 5, abfd)) ++ return FALSE; ++ ++ /* Write out sizes and memory specifiers... */ ++ /* We have to traverse the section list again, bad but no other way... */ ++ if (amiga_base_relative) { ++ for (p=abfd->sections; p!=NULL; p=p->next) ++ { ++ if (amiga_resident && !strcmp(p->name,".data")) ++ { ++ datadata_relocs = determine_datadata_relocs (abfd, p); ++ data_sec = p; ++ } ++ else if (!strcmp(p->name,".bss")) ++ { ++ /* Get size for header */ ++ bss_size = p->_raw_size; ++ } ++ } ++ } ++ ++ for (p=abfd->sections; p!=NULL; p=p->next) ++ { ++ long extra = 0, i; ++ ++ if (index_map[p->index] < 0) ++ continue; ++ ++ if (datadata_relocs && !strcmp(p->name,".text")) ++ extra = datadata_relocs * 4; ++ else if (bss_size && !strcmp (p->name, ".data")) ++ extra = bss_size; ++ /* convert to a size in long words */ ++ n[0] = LONGSIZE (p->_raw_size + extra); ++ ++ i = amiga_per_section(p)->attribute; ++ switch (i) ++ { ++ case MEMF_CHIP: ++ n[0]|=HUNKF_CHIP; ++ i=1; ++ break; ++ case MEMF_FAST: ++ n[0]|=HUNKF_FAST; ++ i=1; ++ break; ++ case 0: /* nothing */ ++ i=1; ++ break; ++ default: /* special one */ ++ n[0]|=0xc0000000; ++ n[1]=i; ++ i=2; ++ break; ++ }/* Of switch */ ++ ++ if (!write_longs (n, i, abfd)) ++ return FALSE; ++ }/* Of for */ ++ } ++ else ++ { /* Unit, no base-relative linking here.. */ ++ DPRINT(5,("Writing unit\n")); ++ ++ /* Write out unit header */ ++ n[0]=HUNK_UNIT; ++ if (!write_longs (n, 1, abfd) || !write_name (abfd, abfd->filename, 0)) ++ return FALSE; ++ ++ for (i=0;i<bfd_get_symcount (abfd);i++) { ++ asymbol *sym_p=abfd->outsymbols[i]; ++ sec_ptr osection=sym_p->section; ++ if (!osection || !bfd_is_com_section(osection->output_section)) ++ continue; ++ for (p=abfd->sections; p!=NULL; p=p->next) { ++ if (!strcmp(p->name, ".bss")) { ++ if (!p->_raw_size && !p->_cooked_size) ++ p->_cooked_size = sym_p->value; ++ break; ++ } ++ } ++ break; ++ } ++ ++ for (p=abfd->sections; p!=NULL; p=p->next) { ++ if (p->_raw_size==0 && p->_cooked_size==0) ++ remove_section_index (p, index_map); ++ } ++ } ++ ++ /* Compute the maximum hunk number of the ouput file */ ++ for (p=abfd->sections; p!=NULL; p=p->next) ++ max_hunk++; ++ ++ /* Write out every section */ ++ for (p=abfd->sections; p!=NULL; p=p->next) ++ { ++ if (index_map[p->index] < 0) ++ continue; ++ ++#define ddrels (datadata_relocs&&!strcmp(p->name,".text")?datadata_relocs:0) ++ if (!amiga_write_section_contents (abfd,p,data_sec,ddrels,index_map, ++ max_hunk)) ++ return FALSE; ++ ++ if (!amiga_write_symbols (abfd,p)) /* Write out symbols + HUNK_END */ ++ return FALSE; ++ }/* of for sections */ ++ ++ /* Write out debug hunk, if requested */ ++ if (AMIGA_DATA(abfd)->IsLoadFile && write_debug_hunk) ++ { ++ extern bfd_boolean ++ translate_to_native_sym_flags (bfd*, asymbol*, struct external_nlist*); ++ ++ unsigned int offset = 4, symbols = 0, i; ++ unsigned long str_size = 4; /* the first 4 bytes will be replaced with the length */ ++ asymbol *sym; ++ sec_ptr s; ++ ++ /* We have to convert all the symbols in abfd to a.out style... */ ++ if (bfd_get_symcount (abfd)) ++ { ++#define CAN_WRITE_OUTSYM(sym) (sym!=NULL && sym->section && \ ++ ((sym->section->owner && \ ++ bfd_get_flavour (sym->section->owner) == \ ++ bfd_target_aout_flavour) || \ ++ bfd_asymbol_flavour (sym) == \ ++ bfd_target_aout_flavour)) ++ ++ for (i = 0; i < bfd_get_symcount (abfd); i++) ++ { ++ sym = abfd->outsymbols[i]; ++ /* NULL entries have been written already... */ ++ if (CAN_WRITE_OUTSYM (sym)) ++ { ++ str_size += strlen(sym->name) + 1; ++ symbols++; ++ } ++ } ++ ++ if (!symbols) ++ return TRUE; ++ ++ /* Now, set the .text, .data and .bss fields in the tdata struct ++ because translate_to_native_sym_flags needs them... */ ++ for (i=0,s=abfd->sections;s!=NULL;s=s->next) ++ if (!strcmp(s->name,".text")) ++ { ++ i|=1; ++ adata(abfd).textsec=s; ++ } ++ else if (!strcmp(s->name,".data")) ++ { ++ i|=2; ++ adata(abfd).datasec=s; ++ } ++ else if (!strcmp(s->name,".bss")) ++ { ++ i|=4; ++ adata(abfd).bsssec=s; ++ } ++ ++ if (i!=7) /* section(s) missing... */ ++ { ++ bfd_msg ("Missing section, debughunk not written"); ++ return TRUE; ++ } ++ ++ /* Write out HUNK_DEBUG, size, ZMAGIC, ... */ ++ n[0] = HUNK_DEBUG; ++ n[1] = 3 + ((symbols * sizeof(struct internal_nlist) + str_size + 3) >> 2); ++ n[2] = ZMAGIC; /* Magic number */ ++ n[3] = symbols * sizeof(struct internal_nlist); ++ n[4] = str_size; ++ if (!write_longs (n, 5, abfd)) ++ return FALSE; ++ ++ /* Write out symbols */ ++ for (i = 0; i < bfd_get_symcount (abfd); i++) /* Translate every symbol */ ++ { ++ sym = abfd->outsymbols[i]; ++ if (CAN_WRITE_OUTSYM (sym)) ++ { ++ amiga_symbol_type *t = (amiga_symbol_type *) sym; ++ struct external_nlist data; ++ ++ bfd_h_put_16(abfd, t->desc, data.e_desc); ++ bfd_h_put_8(abfd, t->other, data.e_other); ++ bfd_h_put_8(abfd, t->type, data.e_type); ++ if (!translate_to_native_sym_flags(abfd,sym,&data)) ++ { ++ bfd_msg ("Cannot translate flags for %s", sym->name); ++ } ++ bfd_h_put_32(abfd, offset, &data.e_strx[0]); /* Store index */ ++ offset += strlen(sym->name) + 1; ++ if (bfd_bwrite ((PTR)&data, sizeof(data), abfd) ++ != sizeof(data)) ++ return FALSE; ++ } ++ } ++ ++ /* Write out strings */ ++ if (!write_longs (&str_size, 1, abfd)) ++ return FALSE; ++ ++ for (i = 0; i < bfd_get_symcount (abfd); i++) ++ { ++ sym = abfd->outsymbols[i]; ++ if (CAN_WRITE_OUTSYM (sym)) ++ { ++ size_t len = strlen(sym->name) + 1; ++ ++ /* Write string tab */ ++ if (bfd_bwrite (sym->name, len, abfd) != len) ++ return FALSE; ++ } ++ } ++ ++ /* Write padding */ ++ n[0] = 0; ++ i = (4 - (str_size & 3)) & 3; ++ if (i && bfd_bwrite ((PTR)n, i, abfd) != i) ++ return FALSE; ++ ++ /* write a HUNK_END here to finish the loadfile, or AmigaOS ++ will refuse to load it */ ++ n[0] = HUNK_END; ++ if (!write_longs (n, 1, abfd)) ++ return FALSE; ++ }/* Of if bfd_get_symcount (abfd) */ ++ }/* Of write out debug hunk */ ++ ++ bfd_release (abfd, index_map); ++ return TRUE; ++} ++ ++/* Write a string padded to 4 bytes and preceded by it's length in ++ long words ORed with <value> */ ++static bfd_boolean ++write_name (abfd, name, value) ++ bfd *abfd; ++ const char *name; ++ unsigned long value; ++{ ++ unsigned long n[1]; ++ size_t l; ++ ++ l = strlen (name); ++ if (AMIGA_DATA(abfd)->IsLoadFile && l > MAX_NAME_SIZE) ++ l = MAX_NAME_SIZE; ++ n[0] = (LONGSIZE (l) | value); ++ if (!write_longs (n, 1, abfd)) ++ return FALSE; ++ if (bfd_bwrite (name, l, abfd) != l) ++ return FALSE; ++ n[0] = 0; ++ l = (4 - (l & 3)) & 3; ++ return (l && bfd_bwrite ((PTR)n, l, abfd) != l ? FALSE : TRUE); ++} ++ ++static bfd_boolean ++amiga_write_archive_contents (arch) ++ bfd *arch; ++{ ++ struct stat status; ++ bfd *object; ++ ++ for (object = arch->archive_head; object; object = object->next) ++ { ++ unsigned long remaining; ++ ++ if (bfd_write_p (object)) ++ { ++ bfd_set_error (bfd_error_invalid_operation); ++ return FALSE; ++ } ++ ++ if (object->arelt_data != NULL) ++ { ++ remaining = arelt_size (object); ++ } ++ else ++ { ++ if (stat (object->filename, &status) != 0) ++ { ++ bfd_set_error (bfd_error_system_call); ++ return FALSE; ++ } ++ remaining = status.st_size; ++ } ++ ++ if (bfd_seek (object, 0, SEEK_SET)) ++ return FALSE; ++ ++ while (remaining) ++ { ++ char buf[DEFAULT_BUFFERSIZE]; ++ unsigned long amt = sizeof(buf); ++ if (amt > remaining) ++ amt = remaining; ++ errno = 0; ++ if (bfd_bread (buf, amt, object) != amt) ++ { ++ if (bfd_get_error () != bfd_error_system_call) ++ bfd_set_error (bfd_error_malformed_archive); ++ return FALSE; ++ } ++ if (bfd_bwrite (buf, amt, arch) != amt) ++ return FALSE; ++ remaining -= amt; ++ } ++ } ++ return TRUE; ++} ++ ++static bfd_boolean ++amiga_write_armap (arch, elength, map, orl_count, stridx) ++ bfd *arch ATTRIBUTE_UNUSED; ++ unsigned int elength ATTRIBUTE_UNUSED; ++ struct orl *map ATTRIBUTE_UNUSED; ++ unsigned int orl_count ATTRIBUTE_UNUSED; ++ int stridx ATTRIBUTE_UNUSED; ++{ ++ return TRUE; ++} ++ ++static int ++determine_type (r) ++ arelent *r; ++{ ++ switch (r->howto->type) ++ { ++ case H_ABS8: /* 8 bit absolute */ ++ case H_PC8: /* 8 bit pcrel */ ++ return 2; ++ ++ case H_ABS16: /* 16 bit absolute */ ++ case H_PC16: /* 16 bit pcrel */ ++ return 1; ++ ++ case H_ABS32: /* 32 bit absolute */ ++ /*case H_PC32:*//* 32 bit pcrel */ ++ return 0; ++ ++ case H_SD8: /* 8 bit base rel */ ++ return 5; ++ ++ case H_SD16: /* 16 bit base rel */ ++ return 4; ++ ++ case H_SD32: /* 32 bit baserel */ ++ return 3; ++ ++ default: /* Error, can't represent this */ ++ bfd_set_error (bfd_error_nonrepresentable_section); ++ return -1; ++ }/* Of switch */ ++} ++ ++#define NB_RELOC_TYPES 6 ++static const unsigned long reloc_types[NB_RELOC_TYPES] = { ++ HUNK_ABSRELOC32, HUNK_RELRELOC16, HUNK_RELRELOC8, ++ HUNK_DREL32, HUNK_DREL16, HUNK_DREL8 ++}; ++ ++/* Write out section contents, including relocs */ ++static bfd_boolean ++amiga_write_section_contents (abfd, section, data_sec, datadata_relocs, ++ index_map, max_hunk) ++ bfd *abfd; ++ sec_ptr section; ++ sec_ptr data_sec; ++ unsigned long datadata_relocs; ++ int *index_map; ++ int max_hunk; ++{ ++ sec_ptr insection; ++ asymbol *sym_p; ++ arelent *r; ++ unsigned long zero=0,disksize,pad,n[2],k,l,s; ++ long *reloc_counts,reloc_count=0; ++ unsigned char *values; ++ int i,j,x,type; ++ ++ DPRINT(5,("Entering write_section_contents\n")); ++ ++ /* If we are base-relative linking and the section is .bss and abfd ++ is a load file, then return */ ++ if (AMIGA_DATA(abfd)->IsLoadFile) ++ { ++ if (amiga_base_relative && !strcmp(section->name, ".bss")) ++ return TRUE; /* Nothing to do */ ++ } ++ else ++ { ++ /* WRITE out HUNK_NAME + section name */ ++ n[0] = HUNK_NAME; ++ if (!write_longs (n, 1, abfd) || !write_name (abfd, section->name, 0)) ++ return FALSE; ++ } ++ ++ /* Depending on the type of the section, write out HUNK_{CODE|DATA|BSS} */ ++ if (section->flags & SEC_CODE) /* Code section */ ++ n[0] = HUNK_CODE; ++ else if (section->flags & (SEC_DATA | SEC_LOAD)) /* data section */ ++ n[0] = HUNK_DATA; ++ else if (section->flags & SEC_ALLOC) /* BSS */ ++ n[0] = HUNK_BSS; ++ else if (section->flags & SEC_DEBUGGING) /* debug section */ ++ n[0] = HUNK_DEBUG; ++ else /* Error */ ++ { ++#if 0 ++ bfd_set_error (bfd_error_nonrepresentable_section); ++ return FALSE; ++#else ++ /* FIXME: Just dump everything we don't currently recognize into ++ a DEBUG hunk. */ ++ n[0] = HUNK_DEBUG; ++#endif ++ } ++ ++ DPRINT(10,("Section type is %lx\n",n[0])); ++ ++ /* Get real size in n[1], this may be shorter than the size in the header */ ++ if (amiga_per_section(section)->disk_size == 0) ++ amiga_per_section(section)->disk_size = section->_raw_size; ++ disksize = LONGSIZE (amiga_per_section(section)->disk_size) + datadata_relocs; ++ n[1] = disksize; ++ ++ /* in a load file, we put section attributes only in the header */ ++ if (!AMIGA_DATA(abfd)->IsLoadFile) ++ { ++ /* Get attribute for section */ ++ switch (amiga_per_section(section)->attribute) ++ { ++ case MEMF_CHIP: ++ n[1] |= HUNKF_CHIP; ++ break; ++ case MEMF_FAST: ++ n[1] |= HUNKF_FAST; ++ break; ++ case 0: ++ break; ++ default: /* error, can't represent this */ ++ bfd_set_error (bfd_error_nonrepresentable_section); ++ return FALSE; ++ break; ++ } ++ }/* Of switch */ ++ ++ if (!write_longs (n, 2, abfd)) ++ return FALSE; ++ ++ DPRINT(5,("Wrote code and size=%lx\n",n[1])); ++ ++ /* If a BSS hunk, we're done, else write out section contents */ ++ if (HUNK_VALUE (n[0]) == HUNK_BSS) ++ return TRUE; ++ ++ DPRINT(5,("Non bss hunk...\n")); ++ ++ /* Traverse through the relocs, sample them in reloc_data, adjust section ++ data to get 0 addend ++ Then compactify reloc_data ++ Set the entry in the section for the reloc to NULL */ ++ ++ if (disksize != 0) ++ BFD_ASSERT ((section->flags & SEC_IN_MEMORY) != 0); ++ ++ reloc_counts = (long *) bfd_zalloc (abfd, NB_RELOC_TYPES * (max_hunk+1) ++ * sizeof (long)); ++ if (!reloc_counts) ++ return FALSE; ++ ++ DPRINT(5,("Section has %d relocs\n",section->reloc_count)); ++ ++ for (l = 0; l < section->reloc_count; l++) ++ { ++ r = section->orelocation[l]; ++ if (r == NULL) ++ continue; ++ ++ sym_p = *(r->sym_ptr_ptr); /* The symbol for this relocation */ ++ insection = sym_p->section; ++ DPRINT(5,("Sec for reloc is %lx(%s)\n",insection,insection->name)); ++ DPRINT(5,("Symbol for this reloc is %lx(%s)\n",sym_p,sym_p->name)); ++ /* Is reloc relative to a special section? */ ++ if (bfd_is_bfd_section(insection)) ++ continue; /* Nothing to do, since this translates to HUNK_EXT */ ++ ++ r->addend += sym_p->value; /* Add offset of symbol from section start */ ++ ++ /* Address of reloc has been unchanged since original reloc, or has ++ been adjusted by get_relocated_section_contents. */ ++ /* For relocs, the vma of the target section is in the data, the ++ addend is -vma of that section =>No need to add vma */ ++ /* Add in offset */ ++ r->addend += insection->output_offset; ++ ++ /* Determine which hunk to write, and index of target */ ++ x = index_map[insection->output_section->index]; ++ if (x<0 || x>max_hunk) { ++ bfd_msg ("erroneous relocation to hunk %d/%s from %s", ++ x, insection->output_section->name, insection->name); ++ bfd_set_error (bfd_error_nonrepresentable_section); ++ return FALSE; ++ } ++ ++ type = determine_type(r); ++ if (type == -1) ++ return FALSE; ++ if (type >= NB_RELOC_TYPES) { ++ bfd_set_error (bfd_error_nonrepresentable_section); ++ return FALSE; ++ } ++ reloc_counts[type+(x*NB_RELOC_TYPES)]++; ++ reloc_count++; ++ ++ /* There is no error checking with these... */ ++ DPRINT(5,("reloc address=%lx,addend=%lx\n",r->address,r->addend)); ++ values = §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 ++++ b/bfd/amigaoslink.c +@@ -0,0 +1,1032 @@ ++/* BFD back-end for Commodore-Amiga AmigaOS binaries. Linker routines. ++ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 ++ Free Software Foundation, Inc. ++ Contributed by Stephan Thesing. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++ ++/* ++INODE ++amigalink, , implementation, amiga ++SECTION ++ amigalink ++ ++This is the description of the linker routines for the amiga. ++In fact, this includes a description of the changes made to the ++a.out code, in order to build a working linker for the Amiga. ++@menu ++@* alterations:: ++@end menu ++ ++INODE ++alterations, , , amigalink ++SUBSECTION ++ alterations ++ ++The file @file{aout-amiga.c} defines the amiga a.out backend. It differs from ++the sun3 backend only in these details: ++ o The @code{final_link} routine is @code{amiga_final_link}. ++ o The routine to get the relocated section contents is ++ @code{get_relocated_section_contents}. ++ ++This ensures that the link is performed properly, but has the side effect of ++loosing performance. ++ ++The amiga bfd code uses the same functions since they check for the used flavour. ++@@* ++ ++The usage of a special linker code has one reason: ++The bfd library assumes that a program is always loaded at a known memory ++address. This is not a case on an Amiga. So the Amiga format has to take over ++some relocs to an executable output file. ++This is not the case with a.out formats, so there relocations can be applied at link time, ++not at run time, like on the Amiga. ++The special routines compensate this: instead of applying the relocations, they are ++copied to the output file, if neccessary. ++As as consequence, @code{final_link} and @code{get_relocated_section_contents} are nearly identical to ++the original routines from @file{linker.c} and @file{reloc.c}. ++*/ ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "libbfd.h" ++#include "bfdlink.h" ++#include "genlink.h" ++#include "libamiga.h" ++ ++#define bfd_msg (*_bfd_error_handler) ++ ++/*#define DEBUG_AMIGA 1*/ ++#if DEBUG_AMIGA ++#include <stdarg.h> ++static void ++error_print (const char *fmt, ...) ++{ ++ va_list args; ++ va_start (args, fmt); ++ vfprintf (stderr, fmt, args); ++ va_end (args); ++} ++#define DPRINT(L,x) if (L>=DEBUG_AMIGA) error_print x ++#else ++#define DPRINT(L,x) ++#endif ++ ++/* This one is used by the linker and tells us, if a debug hunk should be ++ written out */ ++int write_debug_hunk = 1; ++ ++/* This is also used by the linker to set the attribute of sections */ ++int amiga_attribute = 0; ++ ++/* This one is used to indicate base-relative linking */ ++int amiga_base_relative = 0; ++ ++/* This one is used to indicate -resident linking */ ++int amiga_resident = 0; ++ ++bfd_boolean ++default_indirect_link_order PARAMS ((bfd *, struct bfd_link_info *, ++ asection *, struct bfd_link_order *, bfd_boolean)); ++bfd_byte * ++get_relocated_section_contents PARAMS ((bfd *, struct bfd_link_info *, ++ struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **)); ++bfd_boolean ++amiga_final_link PARAMS ((bfd *, struct bfd_link_info *)); ++bfd_boolean ++aout_amiga_final_link PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static bfd_reloc_status_type ++my_add_to PARAMS ((arelent *, PTR, int, int)); ++static bfd_reloc_status_type ++amiga_perform_reloc PARAMS ((bfd *, arelent *, PTR, sec_ptr, bfd *, char **)); ++static bfd_reloc_status_type ++aout_perform_reloc PARAMS ((bfd *, arelent *, PTR, sec_ptr, bfd *, char **)); ++static bfd_boolean ++amiga_reloc_link_order PARAMS ((bfd *, struct bfd_link_info *, asection *, ++ struct bfd_link_order *)); ++ ++enum { ADDEND_UNSIGNED=0x01, RELOC_SIGNED=0x02 }; ++ ++ ++/* This one is nearly identical to bfd_generic_get_relocated_section_contents ++ in reloc.c */ ++bfd_byte * ++get_relocated_section_contents (abfd, link_info, link_order, data, ++ relocateable, symbols) ++ bfd *abfd; ++ struct bfd_link_info *link_info; ++ struct bfd_link_order *link_order; ++ bfd_byte *data; ++ bfd_boolean relocateable; ++ asymbol **symbols; ++{ ++ /* Get enough memory to hold the stuff. */ ++ bfd *input_bfd = link_order->u.indirect.section->owner; ++ asection *input_section = link_order->u.indirect.section; ++ ++ long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); ++ arelent **reloc_vector = NULL; ++ long reloc_count; ++ bfd_reloc_status_type (*reloc_func)(bfd *, arelent *, PTR, sec_ptr, ++ bfd *, char **); ++ ++ DPRINT(5,("Entering get_rel_sec_cont\n")); ++ ++ if (reloc_size < 0) ++ goto error_return; ++ ++ if (bfd_get_flavour (input_bfd) == bfd_target_amiga_flavour) ++ reloc_func = amiga_perform_reloc; ++ else if (bfd_get_flavour (input_bfd) == bfd_target_aout_flavour) ++ reloc_func = aout_perform_reloc; ++ else ++ { ++ bfd_set_error (bfd_error_bad_value); ++ goto error_return; ++ } ++ ++ reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size); ++ if (reloc_vector == NULL && reloc_size != 0) ++ goto error_return; ++ ++ DPRINT(5,("GRSC: GetSecCont()\n")); ++ /* Read in the section. */ ++ if (!bfd_get_section_contents (input_bfd, ++ input_section, ++ (PTR) data, ++ (bfd_vma) 0, ++ input_section->_raw_size)) ++ goto error_return; ++ ++ /* We're not relaxing the section, so just copy the size info. */ ++ input_section->_cooked_size = input_section->_raw_size; ++ input_section->reloc_done = TRUE; ++ ++ DPRINT(5,("GRSC: CanReloc\n")); ++ reloc_count = bfd_canonicalize_reloc (input_bfd, ++ input_section, ++ reloc_vector, ++ symbols); ++ if (reloc_count < 0) ++ goto error_return; ++ ++ if (reloc_count > 0) ++ { ++ arelent **parent; ++ ++ DPRINT(5,("reloc_count=%ld\n",reloc_count)); ++ ++ for (parent = reloc_vector; *parent != (arelent *) NULL; ++ parent++) ++ { ++ char *error_message = (char *) NULL; ++ bfd_reloc_status_type r; ++ ++ DPRINT(5,("Applying a reloc\nparent=%lx, reloc_vector=%lx, " ++ "*parent=%lx\n",parent,reloc_vector,*parent)); ++ r=(*reloc_func) (input_bfd, ++ *parent, ++ (PTR) data, ++ input_section, ++ relocateable ? abfd : (bfd *) NULL, ++ &error_message); ++ if (relocateable) ++ { ++ asection *os = input_section->output_section; ++ ++ DPRINT(5,("Keeping reloc\n")); ++ /* A partial link, so keep the relocs. */ ++ os->orelocation[os->reloc_count] = *parent; ++ os->reloc_count++; ++ } ++ ++ if (r != bfd_reloc_ok) ++ { ++ switch (r) ++ { ++ case bfd_reloc_undefined: ++ if (!((*link_info->callbacks->undefined_symbol) ++ (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), ++ input_bfd, input_section, (*parent)->address, ++ TRUE))) ++ goto error_return; ++ break; ++ case bfd_reloc_dangerous: ++ BFD_ASSERT (error_message != (char *) NULL); ++ if (!((*link_info->callbacks->reloc_dangerous) ++ (link_info, error_message, input_bfd, input_section, ++ (*parent)->address))) ++ goto error_return; ++ break; ++ case bfd_reloc_overflow: ++ if (!((*link_info->callbacks->reloc_overflow) ++ (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), ++ (*parent)->howto->name, (*parent)->addend, ++ input_bfd, input_section, (*parent)->address))) ++ goto error_return; ++ break; ++ case bfd_reloc_outofrange: ++ default: ++ DPRINT(10,("get_rel_sec_cont fails, perform reloc " ++ "returned $%x\n",r)); ++ abort (); ++ break; ++ } ++ ++ } ++ } ++ } ++ if (reloc_vector != NULL) ++ free (reloc_vector); ++ DPRINT(5,("GRSC: Returning ok\n")); ++ return data; ++ ++error_return: ++ DPRINT(5,("GRSC: Error_return\n")); ++ if (reloc_vector != NULL) ++ free (reloc_vector); ++ return NULL; ++} ++ ++ ++/* Add a value to a location */ ++static bfd_reloc_status_type ++my_add_to (r, data, add, flags) ++ arelent *r; ++ PTR data; ++ int add, flags; ++{ ++ bfd_reloc_status_type ret=bfd_reloc_ok; ++ bfd_byte *p=((bfd_byte *)data)+r->address; ++ int val; ++ ++ DPRINT(5,("Entering add_value\n")); ++ ++ switch (r->howto->size) ++ { ++ case 0: /* byte size */ ++ if ((flags & ADDEND_UNSIGNED) == 0) ++ val = ((*p & 0xff) ^ 0x80) - 0x80 + add; ++ else ++ val = (*p & 0xff) + add; ++ /* check for overflow */ ++ if ((flags & RELOC_SIGNED) != 0) { ++ if (val<-0x80 || val>0x7f) ++ ret = bfd_reloc_overflow; ++ } ++ else { ++ if ((val&0xffffff00)!=0 && (val&0xffffff00)!=0xffffff00) ++ ret=bfd_reloc_overflow; ++ } ++ /* set the value */ ++ *p = val & 0xff; ++ break; ++ ++ case 1: /* word size */ ++ if ((flags & ADDEND_UNSIGNED) == 0) ++ val = bfd_getb_signed_16 (p) + add; ++ else ++ val = bfd_getb16 (p) + add; ++ /* check for overflow */ ++ if ((flags & RELOC_SIGNED) != 0) { ++ if (val<-0x8000 || val>0x7fff) ++ ret = bfd_reloc_overflow; ++ } ++ else { ++ if ((val&0xffff0000)!=0 && (val&0xffff0000)!=0xffff0000) ++ ret=bfd_reloc_overflow; ++ } ++ /* set the value */ ++ bfd_putb16 (val, p); ++ break; ++ ++ case 2: /* long word */ ++ val = bfd_getb_signed_32 (p) + add; ++ /* If we are linking a resident program, then we limit the reloc size ++ to about +/- 1 GB. ++ ++ When linking a shared library all variables defined in other ++ libraries are placed in memory >0x80000000, so if the library ++ tries to use one of those variables an error is output. ++ ++ Without this it would be much more difficult to check for ++ incorrect references. */ ++ if (amiga_resident && ++ (val & 0xc0000000)!=0 && (val&0xc0000000)!=0xc0000000) /* Overflow */ ++ { ++ ret=bfd_reloc_overflow; ++ } ++ bfd_putb32 (val, p); ++ break; ++ ++ default: /* Error */ ++ ret=bfd_reloc_notsupported; ++ break; ++ }/* Of switch */ ++ ++ DPRINT(5,("Leaving add_value\n")); ++ return ret; ++} ++ ++ ++/* Perform an Amiga relocation */ ++static bfd_reloc_status_type ++amiga_perform_reloc (abfd, r, data, sec, obfd, error_message) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ arelent *r; ++ PTR data; ++ sec_ptr sec; ++ bfd *obfd; ++ char **error_message ATTRIBUTE_UNUSED; ++{ ++ asymbol *sym; /* Reloc is relative to sym */ ++ sec_ptr target_section; /* reloc is relative to this section */ ++ bfd_reloc_status_type ret; ++ bfd_boolean copy; ++ int relocation,flags; ++ ++ DPRINT(5,("Entering APR\nflavour is %d (amiga_flavour=%d, aout_flavour=%d)\n", ++ bfd_get_flavour (sec->owner), bfd_target_amiga_flavour, ++ bfd_target_aout_flavour)); ++ ++ /* If obfd==NULL: Apply the reloc, if possible. */ ++ /* Else: Modify it and return */ ++ ++ if (obfd!=NULL) /* Only modify the reloc */ ++ { ++ r->address+=sec->output_offset; ++ sec->output_section->flags|=SEC_RELOC; ++ DPRINT(5,("Leaving amiga_perf_reloc, modified\n")); ++ return bfd_reloc_ok; ++ } ++ ++ /* Try to apply the reloc */ ++ ++ sym=*(r->sym_ptr_ptr); ++ ++ /* FIXME: XXX */ ++ if (0 && sym->udata.p) ++ sym = ((struct generic_link_hash_entry *) sym->udata.p)->sym; ++ ++ target_section=sym->section; ++ ++ if (bfd_is_und_section(target_section)) /* Error */ ++ { ++ DPRINT(10,("amiga_perf_reloc: target_sec==UND\n")); ++ return bfd_reloc_undefined; ++ } ++ ++ relocation=0; flags=RELOC_SIGNED; copy=FALSE; ret=bfd_reloc_ok; ++ ++ DPRINT(5,("%s: size=%u\n",r->howto->name,bfd_get_reloc_size(r->howto))); ++ switch (r->howto->type) ++ { ++ case H_ABS32: ++ if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */ ++ relocation=sym->value; ++ else if (bfd_is_com_section(target_section)) /* ref to common */ ++ { ++ relocation=0; ++ copy=TRUE; ++ } ++ else ++ { ++ /* If we access a symbol in the .bss section, we have to convert ++ this to an access to .data section */ ++ /* This is done through a change to the output section of ++ the symbol.. */ ++ if (amiga_base_relative ++ && !strcmp(target_section->output_section->name,".bss")) ++ { ++ /* get value for .data section */ ++ bfd *ibfd; ++ sec_ptr s; ++ ++ ibfd=target_section->output_section->owner; ++ for (s=ibfd->sections;s!=NULL;s=s->next) ++ if (!strcmp(s->name,".data")) ++ { ++ target_section->output_offset=s->_raw_size; ++ target_section->output_section=s; ++ } ++ } ++ relocation=0; ++ copy=TRUE; ++ } ++ break; ++ ++ case H_PC8: /* pcrel */ ++ case H_PC16: ++ case H_PC32: ++ if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */ ++ relocation=sym->value; ++ else if (bfd_is_com_section(target_section)) /* Error.. */ ++ { ++ ret=bfd_reloc_undefined; ++ } ++ else if (sec->output_section!=target_section->output_section) /* Error */ ++ { ++ DPRINT(5,("pc relative, but out-of-range\n")); ++ ret=bfd_reloc_outofrange; ++ } ++ else /* Same section */ ++ { ++ DPRINT(5,("PC relative\n")); ++ relocation = sym->value + target_section->output_offset ++ - (r->address + sec->output_offset); ++ } ++ break; ++ ++ case H_SD8: /* baserel */ ++ case H_SD16: ++ case H_SD32: ++ /* Relocs are always relative to the symbol ___a4_init */ ++ /* Relocs to .bss section are converted to a reloc to .data section, ++ since .bss section contains only COMMON sections...... and should ++ be following .data section.. */ ++ if (bfd_is_abs_section(target_section)) ++ relocation=sym->value; ++ else if (!AMIGA_DATA(target_section->output_section->owner)->baserel) ++ { ++ bfd_msg ("Base symbol for base relative reloc not defined: " ++ "section %s, reloc to symbol %s",sec->name,sym->name); ++ ret=bfd_reloc_notsupported; ++ } ++ else if ((target_section->flags&SEC_CODE)!=0) ++ { ++ bfd_msg ("%s: baserelative text relocation to \"%s\"", ++ abfd->filename, sym->name); ++ ret=bfd_reloc_notsupported; ++ } ++ else ++ { ++ /* If target->out is .bss, add the value of the .data section to ++ sym->value and set new output_section */ ++ if (!strcmp(target_section->output_section->name,".bss")) ++ { ++ bfd *ibfd; ++ sec_ptr s; ++ ++ ibfd=target_section->output_section->owner; ++ for (s=ibfd->sections;s!=NULL;s=s->next) ++ if (!strcmp(s->name,".data")) ++ { ++ target_section->output_offset=s->_raw_size; ++ target_section->output_section=s; ++ } ++ } ++ ++ relocation = sym->value + target_section->output_offset ++ - (AMIGA_DATA(target_section->output_section->owner))->a4init ++ + r->addend; ++ flags|=ADDEND_UNSIGNED; ++ } ++ break; ++ ++ default: ++ bfd_msg ("Error: unsupported reloc: %s(%d)",r->howto->name,r->howto->size); ++ ret=bfd_reloc_notsupported; ++ break; ++ }/* Of switch */ ++ ++ /* Add in relocation */ ++ if (relocation!=0) ++ ret = my_add_to (r, data, relocation, flags); ++ ++ if (copy) /* Copy reloc to output section */ ++ { ++ DPRINT(5,("Copying reloc\n")); ++ target_section=sec->output_section; ++ r->address+=sec->output_offset; ++ target_section->orelocation[target_section->reloc_count++]=r; ++ target_section->flags|=SEC_RELOC; ++ } ++ DPRINT(5,("Leaving amiga_perf_reloc with %d (OK=%d)\n",ret,bfd_reloc_ok)); ++ return ret; ++} ++ ++ ++/* Perform an a.out relocation */ ++static bfd_reloc_status_type ++aout_perform_reloc (abfd, r, data, sec, obfd, error_message) ++ bfd *abfd; ++ arelent *r; ++ PTR data; ++ sec_ptr sec; ++ bfd *obfd; ++ char **error_message ATTRIBUTE_UNUSED; ++{ ++ asymbol *sym; /* Reloc is relative to sym */ ++ sec_ptr target_section; /* reloc is relative to this section */ ++ bfd_reloc_status_type ret; ++ bfd_boolean copy; ++ int relocation,flags; ++ ++ DPRINT(5,("Entering aout_perf_reloc\n")); ++ ++ /* If obfd==NULL: Apply the reloc, if possible. */ ++ /* Else: Modify it and return */ ++ ++ if (obfd!=NULL) /* Only modify the reloc */ ++ { ++ r->address+=sec->output_offset; ++ DPRINT(5,("Leaving aout_perf_reloc, modified\n")); ++ return bfd_reloc_ok; ++ } ++ ++ /* Try to apply the reloc */ ++ ++ sym=*(r->sym_ptr_ptr); ++ target_section=sym->section; ++ ++ if (bfd_is_und_section(target_section)) /* Error */ ++ { ++ if ((sym->flags & BSF_WEAK) == 0) ++ { ++ DPRINT(10,("aout_perf_reloc: target_sec==UND\n")); ++ return bfd_reloc_undefined; ++ } ++ target_section=bfd_abs_section_ptr; ++ } ++ ++ relocation=0; flags=RELOC_SIGNED; copy=FALSE; ret=bfd_reloc_ok; ++ ++ DPRINT(10,("RELOC: %s: size=%u\n",r->howto->name,bfd_get_reloc_size(r->howto))); ++ switch (r->howto->type) ++ { ++ case H_ABS8: /* 8/16 bit reloc, pc relative or absolute */ ++ case H_ABS16: ++ if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */ ++ relocation=sym->value; ++ else if (bfd_is_com_section(target_section)) /* Error.. */ ++ { ++ bfd_msg ("pc relative relocation to common symbol \"%s\" in " ++ "section %s",sym->name,sec->name); ++ DPRINT(10,("Ref to common symbol...aout_perf_reloc\n")); ++ ret=bfd_reloc_undefined; ++ } ++ else if (sec->output_section!=target_section->output_section) ++ { ++ if ((target_section->output_section->flags&SEC_DATA)!=0) ++ goto baserel; /* Dirty, but no code duplication.. */ ++ bfd_msg ("pc relative relocation out-of-range in section %s. " ++ "Relocation was to symbol %s",sec->name,sym->name); ++ DPRINT(10,("Section %s, target %s: Reloc out-of-range...not same " ++ "section, aout_perf\nsec->out=%s, target->out=%s, " ++ "offset=%lx\n",sec->name,target_section->name, ++ sec->output_section->name, ++ target_section->output_section->name,r->address)); ++ ret=bfd_reloc_outofrange; ++ } ++ else ++ { ++ /* Same section, this is a pc relative hunk... */ ++ DPRINT(5,("Reloc to same section...\n")); ++ relocation=-(r->address+sec->output_offset); ++ } ++ break; ++ ++ case H_ABS32: /* 32 bit reloc, pc relative or absolute */ ++ if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */ ++ relocation=sym->value; ++ else if (bfd_is_com_section(target_section)) /* ref to common */ ++ { ++ relocation=0; ++ copy=TRUE; ++ } ++ else ++ { ++ /* If we access a symbol in the .bss section, we have to convert ++ this to an access to .data section */ ++ /* This is done through a change to the output section of ++ the symbol.. */ ++ if (amiga_base_relative ++ && !strcmp(target_section->output_section->name,".bss")) ++ { ++ /* get value for .data section */ ++ bfd *ibfd; ++ sec_ptr s; ++ ++ ibfd=target_section->output_section->owner; ++ for (s=ibfd->sections;s!=NULL;s=s->next) ++ if (!strcmp(s->name,".data")) ++ { ++ target_section->output_offset+=s->_raw_size; ++ target_section->output_section=s; ++ } ++ } ++ relocation=0; ++ copy=TRUE; ++ } ++ DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n", ++ target_section->output_section->name, ++ target_section->output_section,sec->output_section->name, ++ sec->output_section,sym->name)); ++ break; ++ ++ case H_PC8: /* pcrel */ ++ case H_PC16: ++ case H_PC32: ++ if (bfd_is_abs_section(target_section)) /* Ref to absolute hunk */ ++ relocation=sym->value; ++ else ++ { ++ relocation = sym->value + target_section->output_offset ++ - sec->output_offset; ++ } ++ break; ++ ++ case H_SD16: /* baserel */ ++ case H_SD32: ++ baserel: ++ /* We use the symbol ___a4_init as base */ ++ if (bfd_is_abs_section(target_section)) ++ relocation=sym->value; ++ else if (bfd_is_com_section(target_section)) /* Error.. */ ++ { ++ bfd_msg ("baserelative relocation to common \"%s\"",sym->name); ++ DPRINT(10,("Ref to common symbol...aout_perf_reloc\n")); ++ ret=bfd_reloc_undefined; ++ } ++ else if (!AMIGA_DATA(target_section->output_section->owner)->baserel) ++ { ++ bfd_msg ("Base symbol for base relative reloc not defined: " ++ "section %s, reloc to symbol %s",sec->name,sym->name); ++ ret=bfd_reloc_notsupported; ++ } ++ else if ((target_section->flags&SEC_CODE)!=0) ++ { ++ bfd_msg ("%s: baserelative text relocation to \"%s\"", ++ abfd->filename, sym->name); ++ ret=bfd_reloc_notsupported; ++ } ++ else /* Target section and sec need not be the same.. */ ++ { ++ /* If target->out is .bss, add the value of the .data section to ++ sym->value and set new output_section */ ++ if (!strcmp(target_section->output_section->name,".bss")) ++ { ++ bfd *ibfd; ++ sec_ptr s; ++ ++ ibfd=target_section->output_section->owner; ++ for (s=ibfd->sections;s!=NULL;s=s->next) ++ if (!strcmp(s->name,".data")) ++ { ++ target_section->output_offset+=s->_raw_size; ++ target_section->output_section=s; ++ } ++ } ++ ++ relocation = sym->value + target_section->output_offset ++ - (AMIGA_DATA(target_section->output_section->owner))->a4init; ++ /* if the symbol is in .bss, subtract the offset that gas has put ++ into the opcode */ ++ if (target_section->index == 2) ++ relocation -= adata(abfd).datasec->_raw_size; ++ DPRINT(20,("symbol=%s (0x%lx)\nsection %s (0x%lx; %s; output=0x%lx)" ++ "\nrelocation @0x%lx\n", sym->name, sym->value, ++ target_section->name, target_section, ++ target_section->owner->filename, target_section->output_offset, ++ r->address)); ++ flags|=ADDEND_UNSIGNED; ++ } ++ DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n", ++ target_section->output_section->name, ++ target_section->output_section,sec->output_section->name, ++ sec->output_section,sym->name)); ++ break; ++ ++ default: ++ bfd_msg ("Error: unsupported reloc: %s(%d)",r->howto->name,r->howto->size); ++ ret=bfd_reloc_notsupported; ++ break; ++ }/* Of switch */ ++ ++ /* Add in relocation */ ++ if (relocation!=0) ++ ret = my_add_to (r, data, relocation, flags); ++ ++ if (copy) /* Copy reloc to output section */ ++ { ++ DPRINT(5,("Copying reloc\n")); ++ target_section=sec->output_section; ++ r->address+=sec->output_offset; ++ target_section->orelocation[target_section->reloc_count++]=r; ++ } ++ DPRINT(5,("Leaving aout_perf_reloc with %d (OK=%d)\n",ret,bfd_reloc_ok)); ++ return ret; ++} ++ ++ ++/* The final link routine, used both by Amiga and a.out backend */ ++/* This is nearly a copy of linker.c/_bfd_generic_final_link */ ++bfd_boolean ++amiga_final_link (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ bfd *sub; ++ asection *o; ++ struct bfd_link_order *p; ++ size_t outsymalloc; ++ struct generic_write_global_symbol_info wginfo; ++ struct bfd_link_hash_entry *h = ++ bfd_link_hash_lookup (info->hash, "___a4_init", FALSE, FALSE, TRUE); ++ ++ if (amiga_base_relative && h && h->type == bfd_link_hash_defined) { ++ AMIGA_DATA(abfd)->baserel = TRUE; ++ AMIGA_DATA(abfd)->a4init = h->u.def.value; ++ } ++ else ++ AMIGA_DATA(abfd)->baserel = FALSE; ++ ++ DPRINT(5,("Entering final_link\n")); ++ ++ if (bfd_get_flavour (abfd) == bfd_target_aout_flavour) ++ return aout_amiga_final_link (abfd, info); ++ ++ bfd_get_outsymbols (abfd) = (asymbol **) NULL; ++ bfd_get_symcount (abfd) = 0; ++ outsymalloc = 0; ++ ++ /* Mark all sections which will be included in the output file. */ ++ for (o = abfd->sections; o != NULL; o = o->next) ++ for (p = o->link_order_head; p != NULL; p = p->next) ++ if (p->type == bfd_indirect_link_order) ++ p->u.indirect.section->linker_mark = TRUE; ++ ++ /* Build the output symbol table. */ ++ for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next) ++ if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc)) ++ return FALSE; ++ ++ DPRINT(10,("Did build output symbol table\n")); ++ ++ /* Accumulate the global symbols. */ ++ wginfo.info = info; ++ wginfo.output_bfd = abfd; ++ wginfo.psymalloc = &outsymalloc; ++ _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info), ++ _bfd_generic_link_write_global_symbol, ++ (PTR) &wginfo); ++ ++ DPRINT(10,("Accumulated global symbols\n")); ++ ++ DPRINT(10,("Output bfd is %s(%lx)\n",abfd->filename,abfd)); ++ ++ if (1) ++ { ++ /* Allocate space for the output relocs for each section. */ ++ /* We also handle base-relative linking special, by setting the .data ++ sections real length to it's length + .bss length */ ++ /* This is different to bfd_generic_final_link: We ALWAYS alloc space ++ for the relocs, because we may need it anyway */ ++ for (o = abfd->sections; ++ o != (asection *) NULL; ++ o = o->next) ++ { ++ /* If section is .data, find .bss and add that length */ ++ if (!info->relocateable && amiga_base_relative && ++ !strcmp(o->name,".data")) ++ { ++ if (bfd_get_flavour(abfd)!=bfd_target_amiga_flavour) /* oops */ ++ { ++ bfd_msg ("You can't use base relative linking with " ++ "partial links."); ++ } ++ else if (0) /* XXX */ ++ { ++ asection *act_sec; ++ for (act_sec=abfd->sections; act_sec!=NULL;act_sec=act_sec->next) ++ if (!strcmp(act_sec->name,".bss")) ++ amiga_per_section(o)->disk_size = o->_raw_size + ++ act_sec->_raw_size; ++ } ++ }/* Of base-relative linking */ ++ ++ DPRINT(10,("Section in output bfd is %s (%lx)\n",o->name,o)); ++ ++ o->reloc_count = 0; ++ for (p = o->link_order_head; ++ p != (struct bfd_link_order *) NULL; ++ p = p->next) ++ { ++ if (p->type == bfd_section_reloc_link_order ++ || p->type == bfd_symbol_reloc_link_order) ++ ++o->reloc_count; ++ else if (p->type == bfd_indirect_link_order) ++ { ++ asection *input_section; ++ bfd *input_bfd; ++ long relsize; ++ arelent **relocs; ++ asymbol **symbols; ++ long reloc_count; ++ ++ input_section = p->u.indirect.section; ++ input_bfd = input_section->owner; ++ ++ DPRINT(10,("\tIndirect section from bfd %s, section is %s(%lx) " ++ "(COM=%lx)\n", ++ input_bfd->filename,input_section->name,input_section, ++ bfd_com_section_ptr)); ++ ++ relsize = bfd_get_reloc_upper_bound (input_bfd, ++ input_section); ++ if (relsize < 0) ++ { ++ DPRINT(10,("Relsize<0.I..in bfd %s, sec %s\n", ++ input_bfd->filename, input_section->name)); ++ return FALSE; ++ } ++ relocs = (arelent **) bfd_malloc ((bfd_size_type) relsize); ++ if (!relocs && relsize != 0) ++ return FALSE; ++ symbols = _bfd_generic_link_get_symbols (input_bfd); ++ reloc_count = bfd_canonicalize_reloc (input_bfd, ++ input_section, ++ relocs, ++ symbols); ++ free (relocs); ++ if (reloc_count < 0) ++ { ++ DPRINT(10,("Relsize<0.II..in bfd %s, sec %s\n", ++ input_bfd->filename, input_section->name)); ++ return FALSE; ++ } ++ BFD_ASSERT ((unsigned long) reloc_count ++ == input_section->reloc_count); ++ o->reloc_count += reloc_count; ++ } ++ } ++ if (o->reloc_count > 0) ++ { ++ bfd_size_type amt; ++ ++ amt = o->reloc_count; ++ amt *= sizeof (arelent *); ++ o->orelocation = (arelent **) bfd_alloc (abfd, amt); ++ if (!o->orelocation) ++ return FALSE; ++ /* o->flags |= SEC_RELOC; There may be no relocs. This can ++ be determined later only */ ++ /* Reset the count so that it can be used as an index ++ when putting in the output relocs. */ ++ o->reloc_count = 0; ++ } ++ } ++ } ++ ++ DPRINT(10,("Got all relocs\n")); ++ ++ /* Handle all the link order information for the sections. */ ++ for (o = abfd->sections; ++ o != (asection *) NULL; ++ o = o->next) ++ { ++ for (p = o->link_order_head; ++ p != (struct bfd_link_order *) NULL; ++ p = p->next) ++ { ++ switch (p->type) ++ { ++ case bfd_section_reloc_link_order: ++ case bfd_symbol_reloc_link_order: ++ if (! amiga_reloc_link_order (abfd, info, o, p)) /* We use an own routine */ ++ return FALSE; ++ break; ++ case bfd_indirect_link_order: ++ if (! default_indirect_link_order (abfd, info, o, p, FALSE)) ++ /* Calls our get_relocated_section_contents */ ++ return FALSE; ++ break; ++ default: ++ if (! _bfd_default_link_order (abfd, info, o, p)) ++ return FALSE; ++ break; ++ } ++ } ++ } ++ ++ if (bfd_get_flavour(abfd)==bfd_target_amiga_flavour&&!info->relocateable) ++ AMIGA_DATA(abfd)->IsLoadFile = TRUE; ++ ++ DPRINT(10,("Leaving final_link\n")); ++ return TRUE; ++} ++ ++ ++/* Handle reloc link order. ++ This is nearly a copy of linker.c/_bfd_generic_reloc_link_order */ ++static bfd_boolean ++amiga_reloc_link_order (abfd, info, sec, link_order) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ asection *sec; ++ struct bfd_link_order *link_order; ++{ ++ arelent *r; ++ ++ DPRINT(5,("Entering amiga_reloc_link_order\n")); ++ ++ if (sec->orelocation == (arelent **) NULL) ++ { ++ DPRINT(10,("aborting, since orelocation==NULL\n")); ++ abort (); ++ } ++ ++ /* We generate a new ***AMIGA*** style reloc */ ++ r = (arelent *) bfd_zalloc (abfd, (bfd_size_type) sizeof (amiga_reloc_type)); ++ if (r == (arelent *) NULL) ++ { ++ DPRINT(5,("Leaving amiga_reloc_link, no mem\n")); ++ return FALSE; ++ } ++ ++ r->address = link_order->offset; ++ r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc); ++ if (r->howto == 0) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ DPRINT(5,("Leaving amiga_reloc_link, bad value\n")); ++ return FALSE; ++ } ++ ++ /* Get the symbol to use for the relocation. */ ++ if (link_order->type == bfd_section_reloc_link_order) ++ r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr; ++ else ++ { ++ struct generic_link_hash_entry *h; ++ ++ h = ((struct generic_link_hash_entry *) ++ bfd_wrapped_link_hash_lookup (abfd, info, ++ link_order->u.reloc.p->u.name, ++ FALSE, FALSE, TRUE)); ++ if (h == (struct generic_link_hash_entry *) NULL ++ || ! h->written) ++ { ++ if (! ((*info->callbacks->unattached_reloc) ++ (info, link_order->u.reloc.p->u.name, ++ (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) ++ return FALSE; ++ bfd_set_error (bfd_error_bad_value); ++ DPRINT(5,("Leaving amiga_reloc_link, bad value in hash lookup\n")); ++ return FALSE; ++ } ++ r->sym_ptr_ptr = &h->sym; ++ } ++ DPRINT(5,("Got symbol for relocation\n")); ++ /* Store the addend */ ++ r->addend = link_order->u.reloc.p->addend; ++ ++ /* If we are generating relocateable output, just add the reloc */ ++ if (info->relocateable) ++ { ++ DPRINT(5,("Adding reloc\n")); ++ sec->orelocation[sec->reloc_count] = r; ++ ++sec->reloc_count; ++ sec->flags|=SEC_RELOC; ++ } ++ else /* Try to apply the reloc */ ++ { ++ PTR data=(PTR)sec->contents; ++ bfd_reloc_status_type ret; ++ char *em=NULL; ++ ++ DPRINT(5,("Apply link_order_reloc\n")); ++ ++ /* FIXME: Maybe, we have to get the section contents, before we ++ use them, if they have not been set by now.. */ ++ BFD_ASSERT (data!=NULL); ++ ++ if (bfd_get_flavour(abfd)==bfd_target_amiga_flavour) ++ ret=amiga_perform_reloc(abfd,r,data,sec,NULL,&em); ++ else ++ ret=aout_perform_reloc(abfd,r,data,sec,NULL,&em); ++ ++ if (ret!=bfd_reloc_ok) ++ { ++ DPRINT(5,("Leaving amiga_reloc_link, value FALSE\n")); ++ return FALSE; ++ } ++ } ++ DPRINT(5,("Leaving amiga_reloc_link\n")); ++ return TRUE; ++} +diff --git a/bfd/aout-amiga.c b/bfd/aout-amiga.c +new file mode 100644 +index 0000000000000000000000000000000000000000..ced7584521b89943b1636d2b4c9b884242cd81c6 +--- /dev/null ++++ b/bfd/aout-amiga.c +@@ -0,0 +1,152 @@ ++/* BFD back-end for Amiga style m68k a.out binaries. ++ Copyright (C) 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. ++ Contributed by Stephan Thesing. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++ ++#define TARGETNAME "a.out-amiga" ++#define MACHTYPE_OK(m) ((m)==M_UNKNOWN || (m)==M_68010 || (m)==M_68020) ++#define TARGET_IS_BIG_ENDIAN_P ++#define TARGET_PAGE_SIZE 0x2000 ++#define N_HEADER_IN_TEXT(x) 0 ++#define N_SHARED_LIB(x) 0 ++#define TEXT_START_ADDR 0 ++ ++/* Do not "beautify" the CONCAT* macro args. Traditional C will not ++ remove whitespace added here, and thus will fail to concatenate ++ the tokens. */ ++#define MY(OP) CONCAT2 (aout_amiga_,OP) ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "libbfd.h" ++#include "libaout.h" ++#include "aout/aout64.h" ++ ++bfd_boolean ++MY(final_link) PARAMS ((bfd *, struct bfd_link_info *)); ++ ++bfd_boolean ++amiga_final_link PARAMS ((bfd *, struct bfd_link_info *)); ++#define MY_bfd_final_link amiga_final_link ++ ++bfd_byte * ++get_relocated_section_contents PARAMS ((bfd *, struct bfd_link_info *, ++ struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **)); ++#define MY_bfd_get_relocated_section_contents get_relocated_section_contents ++ ++static unsigned long MY(get_mach) PARAMS ((enum machine_type)); ++static bfd_boolean MY(write_object_contents) PARAMS ((bfd *)); ++static bfd_boolean MY(set_sizes) PARAMS ((bfd *)); ++static bfd_boolean MY(link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *)); ++#define MY_bfd_link_add_symbols aout_amiga_link_add_symbols ++ ++static unsigned long ++MY(get_mach) (machtype) ++ enum machine_type machtype; ++{ ++ unsigned long machine; ++ switch (machtype) ++ { ++ default: ++ case M_UNKNOWN: ++ /* Some Sun3s make magic numbers without cpu types in them, so ++ we'll default to the 68000. */ ++ machine = bfd_mach_m68000; ++ break; ++ ++ case M_68010: ++ machine = bfd_mach_m68010; ++ break; ++ ++ case M_68020: ++ machine = bfd_mach_m68020; ++ break; ++ } ++ return machine; ++} ++#define SET_ARCH_MACH(ABFD, EXEC) \ ++ bfd_set_arch_mach (ABFD, bfd_arch_m68k, MY(get_mach) (N_MACHTYPE (EXEC))) ++ ++static bfd_boolean ++MY(write_object_contents) (abfd) ++ bfd *abfd; ++{ ++ struct external_exec exec_bytes; ++ struct internal_exec *execp = exec_hdr (abfd); ++ ++ /* Magic number, maestro, please! */ ++ switch (bfd_get_arch (abfd)) ++ { ++ case bfd_arch_m68k: ++ switch (bfd_get_mach (abfd)) ++ { ++ case bfd_mach_m68000: ++ N_SET_MACHTYPE (*execp, M_UNKNOWN); ++ break; ++ case bfd_mach_m68010: ++ N_SET_MACHTYPE (*execp, M_68010); ++ break; ++ default: ++ case bfd_mach_m68020: ++ N_SET_MACHTYPE (*execp, M_68020); ++ break; ++ } ++ break; ++ default: ++ N_SET_MACHTYPE (*execp, M_UNKNOWN); ++ } ++ ++ WRITE_HEADERS (abfd, execp); ++ ++ return TRUE; ++} ++#define MY_write_object_contents MY(write_object_contents) ++ ++static bfd_boolean ++MY(set_sizes) (abfd) ++ bfd *abfd; ++{ ++ adata (abfd).page_size = TARGET_PAGE_SIZE; ++ adata (abfd).segment_size = TARGET_PAGE_SIZE; ++ adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; ++ return TRUE; ++} ++#define MY_set_sizes MY(set_sizes) ++ ++/* Include the usual a.out support. */ ++#include "aout-target.h" ++ ++/* Add symbols from an object file to the global hash table. */ ++static bfd_boolean ++MY(link_add_symbols) (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ if (info->hash->creator->flavour == bfd_target_amiga_flavour) ++ return _bfd_generic_link_add_symbols (abfd, info); ++ return NAME(aout,link_add_symbols) (abfd, info); ++} ++ ++/* Public final_link routine. */ ++bfd_boolean ++MY(final_link) (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ return NAME(aout,final_link) (abfd, info, MY_final_link_callback); ++} +diff --git a/bfd/aoutx.h b/bfd/aoutx.h +index 1e0ad38f95bcf990a9ffd4cfb89eae3f6496740c..2641f975fd575d0a651540dc886eeee68cf4b173 100644 +--- a/bfd/aoutx.h ++++ b/bfd/aoutx.h +@@ -127,12 +127,16 @@ DESCRIPTION + #include "libaout.h" + #include "libbfd.h" + #include "aout/aout64.h" + #include "aout/stab_gnu.h" + #include "aout/ar.h" + ++/*Amiga hack - used in amigaos.c, must be global */ ++/*static*/ bfd_boolean translate_to_native_sym_flags ++ PARAMS ((bfd *, asymbol *, struct external_nlist *)); ++ + /* + SUBSECTION + Relocations + + DESCRIPTION + The file @file{aoutx.h} provides for both the @emph{standard} +@@ -1550,13 +1554,13 @@ translate_from_native_sym_flags (bfd *abfd, aout_symbol_type *cache_ptr) + + return TRUE; + } + + /* Set the fields of SYM_POINTER according to CACHE_PTR. */ + +-static bfd_boolean ++bfd_boolean + translate_to_native_sym_flags (bfd *abfd, + asymbol *cache_ptr, + struct external_nlist *sym_pointer) + { + bfd_vma value = cache_ptr->value; + asection *sec; +@@ -1946,16 +1950,32 @@ NAME (aout, swap_std_reloc_out) (bfd *abfd, + asection *output_section = sym->section->output_section; + + PUT_WORD (abfd, g->address, natptr->r_address); + + r_length = g->howto->size ; /* Size as a power of two. */ + r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ ++#if 1 ++ /* FIXME! "#if 1" is the wrong way to select this Amiga specific code. */ ++ switch (bfd_asymbol_flavour(sym)) ++ { ++ case bfd_target_amiga_flavour: ++ case bfd_target_aout_flavour: ++ r_baserel = (g->howto->type & 8) != 0; ++ r_jmptable = (g->howto->type & 16) != 0; ++ r_relative = (g->howto->type & 32) != 0; ++ break; ++ default: ++ r_baserel=r_jmptable=r_relative=0; ++ break; ++ } ++#else + /* XXX This relies on relocs coming from a.out files. */ + r_baserel = (g->howto->type & 8) != 0; + r_jmptable = (g->howto->type & 16) != 0; + r_relative = (g->howto->type & 32) != 0; ++#endif + + /* Name was clobbered by aout_write_syms to be symbol index. */ + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + +@@ -2251,14 +2271,18 @@ NAME (aout, swap_std_reloc_in) (bfd *abfd, + else + cache_ptr->howto = NULL; + + /* Base relative relocs are always against the symbol table, + regardless of the setting of r_extern. r_extern just reflects + whether the symbol the reloc is against is local or global. */ ++#if 0 ++ /* FIXME! "#if 0" is the wrong way to disable this code. See comment ++ earlier in file. */ + if (r_baserel) + r_extern = 1; ++#endif + + if (r_extern && r_index > symcount) + { + /* We could arrange to return an error, but it might be useful + to see the file even if it is bad. */ + r_extern = 0; +diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h +index e496083d6ebb0842cfe0a7777dc76cdbd18c7134..8a4d566298f86c56c4a2d21895a39e0d7c5002d7 100644 +--- a/bfd/bfd-in2.h ++++ b/bfd/bfd-in2.h +@@ -3128,12 +3128,16 @@ instruction. */ + BFD_RELOC_PPC_EMB_RELSEC16, + BFD_RELOC_PPC_EMB_RELST_LO, + BFD_RELOC_PPC_EMB_RELST_HI, + BFD_RELOC_PPC_EMB_RELST_HA, + BFD_RELOC_PPC_EMB_BIT_FLD, + BFD_RELOC_PPC_EMB_RELSDA, ++ BFD_RELOC_PPC_MORPHOS_DREL, ++ BFD_RELOC_PPC_MORPHOS_DREL_LO, ++ BFD_RELOC_PPC_MORPHOS_DREL_HI, ++ BFD_RELOC_PPC_MORPHOS_DREL_HA, + BFD_RELOC_PPC_VLE_REL8, + BFD_RELOC_PPC_VLE_REL15, + BFD_RELOC_PPC_VLE_REL24, + BFD_RELOC_PPC_VLE_LO16A, + BFD_RELOC_PPC_VLE_LO16D, + BFD_RELOC_PPC_VLE_HI16A, +@@ -3213,12 +3217,18 @@ instruction. */ + BFD_RELOC_PPC64_DTPREL16_LO_DS, + BFD_RELOC_PPC64_DTPREL16_HIGHER, + BFD_RELOC_PPC64_DTPREL16_HIGHERA, + BFD_RELOC_PPC64_DTPREL16_HIGHEST, + BFD_RELOC_PPC64_DTPREL16_HIGHESTA, + ++/* AmigaOS4 specific relocations */ ++ BFD_RELOC_PPC_AMIGAOS_BREL, ++ BFD_RELOC_PPC_AMIGAOS_BREL_LO, ++ BFD_RELOC_PPC_AMIGAOS_BREL_HI, ++ BFD_RELOC_PPC_AMIGAOS_BREL_HA, ++ + /* IBM 370/390 relocations */ + BFD_RELOC_I370_D12, + + /* The type of reloc used to build a constructor table - at the moment + probably a 32 bit wide absolute relocation, but the target can choose. + It generally does map to one of the other relocation types. */ +@@ -5904,12 +5914,13 @@ struct bfd + struct mach_o_data_struct *mach_o_data; + struct mach_o_fat_data_struct *mach_o_fat_data; + struct plugin_data_struct *plugin_data; + struct bfd_pef_data_struct *pef_data; + struct bfd_pef_xlib_data_struct *pef_xlib_data; + struct bfd_sym_data_struct *sym_data; ++ struct amiga_data_struct *amiga_data; + void *any; + } + tdata; + + /* Used by the application to hold private data. */ + void *usrdata; +@@ -6215,12 +6226,13 @@ bfd_boolean generic_core_file_matches_executable_p + (bfd_assert (__FILE__,__LINE__), NULL)) + #endif + + enum bfd_flavour + { + bfd_target_unknown_flavour, ++ bfd_target_amiga_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_xcoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, +diff --git a/bfd/bfd.c b/bfd/bfd.c +index eed18960855bdc51be8b57ddba27975afb6b02ef..3487694a541417ec20453ca9116bbb86c383f979 100644 +--- a/bfd/bfd.c ++++ b/bfd/bfd.c +@@ -261,12 +261,13 @@ CODE_FRAGMENT + . struct mach_o_data_struct *mach_o_data; + . struct mach_o_fat_data_struct *mach_o_fat_data; + . struct plugin_data_struct *plugin_data; + . struct bfd_pef_data_struct *pef_data; + . struct bfd_pef_xlib_data_struct *pef_xlib_data; + . struct bfd_sym_data_struct *sym_data; ++. struct amiga_data_struct *amiga_data; + . void *any; + . } + . tdata; + . + . {* Used by the application to hold private data. *} + . void *usrdata; +diff --git a/bfd/bfdio.c b/bfd/bfdio.c +index be05581aeb4026addd3f4caf2b185ae73d893a24..a15208b16635c7174592b6ccf26685c4b1d05bc8 100644 +--- a/bfd/bfdio.c ++++ b/bfd/bfdio.c +@@ -325,12 +325,37 @@ bfd_seek (bfd *abfd, file_ptr position, int direction) + + if (abfd->iovec) + result = abfd->iovec->bseek (abfd, file_position, direction); + else + result = -1; + ++/* FIXME: The following code was previously used on AmigaOS. It pads the output file */ ++#if 0 ++ { ++ struct stat stat_buf; ++ if (direction == SEEK_CUR) ++ file_position += ftell (f); ++ fflush (f); ++ if (!(result = fstat (fileno (f), &stat_buf)) && ++ file_position > stat_buf.st_size && ++ !(result = fseek (f, stat_buf.st_size, SEEK_SET))) { ++ int zeroes = file_position - stat_buf.st_size; ++ char *buf = calloc (4096, 1); ++ if (buf) { ++ while (zeroes > 0) { ++ int r, x = (zeroes > 4096? 4096 : zeroes); ++ if ((r = write (fileno (f), buf, x))<=0) ++ break; ++ zeroes -= r; ++ } ++ free (buf); ++ } ++ } ++ result = fseek (f, file_position, SEEK_SET); ++ } ++#endif + if (result != 0) + { + int hold_errno = errno; + + /* Force redetermination of `where' field. */ + bfd_tell (abfd); +diff --git a/bfd/config.bfd b/bfd/config.bfd +index 6025f2641b47915c79a7d643963e9d9080e0ed5c..fcbbce847bc65a44ee68deedd93b2943aac9f77f 100644 +--- a/bfd/config.bfd ++++ b/bfd/config.bfd +@@ -78,15 +78,17 @@ c30*) targ_archs=bfd_tic30_arch ;; + c4x*) targ_archs=bfd_tic4x_arch ;; + c54x*) targ_archs=bfd_tic54x_arch ;; + cr16*) targ_archs=bfd_cr16_arch ;; + crisv32) targ_archs=bfd_cris_arch ;; + crx*) targ_archs=bfd_crx_arch ;; + dlx*) targ_archs=bfd_dlx_arch ;; ++i[3456]86*) targ_archs=bfd_i386_arch ;; ++i370) targ_archs=bfd_i370_arch ;; + fido*) targ_archs=bfd_m68k_arch ;; + hppa*) targ_archs=bfd_hppa_arch ;; +-i[3-7]86) targ_archs=bfd_i386_arch ;; ++i[3-7]86*) targ_archs=bfd_i386_arch ;; + i370) targ_archs=bfd_i370_arch ;; + lm32) targ_archs=bfd_lm32_arch ;; + m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;; + m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;; + m68*) targ_archs=bfd_m68k_arch ;; + m88*) targ_archs=bfd_m88k_arch ;; +@@ -719,12 +721,17 @@ case "${targ}" in + ;; + i[3-7]86-*-chaos) + targ_defvec=bfd_elf32_i386_vec + targ_selfvecs=i386chaos_vec + ;; + ++ i[3456]86be-*-amithlon*) ++ targ_defvec=bfd_elf32_i386be_amithlon_vec ++ targ_selvecs="bfd_elf32_i386_vec bfd_elf32_i386be_amithlon_vec" ++ ;; ++ + i860-*-mach3* | i860-*-osf1* | i860-*-coff*) + targ_defvec=i860coff_vec + ;; + i860-stardent-sysv4* | i860-stardent-elf*) + targ_defvec=bfd_elf32_i860_little_vec + targ_selvecs="bfd_elf32_i860_vec bfd_elf32_i860_little_vec" +@@ -800,12 +807,17 @@ case "${targ}" in + targ_selvecs="bfd_elf32_m68hc11_vec bfd_elf32_m68hc12_vec" + ;; + + m68*-motorola-sysv*) + targ_defvec=m68ksysvcoff_vec + ;; ++ m68*-*-amigaos*) ++ targ_defvec=amiga_vec ++ targ_selvecs="aout_amiga_vec amiga_vec" ++ targ_underscore=yes ++ ;; + m68*-hp-bsd*) + targ_defvec=hp300bsd_vec + targ_underscore=yes + ;; + m68*-*-aout*) + targ_defvec=aout0_big_vec +@@ -871,13 +883,13 @@ case "${targ}" in + ;; + m68*-ericsson-*) + targ_defvec=sunos_big_vec + targ_selvecs="m68kcoff_vec versados_vec tekhex_vec" + targ_underscore=yes + ;; +- m68*-cbm-*) ++ m68*-cbm-amix) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs=m68kcoff_vec + ;; + m68*-*-psos*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs=ieee_vec +@@ -1164,12 +1176,24 @@ case "${targ}" in + *-*-aix4.[3456789]* | *-*-aix[56789]*) + want64=true;; + *) + targ_cflags=-DSMALL_ARCHIVE;; + esac + ;; ++ powerpc-*-amigaoshunk*) ++ targ_defvec=amiga_vec ++ targ_selvecs="bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec aout_amiga_vec" ++ ;; ++ powerpc-*-amiga*) ++ targ_defvec=bfd_elf32_amigaos_vec ++ targ_selvecs="bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec" ++ ;; ++ powerpc-*-morphos*) ++ targ_defvec=bfd_elf32_morphos_vec ++ targ_selvecs="bfd_elf32_morphos_vec" ++ ;; + #ifdef BFD64 + powerpc64-*-aix*) + targ_defvec=rs6000coff64_vec + targ_selvecs=rs6000coff_vec + want64=true + ;; +diff --git a/bfd/configure b/bfd/configure +index e965796ef43d9346cd917bf20243707633fc632e..018a5913f1d96081342c66a64f0167b11cdb1add 100755 +--- a/bfd/configure ++++ b/bfd/configure +@@ -15172,13 +15172,15 @@ do + case "$vec" in + # This list is alphabetized to make it easy to compare + # with the two vector lists in targets.c. For the same reason, + # use one entry per line, even though this leads to long lines. + a_out_adobe_vec) tb="$tb aout-adobe.lo aout32.lo" ;; + aix5coff64_vec) tb="$tb coff64-rs6000.lo xcofflink.lo aix5ppc-core.lo"; target_size=64 ;; ++ amiga_vec) tb="$tb amigaos.lo amigaoslink.lo" ;; + aout0_big_vec) tb="$tb aout0.lo aout32.lo" ;; ++ aout_amiga_vec) tb="$tb aout-amiga.lo aout32.lo";; + aout_arm_big_vec) tb="$tb aout-arm.lo aout32.lo" ;; + aout_arm_little_vec) tb="$tb aout-arm.lo aout32.lo" ;; + apollocoff_vec) tb="$tb coff-apollo.lo" ;; + arm_epoc_pe_big_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;; + arm_epoc_pe_little_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;; + arm_epoc_pei_big_vec) tb="$tb epoc-pei-arm.lo peigen.lo cofflink.lo " ;; +@@ -15195,12 +15197,13 @@ do + armpei_big_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;; + armpei_little_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;; + b_out_vec_big_host) tb="$tb bout.lo aout32.lo" ;; + b_out_vec_little_host) tb="$tb bout.lo aout32.lo" ;; + bfd_pei_ia64_vec) tb="$tb pei-ia64.lo pepigen.lo cofflink.lo"; target_size=64 ;; + bfd_elf32_am33lin_vec) tb="$tb elf32-am33lin.lo elf32.lo $elf" ;; ++ bfd_elf32_amigaos_vec) tb="$tb elf32-amigaos.lo elf32.lo $elf" ;; + bfd_elf32_avr_vec) tb="$tb elf32-avr.lo elf32.lo $elf" ;; + bfd_elf32_bfin_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;; + bfd_elf32_bfinfdpic_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;; + bfd_elf32_big_generic_vec) tb="$tb elf32-gen.lo elf32.lo $elf" ;; + bfd_elf32_bigarc_vec) tb="$tb elf32-arc.lo elf32.lo $elf" ;; + bfd_elf32_bigarm_vec) tb="$tb elf32-arm.lo elf32.lo elf-nacl.lo elf-vxworks.lo $elf" ;; +@@ -15231,12 +15234,13 @@ do + bfd_elf32_i370_vec) tb="$tb elf32-i370.lo elf32.lo $elf" ;; + bfd_elf32_i386_sol2_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_freebsd_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_nacl_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_vxworks_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; ++ bfd_elf32_i386be_amithlon_vec) tb="$tb elf32-i386-amithlon.lo elf32.lo $elf" ;; + bfd_elf32_i860_little_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; + bfd_elf32_i860_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; + bfd_elf32_i960_vec) tb="$tb elf32-i960.lo elf32.lo $elf" ;; + bfd_elf32_ia64_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf" ;; + bfd_elf32_ia64_hpux_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf";; + bfd_elf32_ip2k_vec) tb="$tb elf32-ip2k.lo elf32.lo $elf" ;; +@@ -15267,12 +15271,13 @@ do + bfd_elf32_mcore_little_vec) tb="$tb elf32-mcore.lo elf32.lo $elf" ;; + bfd_elf32_mep_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;; + bfd_elf32_mep_little_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;; + bfd_elf32_microblaze_vec) tb="$tb elf32-microblaze.lo elf32.lo $elf" ;; + bfd_elf32_mn10200_vec) tb="$tb elf-m10200.lo elf32.lo $elf" ;; + bfd_elf32_mn10300_vec) tb="$tb elf-m10300.lo elf32.lo $elf" ;; ++ bfd_elf32_morphos_vec) tb="$tb elf32-morphos.lo elf32.lo $elf";; + bfd_elf32_mt_vec) tb="$tb elf32-mt.lo elf32.lo $elf" ;; + bfd_elf32_msp430_vec) tb="$tb elf32-msp430.lo elf32.lo $elf" ;; + bfd_elf32_nbigmips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; + bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; + bfd_elf32_ntradbigmips_vec | bfd_elf32_ntradbigmips_freebsd_vec) + tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; +diff --git a/bfd/configure.host b/bfd/configure.host +index 7c63de58397426d08501dd7a0fd527cb59a9809c..afa7c909a787d9121d01e4e99d8047cf7f11f0b7 100644 +--- a/bfd/configure.host ++++ b/bfd/configure.host +@@ -53,12 +53,13 @@ mips64*-*-linux*) host64=true;; + mips64*-*-freebsd* | mips64*-*-kfreebsd*-gnu) host64=true;; + mips*-*-sysv4*) ;; + mips*-*-sysv*) HDEFINES="-G 4" ;; + mips*-*-riscos*) HDEFINES="-G 4" ;; + + m68*-hp-hpux*) HDEFINES=-DHOST_HP300HPUX ;; ++m68*-*-amigaos*) HDEFINES=-mstackextend ;; + + # Some Solaris systems (osol0906 at least) have a libc that doesn't recognise + # the "MS-ANSI" code page name, so we define an override for CP_ACP (sets the + # default code page used by windres/windmc when not specified by a commandline + # option) to select the "WINDOWS-1252" name instead. See PR11280 for details. + *-*-solaris2.11) HDEFINES=-DCP_ACP=1 ;; +diff --git a/bfd/configure.in b/bfd/configure.in +index 4b4cb617ef74f5fb33e4de13856d685f5ffba025..5d882b3701b6e0d93f97be655123a2bb2728d63a 100644 +--- a/bfd/configure.in ++++ b/bfd/configure.in +@@ -664,13 +664,15 @@ do + case "$vec" in + # This list is alphabetized to make it easy to compare + # with the two vector lists in targets.c. For the same reason, + # use one entry per line, even though this leads to long lines. + a_out_adobe_vec) tb="$tb aout-adobe.lo aout32.lo" ;; + aix5coff64_vec) tb="$tb coff64-rs6000.lo xcofflink.lo aix5ppc-core.lo"; target_size=64 ;; ++ amiga_vec) tb="$tb amigaos.lo amigaoslink.lo" ;; + aout0_big_vec) tb="$tb aout0.lo aout32.lo" ;; ++ aout_amiga_vec) tb="$tb aout-amiga.lo aout32.lo";; + aout_arm_big_vec) tb="$tb aout-arm.lo aout32.lo" ;; + aout_arm_little_vec) tb="$tb aout-arm.lo aout32.lo" ;; + apollocoff_vec) tb="$tb coff-apollo.lo" ;; + arm_epoc_pe_big_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;; + arm_epoc_pe_little_vec) tb="$tb epoc-pe-arm.lo peigen.lo cofflink.lo " ;; + arm_epoc_pei_big_vec) tb="$tb epoc-pei-arm.lo peigen.lo cofflink.lo " ;; +@@ -687,12 +689,13 @@ do + armpei_big_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;; + armpei_little_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;; + b_out_vec_big_host) tb="$tb bout.lo aout32.lo" ;; + b_out_vec_little_host) tb="$tb bout.lo aout32.lo" ;; + bfd_pei_ia64_vec) tb="$tb pei-ia64.lo pepigen.lo cofflink.lo"; target_size=64 ;; + bfd_elf32_am33lin_vec) tb="$tb elf32-am33lin.lo elf32.lo $elf" ;; ++ bfd_elf32_amigaos_vec) tb="$tb elf32-amigaos.lo elf32.lo $elf" ;; + bfd_elf32_avr_vec) tb="$tb elf32-avr.lo elf32.lo $elf" ;; + bfd_elf32_bfin_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;; + bfd_elf32_bfinfdpic_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;; + bfd_elf32_big_generic_vec) tb="$tb elf32-gen.lo elf32.lo $elf" ;; + bfd_elf32_bigarc_vec) tb="$tb elf32-arc.lo elf32.lo $elf" ;; + bfd_elf32_bigarm_vec) tb="$tb elf32-arm.lo elf32.lo elf-nacl.lo elf-vxworks.lo $elf" ;; +@@ -723,12 +726,13 @@ do + bfd_elf32_i370_vec) tb="$tb elf32-i370.lo elf32.lo $elf" ;; + bfd_elf32_i386_sol2_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_freebsd_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_nacl_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_vxworks_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + bfd_elf32_i386_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; ++ bfd_elf32_i386be_amithlon_vec) tb="$tb elf32-i386-amithlon.lo elf32.lo $elf" ;; + bfd_elf32_i860_little_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; + bfd_elf32_i860_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; + bfd_elf32_i960_vec) tb="$tb elf32-i960.lo elf32.lo $elf" ;; + bfd_elf32_ia64_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf" ;; + bfd_elf32_ia64_hpux_big_vec) tb="$tb elf32-ia64.lo elfxx-ia64.lo elf32.lo $elf";; + bfd_elf32_ip2k_vec) tb="$tb elf32-ip2k.lo elf32.lo $elf" ;; +@@ -759,12 +763,13 @@ do + bfd_elf32_mcore_little_vec) tb="$tb elf32-mcore.lo elf32.lo $elf" ;; + bfd_elf32_mep_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;; + bfd_elf32_mep_little_vec) tb="$tb elf32-mep.lo elf32.lo $elf" ;; + bfd_elf32_microblaze_vec) tb="$tb elf32-microblaze.lo elf32.lo $elf" ;; + bfd_elf32_mn10200_vec) tb="$tb elf-m10200.lo elf32.lo $elf" ;; + bfd_elf32_mn10300_vec) tb="$tb elf-m10300.lo elf32.lo $elf" ;; ++ bfd_elf32_morphos_vec) tb="$tb elf32-morphos.lo elf32.lo $elf";; + bfd_elf32_mt_vec) tb="$tb elf32-mt.lo elf32.lo $elf" ;; + bfd_elf32_msp430_vec) tb="$tb elf32-msp430.lo elf32.lo $elf" ;; + bfd_elf32_nbigmips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; + bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; + bfd_elf32_ntradbigmips_vec | bfd_elf32_ntradbigmips_freebsd_vec) + tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; +diff --git a/bfd/doc/Makefile.am b/bfd/doc/Makefile.am +index 7476ee5bab710b6b418072124b473cf0d340b247..1ddc9e3d2153b55f6f26645e5fc584074bb369fd 100644 +--- a/bfd/doc/Makefile.am ++++ b/bfd/doc/Makefile.am +@@ -1,11 +1,11 @@ + ## Process this file with automake to generate Makefile.in + + AUTOMAKE_OPTIONS = 1.9 cygnus + +-DOCFILES = aoutx.texi archive.texi archures.texi \ ++DOCFILES = amiga.texi amigalink.texi aoutx.texi archive.texi archures.texi \ + bfdt.texi cache.texi coffcode.texi \ + core.texi elf.texi elfcode.texi format.texi \ + libbfd.texi bfdwin.texi bfdio.texi \ + opncls.texi reloc.texi section.texi \ + syms.texi targets.texi init.texi hash.texi linker.texi \ + mmo.texi \ +@@ -26,12 +26,13 @@ IPROTOS = cache.ip libbfd.ip reloc.ip init.ip archures.ip coffcode.ip + SRCDOC = $(srcdir)/../aoutx.h $(srcdir)/../archive.c \ + $(srcdir)/../archures.c $(srcdir)/../bfd.c \ + $(srcdir)/../bfdio.c $(srcdir)/../bfdwin.c \ + $(srcdir)/../cache.c $(srcdir)/../coffcode.h \ + $(srcdir)/../corefile.c $(srcdir)/../elf.c \ + $(srcdir)/../elfcode.h $(srcdir)/../format.c \ ++ $(srcdir)/../amigaos.c $(srcdir)/../amigaoslink.c \ + $(srcdir)/../libbfd.c $(srcdir)/../opncls.c \ + $(srcdir)/../reloc.c $(srcdir)/../section.c \ + $(srcdir)/../syms.c $(srcdir)/../targets.c \ + $(srcdir)/../hash.c $(srcdir)/../linker.c \ + $(srcdir)/../mmo.c + +@@ -183,12 +184,24 @@ hash.texi: chew.c $(srcdir)/../hash.c $(srcdir)/doc.str + + linker.texi: chew.c $(srcdir)/../linker.c $(srcdir)/doc.str + $(MAKE) $(MKDOC) + ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../linker.c >linker.tmp + $(SHELL) $(srcdir)/../../move-if-change linker.tmp linker.texi + ++s-amiga: $(MKDOC) $(srcdir)/../amigaos.c $(srcdir)/doc.str ++ ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaos.c >amiga.tmp ++ $(srcdir)/../../move-if-change amiga.tmp amiga.texi ++ touch s-amiga ++amiga.texi: s-amiga ++ ++s-amigalink: $(MKDOC) $(srcdir)/../amigaoslink.c $(srcdir)/doc.str ++ ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaoslink.c >amigalink.tmp ++ $(srcdir)/../../move-if-change amigalink.tmp amigalink.texi ++ touch s-amigalink ++amigalink.texi: s-amigalink ++ + LIBBFD_H_DEP = \ + $(srcdir)/../libbfd-in.h \ + $(srcdir)/../init.c \ + $(srcdir)/../libbfd.c \ + $(srcdir)/../bfdio.c \ + $(srcdir)/../bfdwin.c \ +diff --git a/bfd/doc/Makefile.in b/bfd/doc/Makefile.in +index 7ba351d742bf53f9e5f51ad7ef74150295519f1a..67db3caf9886839b8d8f52a2a1878de878bb2f6a 100644 +--- a/bfd/doc/Makefile.in ++++ b/bfd/doc/Makefile.in +@@ -268,13 +268,13 @@ target_vendor = @target_vendor@ + tdefaults = @tdefaults@ + top_build_prefix = @top_build_prefix@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ + wordsize = @wordsize@ + AUTOMAKE_OPTIONS = 1.9 cygnus +-DOCFILES = aoutx.texi archive.texi archures.texi \ ++DOCFILES = amiga.texi amigalink.texi aoutx.texi archive.texi archures.texi \ + bfdt.texi cache.texi coffcode.texi \ + core.texi elf.texi elfcode.texi format.texi \ + libbfd.texi bfdwin.texi bfdio.texi \ + opncls.texi reloc.texi section.texi \ + syms.texi targets.texi init.texi hash.texi linker.texi \ + mmo.texi \ +@@ -295,12 +295,13 @@ IPROTOS = cache.ip libbfd.ip reloc.ip init.ip archures.ip coffcode.ip + SRCDOC = $(srcdir)/../aoutx.h $(srcdir)/../archive.c \ + $(srcdir)/../archures.c $(srcdir)/../bfd.c \ + $(srcdir)/../bfdio.c $(srcdir)/../bfdwin.c \ + $(srcdir)/../cache.c $(srcdir)/../coffcode.h \ + $(srcdir)/../corefile.c $(srcdir)/../elf.c \ + $(srcdir)/../elfcode.h $(srcdir)/../format.c \ ++ $(srcdir)/../amigaos.c $(srcdir)/../amigaoslink.c \ + $(srcdir)/../libbfd.c $(srcdir)/../opncls.c \ + $(srcdir)/../reloc.c $(srcdir)/../section.c \ + $(srcdir)/../syms.c $(srcdir)/../targets.c \ + $(srcdir)/../hash.c $(srcdir)/../linker.c \ + $(srcdir)/../mmo.c + +@@ -880,12 +881,24 @@ hash.texi: chew.c $(srcdir)/../hash.c $(srcdir)/doc.str + + linker.texi: chew.c $(srcdir)/../linker.c $(srcdir)/doc.str + $(MAKE) $(MKDOC) + ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../linker.c >linker.tmp + $(SHELL) $(srcdir)/../../move-if-change linker.tmp linker.texi + ++s-amiga: $(MKDOC) $(srcdir)/../amigaos.c $(srcdir)/doc.str ++ ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaos.c >amiga.tmp ++ $(srcdir)/../../move-if-change amiga.tmp amiga.texi ++ touch s-amiga ++amiga.texi: s-amiga ++ ++s-amigalink: $(MKDOC) $(srcdir)/../amigaoslink.c $(srcdir)/doc.str ++ ./$(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../amigaoslink.c >amigalink.tmp ++ $(srcdir)/../../move-if-change amigalink.tmp amigalink.texi ++ touch s-amigalink ++amigalink.texi: s-amigalink ++ + libbfd.h: $(LIBBFD_H_DEP) + echo "$(LIBBFD_H_DEP)" | sed -f $(srcdir)/header.sed > $@ + for file in $(LIBBFD_H_DEP); do \ + case $$file in \ + *-in.h) cat $$file >> $@ ;; \ + */header.sed) break ;; \ +diff --git a/bfd/doc/bfd.texinfo b/bfd/doc/bfd.texinfo +index 45ffa73240ea22a74debe916fcd7e068a947a7dc..7b9774b71a3cb9b3c154c8c75a41de29a6813146 100644 +--- a/bfd/doc/bfd.texinfo ++++ b/bfd/doc/bfd.texinfo +@@ -286,12 +286,13 @@ structures. + @chapter BFD back ends + @menu + * What to Put Where:: + * aout :: a.out backends + * coff :: coff backends + * elf :: elf backends ++* amiga :: amigaos backend + * mmo :: mmo backend + @ignore + * oasys :: oasys backends + * ieee :: ieee backend + * srecord :: s-record backend + @end ignore +@@ -303,18 +304,22 @@ All of BFD lives in one directory. + @node aout, coff, What to Put Where, BFD back ends + @include aoutx.texi + + @node coff, elf, aout, BFD back ends + @include coffcode.texi + +-@node elf, mmo, coff, BFD back ends ++@node elf, amiga, coff, BFD back ends + @include elf.texi + @c Leave this out until the file has some actual contents... + @c @include elfcode.texi + +-@node mmo, , elf, BFD back ends ++@node amiga, mmo, elf, BFD back ends ++@include amiga.texi ++@include amigalink.texi ++ ++@node mmo, , amiga, BFD back ends + @include mmo.texi + + @node GNU Free Documentation License, BFD Index, BFD back ends, Top + @include fdl.texi + + @node BFD Index, , GNU Free Documentation License, Top +diff --git a/bfd/elf32-amiga.c b/bfd/elf32-amiga.c +new file mode 100644 +index 0000000000000000000000000000000000000000..cf6c6cb9efdd15c786932adedd2476ec3a4bc08d +--- /dev/null ++++ b/bfd/elf32-amiga.c +@@ -0,0 +1,3844 @@ ++/* PowerPC-specific support for 32-bit ELF ++ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 ++ Free Software Foundation, Inc. ++ Written by Ian Lance Taylor, Cygnus Support. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++/* This file is based on a preliminary PowerPC ELF ABI. The ++ information may not match the final PowerPC ELF ABI. It includes ++ suggestions from the in-progress Embedded PowerPC ABI, and that ++ information may also not match. */ ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "bfdlink.h" ++#include "libbfd.h" ++#include "elf-bfd.h" ++#include "elf/ppc.h" ++ ++#define USE_RELA /* we want RELA relocations, not REL */ ++ ++static reloc_howto_type *ppc_elf_reloc_type_lookup ++ PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); ++static void ppc_elf_info_to_howto ++ PARAMS ((bfd *abfd, arelent *cache_ptr, Elf32_Internal_Rela *dst)); ++static void ppc_elf_howto_init PARAMS ((void)); ++static int ppc_elf_sort_rela PARAMS ((const PTR, const PTR)); ++static boolean ppc_elf_relax_section ++ PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *)); ++static bfd_reloc_status_type ppc_elf_addr16_ha_reloc ++ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); ++static boolean ppc_elf_object_p PARAMS ((bfd *)); ++static boolean ppc_elf_set_private_flags PARAMS ((bfd *, flagword)); ++static boolean ppc_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *)); ++ ++static int ppc_elf_additional_program_headers PARAMS ((bfd *)); ++static boolean ppc_elf_modify_segment_map PARAMS ((bfd *)); ++ ++static asection *ppc_elf_create_got ++ PARAMS ((bfd *, struct bfd_link_info *)); ++static boolean ppc_elf_create_dynamic_sections ++ PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static boolean ppc_elf_section_from_shdr PARAMS ((bfd *, ++ Elf32_Internal_Shdr *, ++ const char *)); ++static boolean ppc_elf_fake_sections ++ PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *)); ++ ++static elf_linker_section_t *ppc_elf_create_linker_section ++ PARAMS ((bfd *abfd, ++ struct bfd_link_info *info, ++ enum elf_linker_section_enum)); ++ ++static boolean ppc_elf_check_relocs PARAMS ((bfd *, ++ struct bfd_link_info *, ++ asection *, ++ const Elf_Internal_Rela *)); ++ ++static asection * ppc_elf_gc_mark_hook PARAMS ((asection *sec, ++ struct bfd_link_info *info, ++ Elf_Internal_Rela *rel, ++ struct elf_link_hash_entry *h, ++ Elf_Internal_Sym *sym)); ++ ++static boolean ppc_elf_gc_sweep_hook PARAMS ((bfd *abfd, ++ struct bfd_link_info *info, ++ asection *sec, ++ const Elf_Internal_Rela *relocs)); ++ ++static boolean ppc_elf_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, ++ struct elf_link_hash_entry *)); ++ ++static boolean ppc_elf_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static boolean ppc_elf_relocate_section PARAMS ((bfd *, ++ struct bfd_link_info *info, ++ bfd *, ++ asection *, ++ bfd_byte *, ++ Elf_Internal_Rela *relocs, ++ Elf_Internal_Sym *local_syms, ++ asection **)); ++ ++static boolean ppc_elf_add_symbol_hook PARAMS ((bfd *, ++ struct bfd_link_info *, ++ const Elf_Internal_Sym *, ++ const char **, ++ flagword *, ++ asection **, ++ bfd_vma *)); ++ ++static boolean ppc_elf_finish_dynamic_symbol PARAMS ((bfd *, ++ struct bfd_link_info *, ++ struct elf_link_hash_entry *, ++ Elf_Internal_Sym *)); ++ ++static boolean ppc_elf_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); ++static enum elf_reloc_type_class ppc_elf_reloc_type_class ++ PARAMS ((const Elf_Internal_Rela *)); ++static boolean ppc_elf_grok_prstatus ++ PARAMS ((bfd *abfd, Elf_Internal_Note *note)); ++static boolean ppc_elf_grok_psinfo ++ PARAMS ((bfd *abfd, Elf_Internal_Note *note)); ++ ++#define BRANCH_PREDICT_BIT 0x200000 /* branch prediction bit for branch taken relocs */ ++#define RA_REGISTER_MASK 0x001f0000 /* mask to set RA in memory instructions */ ++#define RA_REGISTER_SHIFT 16 /* value to shift register by to insert RA */ ++ ++/* The name of the dynamic interpreter. This is put in the .interp ++ section. */ ++ ++#define ELF_DYNAMIC_INTERPRETER "sys:libs/runtime-linker" ++ ++/* The size in bytes of an entry in the procedure linkage table. */ ++#define PLT_ENTRY_SIZE 12 ++/* The initial size of the plt reserved for the dynamic linker. */ ++#define PLT_INITIAL_ENTRY_SIZE 72 ++/* The size of the gap between entries in the PLT. */ ++#define PLT_SLOT_SIZE 8 ++/* The number of single-slot PLT entries (the rest use two slots). */ ++#define PLT_NUM_SINGLE_ENTRIES 8192 ++ ++/* Will references to this symbol always reference the symbol ++ in this object? */ ++#define SYMBOL_REFERENCES_LOCAL(INFO, H) \ ++ ((! INFO->shared \ ++ || INFO->symbolic \ ++ || H->dynindx == -1 \ ++ || ELF_ST_VISIBILITY (H->other) == STV_INTERNAL \ ++ || ELF_ST_VISIBILITY (H->other) == STV_HIDDEN) \ ++ && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) ++ ++/* Will _calls_ to this symbol always call the version in this object? */ ++#define SYMBOL_CALLS_LOCAL(INFO, H) \ ++ ((! INFO->shared \ ++ || INFO->symbolic \ ++ || H->dynindx == -1 \ ++ || ELF_ST_VISIBILITY (H->other) != STV_DEFAULT) \ ++ && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) ++ ++static reloc_howto_type *ppc_elf_howto_table[(int) R_PPC_max]; ++ ++static reloc_howto_type ppc_elf_howto_raw[] = { ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_NONE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_NONE", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A standard 32 bit relocation. */ ++ HOWTO (R_PPC_ADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 26 bit branch; the lower two bits must be zero. ++ FIXME: we don't check that, we just clear them. */ ++ HOWTO (R_PPC_ADDR24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A standard 16 bit relocation. */ ++ HOWTO (R_PPC_ADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A 16 bit relocation without overflow. */ ++ HOWTO (R_PPC_ADDR16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of an address. */ ++ HOWTO (R_PPC_ADDR16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of an address, plus 1 if the contents of ++ the low 16 bits, treated as a signed number, is negative. */ ++ HOWTO (R_PPC_ADDR16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_ADDR16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch; the lower two bits must be zero. ++ FIXME: we don't check that, we just clear them. */ ++ HOWTO (R_PPC_ADDR14, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch, for which bit 10 should be set to ++ indicate that the branch is expected to be taken. The lower two ++ bits must be zero. */ ++ HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14_BRTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch, for which bit 10 should be set to ++ indicate that the branch is not expected to be taken. The lower ++ two bits must be zero. */ ++ HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14_BRNTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A relative 26 bit branch; the lower two bits must be zero. */ ++ HOWTO (R_PPC_REL24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch; the lower two bits must be zero. */ ++ HOWTO (R_PPC_REL14, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch. Bit 10 should be set to indicate that ++ the branch is expected to be taken. The lower two bits must be ++ zero. */ ++ HOWTO (R_PPC_REL14_BRTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14_BRTAKEN", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch. Bit 10 should be set to indicate that ++ the branch is not expected to be taken. The lower two bits must ++ be zero. */ ++ HOWTO (R_PPC_REL14_BRNTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14_BRNTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16, but referring to the GOT table entry for the ++ symbol. */ ++ HOWTO (R_PPC_GOT16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_GOT16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_REL24, but referring to the procedure linkage table ++ entry for the symbol. */ ++ HOWTO (R_PPC_PLTREL24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* This is used only by the dynamic linker. The symbol should exist ++ both in the object being run and in some shared library. The ++ dynamic linker copies the data addressed by the symbol from the ++ shared library into the object, because the object being ++ run has to have the data at some particular address. */ ++ HOWTO (R_PPC_COPY, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_COPY", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR32, but used when setting global offset table ++ entries. */ ++ HOWTO (R_PPC_GLOB_DAT, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GLOB_DAT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Marks a procedure linkage table entry for a symbol. */ ++ HOWTO (R_PPC_JMP_SLOT, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_JMP_SLOT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Used only by the dynamic linker. When the object is run, this ++ longword is set to the load address of the object, plus the ++ addend. */ ++ HOWTO (R_PPC_RELATIVE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_RELATIVE", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_REL24, but uses the value of the symbol within the ++ object rather than the final value. Normally used for ++ _GLOBAL_OFFSET_TABLE_. */ ++ HOWTO (R_PPC_LOCAL24PC, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_LOCAL24PC", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR32, but may be unaligned. */ ++ HOWTO (R_PPC_UADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_UADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16, but may be unaligned. */ ++ HOWTO (R_PPC_UADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_UADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 32-bit PC relative */ ++ HOWTO (R_PPC_REL32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* 32-bit relocation to the symbol's procedure linkage table. ++ FIXME: not supported. */ ++ HOWTO (R_PPC_PLT32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 32-bit PC relative relocation to the symbol's procedure linkage table. ++ FIXME: not supported. */ ++ HOWTO (R_PPC_PLTREL32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_PLT16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A sign-extended 16 bit value relative to _SDA_BASE_, for use with ++ small data items. */ ++ HOWTO (R_PPC_SDAREL16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SDAREL16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit lower half section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit upper half section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit upper half adjusted section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++ ++ /* 32 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_ADDR16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of the result of the addend minus the address, ++ plus 1 if the contents of the low 16 bits, treated as a signed number, ++ is negative. */ ++ HOWTO (R_PPC_EMB_NADDR16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from allocating a 4 byte word to hold an ++ address in the .sdata section, and returning the offset from ++ _SDA_BASE_ for that relocation */ ++ HOWTO (R_PPC_EMB_SDAI16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDAI16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from allocating a 4 byte word to hold an ++ address in the .sdata2 section, and returning the offset from ++ _SDA2_BASE_ for that relocation */ ++ HOWTO (R_PPC_EMB_SDA2I16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2I16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with ++ small data items. */ ++ HOWTO (R_PPC_EMB_SDA2REL, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2REL", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit ++ signed offset from the appropriate base, and filling in the register ++ field with the appropriate register (0, 2, or 13). */ ++ HOWTO (R_PPC_EMB_SDA21, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA21", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Relocation not handled: R_PPC_EMB_MRKREF */ ++ /* Relocation not handled: R_PPC_EMB_RELSEC16 */ ++ /* Relocation not handled: R_PPC_EMB_RELST_LO */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HI */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HA */ ++ /* Relocation not handled: R_PPC_EMB_BIT_FLD */ ++ ++ /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling ++ in the 16 bit signed offset from the appropriate base, and filling in the ++ register field with the appropriate register (0, 2, or 13). */ ++ HOWTO (R_PPC_EMB_RELSDA, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_RELSDA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* GNU extension to record C++ vtable hierarchy */ ++ HOWTO (R_PPC_GNU_VTINHERIT, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ NULL, /* special_function */ ++ "R_PPC_GNU_VTINHERIT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* GNU extension to record C++ vtable member usage */ ++ HOWTO (R_PPC_GNU_VTENTRY, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ NULL, /* special_function */ ++ "R_PPC_GNU_VTENTRY", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Phony reloc to handle AIX style TOC entries */ ++ HOWTO (R_PPC_TOC16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_TOC16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++}; ++ ++/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ ++ ++static void ++ppc_elf_howto_init () ++{ ++ unsigned int i, type; ++ ++ for (i = 0; i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); i++) ++ { ++ type = ppc_elf_howto_raw[i].type; ++ BFD_ASSERT (type < sizeof (ppc_elf_howto_table) / sizeof (ppc_elf_howto_table[0])); ++ ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i]; ++ } ++} ++ ++/* This function handles relaxing for the PPC with option --mpc860c0[=<n>]. ++ ++ The MPC860, revision C0 or earlier contains a bug in the die. ++ If all of the following conditions are true, the next instruction ++ to be executed *may* be treated as a no-op. ++ 1/ A forward branch is executed. ++ 2/ The branch is predicted as not taken. ++ 3/ The branch is taken. ++ 4/ The branch is located in the last 5 words of a page. ++ (The EOP limit is 5 by default but may be specified as any value from 1-10.) ++ ++ Our software solution is to detect these problematic branches in a ++ linker pass and modify them as follows: ++ 1/ Unconditional branches - Since these are always predicted taken, ++ there is no problem and no action is required. ++ 2/ Conditional backward branches - No problem, no action required. ++ 3/ Conditional forward branches - Ensure that the "inverse prediction ++ bit" is set (ensure it is predicted taken). ++ 4/ Conditional register branches - Ensure that the "y bit" is set ++ (ensure it is predicted taken). ++*/ ++ ++/* Sort sections by address. */ ++ ++static int ++ppc_elf_sort_rela (arg1, arg2) ++ const PTR arg1; ++ const PTR arg2; ++{ ++ const Elf_Internal_Rela **rela1 = (const Elf_Internal_Rela**) arg1; ++ const Elf_Internal_Rela **rela2 = (const Elf_Internal_Rela**) arg2; ++ ++ /* Sort by offset. */ ++ return ((*rela1)->r_offset - (*rela2)->r_offset); ++} ++ ++static boolean ++ppc_elf_relax_section (abfd, isec, link_info, again) ++ bfd *abfd; ++ asection *isec; ++ struct bfd_link_info *link_info; ++ boolean *again; ++{ ++#define PAGESIZE 0x1000 ++ ++ bfd_byte *contents = NULL; ++ bfd_byte *free_contents = NULL; ++ Elf_Internal_Rela *internal_relocs = NULL; ++ Elf_Internal_Rela *free_relocs = NULL; ++ Elf_Internal_Rela **rela_comb = NULL; ++ int comb_curr, comb_count; ++ ++ /* We never have to do this more than once per input section. */ ++ *again = false; ++ ++ /* If needed, initialize this section's cooked size. */ ++ if (isec->_cooked_size == 0) ++ isec->_cooked_size = isec->_raw_size; ++ ++ /* We're only interested in text sections which overlap the ++ troublesome area at the end of a page. */ ++ if (link_info->mpc860c0 && (isec->flags & SEC_CODE) && isec->_cooked_size) ++ { ++ bfd_vma dot, end_page, end_section; ++ boolean section_modified; ++ ++ /* Get the section contents. */ ++ /* Get cached copy if it exists. */ ++ if (elf_section_data (isec)->this_hdr.contents != NULL) ++ contents = elf_section_data (isec)->this_hdr.contents; ++ else ++ { ++ /* Go get them off disk. */ ++ contents = (bfd_byte *) bfd_malloc (isec->_raw_size); ++ if (contents == NULL) ++ goto error_return; ++ free_contents = contents; ++ ++ if (! bfd_get_section_contents (abfd, isec, contents, ++ (file_ptr) 0, isec->_raw_size)) ++ goto error_return; ++ } ++ ++ comb_curr = 0; ++ comb_count = 0; ++ if (isec->reloc_count) ++ { ++ unsigned n; ++ bfd_size_type amt; ++ ++ /* Get a copy of the native relocations. */ ++ internal_relocs = _bfd_elf32_link_read_relocs ( ++ abfd, isec, (PTR) NULL, (Elf_Internal_Rela *) NULL, ++ link_info->keep_memory); ++ if (internal_relocs == NULL) ++ goto error_return; ++ if (! link_info->keep_memory) ++ free_relocs = internal_relocs; ++ ++ /* Setup a faster access method for the reloc info we need. */ ++ amt = isec->reloc_count; ++ amt *= sizeof (Elf_Internal_Rela*); ++ rela_comb = (Elf_Internal_Rela**) bfd_malloc (amt); ++ if (rela_comb == NULL) ++ goto error_return; ++ for (n = 0; n < isec->reloc_count; ++n) ++ { ++ long r_type; ++ ++ r_type = ELF32_R_TYPE (internal_relocs[n].r_info); ++ if (r_type < 0 || r_type >= (int) R_PPC_max) ++ goto error_return; ++ ++ /* Prologue constants are sometimes present in the ".text" ++ sections and they can be identified by their associated relocation. ++ We don't want to process those words and some others which ++ can also be identified by their relocations. However, not all ++ conditional branches will have a relocation so we will ++ only ignore words that 1) have a reloc, and 2) the reloc ++ is not applicable to a conditional branch. ++ The array rela_comb is built here for use in the EOP scan loop. */ ++ switch (r_type) ++ { ++ case R_PPC_ADDR14_BRNTAKEN: /* absolute, predicted not taken */ ++ case R_PPC_REL14: /* relative cond. br. */ ++ case R_PPC_REL14_BRNTAKEN: /* rel. cond. br., predicted not taken */ ++ /* We should check the instruction. */ ++ break; ++ default: ++ /* The word is not a conditional branch - ignore it. */ ++ rela_comb[comb_count++] = &internal_relocs[n]; ++ break; ++ } ++ } ++ if (comb_count > 1) ++ qsort (rela_comb, (size_t) comb_count, sizeof (int), ppc_elf_sort_rela); ++ } ++ ++ /* Enumerate each EOP region that overlaps this section. */ ++ end_section = isec->vma + isec->_cooked_size; ++ dot = end_page = (isec->vma | (PAGESIZE - 1)) + 1; ++ dot -= link_info->mpc860c0; ++ section_modified = false; ++ if (dot < isec->vma) /* Increment the start position if this section */ ++ dot = isec->vma; /* begins in the middle of its first EOP region. */ ++ for (; ++ dot < end_section; ++ dot += PAGESIZE, end_page += PAGESIZE) ++ { ++ ++ /* Check each word in this EOP region. */ ++ for (; dot < end_page; dot += 4) ++ { ++ bfd_vma isec_offset; ++ unsigned long insn; ++ boolean skip, modified; ++ ++ /* Don't process this word if there is a relocation for it and ++ the relocation indicates the word is not a conditional branch. */ ++ skip = false; ++ isec_offset = dot - isec->vma; ++ for (; comb_curr<comb_count; ++comb_curr) ++ { ++ bfd_vma r_offset; ++ ++ r_offset = rela_comb[comb_curr]->r_offset; ++ if (r_offset >= isec_offset) ++ { ++ if (r_offset == isec_offset) skip = true; ++ break; ++ } ++ } ++ if (skip) continue; ++ ++ /* Check the current word for a problematic conditional branch. */ ++#define BO0(insn) ((insn) & 0x02000000) ++#define BO2(insn) ((insn) & 0x00800000) ++#define BO4(insn) ((insn) & 0x00200000) ++ insn = (unsigned long) bfd_get_32 (abfd, contents + isec_offset); ++ modified = false; ++ if ((insn & 0xFc000000) == 0x40000000) ++ { ++ /* Instruction is BCx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ bfd_vma target; ++ /* This branch is predicted as "normal". ++ If this is a forward branch, it is problematic. */ ++ ++ target = insn & 0x0000Fffc; /*extract*/ ++ target = (target ^ 0x8000) - 0x8000; /*sign extend*/ ++ if ((insn & 0x00000002) == 0) ++ target += dot; /*convert to abs*/ ++ if (target > dot) ++ { ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++ } ++ else if ((insn & 0xFc00Fffe) == 0x4c000420) ++ { ++ /* Instruction is BCCTRx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ /* This branch is predicted as not-taken. ++ If this is a forward branch, it is problematic. ++ Since we can't tell statically if it will branch forward, ++ always set the prediction bit. */ ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++ else if ((insn & 0xFc00Fffe) == 0x4c000020) ++ { ++ /* Instruction is BCLRx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ /* This branch is predicted as not-taken. ++ If this is a forward branch, it is problematic. ++ Since we can't tell statically if it will branch forward, ++ always set the prediction bit. */ ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++#undef BO0 ++#undef BO2 ++#undef BO4 ++ if (modified) ++ { ++ bfd_put_32 (abfd, (bfd_vma) insn, contents + isec_offset); ++ section_modified = true; ++ } ++ } ++ } ++ if (section_modified) ++ { ++ elf_section_data (isec)->this_hdr.contents = contents; ++ free_contents = NULL; ++ } ++ } ++ ++ if (rela_comb != NULL) ++ { ++ free (rela_comb); ++ rela_comb = NULL; ++ } ++ ++ if (free_relocs != NULL) ++ { ++ free (free_relocs); ++ free_relocs = NULL; ++ } ++ ++ if (free_contents != NULL) ++ { ++ if (! link_info->keep_memory) ++ free (free_contents); ++ else ++ { ++ /* Cache the section contents for elf_link_input_bfd. */ ++ elf_section_data (isec)->this_hdr.contents = contents; ++ } ++ free_contents = NULL; ++ } ++ ++ return true; ++ ++error_return: ++ if (rela_comb != NULL) ++ free (rela_comb); ++ if (free_relocs != NULL) ++ free (free_relocs); ++ if (free_contents != NULL) ++ free (free_contents); ++ return false; ++} ++ ++static reloc_howto_type * ++ppc_elf_reloc_type_lookup (abfd, code) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ bfd_reloc_code_real_type code; ++{ ++ enum elf_ppc_reloc_type ppc_reloc = R_PPC_NONE; ++ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ switch ((int) code) ++ { ++ default: ++ return (reloc_howto_type *) NULL; ++ ++ case BFD_RELOC_NONE: ppc_reloc = R_PPC_NONE; break; ++ case BFD_RELOC_32: ppc_reloc = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC_BA26: ppc_reloc = R_PPC_ADDR24; break; ++ case BFD_RELOC_16: ppc_reloc = R_PPC_ADDR16; break; ++ case BFD_RELOC_LO16: ppc_reloc = R_PPC_ADDR16_LO; break; ++ case BFD_RELOC_HI16: ppc_reloc = R_PPC_ADDR16_HI; break; ++ case BFD_RELOC_HI16_S: ppc_reloc = R_PPC_ADDR16_HA; break; ++ case BFD_RELOC_PPC_BA16: ppc_reloc = R_PPC_ADDR14; break; ++ case BFD_RELOC_PPC_BA16_BRTAKEN: ppc_reloc = R_PPC_ADDR14_BRTAKEN; break; ++ case BFD_RELOC_PPC_BA16_BRNTAKEN: ppc_reloc = R_PPC_ADDR14_BRNTAKEN; break; ++ case BFD_RELOC_PPC_B26: ppc_reloc = R_PPC_REL24; break; ++ case BFD_RELOC_PPC_B16: ppc_reloc = R_PPC_REL14; break; ++ case BFD_RELOC_PPC_B16_BRTAKEN: ppc_reloc = R_PPC_REL14_BRTAKEN; break; ++ case BFD_RELOC_PPC_B16_BRNTAKEN: ppc_reloc = R_PPC_REL14_BRNTAKEN; break; ++ case BFD_RELOC_16_GOTOFF: ppc_reloc = R_PPC_GOT16; break; ++ case BFD_RELOC_LO16_GOTOFF: ppc_reloc = R_PPC_GOT16_LO; break; ++ case BFD_RELOC_HI16_GOTOFF: ppc_reloc = R_PPC_GOT16_HI; break; ++ case BFD_RELOC_HI16_S_GOTOFF: ppc_reloc = R_PPC_GOT16_HA; break; ++ case BFD_RELOC_24_PLT_PCREL: ppc_reloc = R_PPC_PLTREL24; break; ++ case BFD_RELOC_PPC_COPY: ppc_reloc = R_PPC_COPY; break; ++ case BFD_RELOC_PPC_GLOB_DAT: ppc_reloc = R_PPC_GLOB_DAT; break; ++ case BFD_RELOC_PPC_LOCAL24PC: ppc_reloc = R_PPC_LOCAL24PC; break; ++ case BFD_RELOC_32_PCREL: ppc_reloc = R_PPC_REL32; break; ++ case BFD_RELOC_32_PLTOFF: ppc_reloc = R_PPC_PLT32; break; ++ case BFD_RELOC_32_PLT_PCREL: ppc_reloc = R_PPC_PLTREL32; break; ++ case BFD_RELOC_LO16_PLTOFF: ppc_reloc = R_PPC_PLT16_LO; break; ++ case BFD_RELOC_HI16_PLTOFF: ppc_reloc = R_PPC_PLT16_HI; break; ++ case BFD_RELOC_HI16_S_PLTOFF: ppc_reloc = R_PPC_PLT16_HA; break; ++ case BFD_RELOC_GPREL16: ppc_reloc = R_PPC_SDAREL16; break; ++ case BFD_RELOC_16_BASEREL: ppc_reloc = R_PPC_SECTOFF; break; ++ case BFD_RELOC_LO16_BASEREL: ppc_reloc = R_PPC_SECTOFF_LO; break; ++ case BFD_RELOC_HI16_BASEREL: ppc_reloc = R_PPC_SECTOFF_HI; break; ++ case BFD_RELOC_HI16_S_BASEREL: ppc_reloc = R_PPC_SECTOFF_HA; break; ++ case BFD_RELOC_CTOR: ppc_reloc = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC_TOC16: ppc_reloc = R_PPC_TOC16; break; ++ case BFD_RELOC_PPC_EMB_NADDR32: ppc_reloc = R_PPC_EMB_NADDR32; break; ++ case BFD_RELOC_PPC_EMB_NADDR16: ppc_reloc = R_PPC_EMB_NADDR16; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_LO: ppc_reloc = R_PPC_EMB_NADDR16_LO; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HI: ppc_reloc = R_PPC_EMB_NADDR16_HI; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HA: ppc_reloc = R_PPC_EMB_NADDR16_HA; break; ++ case BFD_RELOC_PPC_EMB_SDAI16: ppc_reloc = R_PPC_EMB_SDAI16; break; ++ case BFD_RELOC_PPC_EMB_SDA2I16: ppc_reloc = R_PPC_EMB_SDA2I16; break; ++ case BFD_RELOC_PPC_EMB_SDA2REL: ppc_reloc = R_PPC_EMB_SDA2REL; break; ++ case BFD_RELOC_PPC_EMB_SDA21: ppc_reloc = R_PPC_EMB_SDA21; break; ++ case BFD_RELOC_PPC_EMB_MRKREF: ppc_reloc = R_PPC_EMB_MRKREF; break; ++ case BFD_RELOC_PPC_EMB_RELSEC16: ppc_reloc = R_PPC_EMB_RELSEC16; break; ++ case BFD_RELOC_PPC_EMB_RELST_LO: ppc_reloc = R_PPC_EMB_RELST_LO; break; ++ case BFD_RELOC_PPC_EMB_RELST_HI: ppc_reloc = R_PPC_EMB_RELST_HI; break; ++ case BFD_RELOC_PPC_EMB_RELST_HA: ppc_reloc = R_PPC_EMB_RELST_HA; break; ++ case BFD_RELOC_PPC_EMB_BIT_FLD: ppc_reloc = R_PPC_EMB_BIT_FLD; break; ++ case BFD_RELOC_PPC_EMB_RELSDA: ppc_reloc = R_PPC_EMB_RELSDA; break; ++ case BFD_RELOC_VTABLE_INHERIT: ppc_reloc = R_PPC_GNU_VTINHERIT; break; ++ case BFD_RELOC_VTABLE_ENTRY: ppc_reloc = R_PPC_GNU_VTENTRY; break; ++ } ++ ++ return ppc_elf_howto_table[(int) ppc_reloc]; ++}; ++ ++/* Set the howto pointer for a PowerPC ELF reloc. */ ++ ++static void ++ppc_elf_info_to_howto (abfd, cache_ptr, dst) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ arelent *cache_ptr; ++ Elf32_Internal_Rela *dst; ++{ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); ++ cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; ++} ++ ++/* Handle the R_PPC_ADDR16_HA reloc. */ ++ ++static bfd_reloc_status_type ++ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section, ++ output_bfd, error_message) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ arelent *reloc_entry; ++ asymbol *symbol; ++ PTR data ATTRIBUTE_UNUSED; ++ asection *input_section; ++ bfd *output_bfd; ++ char **error_message ATTRIBUTE_UNUSED; ++{ ++ bfd_vma relocation; ++ ++ if (output_bfd != NULL) ++ { ++ reloc_entry->address += input_section->output_offset; ++ return bfd_reloc_ok; ++ } ++ ++ if (reloc_entry->address > input_section->_cooked_size) ++ return bfd_reloc_outofrange; ++ ++ if (bfd_is_com_section (symbol->section)) ++ relocation = 0; ++ else ++ relocation = symbol->value; ++ ++ relocation += symbol->section->output_section->vma; ++ relocation += symbol->section->output_offset; ++ relocation += reloc_entry->addend; ++ ++ reloc_entry->addend += (relocation & 0x8000) << 1; ++ ++ return bfd_reloc_continue; ++} ++ ++/* Fix bad default arch selected for a 32 bit input bfd when the ++ default is 64 bit. */ ++ ++static boolean ++ppc_elf_object_p (abfd) ++ bfd *abfd; ++{ ++ if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64) ++ { ++ Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); ++ ++ if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32) ++ { ++ /* Relies on arch after 64 bit default being 32 bit default. */ ++ abfd->arch_info = abfd->arch_info->next; ++ BFD_ASSERT (abfd->arch_info->bits_per_word == 32); ++ } ++ } ++ return true; ++} ++ ++/* Function to set whether a module needs the -mrelocatable bit set. */ ++ ++static boolean ++ppc_elf_set_private_flags (abfd, flags) ++ bfd *abfd; ++ flagword flags; ++{ ++ BFD_ASSERT (!elf_flags_init (abfd) ++ || elf_elfheader (abfd)->e_flags == flags); ++ ++ elf_elfheader (abfd)->e_flags = flags; ++ elf_flags_init (abfd) = true; ++ return true; ++} ++ ++/* Merge backend specific data from an object file to the output ++ object file when linking */ ++static boolean ++ppc_elf_merge_private_bfd_data (ibfd, obfd) ++ bfd *ibfd; ++ bfd *obfd; ++{ ++ flagword old_flags; ++ flagword new_flags; ++ boolean error; ++ ++ /* Check if we have the same endianess */ ++ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) ++ return false; ++ ++ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour ++ || bfd_get_flavour (obfd) != bfd_target_elf_flavour) ++ return true; ++ ++ new_flags = elf_elfheader (ibfd)->e_flags; ++ old_flags = elf_elfheader (obfd)->e_flags; ++ if (!elf_flags_init (obfd)) /* First call, no flags set */ ++ { ++ elf_flags_init (obfd) = true; ++ elf_elfheader (obfd)->e_flags = new_flags; ++ } ++ ++ else if (new_flags == old_flags) /* Compatible flags are ok */ ++ ; ++ ++ else /* Incompatible flags */ ++ { ++ /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib to be linked ++ with either. */ ++ error = false; ++ if ((new_flags & EF_PPC_RELOCATABLE) != 0 ++ && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: compiled with -mrelocatable and linked with modules compiled normally"), ++ bfd_archive_filename (ibfd)); ++ } ++ else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0 ++ && (old_flags & EF_PPC_RELOCATABLE) != 0) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: compiled normally and linked with modules compiled with -mrelocatable"), ++ bfd_archive_filename (ibfd)); ++ } ++ ++ /* The output is -mrelocatable-lib iff both the input files are. */ ++ if (! (new_flags & EF_PPC_RELOCATABLE_LIB)) ++ elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB; ++ ++ /* The output is -mrelocatable iff it can't be -mrelocatable-lib, ++ but each input file is either -mrelocatable or -mrelocatable-lib. */ ++ if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB) ++ && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)) ++ && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))) ++ elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE; ++ ++ /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if any module uses it */ ++ elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB); ++ ++ new_flags &= ~ (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ old_flags &= ~ (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ ++ /* Warn about any other mismatches */ ++ if (new_flags != old_flags) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"), ++ bfd_archive_filename (ibfd), (long) new_flags, (long) old_flags); ++ } ++ ++ if (error) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++/* Handle a PowerPC specific section when reading an object file. This ++ is called when elfcode.h finds a section with an unknown type. */ ++ ++static boolean ++ppc_elf_section_from_shdr (abfd, hdr, name) ++ bfd *abfd; ++ Elf32_Internal_Shdr *hdr; ++ const char *name; ++{ ++ asection *newsect; ++ flagword flags; ++ ++ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) ++ return false; ++ ++ newsect = hdr->bfd_section; ++ flags = bfd_get_section_flags (abfd, newsect); ++ if (hdr->sh_flags & SHF_EXCLUDE) ++ flags |= SEC_EXCLUDE; ++ ++ if (hdr->sh_type == SHT_ORDERED) ++ flags |= SEC_SORT_ENTRIES; ++ ++ bfd_set_section_flags (abfd, newsect, flags); ++ return true; ++} ++ ++/* Set up any other section flags and such that may be necessary. */ ++ ++static boolean ++ppc_elf_fake_sections (abfd, shdr, asect) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ Elf32_Internal_Shdr *shdr; ++ asection *asect; ++{ ++ if ((asect->flags & SEC_EXCLUDE) != 0) ++ shdr->sh_flags |= SHF_EXCLUDE; ++ ++ if ((asect->flags & SEC_SORT_ENTRIES) != 0) ++ shdr->sh_type = SHT_ORDERED; ++ ++ return true; ++} ++ ++/* Create a special linker section */ ++static elf_linker_section_t * ++ppc_elf_create_linker_section (abfd, info, which) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ enum elf_linker_section_enum which; ++{ ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ elf_linker_section_t *lsect; ++ ++ /* Record the first bfd section that needs the special section */ ++ if (!dynobj) ++ dynobj = elf_hash_table (info)->dynobj = abfd; ++ ++ /* If this is the first time, create the section */ ++ lsect = elf_linker_section (dynobj, which); ++ if (!lsect) ++ { ++ elf_linker_section_t defaults; ++ static elf_linker_section_t zero_section; ++ ++ defaults = zero_section; ++ defaults.which = which; ++ defaults.hole_written_p = false; ++ defaults.alignment = 2; ++ ++ /* Both of these sections are (technically) created by the user ++ putting data in them, so they shouldn't be marked ++ SEC_LINKER_CREATED. ++ ++ The linker creates them so it has somewhere to attach their ++ respective symbols. In fact, if they were empty it would ++ be OK to leave the symbol set to 0 (or any random number), because ++ the appropriate register should never be used. */ ++ defaults.flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY); ++ ++ switch (which) ++ { ++ default: ++ (*_bfd_error_handler) (_("%s: Unknown special linker type %d"), ++ bfd_get_filename (abfd), ++ (int) which); ++ ++ bfd_set_error (bfd_error_bad_value); ++ return (elf_linker_section_t *) 0; ++ ++ case LINKER_SECTION_SDATA: /* .sdata/.sbss section */ ++ defaults.name = ".sdata"; ++ defaults.rel_name = ".rela.sdata"; ++ defaults.bss_name = ".sbss"; ++ defaults.sym_name = "_SDA_BASE_"; ++ defaults.sym_offset = 32768; ++ break; ++ ++ case LINKER_SECTION_SDATA2: /* .sdata2/.sbss2 section */ ++ defaults.name = ".sdata2"; ++ defaults.rel_name = ".rela.sdata2"; ++ defaults.bss_name = ".sbss2"; ++ defaults.sym_name = "_SDA2_BASE_"; ++ defaults.sym_offset = 32768; ++ defaults.flags |= SEC_READONLY; ++ break; ++ } ++ ++ lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults); ++ } ++ ++ return lsect; ++} ++ ++/* If we have a non-zero sized .sbss2 or .PPC.EMB.sbss0 sections, we ++ need to bump up the number of section headers. */ ++ ++static int ++ppc_elf_additional_program_headers (abfd) ++ bfd *abfd; ++{ ++ asection *s; ++ int ret; ++ ++ ret = 0; ++ ++ s = bfd_get_section_by_name (abfd, ".interp"); ++ if (s != NULL) ++ ++ret; ++ ++ s = bfd_get_section_by_name (abfd, ".sbss2"); ++ if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0) ++ ++ret; ++ ++ s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0"); ++ if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0) ++ ++ret; ++ ++ return ret; ++} ++ ++/* Modify the segment map if needed. */ ++ ++static boolean ++ppc_elf_modify_segment_map (abfd) ++ bfd *abfd ATTRIBUTE_UNUSED; ++{ ++ return true; ++} ++ ++/* The powerpc .got has a blrl instruction in it. Mark it executable. */ ++ ++static asection * ++ppc_elf_create_got (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ register asection *s; ++ flagword flags; ++ ++ if (!_bfd_elf_create_got_section (abfd, info)) ++ return NULL; ++ ++ s = bfd_get_section_by_name (abfd, ".got"); ++ if (s == NULL) ++ abort (); ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED); ++ if (!bfd_set_section_flags (abfd, s, flags)) ++ return NULL; ++ return s; ++} ++ ++/* We have to create .dynsbss and .rela.sbss here so that they get mapped ++ to output sections (just like _bfd_elf_create_dynamic_sections has ++ to create .dynbss and .rela.bss). */ ++ ++static boolean ++ppc_elf_create_dynamic_sections (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ register asection *s; ++ flagword flags; ++ ++ if (!ppc_elf_create_got (abfd, info)) ++ return false; ++ ++ if (!_bfd_elf_create_dynamic_sections (abfd, info)) ++ return false; ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED); ++ ++ s = bfd_make_section (abfd, ".dynsbss"); ++ if (s == NULL ++ || ! bfd_set_section_flags (abfd, s, SEC_ALLOC)) ++ return false; ++ ++ if (! info->shared) ++ { ++ s = bfd_make_section (abfd, ".rela.sbss"); ++ if (s == NULL ++ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) ++ || ! bfd_set_section_alignment (abfd, s, 2)) ++ return false; ++ } ++ ++ s = bfd_get_section_by_name (abfd, ".plt"); ++ if (s == NULL) ++ abort (); ++ ++ flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED; ++ return bfd_set_section_flags (abfd, s, flags); ++} ++ ++/* Adjust a symbol defined by a dynamic object and referenced by a ++ regular object. The current definition is in some section of the ++ dynamic object, but we're not including those sections. We have to ++ change the definition to something the rest of the link can ++ understand. */ ++ ++static boolean ++ppc_elf_adjust_dynamic_symbol (info, h) ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++{ ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ asection *s; ++ unsigned int power_of_two; ++ bfd_vma plt_offset; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n", h->root.root.string); ++#endif ++ ++ /* Make sure we know what is going on here. */ ++ BFD_ASSERT (dynobj != NULL ++ && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) ++ || h->weakdef != NULL ++ || ((h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_DYNAMIC) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_REF_REGULAR) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_REGULAR) == 0))); ++ ++ /* If this is a function, put it in the procedure linkage table. We ++ will fill in the contents of the procedure linkage table later, ++ when we know the address of the .got section. */ ++ if (h->type == STT_FUNC ++ || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) ++ { ++ if (! elf_hash_table (info)->dynamic_sections_created ++ || SYMBOL_CALLS_LOCAL (info, h) ++ || (info->shared && h->plt.refcount <= 0)) ++ { ++ /* A PLT entry is not required/allowed when: ++ ++ 1. We are not using ld.so; because then the PLT entry ++ can't be set up, so we can't use one. ++ ++ 2. We know for certain that a call to this symbol ++ will go to this object. ++ ++ 3. GC has rendered the entry unused. ++ Note, however, that in an executable all references to the ++ symbol go to the PLT, so we can't turn it off in that case. ++ ??? The correct thing to do here is to reference count ++ all uses of the symbol, not just those to the GOT or PLT. */ ++ h->plt.offset = (bfd_vma) -1; ++ h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; ++ return true; ++ } ++ ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ { ++ if (! bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ } ++ BFD_ASSERT (h->dynindx != -1); ++ ++ s = bfd_get_section_by_name (dynobj, ".plt"); ++ BFD_ASSERT (s != NULL); ++ ++ /* If this is the first .plt entry, make room for the special ++ first entry. */ ++ if (s->_raw_size == 0) ++ s->_raw_size += PLT_INITIAL_ENTRY_SIZE; ++ ++ /* The PowerPC PLT is actually composed of two parts, the first part ++ is 2 words (for a load and a jump), and then there is a remaining ++ word available at the end. */ ++ plt_offset = (PLT_INITIAL_ENTRY_SIZE ++ + (PLT_SLOT_SIZE ++ * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) ++ / PLT_ENTRY_SIZE))); ++ ++ /* If this symbol is not defined in a regular file, and we are ++ not generating a shared library, then set the symbol to this ++ location in the .plt. This is required to make function ++ pointers compare as equal between the normal executable and ++ the shared library. */ ++ if (! info->shared ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ { ++ h->root.u.def.section = s; ++ h->root.u.def.value = plt_offset; ++ } ++ ++ h->plt.offset = plt_offset; ++ ++ /* Make room for this entry. After the 8192nd entry, room ++ for two entries is allocated. */ ++ if ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE ++ >= PLT_NUM_SINGLE_ENTRIES) ++ s->_raw_size += 2 * PLT_ENTRY_SIZE; ++ else ++ s->_raw_size += PLT_ENTRY_SIZE; ++ ++ /* We also need to make an entry in the .rela.plt section. */ ++ s = bfd_get_section_by_name (dynobj, ".rela.plt"); ++ BFD_ASSERT (s != NULL); ++ s->_raw_size += sizeof (Elf32_External_Rela); ++ ++ return true; ++ } ++ else ++ h->plt.offset = (bfd_vma) -1; ++ ++ /* If this is a weak symbol, and there is a real definition, the ++ processor independent code will have arranged for us to see the ++ real definition first, and we can just use the same value. */ ++ if (h->weakdef != NULL) ++ { ++ BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined ++ || h->weakdef->root.type == bfd_link_hash_defweak); ++ h->root.u.def.section = h->weakdef->root.u.def.section; ++ h->root.u.def.value = h->weakdef->root.u.def.value; ++ return true; ++ } ++ ++ /* This is a reference to a symbol defined by a dynamic object which ++ is not a function. */ ++ ++ /* If we are creating a shared library, we must presume that the ++ only references to the symbol are via the global offset table. ++ For such cases we need not do anything here; the relocations will ++ be handled correctly by relocate_section. */ ++ if (info->shared) ++ return true; ++ ++ /* We must allocate the symbol in our .dynbss section, which will ++ become part of the .bss section of the executable. There will be ++ an entry for this symbol in the .dynsym section. The dynamic ++ object will contain position independent code, so all references ++ from the dynamic object to this symbol will go through the global ++ offset table. The dynamic linker will use the .dynsym entry to ++ determine the address it must put in the global offset table, so ++ both the dynamic object and the regular object will refer to the ++ same memory location for the variable. ++ ++ Of course, if the symbol is sufficiently small, we must instead ++ allocate it in .sbss. FIXME: It would be better to do this if and ++ only if there were actually SDAREL relocs for that symbol. */ ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ s = bfd_get_section_by_name (dynobj, ".dynsbss"); ++ else ++ s = bfd_get_section_by_name (dynobj, ".dynbss"); ++ BFD_ASSERT (s != NULL); ++ ++ /* We must generate a R_PPC_COPY reloc to tell the dynamic linker to ++ copy the initial value out of the dynamic object and into the ++ runtime process image. We need to remember the offset into the ++ .rela.bss section we are going to use. */ ++ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) ++ { ++ asection *srel; ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ srel = bfd_get_section_by_name (dynobj, ".rela.sbss"); ++ else ++ srel = bfd_get_section_by_name (dynobj, ".rela.bss"); ++ BFD_ASSERT (srel != NULL); ++ srel->_raw_size += sizeof (Elf32_External_Rela); ++ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; ++ } ++ ++ /* We need to figure out the alignment required for this symbol. I ++ have no idea how ELF linkers handle this. */ ++ power_of_two = bfd_log2 (h->size); ++ if (power_of_two > 4) ++ power_of_two = 4; ++ ++ /* Apply the required alignment. */ ++ s->_raw_size = BFD_ALIGN (s->_raw_size, ++ (bfd_size_type) (1 << power_of_two)); ++ if (power_of_two > bfd_get_section_alignment (dynobj, s)) ++ { ++ if (! bfd_set_section_alignment (dynobj, s, power_of_two)) ++ return false; ++ } ++ ++ /* Define the symbol as being at this point in the section. */ ++ h->root.u.def.section = s; ++ h->root.u.def.value = s->_raw_size; ++ ++ /* Increment the section size to make room for the symbol. */ ++ s->_raw_size += h->size; ++ ++ return true; ++} ++ ++/* Set the sizes of the dynamic sections. */ ++ ++static boolean ++ppc_elf_size_dynamic_sections (output_bfd, info) ++ bfd *output_bfd ATTRIBUTE_UNUSED; ++ struct bfd_link_info *info; ++{ ++ bfd *dynobj; ++ asection *s; ++ boolean plt; ++ boolean relocs; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections called\n"); ++#endif ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ BFD_ASSERT (dynobj != NULL); ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ /* Set the contents of the .interp section to the interpreter. */ ++ if (! info->shared) ++ { ++ s = bfd_get_section_by_name (dynobj, ".interp"); ++ BFD_ASSERT (s != NULL); ++ s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; ++ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; ++ } ++ } ++ else ++ { ++ /* We may have created entries in the .rela.got, .rela.sdata, and ++ .rela.sdata2 sections. However, if we are not creating the ++ dynamic sections, we will not actually use these entries. Reset ++ the size of .rela.got, et al, which will cause it to get ++ stripped from the output file below. */ ++ static char *rela_sections[] = { ".rela.got", ".rela.sdata", ++ ".rela.sdata2", ".rela.sbss", ++ (char *) 0 }; ++ char **p; ++ ++ for (p = rela_sections; *p != (char *) 0; p++) ++ { ++ s = bfd_get_section_by_name (dynobj, *p); ++ if (s != NULL) ++ s->_raw_size = 0; ++ } ++ } ++ ++ /* The check_relocs and adjust_dynamic_symbol entry points have ++ determined the sizes of the various dynamic sections. Allocate ++ memory for them. */ ++ plt = false; ++ relocs = false; ++ for (s = dynobj->sections; s != NULL; s = s->next) ++ { ++ const char *name; ++ boolean strip; ++ ++ if ((s->flags & SEC_LINKER_CREATED) == 0) ++ continue; ++ ++ /* It's OK to base decisions on the section name, because none ++ of the dynobj section names depend upon the input files. */ ++ name = bfd_get_section_name (dynobj, s); ++ ++ strip = false; ++ ++ if (strcmp (name, ".plt") == 0) ++ { ++ if (s->_raw_size == 0) ++ { ++ /* Strip this section if we don't need it; see the ++ comment below. */ ++ strip = true; ++ } ++ else ++ { ++ /* Remember whether there is a PLT. */ ++ plt = true; ++ } ++ } ++ else if (strncmp (name, ".rela", 5) == 0) ++ { ++ if (s->_raw_size == 0) ++ { ++ /* If we don't need this section, strip it from the ++ output file. This is mostly to handle .rela.bss and ++ .rela.plt. We must create both sections in ++ create_dynamic_sections, because they must be created ++ before the linker maps input sections to output ++ sections. The linker does that before ++ adjust_dynamic_symbol is called, and it is that ++ function which decides whether anything needs to go ++ into these sections. */ ++ strip = true; ++ } ++ else ++ { ++ /* Remember whether there are any relocation sections. */ ++ relocs = true; ++ ++ /* We use the reloc_count field as a counter if we need ++ to copy relocs into the output file. */ ++ s->reloc_count = 0; ++ } ++ } ++ else if (strcmp (name, ".got") != 0 ++ && strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sdata2") != 0) ++ { ++ /* It's not one of our sections, so don't allocate space. */ ++ continue; ++ } ++ ++ if (strip) ++ { ++ _bfd_strip_section_from_output (info, s); ++ continue; ++ } ++ ++ /* Allocate memory for the section contents. */ ++ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); ++ if (s->contents == NULL && s->_raw_size != 0) ++ return false; ++ } ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ /* Add some entries to the .dynamic section. We fill in the ++ values later, in ppc_elf_finish_dynamic_sections, but we ++ must add the entries now so that we get the correct size for ++ the .dynamic section. The DT_DEBUG entry is filled in by the ++ dynamic linker and used by the debugger. */ ++#define add_dynamic_entry(TAG, VAL) \ ++ bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL)) ++ ++ if (!info->shared) ++ { ++ if (!add_dynamic_entry (DT_DEBUG, 0)) ++ return false; ++ } ++ ++ if (plt) ++ { ++ if (!add_dynamic_entry (DT_PLTGOT, 0) ++ || !add_dynamic_entry (DT_PLTRELSZ, 0) ++ || !add_dynamic_entry (DT_PLTREL, DT_RELA) ++ || !add_dynamic_entry (DT_JMPREL, 0)) ++ return false; ++ } ++ ++ if (relocs) ++ { ++ if (!add_dynamic_entry (DT_RELA, 0) ++ || !add_dynamic_entry (DT_RELASZ, 0) ++ || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) ++ return false; ++ } ++ ++ if ((info->flags & DF_TEXTREL) != 0) ++ { ++ if (!add_dynamic_entry (DT_TEXTREL, 0)) ++ return false; ++ info->flags |= DF_TEXTREL; ++ } ++ } ++#undef add_dynamic_entry ++ ++ return true; ++} ++ ++/* Look through the relocs for a section during the first phase, and ++ allocate space in the global offset table or procedure linkage ++ table. */ ++ ++static boolean ++ppc_elf_check_relocs (abfd, info, sec, relocs) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ asection *sec; ++ const Elf_Internal_Rela *relocs; ++{ ++ bfd *dynobj; ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; ++ const Elf_Internal_Rela *rel; ++ const Elf_Internal_Rela *rel_end; ++ bfd_signed_vma *local_got_refcounts; ++ elf_linker_section_t *sdata; ++ elf_linker_section_t *sdata2; ++ asection *sreloc; ++ asection *sgot = NULL; ++ asection *srelgot = NULL; ++ ++ if (info->relocateable) ++ return true; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_check_relocs called for section %s in %s\n", ++ bfd_get_section_name (abfd, sec), ++ bfd_archive_filename (abfd)); ++#endif ++ ++ /* Create the linker generated sections all the time so that the ++ special symbols are created. */ ++ ++ if ((sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA)) == NULL) ++ { ++ sdata = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); ++ if (!sdata) ++ return false; ++ } ++ ++ if ((sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2)) == NULL) ++ { ++ sdata2 = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA2); ++ if (!sdata2) ++ return false; ++ } ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ local_got_refcounts = elf_local_got_refcounts (abfd); ++ ++ sym_hashes = elf_sym_hashes (abfd); ++ sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym); ++ if (!elf_bad_symtab (abfd)) ++ sym_hashes_end -= symtab_hdr->sh_info; ++ ++ sreloc = NULL; ++ ++ rel_end = relocs + sec->reloc_count; ++ for (rel = relocs; rel < rel_end; rel++) ++ { ++ unsigned long r_symndx; ++ struct elf_link_hash_entry *h; ++ ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx < symtab_hdr->sh_info) ++ h = NULL; ++ else ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ ++ /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. ++ This shows up in particular in an R_PPC_ADDR32 in the eabi ++ startup code. */ ++ if (h && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) ++ { ++ if (sgot == NULL) ++ { ++ if (dynobj == NULL) ++ elf_hash_table (info)->dynobj = dynobj = abfd; ++ sgot = ppc_elf_create_got (dynobj, info); ++ if (sgot == NULL) ++ return false; ++ } ++ } ++ ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ /* GOT16 relocations */ ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ /* This symbol requires a global offset table entry. */ ++ ++ if (sgot == NULL) ++ { ++ if (dynobj == NULL) ++ elf_hash_table (info)->dynobj = dynobj = abfd; ++ sgot = ppc_elf_create_got (dynobj, info); ++ if (sgot == NULL) ++ return false; ++ } ++ ++ if (srelgot == NULL ++ && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (h != NULL) ++ { ++ if (h->got.refcount == 0) ++ { ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ if (!bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ ++ /* Allocate space in the .got. */ ++ sgot->_raw_size += 4; ++ /* Allocate relocation space. */ ++ srelgot->_raw_size += sizeof (Elf32_External_Rela); ++ } ++ h->got.refcount++; ++ } ++ else ++ { ++ /* This is a global offset table entry for a local symbol. */ ++ if (local_got_refcounts == NULL) ++ { ++ bfd_size_type size; ++ ++ size = symtab_hdr->sh_info; ++ size *= sizeof (bfd_signed_vma); ++ local_got_refcounts ++ = (bfd_signed_vma *) bfd_zalloc (abfd, size); ++ if (local_got_refcounts == NULL) ++ return false; ++ elf_local_got_refcounts (abfd) = local_got_refcounts; ++ } ++ if (local_got_refcounts[r_symndx] == 0) ++ { ++ sgot->_raw_size += 4; ++ ++ /* If we are generating a shared object, we need to ++ output a R_PPC_RELATIVE reloc so that the ++ dynamic linker can adjust this GOT entry. */ ++ if (info->shared) ++ srelgot->_raw_size += sizeof (Elf32_External_Rela); ++ } ++ local_got_refcounts[r_symndx]++; ++ } ++ break; ++ ++ /* Indirect .sdata relocation */ ++ case R_PPC_EMB_SDAI16: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), "R_PPC_EMB_SDAI16")); ++ return false; ++ } ++ ++ if (srelgot == NULL && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata, h, rel)) ++ return false; ++ ++ break; ++ ++ /* Indirect .sdata2 relocation */ ++ case R_PPC_EMB_SDA2I16: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), "R_PPC_EMB_SDA2I16")); ++ return false; ++ } ++ ++ if (srelgot == NULL && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata2, h, rel)) ++ return false; ++ ++ break; ++ ++ case R_PPC_SDAREL16: ++ case R_PPC_EMB_SDA2REL: ++ case R_PPC_EMB_SDA21: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), ++ ppc_elf_howto_table[(int) ELF32_R_TYPE (rel->r_info)]->name)); ++ return false; ++ } ++ break; ++ ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL24: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++#ifdef DEBUG ++ fprintf (stderr, "Reloc requires a PLT entry\n"); ++#endif ++ /* This symbol requires a procedure linkage table entry. We ++ actually build the entry in adjust_dynamic_symbol, ++ because this might be a case of linking PIC code without ++ linking in any dynamic objects, in which case we don't ++ need to generate a procedure linkage table after all. */ ++ ++ if (h == NULL) ++ { ++ /* It does not make sense to have a procedure linkage ++ table entry for a local symbol. */ ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ { ++ if (! bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ } ++ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; ++ h->plt.refcount++; ++ break; ++ ++ /* The following relocations don't need to propagate the ++ relocation if linking a shared object since they are ++ section relative. */ ++ case R_PPC_SECTOFF: ++ case R_PPC_SECTOFF_LO: ++ case R_PPC_SECTOFF_HI: ++ case R_PPC_SECTOFF_HA: ++ break; ++ ++ /* This refers only to functions defined in the shared library */ ++ case R_PPC_LOCAL24PC: ++ break; ++ ++ /* This relocation describes the C++ object vtable hierarchy. ++ Reconstruct it for later use during GC. */ ++ case R_PPC_GNU_VTINHERIT: ++ if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) ++ return false; ++ break; ++ ++ /* This relocation describes which C++ vtable entries are actually ++ used. Record for later use during GC. */ ++ case R_PPC_GNU_VTENTRY: ++ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend)) ++ return false; ++ break; ++ ++ /* When creating a shared object, we must copy these ++ relocs into the output file. We create a reloc ++ section in dynobj and make room for the reloc. */ ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ case R_PPC_REL32: ++ if (h == NULL ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || SYMBOL_REFERENCES_LOCAL (info, h)) ++ break; ++ /* fall through */ ++ ++ default: ++ if (info->shared) ++ { ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_check_relocs need to create relocation for %s\n", ++ (h && h->root.root.string) ? h->root.root.string : "<unknown>"); ++#endif ++ if (sreloc == NULL) ++ { ++ const char *name; ++ ++ name = (bfd_elf_string_from_elf_section ++ (abfd, ++ elf_elfheader (abfd)->e_shstrndx, ++ elf_section_data (sec)->rel_hdr.sh_name)); ++ if (name == NULL) ++ return false; ++ ++ BFD_ASSERT (strncmp (name, ".rela", 5) == 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ++ name + 5) == 0); ++ ++ sreloc = bfd_get_section_by_name (dynobj, name); ++ if (sreloc == NULL) ++ { ++ flagword flags; ++ ++ sreloc = bfd_make_section (dynobj, name); ++ flags = (SEC_HAS_CONTENTS | SEC_READONLY ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ if ((sec->flags & SEC_ALLOC) != 0) ++ flags |= SEC_ALLOC | SEC_LOAD; ++ if (sreloc == NULL ++ || ! bfd_set_section_flags (dynobj, sreloc, flags) ++ || ! bfd_set_section_alignment (dynobj, sreloc, 2)) ++ return false; ++ } ++ if (sec->flags & SEC_READONLY) ++ info->flags |= DF_TEXTREL; ++ } ++ ++ sreloc->_raw_size += sizeof (Elf32_External_Rela); ++ ++ /* FIXME: We should here do what the m68k and i386 ++ backends do: if the reloc is pc-relative, record it ++ in case it turns out that the reloc is unnecessary ++ because the symbol is forced local by versioning or ++ we are linking with -Bdynamic. Fortunately this ++ case is not frequent. */ ++ } ++ ++ break; ++ } ++ } ++ ++ return true; ++} ++ ++/* Return the section that should be marked against GC for a given ++ relocation. */ ++ ++static asection * ++ppc_elf_gc_mark_hook (sec, info, rel, h, sym) ++ asection *sec; ++ struct bfd_link_info *info ATTRIBUTE_UNUSED; ++ Elf_Internal_Rela *rel; ++ struct elf_link_hash_entry *h; ++ Elf_Internal_Sym *sym; ++{ ++ if (h != NULL) ++ { ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_PPC_GNU_VTINHERIT: ++ case R_PPC_GNU_VTENTRY: ++ break; ++ ++ default: ++ switch (h->root.type) ++ { ++ case bfd_link_hash_defined: ++ case bfd_link_hash_defweak: ++ return h->root.u.def.section; ++ ++ case bfd_link_hash_common: ++ return h->root.u.c.p->section; ++ ++ default: ++ break; ++ } ++ } ++ } ++ else ++ return bfd_section_from_elf_index (sec->owner, sym->st_shndx); ++ ++ return NULL; ++} ++ ++/* Update the got entry reference counts for the section being removed. */ ++ ++static boolean ++ppc_elf_gc_sweep_hook (abfd, info, sec, relocs) ++ bfd *abfd; ++ struct bfd_link_info *info ATTRIBUTE_UNUSED; ++ asection *sec; ++ const Elf_Internal_Rela *relocs; ++{ ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes; ++ bfd_signed_vma *local_got_refcounts; ++ const Elf_Internal_Rela *rel, *relend; ++ unsigned long r_symndx; ++ struct elf_link_hash_entry *h; ++ ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ sym_hashes = elf_sym_hashes (abfd); ++ local_got_refcounts = elf_local_got_refcounts (abfd); ++ ++ relend = relocs + sec->reloc_count; ++ for (rel = relocs; rel < relend; rel++) ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ if (h->got.refcount > 0) ++ h->got.refcount--; ++ } ++ else if (local_got_refcounts != NULL) ++ { ++ if (local_got_refcounts[r_symndx] > 0) ++ local_got_refcounts[r_symndx]--; ++ } ++ break; ++ ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL24: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ if (h->plt.refcount > 0) ++ h->plt.refcount--; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return true; ++} ++ ++/* Hook called by the linker routine which adds symbols from an object ++ file. We use it to put .comm items in .sbss, and not .bss. */ ++ ++static boolean ++ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ const Elf_Internal_Sym *sym; ++ const char **namep ATTRIBUTE_UNUSED; ++ flagword *flagsp ATTRIBUTE_UNUSED; ++ asection **secp; ++ bfd_vma *valp; ++{ ++ if (sym->st_shndx == SHN_COMMON ++ && !info->relocateable ++ && sym->st_size <= elf_gp_size (abfd) ++ && info->hash->creator->flavour == bfd_target_elf_flavour) ++ { ++ /* Common symbols less than or equal to -G nn bytes are automatically ++ put into .sdata. */ ++ elf_linker_section_t *sdata ++ = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); ++ ++ if (!sdata->bss_section) ++ { ++ bfd_size_type amt; ++ ++ /* We don't go through bfd_make_section, because we don't ++ want to attach this common section to DYNOBJ. The linker ++ will move the symbols to the appropriate output section ++ when it defines common symbols. */ ++ amt = sizeof (asection); ++ sdata->bss_section = (asection *) bfd_zalloc (abfd, amt); ++ if (sdata->bss_section == NULL) ++ return false; ++ sdata->bss_section->name = sdata->bss_name; ++ sdata->bss_section->flags = SEC_IS_COMMON; ++ sdata->bss_section->output_section = sdata->bss_section; ++ amt = sizeof (asymbol); ++ sdata->bss_section->symbol = (asymbol *) bfd_zalloc (abfd, amt); ++ amt = sizeof (asymbol *); ++ sdata->bss_section->symbol_ptr_ptr = ++ (asymbol **) bfd_zalloc (abfd, amt); ++ if (sdata->bss_section->symbol == NULL ++ || sdata->bss_section->symbol_ptr_ptr == NULL) ++ return false; ++ sdata->bss_section->symbol->name = sdata->bss_name; ++ sdata->bss_section->symbol->flags = BSF_SECTION_SYM; ++ sdata->bss_section->symbol->section = sdata->bss_section; ++ *sdata->bss_section->symbol_ptr_ptr = sdata->bss_section->symbol; ++ } ++ ++ *secp = sdata->bss_section; ++ *valp = sym->st_size; ++ } ++ ++ return true; ++} ++ ++/* Finish up dynamic symbol handling. We set the contents of various ++ dynamic sections here. */ ++ ++static boolean ++ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++ Elf_Internal_Sym *sym; ++{ ++ bfd *dynobj; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s", ++ h->root.root.string); ++#endif ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ BFD_ASSERT (dynobj != NULL); ++ ++ if (h->plt.offset != (bfd_vma) -1) ++ { ++ asection *splt; ++ asection *srela; ++ Elf_Internal_Rela rela; ++ bfd_vma reloc_index; ++ ++#ifdef DEBUG ++ fprintf (stderr, ", plt_offset = %d", h->plt.offset); ++#endif ++ ++ /* This symbol has an entry in the procedure linkage table. Set ++ it up. */ ++ ++ BFD_ASSERT (h->dynindx != -1); ++ ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ srela = bfd_get_section_by_name (dynobj, ".rela.plt"); ++ BFD_ASSERT (splt != NULL && srela != NULL); ++ ++ /* We don't need to fill in the .plt. The ppc dynamic linker ++ will fill it in. */ ++ ++ /* Fill in the entry in the .rela.plt section. */ ++ rela.r_offset = (splt->output_section->vma ++ + splt->output_offset ++ + h->plt.offset); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); ++ rela.r_addend = 0; ++ ++ reloc_index = (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_SLOT_SIZE; ++ if (reloc_index > PLT_NUM_SINGLE_ENTRIES) ++ reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) srela->contents ++ + reloc_index)); ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ { ++ /* Mark the symbol as undefined, rather than as defined in ++ the .plt section. Leave the value alone. */ ++ sym->st_shndx = SHN_UNDEF; ++ /* If the symbol is weak, we do need to clear the value. ++ Otherwise, the PLT entry would provide a definition for ++ the symbol even if the symbol wasn't defined anywhere, ++ and so the symbol would never be NULL. */ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) ++ == 0) ++ sym->st_value = 0; ++ } ++ } ++ ++ if (h->got.offset != (bfd_vma) -1) ++ { ++ asection *sgot; ++ asection *srela; ++ Elf_Internal_Rela rela; ++ ++ /* This symbol has an entry in the global offset table. Set it ++ up. */ ++ ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ srela = bfd_get_section_by_name (dynobj, ".rela.got"); ++ BFD_ASSERT (sgot != NULL && srela != NULL); ++ ++ rela.r_offset = (sgot->output_section->vma ++ + sgot->output_offset ++ + (h->got.offset &~ (bfd_vma) 1)); ++ ++ /* If this is a -Bsymbolic link, and the symbol is defined ++ locally, we just want to emit a RELATIVE reloc. The entry in ++ the global offset table will already have been initialized in ++ the relocate_section function. */ ++ if (info->shared ++ && SYMBOL_REFERENCES_LOCAL (info, h)) ++ { ++ rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ rela.r_addend = (h->root.u.def.value ++ + h->root.u.def.section->output_section->vma ++ + h->root.u.def.section->output_offset); ++ } ++ else ++ { ++ BFD_ASSERT ((h->got.offset & 1) == 0); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_GLOB_DAT); ++ rela.r_addend = 0; ++ } ++ ++ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) srela->contents ++ + srela->reloc_count)); ++ ++srela->reloc_count; ++ } ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) ++ { ++ asection *s; ++ Elf_Internal_Rela rela; ++ ++ /* This symbols needs a copy reloc. Set it up. */ ++ ++#ifdef DEBUG ++ fprintf (stderr, ", copy"); ++#endif ++ ++ BFD_ASSERT (h->dynindx != -1); ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ s = bfd_get_section_by_name (h->root.u.def.section->owner, ++ ".rela.sbss"); ++ else ++ s = bfd_get_section_by_name (h->root.u.def.section->owner, ++ ".rela.bss"); ++ BFD_ASSERT (s != NULL); ++ ++ rela.r_offset = (h->root.u.def.value ++ + h->root.u.def.section->output_section->vma ++ + h->root.u.def.section->output_offset); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY); ++ rela.r_addend = 0; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) s->contents ++ + s->reloc_count)); ++ ++s->reloc_count; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ /* Mark some specially defined symbols as absolute. */ ++ if (strcmp (h->root.root.string, "_DYNAMIC") == 0 ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0) ++ sym->st_shndx = SHN_ABS; ++ ++ return true; ++} ++ ++/* Finish up the dynamic sections. */ ++ ++static boolean ++ppc_elf_finish_dynamic_sections (output_bfd, info) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++{ ++ asection *sdyn; ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ asection *sgot = bfd_get_section_by_name (dynobj, ".got"); ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); ++#endif ++ ++ sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ asection *splt; ++ Elf32_External_Dyn *dyncon, *dynconend; ++ ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ BFD_ASSERT (splt != NULL && sdyn != NULL); ++ ++ dyncon = (Elf32_External_Dyn *) sdyn->contents; ++ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); ++ for (; dyncon < dynconend; dyncon++) ++ { ++ Elf_Internal_Dyn dyn; ++ const char *name; ++ boolean size; ++ ++ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); ++ ++ switch (dyn.d_tag) ++ { ++ case DT_PLTGOT: name = ".plt"; size = false; break; ++ case DT_PLTRELSZ: name = ".rela.plt"; size = true; break; ++ case DT_JMPREL: name = ".rela.plt"; size = false; break; ++ default: name = NULL; size = false; break; ++ } ++ ++ if (name != NULL) ++ { ++ asection *s; ++ ++ s = bfd_get_section_by_name (output_bfd, name); ++ if (s == NULL) ++ dyn.d_un.d_val = 0; ++ else ++ { ++ if (! size) ++ dyn.d_un.d_ptr = s->vma; ++ else ++ { ++ if (s->_cooked_size != 0) ++ dyn.d_un.d_val = s->_cooked_size; ++ else ++ dyn.d_un.d_val = s->_raw_size; ++ } ++ } ++ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); ++ } ++ } ++ } ++ ++ /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can ++ easily find the address of the _GLOBAL_OFFSET_TABLE_. */ ++ if (sgot) ++ { ++ unsigned char *contents = sgot->contents; ++ bfd_put_32 (output_bfd, (bfd_vma) 0x4e800021 /* blrl */, contents); ++ ++ if (sdyn == NULL) ++ bfd_put_32 (output_bfd, (bfd_vma) 0, contents+4); ++ else ++ bfd_put_32 (output_bfd, ++ sdyn->output_section->vma + sdyn->output_offset, ++ contents+4); ++ ++ elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; ++ } ++ ++ return true; ++} ++ ++/* The RELOCATE_SECTION function is called by the ELF backend linker ++ to handle the relocations for a section. ++ ++ The relocs are always passed as Rela structures; if the section ++ actually uses Rel structures, the r_addend field will always be ++ zero. ++ ++ This function is responsible for adjust the section contents as ++ necessary, and (if using Rela relocs and generating a ++ relocateable output file) adjusting the reloc addend as ++ necessary. ++ ++ This function does not have to worry about setting the reloc ++ address or the reloc symbol index. ++ ++ LOCAL_SYMS is a pointer to the swapped in local symbols. ++ ++ LOCAL_SECTIONS is an array giving the section in the input file ++ corresponding to the st_shndx field of each local symbol. ++ ++ The global hash table entry for the global symbols can be found ++ via elf_sym_hashes (input_bfd). ++ ++ When generating relocateable output, this function must handle ++ STB_LOCAL/STT_SECTION symbols specially. The output symbol is ++ going to be the section symbol corresponding to the output ++ section, which means that the addend must be adjusted ++ accordingly. */ ++ ++static boolean ++ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, ++ contents, relocs, local_syms, local_sections) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ bfd *input_bfd; ++ asection *input_section; ++ bfd_byte *contents; ++ Elf_Internal_Rela *relocs; ++ Elf_Internal_Sym *local_syms; ++ asection **local_sections; ++{ ++ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ elf_linker_section_t *sdata = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA) : NULL; ++ elf_linker_section_t *sdata2 = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA2) : NULL; ++ Elf_Internal_Rela *rel = relocs; ++ Elf_Internal_Rela *relend = relocs + input_section->reloc_count; ++ asection *sreloc = NULL; ++ asection *splt; ++ asection *sgot; ++ bfd_vma *local_got_offsets; ++ boolean ret = true; ++ long insn; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_relocate_section called for %s section %s, %ld relocations%s\n", ++ bfd_archive_filename (input_bfd), ++ bfd_section_name(input_bfd, input_section), ++ (long) input_section->reloc_count, ++ (info->relocateable) ? " (relocatable)" : ""); ++#endif ++ ++ if (info->relocateable) ++ return true; ++ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ local_got_offsets = elf_local_got_offsets (input_bfd); ++ ++ splt = sgot = NULL; ++ if (dynobj != NULL) ++ { ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ } ++ ++ for (; rel < relend; rel++) ++ { ++ enum elf_ppc_reloc_type r_type = (enum elf_ppc_reloc_type)ELF32_R_TYPE (rel->r_info); ++ bfd_vma offset = rel->r_offset; ++ bfd_vma addend = rel->r_addend; ++ bfd_reloc_status_type r = bfd_reloc_other; ++ Elf_Internal_Sym *sym = (Elf_Internal_Sym *) 0; ++ asection *sec = (asection *) 0; ++ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) 0; ++ const char *sym_name = (const char *) 0; ++ reloc_howto_type *howto; ++ unsigned long r_symndx; ++ bfd_vma relocation; ++ int will_become_local; ++ ++ /* Unknown relocation handling */ ++ if ((unsigned) r_type >= (unsigned) R_PPC_max ++ || !ppc_elf_howto_table[(int) r_type]) ++ { ++ (*_bfd_error_handler) (_("%s: unknown relocation type %d"), ++ bfd_archive_filename (input_bfd), ++ (int) r_type); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ ++ howto = ppc_elf_howto_table[(int) r_type]; ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ ++ if (r_symndx < symtab_hdr->sh_info) ++ { ++ sym = local_syms + r_symndx; ++ sec = local_sections[r_symndx]; ++ sym_name = "<local symbol>"; ++ ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ addend = rel->r_addend; ++ /* Relocs to local symbols are always resolved. */ ++ will_become_local = 1; ++ } ++ else ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ sym_name = h->root.root.string; ++ ++ /* Can this relocation be resolved immediately? */ ++ will_become_local = SYMBOL_REFERENCES_LOCAL (info, h); ++ ++ if (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ { ++ sec = h->root.u.def.section; ++ if (((r_type == R_PPC_PLT32 ++ || r_type == R_PPC_PLTREL24) ++ && splt != NULL ++ && h->plt.offset != (bfd_vma) -1) ++ || (r_type == R_PPC_LOCAL24PC ++ && sec->output_section == NULL) ++ || ((r_type == R_PPC_GOT16 ++ || r_type == R_PPC_GOT16_LO ++ || r_type == R_PPC_GOT16_HI ++ || r_type == R_PPC_GOT16_HA) ++ && elf_hash_table (info)->dynamic_sections_created ++ && (! info->shared || ! will_become_local)) ++ || (info->shared ++ && ! will_become_local ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ /* Testing SEC_DEBUGGING here may be wrong. ++ It's here to avoid a crash when ++ generating a shared library with DWARF ++ debugging information. */ ++ || ((input_section->flags & SEC_DEBUGGING) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_DYNAMIC) != 0)) ++ && (r_type == R_PPC_ADDR32 ++ || r_type == R_PPC_ADDR24 ++ || r_type == R_PPC_ADDR16 ++ || r_type == R_PPC_ADDR16_LO ++ || r_type == R_PPC_ADDR16_HI ++ || r_type == R_PPC_ADDR16_HA ++ || r_type == R_PPC_ADDR14 ++ || r_type == R_PPC_ADDR14_BRTAKEN ++ || r_type == R_PPC_ADDR14_BRNTAKEN ++ || r_type == R_PPC_COPY ++ || r_type == R_PPC_GLOB_DAT ++ || r_type == R_PPC_JMP_SLOT ++ || r_type == R_PPC_UADDR32 ++ || r_type == R_PPC_UADDR16 ++ || r_type == R_PPC_SDAREL16 ++ || r_type == R_PPC_EMB_NADDR32 ++ || r_type == R_PPC_EMB_NADDR16 ++ || r_type == R_PPC_EMB_NADDR16_LO ++ || r_type == R_PPC_EMB_NADDR16_HI ++ || r_type == R_PPC_EMB_NADDR16_HA ++ || r_type == R_PPC_EMB_SDAI16 ++ || r_type == R_PPC_EMB_SDA2I16 ++ || r_type == R_PPC_EMB_SDA2REL ++ || r_type == R_PPC_EMB_SDA21 ++ || r_type == R_PPC_EMB_MRKREF ++ || r_type == R_PPC_EMB_BIT_FLD ++ || r_type == R_PPC_EMB_RELSDA ++ || ((r_type == R_PPC_REL24 ++ || r_type == R_PPC_REL32 ++ || r_type == R_PPC_REL14 ++ || r_type == R_PPC_REL14_BRTAKEN ++ || r_type == R_PPC_REL14_BRNTAKEN ++ || r_type == R_PPC_RELATIVE) ++ && strcmp (h->root.root.string, ++ "_GLOBAL_OFFSET_TABLE_") != 0)))) ++ { ++ /* In these cases, we don't need the relocation ++ value. We check specially because in some ++ obscure cases sec->output_section will be NULL. */ ++ relocation = 0; ++ } ++ else if (sec->output_section == NULL) ++ { ++ (*_bfd_error_handler) ++ (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"), ++ bfd_archive_filename (input_bfd), h->root.root.string, ++ bfd_get_section_name (input_bfd, input_section)); ++ relocation = 0; ++ } ++ else ++ relocation = (h->root.u.def.value ++ + sec->output_section->vma ++ + sec->output_offset); ++ } ++ else if (h->root.type == bfd_link_hash_undefweak) ++ relocation = 0; ++ else if (info->shared ++ && (!info->symbolic || info->allow_shlib_undefined) ++ && !info->no_undefined ++ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) ++ relocation = 0; ++ else ++ { ++ if (! (*info->callbacks->undefined_symbol) (info, ++ h->root.root.string, ++ input_bfd, ++ input_section, ++ rel->r_offset, ++ (!info->shared ++ || info->no_undefined ++ || ELF_ST_VISIBILITY (h->other)))) ++ return false; ++ relocation = 0; ++ } ++ } ++ ++ switch ((int) r_type) ++ { ++ default: ++ (*_bfd_error_handler) (_("%s: unknown relocation type %d for symbol %s"), ++ bfd_archive_filename (input_bfd), ++ (int) r_type, sym_name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ ++ case (int) R_PPC_NONE: ++ continue; ++ ++ /* Relocations that need no special processing. */ ++ case (int) R_PPC_LOCAL24PC: ++ /* It makes no sense to point a local relocation ++ at a symbol not in this object. */ ++ if (h != NULL ++ && (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && sec->output_section == NULL) ++ { ++ if (! (*info->callbacks->undefined_symbol) (info, ++ h->root.root.string, ++ input_bfd, ++ input_section, ++ rel->r_offset, ++ true)) ++ return false; ++ continue; ++ } ++ break; ++ ++ /* Relocations that may need to be propagated if this is a shared ++ object. */ ++ case (int) R_PPC_REL24: ++ case (int) R_PPC_REL32: ++ case (int) R_PPC_REL14: ++ /* If these relocations are not to a named symbol, they can be ++ handled right here, no need to bother the dynamic linker. */ ++ if (h == NULL ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || SYMBOL_REFERENCES_LOCAL (info, h)) ++ break; ++ /* fall through */ ++ ++ /* Relocations that always need to be propagated if this is a shared ++ object. */ ++ case (int) R_PPC_ADDR32: ++ case (int) R_PPC_ADDR24: ++ case (int) R_PPC_ADDR16: ++ case (int) R_PPC_ADDR16_LO: ++ case (int) R_PPC_ADDR16_HI: ++ case (int) R_PPC_ADDR16_HA: ++ case (int) R_PPC_ADDR14: ++ case (int) R_PPC_UADDR32: ++ case (int) R_PPC_UADDR16: ++ if (info->shared && r_symndx != 0) ++ { ++ Elf_Internal_Rela outrel; ++ int skip; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_relocate_section need to create relocation for %s\n", ++ (h && h->root.root.string) ? h->root.root.string : "<unknown>"); ++#endif ++ ++ /* When generating a shared object, these relocations ++ are copied into the output file to be resolved at run ++ time. */ ++ ++ if (sreloc == NULL) ++ { ++ const char *name; ++ ++ name = (bfd_elf_string_from_elf_section ++ (input_bfd, ++ elf_elfheader (input_bfd)->e_shstrndx, ++ elf_section_data (input_section)->rel_hdr.sh_name)); ++ if (name == NULL) ++ return false; ++ ++ BFD_ASSERT (strncmp (name, ".rela", 5) == 0 ++ && strcmp (bfd_get_section_name (input_bfd, ++ input_section), ++ name + 5) == 0); ++ ++ sreloc = bfd_get_section_by_name (dynobj, name); ++ BFD_ASSERT (sreloc != NULL); ++ } ++ ++ skip = 0; ++ ++ outrel.r_offset = ++ _bfd_elf_section_offset (output_bfd, info, input_section, ++ rel->r_offset); ++ if (outrel.r_offset == (bfd_vma) -1 ++ || outrel.r_offset == (bfd_vma) -2) ++ skip = (int) outrel.r_offset; ++ outrel.r_offset += (input_section->output_section->vma ++ + input_section->output_offset); ++ ++ if (skip) ++ memset (&outrel, 0, sizeof outrel); ++ /* h->dynindx may be -1 if this symbol was marked to ++ become local. */ ++ else if (! will_become_local) ++ { ++ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); ++ outrel.r_addend = rel->r_addend; ++ } ++ else ++ { ++ if (r_type == R_PPC_ADDR32) ++ { ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ outrel.r_addend = relocation + rel->r_addend; ++ } ++ else ++ { ++ long indx; ++ ++ if (h == NULL) ++ sec = local_sections[r_symndx]; ++ else ++ { ++ BFD_ASSERT (h->root.type == bfd_link_hash_defined ++ || (h->root.type ++ == bfd_link_hash_defweak)); ++ sec = h->root.u.def.section; ++ } ++ if (sec != NULL && bfd_is_abs_section (sec)) ++ indx = 0; ++ else if (sec == NULL || sec->owner == NULL) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ else ++ { ++ asection *osec; ++ ++ osec = sec->output_section; ++ indx = elf_section_data (osec)->dynindx; ++ BFD_ASSERT (indx > 0); ++#ifdef DEBUG ++ if (indx <= 0) ++ { ++ printf ("indx=%d section=%s flags=%08x name=%s\n", ++ indx, osec->name, osec->flags, ++ h->root.root.string); ++ } ++#endif ++ } ++ ++ outrel.r_info = ELF32_R_INFO (indx, r_type); ++ outrel.r_addend = relocation + rel->r_addend; ++ } ++ } ++ ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, ++ (((Elf32_External_Rela *) ++ sreloc->contents) ++ + sreloc->reloc_count)); ++ ++sreloc->reloc_count; ++ ++ if (skip == -1) ++ continue; ++ ++ /* This reloc will be computed at runtime. We clear the memory ++ so that it contains predictable value. */ ++ if (! skip ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ || ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE)) ++ { ++ relocation = howto->pc_relative ? outrel.r_offset : 0; ++ addend = 0; ++ break; ++ } ++ } ++ ++ /* Arithmetic adjust relocations that aren't going into a ++ shared object. */ ++ if (r_type == R_PPC_ADDR16_HA ++ /* It's just possible that this symbol is a weak symbol ++ that's not actually defined anywhere. In that case, ++ 'sec' would be NULL, and we should leave the symbol ++ alone (it will be set to zero elsewhere in the link). */ ++ && sec != NULL) ++ { ++ addend += ((relocation + addend) & 0x8000) << 1; ++ } ++ break; ++ ++ /* branch taken prediction relocations */ ++ case (int) R_PPC_ADDR14_BRTAKEN: ++ case (int) R_PPC_REL14_BRTAKEN: ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ if ((relocation - offset) & 0x8000) ++ insn &= ~BRANCH_PREDICT_BIT; ++ else ++ insn |= BRANCH_PREDICT_BIT; ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ break; ++ ++ /* branch not taken predicition relocations */ ++ case (int) R_PPC_ADDR14_BRNTAKEN: ++ case (int) R_PPC_REL14_BRNTAKEN: ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ if ((relocation - offset) & 0x8000) ++ insn |= BRANCH_PREDICT_BIT; ++ else ++ insn &= ~BRANCH_PREDICT_BIT; ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ break; ++ ++ /* GOT16 relocations */ ++ case (int) R_PPC_GOT16: ++ case (int) R_PPC_GOT16_LO: ++ case (int) R_PPC_GOT16_HI: ++ case (int) R_PPC_GOT16_HA: ++ /* Relocation is to the entry for this symbol in the global ++ offset table. */ ++ BFD_ASSERT (sgot != NULL); ++ ++ if (h != NULL) ++ { ++ bfd_vma off; ++ ++ off = h->got.offset; ++ BFD_ASSERT (off != (bfd_vma) -1); ++ ++ if (! elf_hash_table (info)->dynamic_sections_created ++ || (info->shared ++ && SYMBOL_REFERENCES_LOCAL (info, h))) ++ { ++ /* This is actually a static link, or it is a ++ -Bsymbolic link and the symbol is defined ++ locally. We must initialize this entry in the ++ global offset table. Since the offset must ++ always be a multiple of 4, we use the least ++ significant bit to record whether we have ++ initialized it already. ++ ++ When doing a dynamic link, we create a .rela.got ++ relocation entry to initialize the value. This ++ is done in the finish_dynamic_symbol routine. */ ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ bfd_put_32 (output_bfd, relocation, ++ sgot->contents + off); ++ h->got.offset |= 1; ++ } ++ } ++ ++ relocation = sgot->output_offset + off - 4; ++ } ++ else ++ { ++ bfd_vma off; ++ ++ BFD_ASSERT (local_got_offsets != NULL ++ && local_got_offsets[r_symndx] != (bfd_vma) -1); ++ ++ off = local_got_offsets[r_symndx]; ++ ++ /* The offset must always be a multiple of 4. We use ++ the least significant bit to record whether we have ++ already processed this entry. */ ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ ++ if (info->shared) ++ { ++ asection *srelgot; ++ Elf_Internal_Rela outrel; ++ ++ /* We need to generate a R_PPC_RELATIVE reloc ++ for the dynamic linker. */ ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ BFD_ASSERT (srelgot != NULL); ++ ++ outrel.r_offset = (sgot->output_section->vma ++ + sgot->output_offset ++ + off); ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ outrel.r_addend = relocation; ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, ++ (((Elf32_External_Rela *) ++ srelgot->contents) ++ + srelgot->reloc_count)); ++ ++srelgot->reloc_count; ++ relocation = 0; ++ } ++ ++ bfd_put_32 (output_bfd, relocation, sgot->contents + off); ++ local_got_offsets[r_symndx] |= 1; ++ } ++ ++ relocation = sgot->output_offset + off - 4; ++ } ++ break; ++ ++ /* Indirect .sdata relocation */ ++ case (int) R_PPC_EMB_SDAI16: ++ BFD_ASSERT (sdata != NULL); ++ relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, ++ sdata, h, relocation, rel, ++ R_PPC_RELATIVE); ++ break; ++ ++ /* Indirect .sdata2 relocation */ ++ case (int) R_PPC_EMB_SDA2I16: ++ BFD_ASSERT (sdata2 != NULL); ++ relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, ++ sdata2, h, relocation, rel, ++ R_PPC_RELATIVE); ++ break; ++ ++ /* Handle the TOC16 reloc. We want to use the offset within the .got ++ section, not the actual VMA. This is appropriate when generating ++ an embedded ELF object, for which the .got section acts like the ++ AIX .toc section. */ ++ case (int) R_PPC_TOC16: /* phony GOT16 relocations */ ++ BFD_ASSERT (sec != (asection *) 0); ++ BFD_ASSERT (bfd_is_und_section (sec) ++ || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 ++ || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0) ++ ++ addend -= sec->output_section->vma + sec->output_offset + 0x8000; ++ break; ++ ++ case (int) R_PPC_PLTREL24: ++ /* Relocation is to the entry for this symbol in the ++ procedure linkage table. */ ++ BFD_ASSERT (h != NULL); ++ ++ if (h->plt.offset == (bfd_vma) -1 ++ || splt == NULL) ++ { ++ /* We didn't make a PLT entry for this symbol. This ++ happens when statically linking PIC code, or when ++ using -Bsymbolic. */ ++ break; ++ } ++ ++ relocation = (splt->output_section->vma ++ + splt->output_offset ++ + h->plt.offset); ++ break; ++ ++ /* relocate against _SDA_BASE_ */ ++ case (int) R_PPC_SDAREL16: ++ { ++ const char *name; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sbss") != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ } ++ addend -= (sdata->sym_hash->root.u.def.value ++ + sdata->sym_hash->root.u.def.section->output_section->vma ++ + sdata->sym_hash->root.u.def.section->output_offset); ++ } ++ break; ++ ++ /* relocate against _SDA2_BASE_ */ ++ case (int) R_PPC_EMB_SDA2REL: ++ { ++ const char *name; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata2") != 0 && strcmp (name, ".sbss2") != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ addend -= (sdata2->sym_hash->root.u.def.value ++ + sdata2->sym_hash->root.u.def.section->output_section->vma ++ + sdata2->sym_hash->root.u.def.section->output_offset); ++ } ++ break; ++ ++ /* relocate against either _SDA_BASE_, _SDA2_BASE_, or 0 */ ++ case (int) R_PPC_EMB_SDA21: ++ case (int) R_PPC_EMB_RELSDA: ++ { ++ const char *name; ++ int reg; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0) ++ { ++ reg = 13; ++ addend -= (sdata->sym_hash->root.u.def.value ++ + sdata->sym_hash->root.u.def.section->output_section->vma ++ + sdata->sym_hash->root.u.def.section->output_offset); ++ } ++ ++ else if (strcmp (name, ".sdata2") == 0 ++ || strcmp (name, ".sbss2") == 0) ++ { ++ reg = 2; ++ addend -= (sdata2->sym_hash->root.u.def.value ++ + sdata2->sym_hash->root.u.def.section->output_section->vma ++ + sdata2->sym_hash->root.u.def.section->output_offset); ++ } ++ ++ else if (strcmp (name, ".PPC.EMB.sdata0") == 0 ++ || strcmp (name, ".PPC.EMB.sbss0") == 0) ++ { ++ reg = 0; ++ } ++ ++ else ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ ++ if (r_type == R_PPC_EMB_SDA21) ++ { /* fill in register field */ ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ } ++ } ++ break; ++ ++ /* Relocate against the beginning of the section */ ++ case (int) R_PPC_SECTOFF: ++ case (int) R_PPC_SECTOFF_LO: ++ case (int) R_PPC_SECTOFF_HI: ++ BFD_ASSERT (sec != (asection *) 0); ++ addend -= sec->output_section->vma; ++ break; ++ ++ case (int) R_PPC_SECTOFF_HA: ++ BFD_ASSERT (sec != (asection *) 0); ++ addend -= sec->output_section->vma; ++ addend += ((relocation + addend) & 0x8000) << 1; ++ break; ++ ++ /* Negative relocations */ ++ case (int) R_PPC_EMB_NADDR32: ++ case (int) R_PPC_EMB_NADDR16: ++ case (int) R_PPC_EMB_NADDR16_LO: ++ case (int) R_PPC_EMB_NADDR16_HI: ++ addend -= 2 * relocation; ++ break; ++ ++ case (int) R_PPC_EMB_NADDR16_HA: ++ addend -= 2 * relocation; ++ addend += ((relocation + addend) & 0x8000) << 1; ++ break; ++ ++ /* NOP relocation that prevents garbage collecting linkers from omitting a ++ reference. */ ++ case (int) R_PPC_EMB_MRKREF: ++ continue; ++ ++ case (int) R_PPC_COPY: ++ case (int) R_PPC_GLOB_DAT: ++ case (int) R_PPC_JMP_SLOT: ++ case (int) R_PPC_RELATIVE: ++ case (int) R_PPC_PLT32: ++ case (int) R_PPC_PLTREL32: ++ case (int) R_PPC_PLT16_LO: ++ case (int) R_PPC_PLT16_HI: ++ case (int) R_PPC_PLT16_HA: ++ case (int) R_PPC_EMB_RELSEC16: ++ case (int) R_PPC_EMB_RELST_LO: ++ case (int) R_PPC_EMB_RELST_HI: ++ case (int) R_PPC_EMB_RELST_HA: ++ case (int) R_PPC_EMB_BIT_FLD: ++ (*_bfd_error_handler) (_("%s: Relocation %s is not yet supported for symbol %s."), ++ bfd_archive_filename (input_bfd), ++ ppc_elf_howto_table[(int) r_type]->name, ++ sym_name); ++ ++ bfd_set_error (bfd_error_invalid_operation); ++ ret = false; ++ continue; ++ ++ case (int) R_PPC_GNU_VTINHERIT: ++ case (int) R_PPC_GNU_VTENTRY: ++ /* These are no-ops in the end. */ ++ continue; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, offset = %ld, addend = %ld\n", ++ howto->name, ++ (int) r_type, ++ sym_name, ++ r_symndx, ++ (long) offset, ++ (long) addend); ++#endif ++ ++ r = _bfd_final_link_relocate (howto, ++ input_bfd, ++ input_section, ++ contents, ++ offset, ++ relocation, ++ addend); ++ ++ if (r == bfd_reloc_ok) ++ ; ++ else if (r == bfd_reloc_overflow) ++ { ++ const char *name; ++ ++ if (h != NULL) ++ { ++ if (h->root.type == bfd_link_hash_undefweak ++ && howto->pc_relative) ++ { ++ /* Assume this is a call protected by other code that ++ detect the symbol is undefined. If this is the case, ++ we can safely ignore the overflow. If not, the ++ program is hosed anyway, and a little warning isn't ++ going to help. */ ++ ++ continue; ++ } ++ ++ name = h->root.root.string; ++ } ++ else ++ { ++ name = bfd_elf_string_from_elf_section (input_bfd, ++ symtab_hdr->sh_link, ++ sym->st_name); ++ if (name == NULL) ++ continue; ++ if (*name == '\0') ++ name = bfd_section_name (input_bfd, sec); ++ } ++ ++ if (! (*info->callbacks->reloc_overflow) (info, ++ name, ++ howto->name, ++ (bfd_vma) 0, ++ input_bfd, ++ input_section, ++ offset)) ++ return false; ++ } ++ else ++ ret = false; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ return ret; ++} ++ ++static enum elf_reloc_type_class ++ppc_elf_reloc_type_class (rela) ++ const Elf_Internal_Rela *rela; ++{ ++ switch ((int) ELF32_R_TYPE (rela->r_info)) ++ { ++ case R_PPC_RELATIVE: ++ return reloc_class_relative; ++ case R_PPC_REL24: ++ case R_PPC_ADDR24: ++ case R_PPC_JMP_SLOT: ++ return reloc_class_plt; ++ case R_PPC_COPY: ++ return reloc_class_copy; ++ default: ++ return reloc_class_normal; ++ } ++} ++ ++/* Support for core dump NOTE sections */ ++static boolean ++ppc_elf_grok_prstatus (abfd, note) ++ bfd *abfd; ++ Elf_Internal_Note *note; ++{ ++ int offset; ++ unsigned int raw_size; ++ ++ switch (note->descsz) ++ { ++ default: ++ return false; ++ ++ case 268: /* Linux/PPC */ ++ /* pr_cursig */ ++ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); ++ ++ /* pr_pid */ ++ elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); ++ ++ /* pr_reg */ ++ offset = 72; ++ raw_size = 192; ++ ++ break; ++ } ++ ++ /* Make a ".reg/999" section. */ ++ return _bfd_elfcore_make_pseudosection (abfd, ".reg", ++ raw_size, note->descpos + offset); ++} ++ ++static boolean ++ppc_elf_grok_psinfo (abfd, note) ++ bfd *abfd; ++ Elf_Internal_Note *note; ++{ ++ switch (note->descsz) ++ { ++ default: ++ return false; ++ ++ case 128: /* Linux/PPC elf_prpsinfo */ ++ elf_tdata (abfd)->core_program ++ = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); ++ elf_tdata (abfd)->core_command ++ = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); ++ } ++ ++ /* Note that for some reason, a spurious space is tacked ++ onto the end of the args in some (at least one anyway) ++ implementations, so strip it off if it exists. */ ++ ++ { ++ char *command = elf_tdata (abfd)->core_command; ++ int n = strlen (command); ++ ++ if (0 < n && command[n - 1] == ' ') ++ command[n - 1] = '\0'; ++ } ++ ++ return true; ++} ++ ++#define TARGET_BIG_SYM bfd_elf32_amiga_vec ++#define TARGET_BIG_NAME "elf32-amiga" ++#define ELF_ARCH bfd_arch_powerpc ++#define ELF_MACHINE_CODE EM_PPC ++#define ELF_MAXPAGESIZE 0x10000 ++#define elf_info_to_howto ppc_elf_info_to_howto ++ ++#ifdef EM_CYGNUS_POWERPC ++#define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC ++#endif ++ ++#ifdef EM_PPC_OLD ++#define ELF_MACHINE_ALT2 EM_PPC_OLD ++#endif ++ ++#define elf_backend_plt_not_loaded 1 ++#define elf_backend_got_symbol_offset 4 ++#define elf_backend_can_gc_sections 1 ++#define elf_backend_can_refcount 1 ++#define elf_backend_got_header_size 12 ++#define elf_backend_plt_header_size PLT_INITIAL_ENTRY_SIZE ++#define elf_backend_rela_normal 1 ++ ++#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data ++#define bfd_elf32_bfd_relax_section ppc_elf_relax_section ++#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup ++#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags ++#define bfd_elf32_bfd_final_link _bfd_elf32_gc_common_final_link ++ ++#define elf_backend_object_p ppc_elf_object_p ++#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook ++#define elf_backend_gc_sweep_hook ppc_elf_gc_sweep_hook ++#define elf_backend_section_from_shdr ppc_elf_section_from_shdr ++#define elf_backend_relocate_section ppc_elf_relocate_section ++#define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections ++#define elf_backend_check_relocs ppc_elf_check_relocs ++#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol ++#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook ++#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections ++#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol ++#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections ++#define elf_backend_fake_sections ppc_elf_fake_sections ++#define elf_backend_additional_program_headers ppc_elf_additional_program_headers ++#define elf_backend_modify_segment_map ppc_elf_modify_segment_map ++#define elf_backend_grok_prstatus ppc_elf_grok_prstatus ++#define elf_backend_grok_psinfo ppc_elf_grok_psinfo ++#define elf_backend_reloc_type_class ppc_elf_reloc_type_class ++ ++#include "elf32-target.h" +diff --git a/bfd/elf32-ppc.c b/bfd/elf32-amigaos.c +similarity index 97% +copy from bfd/elf32-ppc.c +copy to bfd/elf32-amigaos.c +index 6454a8350da35adf6ed1e2209d9e4774ab7c50e3..9bf9535888f2345d60a8f802680ae03f41f67a5f 100644 +--- a/bfd/elf32-ppc.c ++++ b/bfd/elf32-amigaos.c +@@ -31,32 +31,50 @@ + #include <stdarg.h> + #include "bfd.h" + #include "bfdlink.h" + #include "libbfd.h" + #include "elf-bfd.h" + #include "elf/ppc.h" ++#include "elf/amigaos.h" + #include "elf32-ppc.h" + #include "elf-vxworks.h" + #include "dwarf2.h" + ++#undef DEBUG ++ + typedef enum split16_format_type + { + split16a_type = 0, + split16d_type + } + split16_format_type; + + /* RELA relocations are used here. */ ++#define USE_RELA ++#define USE_REL 0 + + static bfd_reloc_status_type ppc_elf_addr16_ha_reloc + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + static bfd_reloc_status_type ppc_elf_unhandled_reloc + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + static void ppc_elf_vle_split16 + (bfd *, bfd_byte *, bfd_vma, bfd_vma, split16_format_type); + ++int ppc_elf_amigaos_select_plt_layout (bfd *, struct bfd_link_info *, ++ enum ppc_elf_plt_type, int); ++ ++bfd_boolean ppc_elf_amigaos_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr); ++bfd_boolean ppc_elf_amigaos_modify_segment_map (bfd *abfd, ++ struct bfd_link_info *info ATTRIBUTE_UNUSED); ++asection *ppc_elf_amigaos_tls_setup (bfd *obfd, struct bfd_link_info *info, ++ int no_tls_get_addr_opt); ++bfd_boolean ppc_elf_amigaos_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, ++ struct bfd_link_info *info); ++unsigned int _bfd_elf_amigaos_ppc_at_tls_transform (unsigned int insn, unsigned int reg); ++unsigned int _bfd_elf_amigaos_ppc_at_tprel_transform (unsigned int insn, unsigned int reg); ++ + /* Branch prediction bit for branch taken relocs. */ + #define BRANCH_PREDICT_BIT 0x200000 + /* Mask to set RA in memory instructions. */ + #define RA_REGISTER_MASK 0x001f0000 + /* Value to shift register by to insert RA. */ + #define RA_REGISTER_SHIFT 16 +@@ -1381,12 +1399,74 @@ static reloc_howto_type ppc_elf_howto_raw[] = { + /* Relocation not handled: R_PPC_EMB_RELSEC16 */ + /* Relocation not handled: R_PPC_EMB_RELST_LO */ + /* Relocation not handled: R_PPC_EMB_RELST_HI */ + /* Relocation not handled: R_PPC_EMB_RELST_HA */ + /* Relocation not handled: R_PPC_EMB_BIT_FLD */ + ++ ++ /* A standard 32 bit base relative relocation. */ ++ HOWTO (R_PPC_AMIGAOS_BREL, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_AMIGAOS_BREL", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* A 16 bit base relative relocation without overflow. */ ++ HOWTO (R_PPC_AMIGAOS_BREL_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_AMIGAOS_BREL_LO",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of a base relative address. */ ++ HOWTO (R_PPC_AMIGAOS_BREL_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_AMIGAOS_BREL_HI",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ ++ /* The high order 16 bits of a base relative address, plus 1 if the contents ++ of the low 16 bits, treated as a signed number, is negative. */ ++ HOWTO (R_PPC_AMIGAOS_BREL_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_AMIGAOS_BREL_HA",/* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ + /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling + in the 16 bit signed offset from the appropriate base, and filling in the + register field with the appropriate register (0, 2, or 13). */ + HOWTO (R_PPC_EMB_RELSDA, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ +@@ -1935,12 +2015,16 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + r = R_PPC_VLE_SDAREL_HA16D; + break; + case BFD_RELOC_16_PCREL: r = R_PPC_REL16; break; + case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break; + case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break; + case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL: r = R_PPC_AMIGAOS_BREL; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL_LO: r = R_PPC_AMIGAOS_BREL_LO; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL_HI: r = R_PPC_AMIGAOS_BREL_HI; break; ++ case BFD_RELOC_PPC_AMIGAOS_BREL_HA: r = R_PPC_AMIGAOS_BREL_HA; break; + case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break; + case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break; + } + + return ppc_elf_howto_table[r]; + }; +@@ -2268,13 +2352,13 @@ ppc_elf_lookup_section_flags (char *flag_name) + return 0; + } + + /* Add the VLE flag if required. */ + + bfd_boolean +-ppc_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr) ++ppc_elf_amigaos_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr) + { + if (bfd_get_mach (abfd) == bfd_mach_ppc_vle + && (shdr->sh_flags & SHF_EXECINSTR) != 0) + shdr->sh_flags |= SHF_PPC_VLE; + + return TRUE; +@@ -2285,12 +2369,15 @@ ppc_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr) + + static bfd_vma + ppc_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED, + const asection *plt ATTRIBUTE_UNUSED, + const arelent *rel) + { ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_plt_sym_cal (0x%08x)\n", (unsigned int)rel->address); ++#endif + return rel->address; + } + + /* Handle a PowerPC specific section when reading an object file. This + is called when bfd_section_from_shdr finds a section with an unknown + type. */ +@@ -2337,13 +2424,14 @@ ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, + + static int + ppc_elf_additional_program_headers (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) + { + asection *s; +- int ret = 0; ++// int ret = 0; ++ int ret = 1; + + s = bfd_get_section_by_name (abfd, ".sbss2"); + if (s != NULL && (s->flags & SEC_ALLOC) != 0) + ++ret; + + s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0"); +@@ -2353,13 +2441,13 @@ ppc_elf_additional_program_headers (bfd *abfd, + return ret; + } + + /* Modify the segment map for VLE executables. */ + + bfd_boolean +-ppc_elf_modify_segment_map (bfd *abfd, ++ppc_elf_amigaos_modify_segment_map (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) + { + struct elf_segment_map *m, *n; + bfd_size_type amt; + unsigned int j, k; + bfd_boolean sect0_vle, sectj_vle; +@@ -2546,13 +2634,13 @@ apuinfo_list_finish (void) + #define APUINFO_LABEL "APUinfo" + + /* Scan the input BFDs and create a linked list of + the APUinfo values that will need to be emitted. */ + + static void +-ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info) ++ppc_elf_amigaos_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info) + { + bfd *ibfd; + asection *asec; + char *buffer = NULL; + bfd_size_type largest_input_size = 0; + unsigned i; +@@ -2646,24 +2734,24 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info) + } + + /* Prevent the output section from accumulating the input sections' + contents. We have already stored this in our linked list structure. */ + + static bfd_boolean +-ppc_elf_write_section (bfd *abfd ATTRIBUTE_UNUSED, ++ppc_elf_amigaos_write_section (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *link_info ATTRIBUTE_UNUSED, + asection *asec, + bfd_byte *contents ATTRIBUTE_UNUSED) + { + return apuinfo_set && strcmp (asec->name, APUINFO_SECTION_NAME) == 0; + } + + /* Finally we can generate the output section. */ + + static void +-ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) ++ppc_elf_amigaos_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) + { + bfd_byte *buffer; + asection *asec; + unsigned i; + unsigned num_entries; + bfd_size_type length; +@@ -3232,13 +3320,13 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) + abort (); + } + else + { + /* The powerpc .got has a blrl instruction in it. Mark it + executable. */ +- flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS ++ flags = (SEC_ALLOC | SEC_LOAD | /*SEC_CODE |*/ SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + if (!bfd_set_section_flags (abfd, s, flags)) + return FALSE; + } + + htab->relgot = bfd_get_linker_section (abfd, ".rela.got"); +@@ -3340,13 +3428,13 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) + + htab->relplt = bfd_get_linker_section (abfd, ".rela.plt"); + htab->plt = s = bfd_get_linker_section (abfd, ".plt"); + if (s == NULL) + abort (); + +- flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED; ++ flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED | SEC_READONLY; + if (htab->plt_type == PLT_VXWORKS) + /* The VxWorks PLT is a loaded section with contents. */ + flags |= SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY; + return bfd_set_section_flags (abfd, s, flags); + } + +@@ -3410,13 +3498,13 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info, + eind->dyn_relocs = NULL; + } + + /* If we were called to copy over info for a weak sym, that's all. + You might think dyn_relocs need not be copied over; After all, + both syms will be dynamic or both non-dynamic so we're just +- moving reloc accounting around. However, ELIMINATE_COPY_RELOCS ++ moving reloc accounting around. However, ELIMINATE_COPY_RELOCS + code in ppc_elf_adjust_dynamic_symbol needs to check for + dyn_relocs in read-only sections, and it does so on what is the + DIR sym here. */ + if (eind->elf.root.type != bfd_link_hash_indirect) + return; + +@@ -4186,12 +4274,19 @@ ppc_elf_check_relocs (bfd *abfd, + case R_PPC_EMB_RELST_LO: + case R_PPC_EMB_RELST_HI: + case R_PPC_EMB_RELST_HA: + case R_PPC_EMB_BIT_FLD: + break; + ++ /* These don't work with a GOT */ ++ case R_PPC_AMIGAOS_BREL: ++ case R_PPC_AMIGAOS_BREL_HI: ++ case R_PPC_AMIGAOS_BREL_LO: ++ case R_PPC_AMIGAOS_BREL_HA: ++ break; ++ + /* This refers only to functions defined in the shared library. */ + case R_PPC_LOCAL24PC: + if (h != NULL && h == htab->elf.hgot && htab->plt_type == PLT_UNSET) + { + htab->plt_type = PLT_OLD; + htab->old_bfd = abfd; +@@ -4679,13 +4774,13 @@ ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents, + } + + + /* Choose which PLT scheme to use, and set .plt flags appropriately. + Returns -1 on error, 0 for old PLT, 1 for new PLT. */ + int +-ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, ++ppc_elf_amigaos_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info, + enum ppc_elf_plt_type plt_style, + int emit_stub_syms) + { + struct ppc_elf_link_hash_table *htab; + flagword flags; +@@ -4976,13 +5071,13 @@ ppc_elf_gc_sweep_hook (bfd *abfd, + } + + /* Set plt output section type, htab->tls_get_addr, and call the + generic ELF tls_setup function. */ + + asection * +-ppc_elf_tls_setup (bfd *obfd, ++ppc_elf_amigaos_tls_setup (bfd *obfd, + struct bfd_link_info *info, + int no_tls_get_addr_opt) + { + struct ppc_elf_link_hash_table *htab; + + htab = ppc_elf_hash_table (info); +@@ -5075,13 +5170,13 @@ branch_reloc_hash_match (const bfd *ibfd, + } + + /* Run through all the TLS relocs looking for optimization + opportunities. */ + + bfd_boolean +-ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, ++ppc_elf_amigaos_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) + { + bfd *ibfd; + asection *sec; + struct ppc_elf_link_hash_table *htab; + int pass; +@@ -6008,12 +6103,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, + fprintf (stderr, "ppc_elf_size_dynamic_sections called\n"); + #endif + + htab = ppc_elf_hash_table (info); + BFD_ASSERT (htab->elf.dynobj != NULL); + ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections: dynamic_sections_created = %d\n", elf_hash_table (info)->dynamic_sections_created); ++#endif ++ + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (info->executable) + { + s = bfd_get_linker_section (htab->elf.dynobj, ".interp"); +@@ -6037,12 +6136,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, + struct plt_entry **local_plt; + struct plt_entry **end_local_plt; + char *lgot_masks; + bfd_size_type locsymcount; + Elf_Internal_Shdr *symtab_hdr; + ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections: is_ppc_elf() = %d (flavour = %d)\n", is_ppc_elf (ibfd), bfd_get_flavour (ibfd)); ++#endif ++ + if (!is_ppc_elf (ibfd)) + continue; + + for (s = ibfd->sections; s != NULL; s = s->next) + { + struct elf_dyn_relocs *p; +@@ -6400,12 +6503,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, + if (!add_dynamic_entry (DT_TEXTREL, 0)) + return FALSE; + } + if (htab->is_vxworks + && !elf_vxworks_add_dynamic_entries (output_bfd, info)) + return FALSE; ++ ++ /* Flag it as a version 2 dynamic binary */ ++ if (!add_dynamic_entry(DT_AMIGAOS_DYNVERSION, 2)) ++ return FALSE; + } + #undef add_dynamic_entry + + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->contents != NULL) + { +@@ -7172,13 +7279,13 @@ is_static_defined (struct elf_link_hash_entry *h) + + /* If INSN is an opcode that may be used with an @tls operand, return + the transformed insn for TLS optimisation, otherwise return 0. If + REG is non-zero only match an insn with RB or RA equal to REG. */ + + unsigned int +-_bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg) ++_bfd_elf_amigaos_ppc_at_tls_transform (unsigned int insn, unsigned int reg) + { + unsigned int rtra; + + if ((insn & (0x3f << 26)) != 31 << 26) + return 0; + +@@ -7212,13 +7319,13 @@ _bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg) + + /* If INSN is an opcode that may be used with an @tprel operand, return + the transformed insn for an undefined weak symbol, ie. with the + thread pointer REG operand removed. Otherwise return 0. */ + + unsigned int +-_bfd_elf_ppc_at_tprel_transform (unsigned int insn, unsigned int reg) ++_bfd_elf_amigaos_ppc_at_tprel_transform (unsigned int insn, unsigned int reg) + { + if ((insn & (0x1f << 16)) == reg << 16 + && ((insn & (0x3f << 26)) == 14u << 26 /* addi */ + || (insn & (0x3f << 26)) == 15u << 26 /* addis */ + || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ + || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ +@@ -8076,13 +8183,13 @@ ppc_elf_relocate_section (bfd *output_bfd, + /* Make this relocation against an undefined weak symbol + resolve to zero. This is really just a tweak, since + code using weak externs ought to check that they are + defined before using them. */ + bfd_byte *p = contents + rel->r_offset - d_offset; + unsigned int insn = bfd_get_32 (output_bfd, p); +- insn = _bfd_elf_ppc_at_tprel_transform (insn, 2); ++ insn = _bfd_elf_amigaos_ppc_at_tprel_transform (insn, 2); + if (insn != 0) + bfd_put_32 (output_bfd, insn, p); + break; + } + addend -= htab->elf.tls_sec->vma + TP_OFFSET; + /* The TPREL16 relocs shouldn't really be used in shared +@@ -8502,13 +8609,47 @@ ppc_elf_relocate_section (bfd *output_bfd, + sym_name, + howto->name, + name); + } + } + break; ++#if 0 ++ case R_PPC_AMIGAOS_BREL: ++ case R_PPC_AMIGAOS_BREL_HI: ++ case R_PPC_AMIGAOS_BREL_LO: ++ case R_PPC_AMIGAOS_BREL_HA: ++ { ++ if (data_section == NULL) ++ data_section = bfd_get_section_by_name (output_bfd, ".data"); ++ ++ if (sec) ++ { ++ const char *name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sbss") != 0 ++ && strcmp (name, ".data") != 0 ++ && strcmp (name, ".bss") != 0 ++ && strncmp (name, ".ctors", 6) != 0 ++ && strncmp (name, ".dtors", 6) != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ input_bfd, ++ sym_name, ++ howto->name, ++ name); ++ } ++ } ++ ++ addend = addend - data_section->vma; ++ ++ if (r_type == R_PPC_AMIGAOS_BREL_HA) ++ addend += ((relocation + addend) & 0x8000) << 1; + ++ } ++ break; ++#endif + case R_PPC_VLE_LO16A: + relocation = (relocation + addend) & 0xffff; + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + relocation, split16a_type); + continue; + +@@ -8899,12 +9040,15 @@ ppc_elf_relocate_section (bfd *output_bfd, + input_section, + contents, + rel->r_offset, + relocation, + addend); + ++#ifdef DEBUG ++ fprintf (stderr, "%p %p %p\n", (void *)rel->r_offset, (void *)relocation, (void *)addend); ++#endif + if (r != bfd_reloc_ok) + { + if (r == bfd_reloc_overflow) + { + if (warned) + continue; +@@ -9124,18 +9268,24 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, + || h->dynindx == -1) + splt = htab->iplt; + + rela.r_offset = (splt->output_section->vma + + splt->output_offset + + ent->plt.offset); ++#ifdef DEBUG ++ fprintf (stderr, " r_offset = %p ", (void *)rela.r_offset); ++#endif + if (htab->plt_type == PLT_OLD + || !htab->elf.dynamic_sections_created + || h->dynindx == -1) + { + /* We don't need to fill in the .plt. The ppc dynamic + linker will fill it in. */ ++#ifdef DEBUG ++ fprintf (stderr, " not filling in .plt "); ++#endif + } + else + { + bfd_vma val = (htab->glink_pltresolve + ent->plt.offset + + htab->glink->output_section->vma + + htab->glink->output_offset); +@@ -9166,24 +9316,34 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, + * sizeof (Elf32_External_Rela))); + else + loc = (htab->relplt->contents + + reloc_index * sizeof (Elf32_External_Rela)); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + ++#ifdef DEBUG ++ fprintf (stderr, " r_offset = %p r_addednd = %p, r_info = 0x%08x, h->def_regular = %d", (void *)rela.r_offset, (void *)rela.r_addend, (unsigned int)rela.r_info, (int)h->def_regular); ++#endif + if (!h->def_regular) + { + /* Mark the symbol as undefined, rather than as + defined in the .plt section. Leave the value if + there were any relocations where pointer equality + matters (this is a clue for the dynamic linker, to + make function pointer comparisons work between an + application and shared library), otherwise set it + to zero. */ + sym->st_shndx = SHN_UNDEF; + if (!h->pointer_equality_needed) +- sym->st_value = 0; ++ { ++ /* THF: This is peculiar. The compiler generates a R_PPC_REL24 for externally referenced ++ * symbols impoted from libc.so. Relocation in elf.library requires the symbol to have it's .plt ++ * stub value, but the linker specifically clears the value to 0, resulting in run-time ++ * errors when the binary tries to call libc functions. ++ */ ++ // sym->st_value = 0; ++ } + else if (!h->ref_regular_nonweak) + { + /* This breaks function pointer comparisons, but + that is better than breaking tests for a NULL + function pointer. */ + sym->st_value = 0; +@@ -9275,12 +9435,15 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, + rela.r_addend = 0; + loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + } + + #ifdef DEBUG ++ fprintf (stderr, " SYM_VAL(%p) ", (void *)SYM_VAL(h)); ++#endif ++#ifdef DEBUG + fprintf (stderr, "\n"); + #endif + + return TRUE; + } + +@@ -9735,16 +9898,14 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, + return FALSE; + } + + return ret; + } + +-#define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec +-#define TARGET_LITTLE_NAME "elf32-powerpcle" +-#define TARGET_BIG_SYM bfd_elf32_powerpc_vec +-#define TARGET_BIG_NAME "elf32-powerpc" ++#define TARGET_BIG_SYM bfd_elf32_amigaos_vec ++#define TARGET_BIG_NAME "elf32-amigaos" + #define ELF_ARCH bfd_arch_powerpc + #define ELF_TARGET_ID PPC32_ELF_DATA + #define ELF_MACHINE_CODE EM_PPC + #ifdef __QNXTARGET__ + #define ELF_MAXPAGESIZE 0x1000 + #else +@@ -9789,153 +9950,23 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, + #define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections + #define elf_backend_hash_symbol ppc_elf_hash_symbol + #define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol + #define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections + #define elf_backend_fake_sections ppc_elf_fake_sections + #define elf_backend_additional_program_headers ppc_elf_additional_program_headers +-#define elf_backend_modify_segment_map ppc_elf_modify_segment_map ++#define elf_backend_modify_segment_map ppc_elf_amigaos_modify_segment_map + #define elf_backend_grok_prstatus ppc_elf_grok_prstatus + #define elf_backend_grok_psinfo ppc_elf_grok_psinfo + #define elf_backend_write_core_note ppc_elf_write_core_note + #define elf_backend_reloc_type_class ppc_elf_reloc_type_class +-#define elf_backend_begin_write_processing ppc_elf_begin_write_processing +-#define elf_backend_final_write_processing ppc_elf_final_write_processing +-#define elf_backend_write_section ppc_elf_write_section ++#define elf_backend_begin_write_processing ppc_elf_amigaos_begin_write_processing ++#define elf_backend_final_write_processing ppc_elf_amigaos_final_write_processing ++#define elf_backend_write_section ppc_elf_amigaos_write_section + #define elf_backend_get_sec_type_attr ppc_elf_get_sec_type_attr + #define elf_backend_plt_sym_val ppc_elf_plt_sym_val + #define elf_backend_action_discarded ppc_elf_action_discarded + #define elf_backend_init_index_section _bfd_elf_init_1_index_section + #define elf_backend_post_process_headers _bfd_elf_set_osabi + #define elf_backend_lookup_section_flags_hook ppc_elf_lookup_section_flags +-#define elf_backend_section_processing ppc_elf_section_processing +- +-#include "elf32-target.h" +- +-/* FreeBSD Target */ +- +-#undef TARGET_LITTLE_SYM +-#undef TARGET_LITTLE_NAME +- +-#undef TARGET_BIG_SYM +-#define TARGET_BIG_SYM bfd_elf32_powerpc_freebsd_vec +-#undef TARGET_BIG_NAME +-#define TARGET_BIG_NAME "elf32-powerpc-freebsd" +- +-#undef ELF_OSABI +-#define ELF_OSABI ELFOSABI_FREEBSD +- +-#undef elf32_bed +-#define elf32_bed elf32_powerpc_fbsd_bed +- +-#include "elf32-target.h" +- +-/* VxWorks Target */ +- +-#undef TARGET_LITTLE_SYM +-#undef TARGET_LITTLE_NAME +- +-#undef TARGET_BIG_SYM +-#define TARGET_BIG_SYM bfd_elf32_powerpc_vxworks_vec +-#undef TARGET_BIG_NAME +-#define TARGET_BIG_NAME "elf32-powerpc-vxworks" +- +-#undef ELF_OSABI +- +-/* VxWorks uses the elf default section flags for .plt. */ +-static const struct bfd_elf_special_section * +-ppc_elf_vxworks_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) +-{ +- if (sec->name == NULL) +- return NULL; +- +- if (strcmp (sec->name, ".plt") == 0) +- return _bfd_elf_get_sec_type_attr (abfd, sec); +- +- return ppc_elf_get_sec_type_attr (abfd, sec); +-} +- +-/* Like ppc_elf_link_hash_table_create, but overrides +- appropriately for VxWorks. */ +-static struct bfd_link_hash_table * +-ppc_elf_vxworks_link_hash_table_create (bfd *abfd) +-{ +- struct bfd_link_hash_table *ret; +- +- ret = ppc_elf_link_hash_table_create (abfd); +- if (ret) +- { +- struct ppc_elf_link_hash_table *htab +- = (struct ppc_elf_link_hash_table *)ret; +- htab->is_vxworks = 1; +- htab->plt_type = PLT_VXWORKS; +- htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE; +- htab->plt_slot_size = VXWORKS_PLT_ENTRY_SIZE; +- htab->plt_initial_entry_size = VXWORKS_PLT_INITIAL_ENTRY_SIZE; +- } +- return ret; +-} +- +-/* Tweak magic VxWorks symbols as they are loaded. */ +-static bfd_boolean +-ppc_elf_vxworks_add_symbol_hook (bfd *abfd, +- struct bfd_link_info *info, +- Elf_Internal_Sym *sym, +- const char **namep ATTRIBUTE_UNUSED, +- flagword *flagsp ATTRIBUTE_UNUSED, +- asection **secp, +- bfd_vma *valp) +-{ +- if (!elf_vxworks_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, +- valp)) +- return FALSE; +- +- return ppc_elf_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, valp); +-} +- +-static void +-ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) +-{ +- ppc_elf_final_write_processing(abfd, linker); +- elf_vxworks_final_write_processing(abfd, linker); +-} +- +-/* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so +- define it. */ +-#undef elf_backend_want_plt_sym +-#define elf_backend_want_plt_sym 1 +-#undef elf_backend_want_got_plt +-#define elf_backend_want_got_plt 1 +-#undef elf_backend_got_symbol_offset +-#define elf_backend_got_symbol_offset 0 +-#undef elf_backend_plt_not_loaded +-#define elf_backend_plt_not_loaded 0 +-#undef elf_backend_plt_readonly +-#define elf_backend_plt_readonly 1 +-#undef elf_backend_got_header_size +-#define elf_backend_got_header_size 12 +- +-#undef bfd_elf32_get_synthetic_symtab +- +-#undef bfd_elf32_bfd_link_hash_table_create +-#define bfd_elf32_bfd_link_hash_table_create \ +- ppc_elf_vxworks_link_hash_table_create +-#undef elf_backend_add_symbol_hook +-#define elf_backend_add_symbol_hook \ +- ppc_elf_vxworks_add_symbol_hook +-#undef elf_backend_link_output_symbol_hook +-#define elf_backend_link_output_symbol_hook \ +- elf_vxworks_link_output_symbol_hook +-#undef elf_backend_final_write_processing +-#define elf_backend_final_write_processing \ +- ppc_elf_vxworks_final_write_processing +-#undef elf_backend_get_sec_type_attr +-#define elf_backend_get_sec_type_attr \ +- ppc_elf_vxworks_get_sec_type_attr +-#undef elf_backend_emit_relocs +-#define elf_backend_emit_relocs \ +- elf_vxworks_emit_relocs +- +-#undef elf32_bed +-#define elf32_bed ppc_elf_vxworks_bed +-#undef elf_backend_post_process_headers ++#define elf_backend_section_processing ppc_elf_amigaos_section_processing + + #include "elf32-target.h" +diff --git a/bfd/elf32-i386-amithlon.c b/bfd/elf32-i386-amithlon.c +new file mode 100644 +index 0000000000000000000000000000000000000000..4e029a5e90187a96013ed97e078fba920d95db28 +--- /dev/null ++++ b/bfd/elf32-i386-amithlon.c +@@ -0,0 +1,198 @@ ++/* Intel IA-32 specific support for 32-bit big endian ELF on Amithlon. ++ Copyright 2002 Free Software Foundation, Inc. ++ Written by Martin Blom. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++#define TARGET_LITTLE_SYM bfd_elf32_i386_amithlon_vec ++#define TARGET_LITTLE_NAME "elf32-i386-amithlon" ++#define TARGET_BIG_SYM bfd_elf32_i386be_amithlon_vec ++#define TARGET_BIG_NAME "elf32-i386be-amithlon" ++#define ELF_ARCH bfd_arch_i386 ++#define ELF_MACHINE_CODE EM_386 ++#define ELF_MAXPAGESIZE 32 //0x1000 ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "elf-bfd.h" ++ ++/* Forward declarations */ ++extern const bfd_target bfd_elf32_i386_amithlon_vec; ++extern const bfd_target bfd_elf32_i386be_amithlon_vec; ++ ++static boolean elf_i386_relocate_section ++ PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, ++ Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); ++ ++static boolean elf_i386_finish_dynamic_sections ++ PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static boolean elf_i386_finish_dynamic_symbol ++ PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, ++ Elf_Internal_Sym *)); ++ ++boolean elf_link_output_relocs ++ PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *)); ++ ++#define swap_xvec(xvec,c) \ ++do { \ ++ xvec->bfd_getx64 = bfd_get ## c ## 64; \ ++ xvec->bfd_getx_signed_64 = bfd_get ## c ## _signed_64; \ ++ xvec->bfd_putx64 = bfd_put ## c ## 64; \ ++ xvec->bfd_getx32 = bfd_get ## c ## 32; \ ++ xvec->bfd_getx_signed_32 = bfd_get ## c ## _signed_32; \ ++ xvec->bfd_putx32 = bfd_put ## c ## 32; \ ++ xvec->bfd_getx16 = bfd_get ## c ## 16; \ ++ xvec->bfd_getx_signed_16 = bfd_get ## c ## _signed_16; \ ++ xvec->bfd_putx16 = bfd_put ## c ## 16; \ ++} while(0) ++ ++/* Relocate a big endian i386 ELF section. */ ++ ++static boolean ++amithlon_relocate_section (output_bfd, info, input_bfd, input_section, ++ contents, relocs, local_syms, local_sections) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ bfd *input_bfd; ++ asection *input_section; ++ bfd_byte *contents; ++ Elf_Internal_Rela *relocs; ++ Elf_Internal_Sym *local_syms; ++ asection **local_sections; ++{ ++ boolean switched_input = false; ++ boolean switched_output = false; ++ boolean rc; ++ ++ /* Since code sections are actually little endian, no matter what ++ endian mode we're operating in, this rather dirty hack is used to ++ make sure the correct data access routines are used. */ ++ ++ if ((bfd_get_section_flags (input_bfd, input_section) & SEC_CODE)) ++ { ++ if (input_bfd->xvec == &bfd_elf32_i386be_amithlon_vec) ++ { ++ switched_input = true; ++ ++ swap_xvec(input_bfd->xvec,l); ++ } ++ ++ if (output_bfd->xvec == &bfd_elf32_i386be_amithlon_vec) ++ { ++ switched_output = true; ++ ++ swap_xvec(output_bfd->xvec,l); ++ } ++ } ++ ++ rc = elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, ++ contents, relocs, ++ local_syms, local_sections); ++ ++ if (switched_input) ++ { ++ swap_xvec(input_bfd->xvec,b); ++ } ++ ++ if (switched_output) ++ { ++ swap_xvec(output_bfd->xvec,b); ++ } ++ ++ return rc; ++} ++ ++static boolean ++amithlon_finish_dynamic_sections (output_bfd, info) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++{ ++ boolean switched_output = false; ++ boolean rc; ++ ++ /* Since code sections are actually little endian, no matter what ++ endian mode we're operating in, this rather dirty hack is used to ++ make sure the correct data access routines are used. */ ++ ++ if (output_bfd->xvec == &bfd_elf32_i386be_amithlon_vec) ++ { ++ switched_output = true; ++ ++ swap_xvec(output_bfd->xvec,l); ++ } ++ ++ rc = elf_i386_finish_dynamic_sections (output_bfd, info); ++ ++ if (switched_output) ++ { ++ swap_xvec(output_bfd->xvec,b); ++ } ++ ++ return rc; ++} ++ ++static boolean ++amithlon_finish_dynamic_symbol (output_bfd, info, h, sym) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++ Elf_Internal_Sym *sym; ++{ ++ boolean switched_output = false; ++ boolean rc; ++ ++ /* Since code sections are actually little endian, no matter what ++ endian mode we're operating in, this rather dirty hack is used to ++ make sure the correct data access routines are used. */ ++ ++ if (output_bfd->xvec == &bfd_elf32_i386be_amithlon_vec) ++ { ++ switched_output = true; ++ ++ swap_xvec(output_bfd->xvec,l); ++ } ++ ++ rc = elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym); ++ ++ if (switched_output) ++ { ++ swap_xvec(output_bfd->xvec,b); ++ } ++ ++ return rc; ++} ++ ++static bfd_size_type ++amithlon_additional_program_headers (abfd) ++ bfd *abfd; ++{ ++// printf("big: %x little: %x\n", ++// &bfd_elf32_i386be_amithlon_vec, ++// &bfd_elf32_i386_amithlon_vec); ++ // headers, text, rodata, data+bss ++ return -2+4; ++} ++ ++#define elf_backend_relocate_section amithlon_relocate_section ++#define elf_backend_finish_dynamic_sections amithlon_finish_dynamic_sections ++#define elf_backend_finish_dynamic_symbol amithlon_finish_dynamic_symbol ++#define elf_backend_additional_program_headers amithlon_additional_program_headers ++ ++#define ELF32_I386_RELOCATABLE_EXECUTABLES 1 ++ ++#include "elf32-i386.c" +diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c +index 0a6b22ec19ec9daee29e49c64c5d3ba2299e99c1..46396c83d45bab97de1470ee44ffa21f9d03e4b4 100644 +--- a/bfd/elf32-i386.c ++++ b/bfd/elf32-i386.c +@@ -29,12 +29,16 @@ + #include "elf-vxworks.h" + #include "bfd_stdint.h" + #include "objalloc.h" + #include "hashtab.h" + #include "dwarf2.h" + ++#ifndef ELF32_I386_RELOCATABLE_EXECUTABLES ++#define ELF32_I386_RELOCATABLE_EXECUTABLES 0 ++#endif ++ + /* 386 uses REL relocations instead of RELA. */ + #define USE_REL 1 + + #include "elf/i386.h" + + static reloc_howto_type elf_howto_table[]= +@@ -1779,13 +1783,13 @@ elf_i386_check_relocs (bfd *abfd, + symbol local. + + If on the other hand, we are creating an executable, we + may need to keep relocations for symbols satisfied by a + dynamic library if we manage to avoid copy relocs for the + symbol. */ +- if ((info->shared ++ if (((ELF32_I386_RELOCATABLE_EXECUTABLES || info->shared) + && (sec->flags & SEC_ALLOC) != 0 + && (r_type != R_386_PC32 + || (h != NULL + && (! SYMBOLIC_BIND (info, h) + || h->root.type == bfd_link_hash_defweak + || !h->def_regular)))) +@@ -2410,13 +2414,13 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to be + defined in regular objects. For the normal shared case, discard + space for pc-relative relocs that have become local due to symbol + visibility changes. */ + +- if (info->shared) ++ if (ELF32_I386_RELOCATABLE_EXECUTABLES || info->shared) + { + /* The only reloc that uses pc_count is R_386_PC32, which will + appear on a call or on something like ".long foo - .". We + want calls to protected symbols to resolve directly to the + function rather than going via the plt. If people want + function pointer comparisons to work as expected then they +@@ -3592,13 +3596,13 @@ elf_i386_relocate_section (bfd *output_bfd, + case R_386_32: + case R_386_PC32: + if ((input_section->flags & SEC_ALLOC) == 0 + || is_vxworks_tls) + break; + +- if ((info->shared ++ if (((ELF32_I386_RELOCATABLE_EXECUTABLES || info->shared) + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && (r_type != R_386_PC32 + || !SYMBOL_CALLS_LOCAL (info, h))) + || (ELIMINATE_COPY_RELOCS +@@ -3633,12 +3637,13 @@ elf_i386_relocate_section (bfd *output_bfd, + + input_section->output_offset); + + if (skip) + memset (&outrel, 0, sizeof outrel); + else if (h != NULL + && h->dynindx != -1 ++ && !(ELF32_I386_RELOCATABLE_EXECUTABLES && !info->shared) + && (r_type == R_386_PC32 + || !info->shared + || !SYMBOLIC_BIND (info, h) + || !h->def_regular)) + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + else +@@ -4953,20 +4958,26 @@ elf_i386_add_symbol_hook (bfd * abfd, + #define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol + #define elf_backend_relocs_compatible _bfd_elf_relocs_compatible + #define elf_backend_check_relocs elf_i386_check_relocs + #define elf_backend_copy_indirect_symbol elf_i386_copy_indirect_symbol + #define elf_backend_create_dynamic_sections elf_i386_create_dynamic_sections + #define elf_backend_fake_sections elf_i386_fake_sections ++#ifndef elf_backend_finish_dynamic_sections + #define elf_backend_finish_dynamic_sections elf_i386_finish_dynamic_sections ++#endif ++#ifndef elf_backend_finish_dynamic_symbol + #define elf_backend_finish_dynamic_symbol elf_i386_finish_dynamic_symbol ++#endif + #define elf_backend_gc_mark_hook elf_i386_gc_mark_hook + #define elf_backend_gc_sweep_hook elf_i386_gc_sweep_hook + #define elf_backend_grok_prstatus elf_i386_grok_prstatus + #define elf_backend_grok_psinfo elf_i386_grok_psinfo + #define elf_backend_reloc_type_class elf_i386_reloc_type_class ++#ifndef elf_backend_relocate_section + #define elf_backend_relocate_section elf_i386_relocate_section ++#endif + #define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections + #define elf_backend_always_size_sections elf_i386_always_size_sections + #define elf_backend_omit_section_dynsym \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) + #define elf_backend_plt_sym_val elf_i386_plt_sym_val + #define elf_backend_hash_symbol elf_i386_hash_symbol +diff --git a/bfd/elf32-morphos.c b/bfd/elf32-morphos.c +new file mode 100644 +index 0000000000000000000000000000000000000000..accc2d426bede6c9441313115fcd5ab5f99630f9 +--- /dev/null ++++ b/bfd/elf32-morphos.c +@@ -0,0 +1,7137 @@ ++/* PowerPC-specific support for 32-bit ELF ++ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 ++ Free Software Foundation, Inc. ++ Written by Ian Lance Taylor, Cygnus Support. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++/* This file is based on a preliminary PowerPC ELF ABI. The ++ information may not match the final PowerPC ELF ABI. It includes ++ suggestions from the in-progress Embedded PowerPC ABI, and that ++ information may also not match. */ ++ ++#define ARCH_SIZE 32 ++ ++#include "bfd.h" ++#include "sysdep.h" ++#include "bfdlink.h" ++#include "genlink.h" ++#include "libbfd.h" ++#include "elf-bfd.h" ++#include "elf/ppc.h" ++ ++#define USE_RELA /* we want RELA relocations, not REL */ ++ ++/* Renaming structures, typedefs, macros and functions to be size-specific. */ ++#define Elf_External_Ehdr NAME(Elf,External_Ehdr) ++#define Elf_External_Sym NAME(Elf,External_Sym) ++#define Elf_External_Shdr NAME(Elf,External_Shdr) ++#define Elf_External_Phdr NAME(Elf,External_Phdr) ++#define Elf_External_Rel NAME(Elf,External_Rel) ++#define Elf_External_Rela NAME(Elf,External_Rela) ++#define Elf_External_Dyn NAME(Elf,External_Dyn) ++ ++#define elf_core_file_failing_command NAME(bfd_elf,core_file_failing_command) ++#define elf_core_file_failing_signal NAME(bfd_elf,core_file_failing_signal) ++#define elf_core_file_matches_executable_p \ ++ NAME(bfd_elf,core_file_matches_executable_p) ++#define elf_object_p NAME(bfd_elf,object_p) ++#define elf_core_file_p NAME(bfd_elf,core_file_p) ++#define elf_get_symtab_upper_bound NAME(bfd_elf,get_symtab_upper_bound) ++#define elf_get_dynamic_symtab_upper_bound \ ++ NAME(bfd_elf,get_dynamic_symtab_upper_bound) ++#define elf_swap_reloc_in NAME(bfd_elf,swap_reloc_in) ++#define elf_swap_reloca_in NAME(bfd_elf,swap_reloca_in) ++#define elf_swap_reloc_out NAME(bfd_elf,swap_reloc_out) ++#define elf_swap_reloca_out NAME(bfd_elf,swap_reloca_out) ++#define elf_swap_symbol_in NAME(bfd_elf,swap_symbol_in) ++#define elf_swap_symbol_out NAME(bfd_elf,swap_symbol_out) ++#define elf_swap_phdr_in NAME(bfd_elf,swap_phdr_in) ++#define elf_swap_phdr_out NAME(bfd_elf,swap_phdr_out) ++#define elf_swap_dyn_in NAME(bfd_elf,swap_dyn_in) ++#define elf_swap_dyn_out NAME(bfd_elf,swap_dyn_out) ++#define elf_get_reloc_upper_bound NAME(bfd_elf,get_reloc_upper_bound) ++#define elf_canonicalize_reloc NAME(bfd_elf,canonicalize_reloc) ++#define elf_slurp_symbol_table NAME(bfd_elf,slurp_symbol_table) ++#define elf_get_symtab NAME(bfd_elf,get_symtab) ++#define elf_canonicalize_dynamic_symtab \ ++ NAME(bfd_elf,canonicalize_dynamic_symtab) ++#define elf_make_empty_symbol NAME(bfd_elf,make_empty_symbol) ++#define elf_get_symbol_info NAME(bfd_elf,get_symbol_info) ++#define elf_get_lineno NAME(bfd_elf,get_lineno) ++#define elf_set_arch_mach NAME(bfd_elf,set_arch_mach) ++#define elf_find_nearest_line NAME(bfd_elf,find_nearest_line) ++#define elf_sizeof_headers NAME(bfd_elf,sizeof_headers) ++#define elf_set_section_contents NAME(bfd_elf,set_section_contents) ++#define elf_no_info_to_howto NAME(bfd_elf,no_info_to_howto) ++#define elf_no_info_to_howto_rel NAME(bfd_elf,no_info_to_howto_rel) ++#define elf_find_section NAME(bfd_elf,find_section) ++#define elf_bfd_link_add_symbols NAME(bfd_elf,bfd_link_add_symbols) ++#define elf_add_dynamic_entry NAME(bfd_elf,add_dynamic_entry) ++#define elf_write_shdrs_and_ehdr NAME(bfd_elf,write_shdrs_and_ehdr) ++#define elf_write_out_phdrs NAME(bfd_elf,write_out_phdrs) ++#define elf_write_relocs NAME(bfd_elf,write_relocs) ++#define elf_slurp_reloc_table NAME(bfd_elf,slurp_reloc_table) ++#define elf_link_create_dynamic_sections \ ++ NAME(bfd_elf,link_create_dynamic_sections) ++#define elf_bfd_discard_info NAME(bfd_elf,discard_info) ++#define elf_reloc_symbol_deleted_p NAME(_bfd_elf,reloc_symbol_deleted_p) ++#define elf_link_record_dynamic_symbol _bfd_elf_link_record_dynamic_symbol ++#define elf_bfd_final_link NAME(bfd_elf,bfd_final_link) ++#define elf_create_pointer_linker_section NAME(bfd_elf,create_pointer_linker_section) ++#define elf_finish_pointer_linker_section NAME(bfd_elf,finish_pointer_linker_section) ++#define elf_gc_sections NAME(_bfd_elf,gc_sections) ++#define elf_gc_common_finalize_got_offsets \ ++ NAME(_bfd_elf,gc_common_finalize_got_offsets) ++#define elf_gc_common_final_link NAME(_bfd_elf,gc_common_final_link) ++#define elf_gc_record_vtinherit NAME(_bfd_elf,gc_record_vtinherit) ++#define elf_gc_record_vtentry NAME(_bfd_elf,gc_record_vtentry) ++#define elf_link_record_local_dynamic_symbol \ ++ NAME(_bfd_elf,link_record_local_dynamic_symbol) ++ ++#define ELF_R_INFO(X,Y) ELF32_R_INFO(X,Y) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELFCLASS ELFCLASS32 ++#define FILE_ALIGN 4 ++#define LOG_FILE_ALIGN 2 ++ ++#define H_PUT_WORD H_PUT_32 ++#define H_PUT_SIGNED_WORD H_PUT_S32 ++#define H_GET_WORD H_GET_32 ++#define H_GET_SIGNED_WORD H_GET_S32 ++ ++#define elf_stringtab_init _bfd_elf_stringtab_init ++ ++#define section_from_elf_index bfd_section_from_elf_index ++ ++static int ddr_count; ++static unsigned *ddr_ptr; ++ ++static reloc_howto_type *ppc_elf_reloc_type_lookup ++ PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); ++static void ppc_elf_info_to_howto ++ PARAMS ((bfd *abfd, arelent *cache_ptr, Elf32_Internal_Rela *dst)); ++static void ppc_elf_howto_init PARAMS ((void)); ++static int ppc_elf_sort_rela PARAMS ((const PTR, const PTR)); ++static boolean ppc_elf_relax_section ++ PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *)); ++static bfd_reloc_status_type ppc_elf_addr16_ha_reloc ++ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); ++static boolean ppc_elf_object_p PARAMS ((bfd *)); ++static boolean ppc_elf_set_private_flags PARAMS ((bfd *, flagword)); ++static boolean ppc_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *)); ++ ++static int ppc_elf_additional_program_headers PARAMS ((bfd *)); ++static boolean ppc_elf_modify_segment_map PARAMS ((bfd *)); ++ ++static asection *ppc_elf_create_got ++ PARAMS ((bfd *, struct bfd_link_info *)); ++static boolean ppc_elf_create_dynamic_sections ++ PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static boolean ppc_elf_section_from_shdr PARAMS ((bfd *, ++ Elf32_Internal_Shdr *, ++ const char *)); ++static boolean ppc_elf_fake_sections ++ PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *)); ++ ++static elf_linker_section_t *ppc_elf_create_linker_section ++ PARAMS ((bfd *abfd, ++ struct bfd_link_info *info, ++ enum elf_linker_section_enum)); ++ ++static boolean ppc_elf_check_relocs PARAMS ((bfd *, ++ struct bfd_link_info *, ++ asection *, ++ const Elf_Internal_Rela *)); ++ ++static asection * ppc_elf_gc_mark_hook PARAMS ((asection *sec, ++ struct bfd_link_info *info, ++ Elf_Internal_Rela *rel, ++ struct elf_link_hash_entry *h, ++ Elf_Internal_Sym *sym)); ++ ++static boolean ppc_elf_gc_sweep_hook PARAMS ((bfd *abfd, ++ struct bfd_link_info *info, ++ asection *sec, ++ const Elf_Internal_Rela *relocs)); ++ ++static boolean ppc_elf_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, ++ struct elf_link_hash_entry *)); ++ ++static boolean ppc_elf_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); ++ ++static boolean ppc_elf_relocate_section PARAMS ((bfd *, ++ struct bfd_link_info *info, ++ bfd *, ++ asection *, ++ bfd_byte *, ++ Elf_Internal_Rela *relocs, ++ Elf_Internal_Sym *local_syms, ++ asection **)); ++ ++static boolean ppc_elf_add_symbol_hook PARAMS ((bfd *, ++ struct bfd_link_info *, ++ const Elf_Internal_Sym *, ++ const char **, ++ flagword *, ++ asection **, ++ bfd_vma *)); ++ ++static boolean ppc_elf_finish_dynamic_symbol PARAMS ((bfd *, ++ struct bfd_link_info *, ++ struct elf_link_hash_entry *, ++ Elf_Internal_Sym *)); ++ ++static boolean ppc_elf_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); ++static enum elf_reloc_type_class ppc_elf_reloc_type_class ++ PARAMS ((const Elf_Internal_Rela *)); ++static boolean ppc_elf_grok_prstatus ++ PARAMS ((bfd *abfd, Elf_Internal_Note *note)); ++static boolean ppc_elf_grok_psinfo ++ PARAMS ((bfd *abfd, Elf_Internal_Note *note)); ++ ++#define BRANCH_PREDICT_BIT 0x200000 /* branch prediction bit for branch taken relocs */ ++#define RA_REGISTER_MASK 0x001f0000 /* mask to set RA in memory instructions */ ++#define RA_REGISTER_SHIFT 16 /* value to shift register by to insert RA */ ++ ++/* The name of the dynamic interpreter. This is put in the .interp ++ section. */ ++ ++#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" ++ ++/* The size in bytes of an entry in the procedure linkage table. */ ++#define PLT_ENTRY_SIZE 12 ++/* The initial size of the plt reserved for the dynamic linker. */ ++#define PLT_INITIAL_ENTRY_SIZE 72 ++/* The size of the gap between entries in the PLT. */ ++#define PLT_SLOT_SIZE 8 ++/* The number of single-slot PLT entries (the rest use two slots). */ ++#define PLT_NUM_SINGLE_ENTRIES 8192 ++ ++/* Will references to this symbol always reference the symbol ++ in this object? */ ++#define SYMBOL_REFERENCES_LOCAL(INFO, H) \ ++ ((! INFO->shared \ ++ || INFO->symbolic \ ++ || H->dynindx == -1 \ ++ || ELF_ST_VISIBILITY (H->other) == STV_INTERNAL \ ++ || ELF_ST_VISIBILITY (H->other) == STV_HIDDEN) \ ++ && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) ++ ++/* Will _calls_ to this symbol always call the version in this object? */ ++#define SYMBOL_CALLS_LOCAL(INFO, H) \ ++ ((! INFO->shared \ ++ || INFO->symbolic \ ++ || H->dynindx == -1 \ ++ || ELF_ST_VISIBILITY (H->other) != STV_DEFAULT) \ ++ && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) ++ ++static reloc_howto_type *ppc_elf_howto_table[(int) R_PPC_max]; ++ ++static reloc_howto_type ppc_elf_howto_raw[] = { ++ /* This reloc does nothing. */ ++ HOWTO (R_PPC_NONE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_NONE", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A standard 32 bit relocation. */ ++ HOWTO (R_PPC_ADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 26 bit branch; the lower two bits must be zero. ++ FIXME: we don't check that, we just clear them. */ ++ HOWTO (R_PPC_ADDR24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A standard 16 bit relocation. */ ++ HOWTO (R_PPC_ADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A 16 bit relocation without overflow. */ ++ HOWTO (R_PPC_ADDR16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of an address. */ ++ HOWTO (R_PPC_ADDR16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of an address, plus 1 if the contents of ++ the low 16 bits, treated as a signed number, is negative. */ ++ HOWTO (R_PPC_ADDR16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_ADDR16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch; the lower two bits must be zero. ++ FIXME: we don't check that, we just clear them. */ ++ HOWTO (R_PPC_ADDR14, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch, for which bit 10 should be set to ++ indicate that the branch is expected to be taken. The lower two ++ bits must be zero. */ ++ HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14_BRTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* An absolute 16 bit branch, for which bit 10 should be set to ++ indicate that the branch is not expected to be taken. The lower ++ two bits must be zero. */ ++ HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_ADDR14_BRNTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A relative 26 bit branch; the lower two bits must be zero. */ ++ HOWTO (R_PPC_REL24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch; the lower two bits must be zero. */ ++ HOWTO (R_PPC_REL14, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch. Bit 10 should be set to indicate that ++ the branch is expected to be taken. The lower two bits must be ++ zero. */ ++ HOWTO (R_PPC_REL14_BRTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14_BRTAKEN", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* A relative 16 bit branch. Bit 10 should be set to indicate that ++ the branch is not expected to be taken. The lower two bits must ++ be zero. */ ++ HOWTO (R_PPC_REL14_BRNTAKEN, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL14_BRNTAKEN",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xfffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16, but referring to the GOT table entry for the ++ symbol. */ ++ HOWTO (R_PPC_GOT16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GOT16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_GOT16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_GOT16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_REL24, but referring to the procedure linkage table ++ entry for the symbol. */ ++ HOWTO (R_PPC_PLTREL24, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL24", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* This is used only by the dynamic linker. The symbol should exist ++ both in the object being run and in some shared library. The ++ dynamic linker copies the data addressed by the symbol from the ++ shared library into the object, because the object being ++ run has to have the data at some particular address. */ ++ HOWTO (R_PPC_COPY, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_COPY", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR32, but used when setting global offset table ++ entries. */ ++ HOWTO (R_PPC_GLOB_DAT, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_GLOB_DAT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Marks a procedure linkage table entry for a symbol. */ ++ HOWTO (R_PPC_JMP_SLOT, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_JMP_SLOT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Used only by the dynamic linker. When the object is run, this ++ longword is set to the load address of the object, plus the ++ addend. */ ++ HOWTO (R_PPC_RELATIVE, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_RELATIVE", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_REL24, but uses the value of the symbol within the ++ object rather than the final value. Normally used for ++ _GLOBAL_OFFSET_TABLE_. */ ++ HOWTO (R_PPC_LOCAL24PC, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 26, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_LOCAL24PC", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0x3fffffc, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR32, but may be unaligned. */ ++ HOWTO (R_PPC_UADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_UADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16, but may be unaligned. */ ++ HOWTO (R_PPC_UADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_UADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 32-bit PC relative */ ++ HOWTO (R_PPC_REL32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_REL32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* 32-bit relocation to the symbol's procedure linkage table. ++ FIXME: not supported. */ ++ HOWTO (R_PPC_PLT32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 32-bit PC relative relocation to the symbol's procedure linkage table. ++ FIXME: not supported. */ ++ HOWTO (R_PPC_PLTREL32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLTREL32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ true), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_PLT16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for ++ the symbol. */ ++ HOWTO (R_PPC_PLT16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_PLT16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A sign-extended 16 bit value relative to _SDA_BASE_, for use with ++ small data items. */ ++ HOWTO (R_PPC_SDAREL16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SDAREL16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit lower half section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit upper half section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16-bit upper half adjusted section relative relocation. */ ++ HOWTO (R_PPC_SECTOFF_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_SECTOFF_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++ ++ /* 32 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR32, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR32", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffffffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_ADDR16_LO", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of the addend minus the symbol */ ++ HOWTO (R_PPC_EMB_NADDR16_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HI", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* The high order 16 bits of the result of the addend minus the address, ++ plus 1 if the contents of the low 16 bits, treated as a signed number, ++ is negative. */ ++ HOWTO (R_PPC_EMB_NADDR16_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ ppc_elf_addr16_ha_reloc, /* special_function */ ++ "R_PPC_EMB_NADDR16_HA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from allocating a 4 byte word to hold an ++ address in the .sdata section, and returning the offset from ++ _SDA_BASE_ for that relocation */ ++ HOWTO (R_PPC_EMB_SDAI16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDAI16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 16 bit value resulting from allocating a 4 byte word to hold an ++ address in the .sdata2 section, and returning the offset from ++ _SDA2_BASE_ for that relocation */ ++ HOWTO (R_PPC_EMB_SDA2I16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2I16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with ++ small data items. */ ++ HOWTO (R_PPC_EMB_SDA2REL, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA2REL", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit ++ signed offset from the appropriate base, and filling in the register ++ field with the appropriate register (0, 2, or 13). */ ++ HOWTO (R_PPC_EMB_SDA21, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_SDA21", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Relocation not handled: R_PPC_EMB_MRKREF */ ++ /* Relocation not handled: R_PPC_EMB_RELSEC16 */ ++ /* Relocation not handled: R_PPC_EMB_RELST_LO */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HI */ ++ /* Relocation not handled: R_PPC_EMB_RELST_HA */ ++ /* Relocation not handled: R_PPC_EMB_BIT_FLD */ ++ ++ /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling ++ in the 16 bit signed offset from the appropriate base, and filling in the ++ register field with the appropriate register (0, 2, or 13). */ ++ HOWTO (R_PPC_EMB_RELSDA, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ true, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_EMB_RELSDA", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* GNU extension to record C++ vtable hierarchy */ ++ HOWTO (R_PPC_GNU_VTINHERIT, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ NULL, /* special_function */ ++ "R_PPC_GNU_VTINHERIT", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* GNU extension to record C++ vtable member usage */ ++ HOWTO (R_PPC_GNU_VTENTRY, /* type */ ++ 0, /* rightshift */ ++ 0, /* size (0 = byte, 1 = short, 2 = long) */ ++ 0, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ NULL, /* special_function */ ++ "R_PPC_GNU_VTENTRY", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Phony reloc to handle AIX style TOC entries */ ++ HOWTO (R_PPC_TOC16, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_signed, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_TOC16", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* 32-bit relocation relative to _SDA_BASE_ */ ++ HOWTO (R_PPC_MORPHOS_DREL, /* type */ ++ 0, /* rightshift */ ++ 2, /* size (0 = byte, 1 = short, 2 = long) */ ++ 32, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_bitfield, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_MORPHOS_DREL", /* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Lower 16 bits of a relocation relative to _SDA_BASE */ ++ HOWTO (R_PPC_MORPHOS_DREL_LO, /* type */ ++ 0, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ /*complain_overflow_bitfield,*/ /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_MORPHOS_DREL_LO",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Upper 16 bits of a relocation relative to _SDA_BASE */ ++ HOWTO (R_PPC_MORPHOS_DREL_HI, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ /*complain_overflow_bitfield,*/ /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_MORPHOS_DREL_HI",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++ ++ /* Upper 16 bits of a relocation relative to _SDA_BASE */ ++ HOWTO (R_PPC_MORPHOS_DREL_HA, /* type */ ++ 16, /* rightshift */ ++ 1, /* size (0 = byte, 1 = short, 2 = long) */ ++ 16, /* bitsize */ ++ false, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont,/* complain_on_overflow */ ++ /*complain_overflow_bitfield,*/ /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_MORPHOS_DREL_HA",/* name */ ++ false, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0xffff, /* dst_mask */ ++ false), /* pcrel_offset */ ++}; ++ ++/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ ++ ++static void ++ppc_elf_howto_init () ++{ ++ unsigned int i, type; ++ ++ for (i = 0; i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); i++) ++ { ++ type = ppc_elf_howto_raw[i].type; ++ BFD_ASSERT (type < sizeof (ppc_elf_howto_table) / sizeof (ppc_elf_howto_table[0])); ++ ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i]; ++ } ++} ++ ++/* This function handles relaxing for the PPC with option --mpc860c0[=<n>]. ++ ++ The MPC860, revision C0 or earlier contains a bug in the die. ++ If all of the following conditions are true, the next instruction ++ to be executed *may* be treated as a no-op. ++ 1/ A forward branch is executed. ++ 2/ The branch is predicted as not taken. ++ 3/ The branch is taken. ++ 4/ The branch is located in the last 5 words of a page. ++ (The EOP limit is 5 by default but may be specified as any value from 1-10.) ++ ++ Our software solution is to detect these problematic branches in a ++ linker pass and modify them as follows: ++ 1/ Unconditional branches - Since these are always predicted taken, ++ there is no problem and no action is required. ++ 2/ Conditional backward branches - No problem, no action required. ++ 3/ Conditional forward branches - Ensure that the "inverse prediction ++ bit" is set (ensure it is predicted taken). ++ 4/ Conditional register branches - Ensure that the "y bit" is set ++ (ensure it is predicted taken). ++*/ ++ ++/* Sort sections by address. */ ++ ++static int ++ppc_elf_sort_rela (arg1, arg2) ++ const PTR arg1; ++ const PTR arg2; ++{ ++ const Elf_Internal_Rela **rela1 = (const Elf_Internal_Rela**) arg1; ++ const Elf_Internal_Rela **rela2 = (const Elf_Internal_Rela**) arg2; ++ ++ /* Sort by offset. */ ++ return ((*rela1)->r_offset - (*rela2)->r_offset); ++} ++ ++static boolean ++ppc_elf_relax_section (abfd, isec, link_info, again) ++ bfd *abfd; ++ asection *isec; ++ struct bfd_link_info *link_info; ++ boolean *again; ++{ ++#define PAGESIZE 0x1000 ++ ++ bfd_byte *contents = NULL; ++ bfd_byte *free_contents = NULL; ++ Elf_Internal_Rela *internal_relocs = NULL; ++ Elf_Internal_Rela *free_relocs = NULL; ++ Elf_Internal_Rela **rela_comb = NULL; ++ int comb_curr, comb_count; ++ ++ /* We never have to do this more than once per input section. */ ++ *again = false; ++ ++ /* If needed, initialize this section's cooked size. */ ++ if (isec->_cooked_size == 0) ++ isec->_cooked_size = isec->_raw_size; ++ ++ /* We're only interested in text sections which overlap the ++ troublesome area at the end of a page. */ ++ if (link_info->mpc860c0 && (isec->flags & SEC_CODE) && isec->_cooked_size) ++ { ++ bfd_vma dot, end_page, end_section; ++ boolean section_modified; ++ ++ /* Get the section contents. */ ++ /* Get cached copy if it exists. */ ++ if (elf_section_data (isec)->this_hdr.contents != NULL) ++ contents = elf_section_data (isec)->this_hdr.contents; ++ else ++ { ++ /* Go get them off disk. */ ++ contents = (bfd_byte *) bfd_malloc (isec->_raw_size); ++ if (contents == NULL) ++ goto error_return; ++ free_contents = contents; ++ ++ if (! bfd_get_section_contents (abfd, isec, contents, ++ (file_ptr) 0, isec->_raw_size)) ++ goto error_return; ++ } ++ ++ comb_curr = 0; ++ comb_count = 0; ++ if (isec->reloc_count) ++ { ++ unsigned n; ++ bfd_size_type amt; ++ ++ /* Get a copy of the native relocations. */ ++ internal_relocs = _bfd_elf32_link_read_relocs ( ++ abfd, isec, (PTR) NULL, (Elf_Internal_Rela *) NULL, ++ link_info->keep_memory); ++ if (internal_relocs == NULL) ++ goto error_return; ++ if (! link_info->keep_memory) ++ free_relocs = internal_relocs; ++ ++ /* Setup a faster access method for the reloc info we need. */ ++ amt = isec->reloc_count; ++ amt *= sizeof (Elf_Internal_Rela*); ++ rela_comb = (Elf_Internal_Rela**) bfd_malloc (amt); ++ if (rela_comb == NULL) ++ goto error_return; ++ for (n = 0; n < isec->reloc_count; ++n) ++ { ++ long r_type; ++ ++ r_type = ELF32_R_TYPE (internal_relocs[n].r_info); ++ if (r_type < 0 || r_type >= (int) R_PPC_max) ++ goto error_return; ++ ++ /* Prologue constants are sometimes present in the ".text" ++ sections and they can be identified by their associated relocation. ++ We don't want to process those words and some others which ++ can also be identified by their relocations. However, not all ++ conditional branches will have a relocation so we will ++ only ignore words that 1) have a reloc, and 2) the reloc ++ is not applicable to a conditional branch. ++ The array rela_comb is built here for use in the EOP scan loop. */ ++ switch (r_type) ++ { ++ case R_PPC_ADDR14_BRNTAKEN: /* absolute, predicted not taken */ ++ case R_PPC_REL14: /* relative cond. br. */ ++ case R_PPC_REL14_BRNTAKEN: /* rel. cond. br., predicted not taken */ ++ /* We should check the instruction. */ ++ break; ++ default: ++ /* The word is not a conditional branch - ignore it. */ ++ rela_comb[comb_count++] = &internal_relocs[n]; ++ break; ++ } ++ } ++ if (comb_count > 1) ++ qsort (rela_comb, (size_t) comb_count, sizeof (int), ppc_elf_sort_rela); ++ } ++ ++ /* Enumerate each EOP region that overlaps this section. */ ++ end_section = isec->vma + isec->_cooked_size; ++ dot = end_page = (isec->vma | (PAGESIZE - 1)) + 1; ++ dot -= link_info->mpc860c0; ++ section_modified = false; ++ if (dot < isec->vma) /* Increment the start position if this section */ ++ dot = isec->vma; /* begins in the middle of its first EOP region. */ ++ for (; ++ dot < end_section; ++ dot += PAGESIZE, end_page += PAGESIZE) ++ { ++ ++ /* Check each word in this EOP region. */ ++ for (; dot < end_page; dot += 4) ++ { ++ bfd_vma isec_offset; ++ unsigned long insn; ++ boolean skip, modified; ++ ++ /* Don't process this word if there is a relocation for it and ++ the relocation indicates the word is not a conditional branch. */ ++ skip = false; ++ isec_offset = dot - isec->vma; ++ for (; comb_curr<comb_count; ++comb_curr) ++ { ++ bfd_vma r_offset; ++ ++ r_offset = rela_comb[comb_curr]->r_offset; ++ if (r_offset >= isec_offset) ++ { ++ if (r_offset == isec_offset) skip = true; ++ break; ++ } ++ } ++ if (skip) continue; ++ ++ /* Check the current word for a problematic conditional branch. */ ++#define BO0(insn) ((insn) & 0x02000000) ++#define BO2(insn) ((insn) & 0x00800000) ++#define BO4(insn) ((insn) & 0x00200000) ++ insn = (unsigned long) bfd_get_32 (abfd, contents + isec_offset); ++ modified = false; ++ if ((insn & 0xFc000000) == 0x40000000) ++ { ++ /* Instruction is BCx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ bfd_vma target; ++ /* This branch is predicted as "normal". ++ If this is a forward branch, it is problematic. */ ++ ++ target = insn & 0x0000Fffc; /*extract*/ ++ target = (target ^ 0x8000) - 0x8000; /*sign extend*/ ++ if ((insn & 0x00000002) == 0) ++ target += dot; /*convert to abs*/ ++ if (target > dot) ++ { ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++ } ++ else if ((insn & 0xFc00Fffe) == 0x4c000420) ++ { ++ /* Instruction is BCCTRx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ /* This branch is predicted as not-taken. ++ If this is a forward branch, it is problematic. ++ Since we can't tell statically if it will branch forward, ++ always set the prediction bit. */ ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++ else if ((insn & 0xFc00Fffe) == 0x4c000020) ++ { ++ /* Instruction is BCLRx */ ++ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn)) ++ { ++ /* This branch is predicted as not-taken. ++ If this is a forward branch, it is problematic. ++ Since we can't tell statically if it will branch forward, ++ always set the prediction bit. */ ++ insn |= 0x00200000; /* set the prediction bit */ ++ modified = true; ++ } ++ } ++#undef BO0 ++#undef BO2 ++#undef BO4 ++ if (modified) ++ { ++ bfd_put_32 (abfd, (bfd_vma) insn, contents + isec_offset); ++ section_modified = true; ++ } ++ } ++ } ++ if (section_modified) ++ { ++ elf_section_data (isec)->this_hdr.contents = contents; ++ free_contents = NULL; ++ } ++ } ++ ++ if (rela_comb != NULL) ++ { ++ free (rela_comb); ++ rela_comb = NULL; ++ } ++ ++ if (free_relocs != NULL) ++ { ++ free (free_relocs); ++ free_relocs = NULL; ++ } ++ ++ if (free_contents != NULL) ++ { ++ if (! link_info->keep_memory) ++ free (free_contents); ++ else ++ { ++ /* Cache the section contents for elf_link_input_bfd. */ ++ elf_section_data (isec)->this_hdr.contents = contents; ++ } ++ free_contents = NULL; ++ } ++ ++ return true; ++ ++error_return: ++ if (rela_comb != NULL) ++ free (rela_comb); ++ if (free_relocs != NULL) ++ free (free_relocs); ++ if (free_contents != NULL) ++ free (free_contents); ++ return false; ++} ++ ++static reloc_howto_type * ++ppc_elf_reloc_type_lookup (abfd, code) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ bfd_reloc_code_real_type code; ++{ ++ enum elf_ppc_reloc_type ppc_reloc = R_PPC_NONE; ++ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ switch ((int) code) ++ { ++ default: ++ return (reloc_howto_type *) NULL; ++ ++ case BFD_RELOC_NONE: ppc_reloc = R_PPC_NONE; break; ++ case BFD_RELOC_32: ppc_reloc = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC_BA26: ppc_reloc = R_PPC_ADDR24; break; ++ case BFD_RELOC_16: ppc_reloc = R_PPC_ADDR16; break; ++ case BFD_RELOC_LO16: ppc_reloc = R_PPC_ADDR16_LO; break; ++ case BFD_RELOC_HI16: ppc_reloc = R_PPC_ADDR16_HI; break; ++ case BFD_RELOC_HI16_S: ppc_reloc = R_PPC_ADDR16_HA; break; ++ case BFD_RELOC_PPC_BA16: ppc_reloc = R_PPC_ADDR14; break; ++ case BFD_RELOC_PPC_BA16_BRTAKEN: ppc_reloc = R_PPC_ADDR14_BRTAKEN; break; ++ case BFD_RELOC_PPC_BA16_BRNTAKEN: ppc_reloc = R_PPC_ADDR14_BRNTAKEN; break; ++ case BFD_RELOC_PPC_B26: ppc_reloc = R_PPC_REL24; break; ++ case BFD_RELOC_PPC_B16: ppc_reloc = R_PPC_REL14; break; ++ case BFD_RELOC_PPC_B16_BRTAKEN: ppc_reloc = R_PPC_REL14_BRTAKEN; break; ++ case BFD_RELOC_PPC_B16_BRNTAKEN: ppc_reloc = R_PPC_REL14_BRNTAKEN; break; ++ case BFD_RELOC_16_GOTOFF: ppc_reloc = R_PPC_GOT16; break; ++ case BFD_RELOC_LO16_GOTOFF: ppc_reloc = R_PPC_GOT16_LO; break; ++ case BFD_RELOC_HI16_GOTOFF: ppc_reloc = R_PPC_GOT16_HI; break; ++ case BFD_RELOC_HI16_S_GOTOFF: ppc_reloc = R_PPC_GOT16_HA; break; ++ case BFD_RELOC_24_PLT_PCREL: ppc_reloc = R_PPC_PLTREL24; break; ++ case BFD_RELOC_PPC_COPY: ppc_reloc = R_PPC_COPY; break; ++ case BFD_RELOC_PPC_GLOB_DAT: ppc_reloc = R_PPC_GLOB_DAT; break; ++ case BFD_RELOC_PPC_LOCAL24PC: ppc_reloc = R_PPC_LOCAL24PC; break; ++ case BFD_RELOC_32_PCREL: ppc_reloc = R_PPC_REL32; break; ++ case BFD_RELOC_32_PLTOFF: ppc_reloc = R_PPC_PLT32; break; ++ case BFD_RELOC_32_PLT_PCREL: ppc_reloc = R_PPC_PLTREL32; break; ++ case BFD_RELOC_LO16_PLTOFF: ppc_reloc = R_PPC_PLT16_LO; break; ++ case BFD_RELOC_HI16_PLTOFF: ppc_reloc = R_PPC_PLT16_HI; break; ++ case BFD_RELOC_HI16_S_PLTOFF: ppc_reloc = R_PPC_PLT16_HA; break; ++ case BFD_RELOC_GPREL16: ppc_reloc = R_PPC_SDAREL16; break; ++ case BFD_RELOC_16_BASEREL: ppc_reloc = R_PPC_SECTOFF; break; ++ case BFD_RELOC_LO16_BASEREL: ppc_reloc = R_PPC_SECTOFF_LO; break; ++ case BFD_RELOC_HI16_BASEREL: ppc_reloc = R_PPC_SECTOFF_HI; break; ++ case BFD_RELOC_HI16_S_BASEREL: ppc_reloc = R_PPC_SECTOFF_HA; break; ++ case BFD_RELOC_CTOR: ppc_reloc = R_PPC_ADDR32; break; ++ case BFD_RELOC_PPC_TOC16: ppc_reloc = R_PPC_TOC16; break; ++ case BFD_RELOC_PPC_EMB_NADDR32: ppc_reloc = R_PPC_EMB_NADDR32; break; ++ case BFD_RELOC_PPC_EMB_NADDR16: ppc_reloc = R_PPC_EMB_NADDR16; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_LO: ppc_reloc = R_PPC_EMB_NADDR16_LO; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HI: ppc_reloc = R_PPC_EMB_NADDR16_HI; break; ++ case BFD_RELOC_PPC_EMB_NADDR16_HA: ppc_reloc = R_PPC_EMB_NADDR16_HA; break; ++ case BFD_RELOC_PPC_EMB_SDAI16: ppc_reloc = R_PPC_EMB_SDAI16; break; ++ case BFD_RELOC_PPC_EMB_SDA2I16: ppc_reloc = R_PPC_EMB_SDA2I16; break; ++ case BFD_RELOC_PPC_EMB_SDA2REL: ppc_reloc = R_PPC_EMB_SDA2REL; break; ++ case BFD_RELOC_PPC_EMB_SDA21: ppc_reloc = R_PPC_EMB_SDA21; break; ++ case BFD_RELOC_PPC_EMB_MRKREF: ppc_reloc = R_PPC_EMB_MRKREF; break; ++ case BFD_RELOC_PPC_EMB_RELSEC16: ppc_reloc = R_PPC_EMB_RELSEC16; break; ++ case BFD_RELOC_PPC_EMB_RELST_LO: ppc_reloc = R_PPC_EMB_RELST_LO; break; ++ case BFD_RELOC_PPC_EMB_RELST_HI: ppc_reloc = R_PPC_EMB_RELST_HI; break; ++ case BFD_RELOC_PPC_EMB_RELST_HA: ppc_reloc = R_PPC_EMB_RELST_HA; break; ++ case BFD_RELOC_PPC_EMB_BIT_FLD: ppc_reloc = R_PPC_EMB_BIT_FLD; break; ++ case BFD_RELOC_PPC_EMB_RELSDA: ppc_reloc = R_PPC_EMB_RELSDA; break; ++ case BFD_RELOC_PPC_MORPHOS_DREL: ppc_reloc = R_PPC_MORPHOS_DREL; break; ++ case BFD_RELOC_PPC_MORPHOS_DREL_LO: ppc_reloc = R_PPC_MORPHOS_DREL_LO; break; ++ case BFD_RELOC_PPC_MORPHOS_DREL_HI: ppc_reloc = R_PPC_MORPHOS_DREL_HI; break; ++ case BFD_RELOC_PPC_MORPHOS_DREL_HA: ppc_reloc = R_PPC_MORPHOS_DREL_HA; break; ++ case BFD_RELOC_VTABLE_INHERIT: ppc_reloc = R_PPC_GNU_VTINHERIT; break; ++ case BFD_RELOC_VTABLE_ENTRY: ppc_reloc = R_PPC_GNU_VTENTRY; break; ++ } ++ ++ return ppc_elf_howto_table[(int) ppc_reloc]; ++}; ++ ++/* Set the howto pointer for a PowerPC ELF reloc. */ ++ ++static void ++ppc_elf_info_to_howto (abfd, cache_ptr, dst) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ arelent *cache_ptr; ++ Elf32_Internal_Rela *dst; ++{ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); ++ cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; ++} ++ ++/* Handle the R_PPC_ADDR16_HA reloc. */ ++ ++static bfd_reloc_status_type ++ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section, ++ output_bfd, error_message) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ arelent *reloc_entry; ++ asymbol *symbol; ++ PTR data ATTRIBUTE_UNUSED; ++ asection *input_section; ++ bfd *output_bfd; ++ char **error_message ATTRIBUTE_UNUSED; ++{ ++ /*bfd_vma relocation;*/ ++ ++ if (output_bfd != NULL) ++ { ++ reloc_entry->address += input_section->output_offset; ++ return bfd_reloc_ok; ++ } ++ else ++ { ++ reloc_entry->address += input_section->output_offset; ++ input_section->output_section->orelocation[input_section->output_section->reloc_count++]=reloc_entry; ++ return bfd_reloc_ok; ++ } ++ ++ /*if (reloc_entry->address > input_section->_cooked_size) ++ return bfd_reloc_outofrange; ++ ++ if (bfd_is_com_section (symbol->section)) ++ relocation = 0; ++ else ++ relocation = symbol->value; ++ ++ relocation += symbol->section->output_section->vma; ++ relocation += symbol->section->output_offset; ++ relocation += reloc_entry->addend; ++ ++ reloc_entry->addend += (relocation & 0x8000) << 1; ++ ++ return bfd_reloc_continue;*/ ++} ++ ++/* Fix bad default arch selected for a 32 bit input bfd when the ++ default is 64 bit. */ ++ ++static boolean ++ppc_elf_object_p (abfd) ++ bfd *abfd; ++{ ++ if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64) ++ { ++ Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); ++ ++ if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32) ++ { ++ /* Relies on arch after 64 bit default being 32 bit default. */ ++ abfd->arch_info = abfd->arch_info->next; ++ BFD_ASSERT (abfd->arch_info->bits_per_word == 32); ++ } ++ } ++ return true; ++} ++ ++/* Function to set whether a module needs the -mrelocatable bit set. */ ++ ++static boolean ++ppc_elf_set_private_flags (abfd, flags) ++ bfd *abfd; ++ flagword flags; ++{ ++ BFD_ASSERT (!elf_flags_init (abfd) ++ || elf_elfheader (abfd)->e_flags == flags); ++ ++ elf_elfheader (abfd)->e_flags = flags; ++ elf_flags_init (abfd) = true; ++ return true; ++} ++ ++/* Merge backend specific data from an object file to the output ++ object file when linking */ ++static boolean ++ppc_elf_merge_private_bfd_data (ibfd, obfd) ++ bfd *ibfd; ++ bfd *obfd; ++{ ++ flagword old_flags; ++ flagword new_flags; ++ boolean error; ++ ++ /* Check if we have the same endianess */ ++ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) ++ return false; ++ ++ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour ++ || bfd_get_flavour (obfd) != bfd_target_elf_flavour) ++ return true; ++ ++ new_flags = elf_elfheader (ibfd)->e_flags; ++ old_flags = elf_elfheader (obfd)->e_flags; ++ if (!elf_flags_init (obfd)) /* First call, no flags set */ ++ { ++ elf_flags_init (obfd) = true; ++ elf_elfheader (obfd)->e_flags = new_flags; ++ } ++ ++ else if (new_flags == old_flags) /* Compatible flags are ok */ ++ ; ++ ++ else /* Incompatible flags */ ++ { ++ /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib to be linked ++ with either. */ ++ error = false; ++ if ((new_flags & EF_PPC_RELOCATABLE) != 0 ++ && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: compiled with -mrelocatable and linked with modules compiled normally"), ++ bfd_archive_filename (ibfd)); ++ } ++ else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0 ++ && (old_flags & EF_PPC_RELOCATABLE) != 0) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: compiled normally and linked with modules compiled with -mrelocatable"), ++ bfd_archive_filename (ibfd)); ++ } ++ ++ /* The output is -mrelocatable-lib iff both the input files are. */ ++ if (! (new_flags & EF_PPC_RELOCATABLE_LIB)) ++ elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB; ++ ++ /* The output is -mrelocatable iff it can't be -mrelocatable-lib, ++ but each input file is either -mrelocatable or -mrelocatable-lib. */ ++ if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB) ++ && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)) ++ && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))) ++ elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE; ++ ++ /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if any module uses it */ ++ elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB); ++ ++ new_flags &= ~ (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ old_flags &= ~ (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); ++ ++ /* Warn about any other mismatches */ ++ if (new_flags != old_flags) ++ { ++ error = true; ++ (*_bfd_error_handler) ++ (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"), ++ bfd_archive_filename (ibfd), (long) new_flags, (long) old_flags); ++ } ++ ++ if (error) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++/* Handle a PowerPC specific section when reading an object file. This ++ is called when elfcode.h finds a section with an unknown type. */ ++ ++static boolean ++ppc_elf_section_from_shdr (abfd, hdr, name) ++ bfd *abfd; ++ Elf32_Internal_Shdr *hdr; ++ const char *name; ++{ ++ asection *newsect; ++ flagword flags; ++ ++ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) ++ return false; ++ ++ newsect = hdr->bfd_section; ++ flags = bfd_get_section_flags (abfd, newsect); ++ if (hdr->sh_flags & SHF_EXCLUDE) ++ flags |= SEC_EXCLUDE; ++ ++ if (hdr->sh_type == SHT_ORDERED) ++ flags |= SEC_SORT_ENTRIES; ++ ++ bfd_set_section_flags (abfd, newsect, flags); ++ return true; ++} ++ ++/* Set up any other section flags and such that may be necessary. */ ++ ++static boolean ++ppc_elf_fake_sections (abfd, shdr, asect) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ Elf32_Internal_Shdr *shdr; ++ asection *asect; ++{ ++ if ((asect->flags & SEC_EXCLUDE) != 0) ++ shdr->sh_flags |= SHF_EXCLUDE; ++ ++ if ((asect->flags & SEC_SORT_ENTRIES) != 0) ++ shdr->sh_type = SHT_ORDERED; ++ ++ return true; ++} ++ ++/* Create a special linker section */ ++static elf_linker_section_t * ++ppc_elf_create_linker_section (abfd, info, which) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ enum elf_linker_section_enum which; ++{ ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ elf_linker_section_t *lsect; ++ ++ /* Record the first bfd section that needs the special section */ ++ if (!dynobj) ++ dynobj = elf_hash_table (info)->dynobj = abfd; ++ ++ /* If this is the first time, create the section */ ++ lsect = elf_linker_section (dynobj, which); ++ if (!lsect) ++ { ++ elf_linker_section_t defaults; ++ static elf_linker_section_t zero_section; ++ ++ defaults = zero_section; ++ defaults.which = which; ++ defaults.hole_written_p = false; ++ defaults.alignment = 2; ++ ++ /* Both of these sections are (technically) created by the user ++ putting data in them, so they shouldn't be marked ++ SEC_LINKER_CREATED. ++ ++ The linker creates them so it has somewhere to attach their ++ respective symbols. In fact, if they were empty it would ++ be OK to leave the symbol set to 0 (or any random number), because ++ the appropriate register should never be used. */ ++ defaults.flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY); ++ ++ switch (which) ++ { ++ default: ++ (*_bfd_error_handler) (_("%s: Unknown special linker type %d"), ++ bfd_get_filename (abfd), ++ (int) which); ++ ++ bfd_set_error (bfd_error_bad_value); ++ return (elf_linker_section_t *) 0; ++ ++ case LINKER_SECTION_SDATA: /* .sdata/.sbss section */ ++ defaults.name = ".sdata"; ++ defaults.rel_name = ".rela.sdata"; ++ defaults.bss_name = ".sbss"; ++ defaults.sym_name = "_SDA_BASE_"; ++ defaults.sym_offset = 32768; ++ break; ++ ++ case LINKER_SECTION_SDATA2: /* .sdata2/.sbss2 section */ ++ defaults.name = ".sdata2"; ++ defaults.rel_name = ".rela.sdata2"; ++ defaults.bss_name = ".sbss2"; ++ defaults.sym_name = "_SDA2_BASE_"; ++ defaults.sym_offset = 32768; ++ defaults.flags |= SEC_READONLY; ++ break; ++ } ++ ++ lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults); ++ } ++ ++ return lsect; ++} ++ ++/* If we have a non-zero sized .sbss2 or .PPC.EMB.sbss0 sections, we ++ need to bump up the number of section headers. */ ++ ++static int ++ppc_elf_additional_program_headers (abfd) ++ bfd *abfd; ++{ ++ asection *s; ++ int ret; ++ ++ ret = 0; ++ ++ s = bfd_get_section_by_name (abfd, ".interp"); ++ if (s != NULL) ++ ++ret; ++ ++ s = bfd_get_section_by_name (abfd, ".sbss2"); ++ if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0) ++ ++ret; ++ ++ s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0"); ++ if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0) ++ ++ret; ++ ++ return ret; ++} ++ ++/* Modify the segment map if needed. */ ++ ++static boolean ++ppc_elf_modify_segment_map (abfd) ++ bfd *abfd ATTRIBUTE_UNUSED; ++{ ++ return true; ++} ++ ++/* The powerpc .got has a blrl instruction in it. Mark it executable. */ ++ ++static asection * ++ppc_elf_create_got (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ register asection *s; ++ flagword flags; ++ ++ if (!_bfd_elf_create_got_section (abfd, info)) ++ return NULL; ++ ++ s = bfd_get_section_by_name (abfd, ".got"); ++ if (s == NULL) ++ abort (); ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED); ++ if (!bfd_set_section_flags (abfd, s, flags)) ++ return NULL; ++ return s; ++} ++ ++/* We have to create .dynsbss and .rela.sbss here so that they get mapped ++ to output sections (just like _bfd_elf_create_dynamic_sections has ++ to create .dynbss and .rela.bss). */ ++ ++static boolean ++ppc_elf_create_dynamic_sections (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ register asection *s; ++ flagword flags; ++ ++ if (!ppc_elf_create_got (abfd, info)) ++ return false; ++ ++ if (!_bfd_elf_create_dynamic_sections (abfd, info)) ++ return false; ++ ++ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED); ++ ++ s = bfd_make_section (abfd, ".dynsbss"); ++ if (s == NULL ++ || ! bfd_set_section_flags (abfd, s, SEC_ALLOC)) ++ return false; ++ ++ if (! info->shared) ++ { ++ s = bfd_make_section (abfd, ".rela.sbss"); ++ if (s == NULL ++ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) ++ || ! bfd_set_section_alignment (abfd, s, 2)) ++ return false; ++ } ++ ++ s = bfd_get_section_by_name (abfd, ".plt"); ++ if (s == NULL) ++ abort (); ++ ++ flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED; ++ return bfd_set_section_flags (abfd, s, flags); ++} ++ ++/* Adjust a symbol defined by a dynamic object and referenced by a ++ regular object. The current definition is in some section of the ++ dynamic object, but we're not including those sections. We have to ++ change the definition to something the rest of the link can ++ understand. */ ++ ++static boolean ++ppc_elf_adjust_dynamic_symbol (info, h) ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++{ ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ asection *s; ++ unsigned int power_of_two; ++ bfd_vma plt_offset; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n", h->root.root.string); ++#endif ++ ++ /* Make sure we know what is going on here. */ ++ BFD_ASSERT (dynobj != NULL ++ && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) ++ || h->weakdef != NULL ++ || ((h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_DYNAMIC) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_REF_REGULAR) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_REGULAR) == 0))); ++ ++ /* If this is a function, put it in the procedure linkage table. We ++ will fill in the contents of the procedure linkage table later, ++ when we know the address of the .got section. */ ++ if (h->type == STT_FUNC ++ || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) ++ { ++ if (! elf_hash_table (info)->dynamic_sections_created ++ || SYMBOL_CALLS_LOCAL (info, h) ++ || (info->shared && h->plt.refcount <= 0)) ++ { ++ /* A PLT entry is not required/allowed when: ++ ++ 1. We are not using ld.so; because then the PLT entry ++ can't be set up, so we can't use one. ++ ++ 2. We know for certain that a call to this symbol ++ will go to this object. ++ ++ 3. GC has rendered the entry unused. ++ Note, however, that in an executable all references to the ++ symbol go to the PLT, so we can't turn it off in that case. ++ ??? The correct thing to do here is to reference count ++ all uses of the symbol, not just those to the GOT or PLT. */ ++ h->plt.offset = (bfd_vma) -1; ++ h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; ++ return true; ++ } ++ ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ { ++ if (! bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ } ++ BFD_ASSERT (h->dynindx != -1); ++ ++ s = bfd_get_section_by_name (dynobj, ".plt"); ++ BFD_ASSERT (s != NULL); ++ ++ /* If this is the first .plt entry, make room for the special ++ first entry. */ ++ if (s->_raw_size == 0) ++ s->_raw_size += PLT_INITIAL_ENTRY_SIZE; ++ ++ /* The PowerPC PLT is actually composed of two parts, the first part ++ is 2 words (for a load and a jump), and then there is a remaining ++ word available at the end. */ ++ plt_offset = (PLT_INITIAL_ENTRY_SIZE ++ + (PLT_SLOT_SIZE ++ * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) ++ / PLT_ENTRY_SIZE))); ++ ++ /* If this symbol is not defined in a regular file, and we are ++ not generating a shared library, then set the symbol to this ++ location in the .plt. This is required to make function ++ pointers compare as equal between the normal executable and ++ the shared library. */ ++ if (! info->shared ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ { ++ h->root.u.def.section = s; ++ h->root.u.def.value = plt_offset; ++ } ++ ++ h->plt.offset = plt_offset; ++ ++ /* Make room for this entry. After the 8192nd entry, room ++ for two entries is allocated. */ ++ if ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE ++ >= PLT_NUM_SINGLE_ENTRIES) ++ s->_raw_size += 2 * PLT_ENTRY_SIZE; ++ else ++ s->_raw_size += PLT_ENTRY_SIZE; ++ ++ /* We also need to make an entry in the .rela.plt section. */ ++ s = bfd_get_section_by_name (dynobj, ".rela.plt"); ++ BFD_ASSERT (s != NULL); ++ s->_raw_size += sizeof (Elf32_External_Rela); ++ ++ return true; ++ } ++ else ++ h->plt.offset = (bfd_vma) -1; ++ ++ /* If this is a weak symbol, and there is a real definition, the ++ processor independent code will have arranged for us to see the ++ real definition first, and we can just use the same value. */ ++ if (h->weakdef != NULL) ++ { ++ BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined ++ || h->weakdef->root.type == bfd_link_hash_defweak); ++ h->root.u.def.section = h->weakdef->root.u.def.section; ++ h->root.u.def.value = h->weakdef->root.u.def.value; ++ return true; ++ } ++ ++ /* This is a reference to a symbol defined by a dynamic object which ++ is not a function. */ ++ ++ /* If we are creating a shared library, we must presume that the ++ only references to the symbol are via the global offset table. ++ For such cases we need not do anything here; the relocations will ++ be handled correctly by relocate_section. */ ++ if (info->shared) ++ return true; ++ ++ /* We must allocate the symbol in our .dynbss section, which will ++ become part of the .bss section of the executable. There will be ++ an entry for this symbol in the .dynsym section. The dynamic ++ object will contain position independent code, so all references ++ from the dynamic object to this symbol will go through the global ++ offset table. The dynamic linker will use the .dynsym entry to ++ determine the address it must put in the global offset table, so ++ both the dynamic object and the regular object will refer to the ++ same memory location for the variable. ++ ++ Of course, if the symbol is sufficiently small, we must instead ++ allocate it in .sbss. FIXME: It would be better to do this if and ++ only if there were actually SDAREL relocs for that symbol. */ ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ s = bfd_get_section_by_name (dynobj, ".dynsbss"); ++ else ++ s = bfd_get_section_by_name (dynobj, ".dynbss"); ++ BFD_ASSERT (s != NULL); ++ ++ /* We must generate a R_PPC_COPY reloc to tell the dynamic linker to ++ copy the initial value out of the dynamic object and into the ++ runtime process image. We need to remember the offset into the ++ .rela.bss section we are going to use. */ ++ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) ++ { ++ asection *srel; ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ srel = bfd_get_section_by_name (dynobj, ".rela.sbss"); ++ else ++ srel = bfd_get_section_by_name (dynobj, ".rela.bss"); ++ BFD_ASSERT (srel != NULL); ++ srel->_raw_size += sizeof (Elf32_External_Rela); ++ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; ++ } ++ ++ /* We need to figure out the alignment required for this symbol. I ++ have no idea how ELF linkers handle this. */ ++ power_of_two = bfd_log2 (h->size); ++ if (power_of_two > 4) ++ power_of_two = 4; ++ ++ /* Apply the required alignment. */ ++ s->_raw_size = BFD_ALIGN (s->_raw_size, ++ (bfd_size_type) (1 << power_of_two)); ++ if (power_of_two > bfd_get_section_alignment (dynobj, s)) ++ { ++ if (! bfd_set_section_alignment (dynobj, s, power_of_two)) ++ return false; ++ } ++ ++ /* Define the symbol as being at this point in the section. */ ++ h->root.u.def.section = s; ++ h->root.u.def.value = s->_raw_size; ++ ++ /* Increment the section size to make room for the symbol. */ ++ s->_raw_size += h->size; ++ ++ return true; ++} ++ ++/* Set the sizes of the dynamic sections. */ ++ ++static boolean ++ppc_elf_size_dynamic_sections (output_bfd, info) ++ bfd *output_bfd ATTRIBUTE_UNUSED; ++ struct bfd_link_info *info; ++{ ++ bfd *dynobj; ++ asection *s; ++ boolean plt; ++ boolean relocs; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_size_dynamic_sections called\n"); ++#endif ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ BFD_ASSERT (dynobj != NULL); ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ /* Set the contents of the .interp section to the interpreter. */ ++ if (! info->shared) ++ { ++ s = bfd_get_section_by_name (dynobj, ".interp"); ++ BFD_ASSERT (s != NULL); ++ s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; ++ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; ++ } ++ } ++ else ++ { ++ /* We may have created entries in the .rela.got, .rela.sdata, and ++ .rela.sdata2 sections. However, if we are not creating the ++ dynamic sections, we will not actually use these entries. Reset ++ the size of .rela.got, et al, which will cause it to get ++ stripped from the output file below. */ ++ static char *rela_sections[] = { ".rela.got", ".rela.sdata", ++ ".rela.sdata2", ".rela.sbss", ++ (char *) 0 }; ++ char **p; ++ ++ for (p = rela_sections; *p != (char *) 0; p++) ++ { ++ s = bfd_get_section_by_name (dynobj, *p); ++ if (s != NULL) ++ s->_raw_size = 0; ++ } ++ } ++ ++ /* The check_relocs and adjust_dynamic_symbol entry points have ++ determined the sizes of the various dynamic sections. Allocate ++ memory for them. */ ++ plt = false; ++ relocs = false; ++ for (s = dynobj->sections; s != NULL; s = s->next) ++ { ++ const char *name; ++ boolean strip; ++ ++ if ((s->flags & SEC_LINKER_CREATED) == 0) ++ continue; ++ ++ /* It's OK to base decisions on the section name, because none ++ of the dynobj section names depend upon the input files. */ ++ name = bfd_get_section_name (dynobj, s); ++ ++ strip = false; ++ ++ if (strcmp (name, ".plt") == 0) ++ { ++ if (s->_raw_size == 0) ++ { ++ /* Strip this section if we don't need it; see the ++ comment below. */ ++ strip = true; ++ } ++ else ++ { ++ /* Remember whether there is a PLT. */ ++ plt = true; ++ } ++ } ++ else if (strncmp (name, ".rela", 5) == 0) ++ { ++ if (s->_raw_size == 0) ++ { ++ /* If we don't need this section, strip it from the ++ output file. This is mostly to handle .rela.bss and ++ .rela.plt. We must create both sections in ++ create_dynamic_sections, because they must be created ++ before the linker maps input sections to output ++ sections. The linker does that before ++ adjust_dynamic_symbol is called, and it is that ++ function which decides whether anything needs to go ++ into these sections. */ ++ strip = true; ++ } ++ else ++ { ++ /* Remember whether there are any relocation sections. */ ++ relocs = true; ++ ++ /* We use the reloc_count field as a counter if we need ++ to copy relocs into the output file. */ ++ s->reloc_count = 0; ++ } ++ } ++ else if (strcmp (name, ".got") != 0 ++ && strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sdata2") != 0) ++ { ++ /* It's not one of our sections, so don't allocate space. */ ++ continue; ++ } ++ ++ if (strip) ++ { ++ _bfd_strip_section_from_output (info, s); ++ continue; ++ } ++ ++ /* Allocate memory for the section contents. */ ++ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); ++ if (s->contents == NULL && s->_raw_size != 0) ++ return false; ++ } ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ /* Add some entries to the .dynamic section. We fill in the ++ values later, in ppc_elf_finish_dynamic_sections, but we ++ must add the entries now so that we get the correct size for ++ the .dynamic section. The DT_DEBUG entry is filled in by the ++ dynamic linker and used by the debugger. */ ++#define add_dynamic_entry(TAG, VAL) \ ++ bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL)) ++ ++ if (!info->shared) ++ { ++ if (!add_dynamic_entry (DT_DEBUG, 0)) ++ return false; ++ } ++ ++ if (plt) ++ { ++ if (!add_dynamic_entry (DT_PLTGOT, 0) ++ || !add_dynamic_entry (DT_PLTRELSZ, 0) ++ || !add_dynamic_entry (DT_PLTREL, DT_RELA) ++ || !add_dynamic_entry (DT_JMPREL, 0)) ++ return false; ++ } ++ ++ if (relocs) ++ { ++ if (!add_dynamic_entry (DT_RELA, 0) ++ || !add_dynamic_entry (DT_RELASZ, 0) ++ || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) ++ return false; ++ } ++ ++ if ((info->flags & DF_TEXTREL) != 0) ++ { ++ if (!add_dynamic_entry (DT_TEXTREL, 0)) ++ return false; ++ info->flags |= DF_TEXTREL; ++ } ++ } ++#undef add_dynamic_entry ++ ++ return true; ++} ++ ++/* Look through the relocs for a section during the first phase, and ++ allocate space in the global offset table or procedure linkage ++ table. */ ++ ++static boolean ++ppc_elf_check_relocs (abfd, info, sec, relocs) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ asection *sec; ++ const Elf_Internal_Rela *relocs; ++{ ++ bfd *dynobj; ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; ++ const Elf_Internal_Rela *rel; ++ const Elf_Internal_Rela *rel_end; ++ bfd_signed_vma *local_got_refcounts; ++ elf_linker_section_t *sdata; ++ elf_linker_section_t *sdata2; ++ asection *sreloc; ++ asection *sgot = NULL; ++ asection *srelgot = NULL; ++ ++ if (info->relocateable) ++ return true; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_check_relocs called for section %s in %s\n", ++ bfd_get_section_name (abfd, sec), ++ bfd_archive_filename (abfd)); ++#endif ++ ++ /* Create the linker generated sections all the time so that the ++ special symbols are created. */ ++ ++ if ((sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA)) == NULL) ++ { ++ sdata = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); ++ if (!sdata) ++ return false; ++ } ++ ++ if ((sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2)) == NULL) ++ { ++ sdata2 = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA2); ++ if (!sdata2) ++ return false; ++ } ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ local_got_refcounts = elf_local_got_refcounts (abfd); ++ ++ sym_hashes = elf_sym_hashes (abfd); ++ sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym); ++ if (!elf_bad_symtab (abfd)) ++ sym_hashes_end -= symtab_hdr->sh_info; ++ ++ sreloc = NULL; ++ ++ rel_end = relocs + sec->reloc_count; ++ for (rel = relocs; rel < rel_end; rel++) ++ { ++ unsigned long r_symndx; ++ struct elf_link_hash_entry *h; ++ ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx < symtab_hdr->sh_info) ++ h = NULL; ++ else ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ ++ /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. ++ This shows up in particular in an R_PPC_ADDR32 in the eabi ++ startup code. */ ++ if (h && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) ++ { ++ if (sgot == NULL) ++ { ++ if (dynobj == NULL) ++ elf_hash_table (info)->dynobj = dynobj = abfd; ++ sgot = ppc_elf_create_got (dynobj, info); ++ if (sgot == NULL) ++ return false; ++ } ++ } ++ ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ /* GOT16 relocations */ ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ /* This symbol requires a global offset table entry. */ ++ ++ if (sgot == NULL) ++ { ++ if (dynobj == NULL) ++ elf_hash_table (info)->dynobj = dynobj = abfd; ++ sgot = ppc_elf_create_got (dynobj, info); ++ if (sgot == NULL) ++ return false; ++ } ++ ++ if (srelgot == NULL ++ && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (h != NULL) ++ { ++ if (h->got.refcount == 0) ++ { ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ if (!bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ ++ /* Allocate space in the .got. */ ++ sgot->_raw_size += 4; ++ /* Allocate relocation space. */ ++ srelgot->_raw_size += sizeof (Elf32_External_Rela); ++ } ++ h->got.refcount++; ++ } ++ else ++ { ++ /* This is a global offset table entry for a local symbol. */ ++ if (local_got_refcounts == NULL) ++ { ++ bfd_size_type size; ++ ++ size = symtab_hdr->sh_info; ++ size *= sizeof (bfd_signed_vma); ++ local_got_refcounts ++ = (bfd_signed_vma *) bfd_zalloc (abfd, size); ++ if (local_got_refcounts == NULL) ++ return false; ++ elf_local_got_refcounts (abfd) = local_got_refcounts; ++ } ++ if (local_got_refcounts[r_symndx] == 0) ++ { ++ sgot->_raw_size += 4; ++ ++ /* If we are generating a shared object, we need to ++ output a R_PPC_RELATIVE reloc so that the ++ dynamic linker can adjust this GOT entry. */ ++ if (info->shared) ++ srelgot->_raw_size += sizeof (Elf32_External_Rela); ++ } ++ local_got_refcounts[r_symndx]++; ++ } ++ break; ++ ++ /* Indirect .sdata relocation */ ++ case R_PPC_EMB_SDAI16: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), "R_PPC_EMB_SDAI16")); ++ return false; ++ } ++ ++ if (srelgot == NULL && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata, h, rel)) ++ return false; ++ ++ break; ++ ++ /* Indirect .sdata2 relocation */ ++ case R_PPC_EMB_SDA2I16: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), "R_PPC_EMB_SDA2I16")); ++ return false; ++ } ++ ++ if (srelgot == NULL && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rela.got"); ++ if (srelgot == NULL ++ || ! bfd_set_section_flags (dynobj, srelgot, ++ (SEC_ALLOC ++ | SEC_LOAD ++ | SEC_HAS_CONTENTS ++ | SEC_IN_MEMORY ++ | SEC_LINKER_CREATED ++ | SEC_READONLY)) ++ || ! bfd_set_section_alignment (dynobj, srelgot, 2)) ++ return false; ++ } ++ } ++ ++ if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata2, h, rel)) ++ return false; ++ ++ break; ++ ++ case R_PPC_SDAREL16: ++ case R_PPC_EMB_SDA2REL: ++ case R_PPC_EMB_SDA21: ++ if (info->shared) ++ { ++ ((*_bfd_error_handler) ++ (_("%s: relocation %s cannot be used when making a shared object"), ++ bfd_archive_filename (abfd), ++ ppc_elf_howto_table[(int) ELF32_R_TYPE (rel->r_info)]->name)); ++ return false; ++ } ++ break; ++ ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL24: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++#ifdef DEBUG ++ fprintf (stderr, "Reloc requires a PLT entry\n"); ++#endif ++ /* This symbol requires a procedure linkage table entry. We ++ actually build the entry in adjust_dynamic_symbol, ++ because this might be a case of linking PIC code without ++ linking in any dynamic objects, in which case we don't ++ need to generate a procedure linkage table after all. */ ++ ++ if (h == NULL) ++ { ++ /* It does not make sense to have a procedure linkage ++ table entry for a local symbol. */ ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ ++ /* Make sure this symbol is output as a dynamic symbol. */ ++ if (h->dynindx == -1) ++ { ++ if (! bfd_elf32_link_record_dynamic_symbol (info, h)) ++ return false; ++ } ++ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; ++ h->plt.refcount++; ++ break; ++ ++ /* The following relocations don't need to propagate the ++ relocation if linking a shared object since they are ++ section relative. */ ++ case R_PPC_SECTOFF: ++ case R_PPC_SECTOFF_LO: ++ case R_PPC_SECTOFF_HI: ++ case R_PPC_SECTOFF_HA: ++ break; ++ ++ /* This refers only to functions defined in the shared library */ ++ case R_PPC_LOCAL24PC: ++ break; ++ ++ /* This relocation describes the C++ object vtable hierarchy. ++ Reconstruct it for later use during GC. */ ++ case R_PPC_GNU_VTINHERIT: ++ if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) ++ return false; ++ break; ++ ++ /* This relocation describes which C++ vtable entries are actually ++ used. Record for later use during GC. */ ++ case R_PPC_GNU_VTENTRY: ++ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend)) ++ return false; ++ break; ++ ++ /* When creating a shared object, we must copy these ++ relocs into the output file. We create a reloc ++ section in dynobj and make room for the reloc. */ ++ case R_PPC_REL24: ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ case R_PPC_REL32: ++ if (h == NULL ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || SYMBOL_REFERENCES_LOCAL (info, h)) ++ break; ++ /* fall through */ ++ ++ default: ++ if (info->shared) ++ { ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_check_relocs need to create relocation for %s\n", ++ (h && h->root.root.string) ? h->root.root.string : "<unknown>"); ++#endif ++ if (sreloc == NULL) ++ { ++ const char *name; ++ ++ name = (bfd_elf_string_from_elf_section ++ (abfd, ++ elf_elfheader (abfd)->e_shstrndx, ++ elf_section_data (sec)->rel_hdr.sh_name)); ++ if (name == NULL) ++ return false; ++ ++ BFD_ASSERT (strncmp (name, ".rela", 5) == 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ++ name + 5) == 0); ++ ++ sreloc = bfd_get_section_by_name (dynobj, name); ++ if (sreloc == NULL) ++ { ++ flagword flags; ++ ++ sreloc = bfd_make_section (dynobj, name); ++ flags = (SEC_HAS_CONTENTS | SEC_READONLY ++ | SEC_IN_MEMORY | SEC_LINKER_CREATED); ++ if ((sec->flags & SEC_ALLOC) != 0) ++ flags |= SEC_ALLOC | SEC_LOAD; ++ if (sreloc == NULL ++ || ! bfd_set_section_flags (dynobj, sreloc, flags) ++ || ! bfd_set_section_alignment (dynobj, sreloc, 2)) ++ return false; ++ } ++ if (sec->flags & SEC_READONLY) ++ info->flags |= DF_TEXTREL; ++ } ++ ++ sreloc->_raw_size += sizeof (Elf32_External_Rela); ++ ++ /* FIXME: We should here do what the m68k and i386 ++ backends do: if the reloc is pc-relative, record it ++ in case it turns out that the reloc is unnecessary ++ because the symbol is forced local by versioning or ++ we are linking with -Bdynamic. Fortunately this ++ case is not frequent. */ ++ } ++ ++ break; ++ } ++ } ++ ++ return true; ++} ++ ++/* Return the section that should be marked against GC for a given ++ relocation. */ ++ ++static asection * ++ppc_elf_gc_mark_hook (sec, info, rel, h, sym) ++ asection *sec; ++ struct bfd_link_info *info ATTRIBUTE_UNUSED; ++ Elf_Internal_Rela *rel; ++ struct elf_link_hash_entry *h; ++ Elf_Internal_Sym *sym; ++{ ++ if (h != NULL) ++ { ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_PPC_GNU_VTINHERIT: ++ case R_PPC_GNU_VTENTRY: ++ break; ++ ++ default: ++ switch (h->root.type) ++ { ++ case bfd_link_hash_defined: ++ case bfd_link_hash_defweak: ++ return h->root.u.def.section; ++ ++ case bfd_link_hash_common: ++ return h->root.u.c.p->section; ++ ++ default: ++ break; ++ } ++ } ++ } ++ else ++ return bfd_section_from_elf_index (sec->owner, sym->st_shndx); ++ ++ return NULL; ++} ++ ++/* Update the got entry reference counts for the section being removed. */ ++ ++static boolean ++ppc_elf_gc_sweep_hook (abfd, info, sec, relocs) ++ bfd *abfd; ++ struct bfd_link_info *info ATTRIBUTE_UNUSED; ++ asection *sec; ++ const Elf_Internal_Rela *relocs; ++{ ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes; ++ bfd_signed_vma *local_got_refcounts; ++ const Elf_Internal_Rela *rel, *relend; ++ unsigned long r_symndx; ++ struct elf_link_hash_entry *h; ++ ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ sym_hashes = elf_sym_hashes (abfd); ++ local_got_refcounts = elf_local_got_refcounts (abfd); ++ ++ relend = relocs + sec->reloc_count; ++ for (rel = relocs; rel < relend; rel++) ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_PPC_GOT16: ++ case R_PPC_GOT16_LO: ++ case R_PPC_GOT16_HI: ++ case R_PPC_GOT16_HA: ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ if (h->got.refcount > 0) ++ h->got.refcount--; ++ } ++ else if (local_got_refcounts != NULL) ++ { ++ if (local_got_refcounts[r_symndx] > 0) ++ local_got_refcounts[r_symndx]--; ++ } ++ break; ++ ++ case R_PPC_PLT32: ++ case R_PPC_PLTREL24: ++ case R_PPC_PLT16_LO: ++ case R_PPC_PLT16_HI: ++ case R_PPC_PLT16_HA: ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ if (r_symndx >= symtab_hdr->sh_info) ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ if (h->plt.refcount > 0) ++ h->plt.refcount--; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return true; ++} ++ ++/* Hook called by the linker routine which adds symbols from an object ++ file. We use it to put .comm items in .sbss, and not .bss. */ ++ ++static boolean ++ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ const Elf_Internal_Sym *sym; ++ const char **namep ATTRIBUTE_UNUSED; ++ flagword *flagsp ATTRIBUTE_UNUSED; ++ asection **secp; ++ bfd_vma *valp; ++{ ++ if (sym->st_shndx == SHN_COMMON ++ && !info->relocateable ++ && sym->st_size <= elf_gp_size (abfd) ++ && info->hash->creator->flavour == bfd_target_elf_flavour) ++ { ++ /* Common symbols less than or equal to -G nn bytes are automatically ++ put into .sdata. */ ++ elf_linker_section_t *sdata ++ = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); ++ ++ if (!sdata->bss_section) ++ { ++ bfd_size_type amt; ++ ++ /* We don't go through bfd_make_section, because we don't ++ want to attach this common section to DYNOBJ. The linker ++ will move the symbols to the appropriate output section ++ when it defines common symbols. */ ++ amt = sizeof (asection); ++ sdata->bss_section = (asection *) bfd_zalloc (abfd, amt); ++ if (sdata->bss_section == NULL) ++ return false; ++ sdata->bss_section->name = sdata->bss_name; ++ sdata->bss_section->flags = SEC_IS_COMMON; ++ sdata->bss_section->output_section = sdata->bss_section; ++ amt = sizeof (asymbol); ++ sdata->bss_section->symbol = (asymbol *) bfd_zalloc (abfd, amt); ++ amt = sizeof (asymbol *); ++ sdata->bss_section->symbol_ptr_ptr = ++ (asymbol **) bfd_zalloc (abfd, amt); ++ if (sdata->bss_section->symbol == NULL ++ || sdata->bss_section->symbol_ptr_ptr == NULL) ++ return false; ++ sdata->bss_section->symbol->name = sdata->bss_name; ++ sdata->bss_section->symbol->flags = BSF_SECTION_SYM; ++ sdata->bss_section->symbol->section = sdata->bss_section; ++ *sdata->bss_section->symbol_ptr_ptr = sdata->bss_section->symbol; ++ } ++ ++ *secp = sdata->bss_section; ++ *valp = sym->st_size; ++ } ++ ++ return true; ++} ++ ++/* Finish up dynamic symbol handling. We set the contents of various ++ dynamic sections here. */ ++ ++static boolean ++ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++ Elf_Internal_Sym *sym; ++{ ++ bfd *dynobj; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s", ++ h->root.root.string); ++#endif ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ BFD_ASSERT (dynobj != NULL); ++ ++ if (h->plt.offset != (bfd_vma) -1) ++ { ++ asection *splt; ++ asection *srela; ++ Elf_Internal_Rela rela; ++ bfd_vma reloc_index; ++ ++#ifdef DEBUG ++ fprintf (stderr, ", plt_offset = %d", h->plt.offset); ++#endif ++ ++ /* This symbol has an entry in the procedure linkage table. Set ++ it up. */ ++ ++ BFD_ASSERT (h->dynindx != -1); ++ ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ srela = bfd_get_section_by_name (dynobj, ".rela.plt"); ++ BFD_ASSERT (splt != NULL && srela != NULL); ++ ++ /* We don't need to fill in the .plt. The ppc dynamic linker ++ will fill it in. */ ++ ++ /* Fill in the entry in the .rela.plt section. */ ++ rela.r_offset = (splt->output_section->vma ++ + splt->output_offset ++ + h->plt.offset); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); ++ rela.r_addend = 0; ++ ++ reloc_index = (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_SLOT_SIZE; ++ if (reloc_index > PLT_NUM_SINGLE_ENTRIES) ++ reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) srela->contents ++ + reloc_index)); ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ { ++ /* Mark the symbol as undefined, rather than as defined in ++ the .plt section. Leave the value alone. */ ++ sym->st_shndx = SHN_UNDEF; ++ /* If the symbol is weak, we do need to clear the value. ++ Otherwise, the PLT entry would provide a definition for ++ the symbol even if the symbol wasn't defined anywhere, ++ and so the symbol would never be NULL. */ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) ++ == 0) ++ sym->st_value = 0; ++ } ++ } ++ ++ if (h->got.offset != (bfd_vma) -1) ++ { ++ asection *sgot; ++ asection *srela; ++ Elf_Internal_Rela rela; ++ ++ /* This symbol has an entry in the global offset table. Set it ++ up. */ ++ ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ srela = bfd_get_section_by_name (dynobj, ".rela.got"); ++ BFD_ASSERT (sgot != NULL && srela != NULL); ++ ++ rela.r_offset = (sgot->output_section->vma ++ + sgot->output_offset ++ + (h->got.offset &~ (bfd_vma) 1)); ++ ++ /* If this is a -Bsymbolic link, and the symbol is defined ++ locally, we just want to emit a RELATIVE reloc. The entry in ++ the global offset table will already have been initialized in ++ the relocate_section function. */ ++ if (info->shared ++ && SYMBOL_REFERENCES_LOCAL (info, h)) ++ { ++ rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ rela.r_addend = (h->root.u.def.value ++ + h->root.u.def.section->output_section->vma ++ + h->root.u.def.section->output_offset); ++ } ++ else ++ { ++ BFD_ASSERT ((h->got.offset & 1) == 0); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_GLOB_DAT); ++ rela.r_addend = 0; ++ } ++ ++ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) srela->contents ++ + srela->reloc_count)); ++ ++srela->reloc_count; ++ } ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) ++ { ++ asection *s; ++ Elf_Internal_Rela rela; ++ ++ /* This symbols needs a copy reloc. Set it up. */ ++ ++#ifdef DEBUG ++ fprintf (stderr, ", copy"); ++#endif ++ ++ BFD_ASSERT (h->dynindx != -1); ++ ++ if (h->size <= elf_gp_size (dynobj)) ++ s = bfd_get_section_by_name (h->root.u.def.section->owner, ++ ".rela.sbss"); ++ else ++ s = bfd_get_section_by_name (h->root.u.def.section->owner, ++ ".rela.bss"); ++ BFD_ASSERT (s != NULL); ++ ++ rela.r_offset = (h->root.u.def.value ++ + h->root.u.def.section->output_section->vma ++ + h->root.u.def.section->output_offset); ++ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY); ++ rela.r_addend = 0; ++ bfd_elf32_swap_reloca_out (output_bfd, &rela, ++ ((Elf32_External_Rela *) s->contents ++ + s->reloc_count)); ++ ++s->reloc_count; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ /* Mark some specially defined symbols as absolute. */ ++ if (strcmp (h->root.root.string, "_DYNAMIC") == 0 ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0) ++ sym->st_shndx = SHN_ABS; ++ ++ return true; ++} ++ ++/* Finish up the dynamic sections. */ ++ ++static boolean ++ppc_elf_finish_dynamic_sections (output_bfd, info) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++{ ++ asection *sdyn; ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ asection *sgot = bfd_get_section_by_name (dynobj, ".got"); ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); ++#endif ++ ++ sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); ++ ++ if (elf_hash_table (info)->dynamic_sections_created) ++ { ++ asection *splt; ++ Elf32_External_Dyn *dyncon, *dynconend; ++ ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ BFD_ASSERT (splt != NULL && sdyn != NULL); ++ ++ dyncon = (Elf32_External_Dyn *) sdyn->contents; ++ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); ++ for (; dyncon < dynconend; dyncon++) ++ { ++ Elf_Internal_Dyn dyn; ++ const char *name; ++ boolean size; ++ ++ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); ++ ++ switch (dyn.d_tag) ++ { ++ case DT_PLTGOT: name = ".plt"; size = false; break; ++ case DT_PLTRELSZ: name = ".rela.plt"; size = true; break; ++ case DT_JMPREL: name = ".rela.plt"; size = false; break; ++ default: name = NULL; size = false; break; ++ } ++ ++ if (name != NULL) ++ { ++ asection *s; ++ ++ s = bfd_get_section_by_name (output_bfd, name); ++ if (s == NULL) ++ dyn.d_un.d_val = 0; ++ else ++ { ++ if (! size) ++ dyn.d_un.d_ptr = s->vma; ++ else ++ { ++ if (s->_cooked_size != 0) ++ dyn.d_un.d_val = s->_cooked_size; ++ else ++ dyn.d_un.d_val = s->_raw_size; ++ } ++ } ++ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); ++ } ++ } ++ } ++ ++ /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can ++ easily find the address of the _GLOBAL_OFFSET_TABLE_. */ ++ if (sgot) ++ { ++ unsigned char *contents = sgot->contents; ++ bfd_put_32 (output_bfd, (bfd_vma) 0x4e800021 /* blrl */, contents); ++ ++ if (sdyn == NULL) ++ bfd_put_32 (output_bfd, (bfd_vma) 0, contents+4); ++ else ++ bfd_put_32 (output_bfd, ++ sdyn->output_section->vma + sdyn->output_offset, ++ contents+4); ++ ++ elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; ++ } ++ ++ return true; ++} ++ ++/* The RELOCATE_SECTION function is called by the ELF backend linker ++ to handle the relocations for a section. ++ ++ The relocs are always passed as Rela structures; if the section ++ actually uses Rel structures, the r_addend field will always be ++ zero. ++ ++ This function is responsible for adjust the section contents as ++ necessary, and (if using Rela relocs and generating a ++ relocateable output file) adjusting the reloc addend as ++ necessary. ++ ++ This function does not have to worry about setting the reloc ++ address or the reloc symbol index. ++ ++ LOCAL_SYMS is a pointer to the swapped in local symbols. ++ ++ LOCAL_SECTIONS is an array giving the section in the input file ++ corresponding to the st_shndx field of each local symbol. ++ ++ The global hash table entry for the global symbols can be found ++ via elf_sym_hashes (input_bfd). ++ ++ When generating relocateable output, this function must handle ++ STB_LOCAL/STT_SECTION symbols specially. The output symbol is ++ going to be the section symbol corresponding to the output ++ section, which means that the addend must be adjusted ++ accordingly. */ ++ ++static boolean ++ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, ++ contents, relocs, local_syms, local_sections) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ bfd *input_bfd; ++ asection *input_section; ++ bfd_byte *contents; ++ Elf_Internal_Rela *relocs; ++ Elf_Internal_Sym *local_syms; ++ asection **local_sections; ++{ ++ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ elf_linker_section_t *sdata = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA) : NULL; ++ elf_linker_section_t *sdata2 = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA2) : NULL; ++ Elf_Internal_Rela *rel = relocs; ++ Elf_Internal_Rela *relend = relocs + input_section->reloc_count; ++ asection *sreloc = NULL; ++ asection *splt; ++ asection *sgot; ++ bfd_vma *local_got_offsets; ++ boolean ret = true; ++ long insn; ++ asection *sdata_sec = NULL; ++ asection *sbss_sec = NULL; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_relocate_section called for %s section %s, %ld relocations%s\n", ++ bfd_archive_filename (input_bfd), ++ bfd_section_name(input_bfd, input_section), ++ (long) input_section->reloc_count, ++ (info->relocateable) ? " (relocatable)" : ""); ++#endif ++ ++ if (info->relocateable) ++ return true; ++ ++ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ++ /* Initialize howto table if needed. */ ++ ppc_elf_howto_init (); ++ ++ if (!strcmp(bfd_section_name(output_bfd, input_section), ".sdata") || ++ !strcmp(bfd_section_name(output_bfd, input_section), ".sbss")) ++ { ++ sdata_sec = bfd_get_section_by_name(output_bfd, ".sdata"); ++ if (sdata_sec) ++ sdata_sec = sdata_sec->output_section; ++ sbss_sec = bfd_get_section_by_name(output_bfd, ".sbss"); ++ if (sbss_sec) ++ sbss_sec = sbss_sec->output_section; ++ } ++ ++ local_got_offsets = elf_local_got_offsets (input_bfd); ++ ++ splt = sgot = NULL; ++ if (dynobj != NULL) ++ { ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ } ++ ++ for (; rel < relend; rel++) ++ { ++ enum elf_ppc_reloc_type r_type = (enum elf_ppc_reloc_type)ELF32_R_TYPE (rel->r_info); ++ bfd_vma offset = rel->r_offset; ++ bfd_vma addend = rel->r_addend; ++ bfd_reloc_status_type r = bfd_reloc_other; ++ Elf_Internal_Sym *sym = (Elf_Internal_Sym *) 0; ++ asection *sec = (asection *) 0; ++ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) 0; ++ const char *sym_name = (const char *) 0; ++ boolean copy = false; ++ reloc_howto_type *howto; ++ unsigned long r_symndx; ++ bfd_vma relocation; ++ int will_become_local; ++ ++ /* Unknown relocation handling */ ++ if ((unsigned) r_type >= (unsigned) R_PPC_max ++ || !ppc_elf_howto_table[(int) r_type]) ++ { ++ (*_bfd_error_handler) (_("%s: unknown relocation type %d"), ++ bfd_archive_filename (input_bfd), ++ (int) r_type); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ ++ howto = ppc_elf_howto_table[(int) r_type]; ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ ++ if (r_symndx < symtab_hdr->sh_info) ++ { ++ sym = local_syms + r_symndx; ++ sec = local_sections[r_symndx]; ++ sym_name = "<local symbol>"; ++ ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ addend = rel->r_addend; ++ /* Relocs to local symbols are always resolved. */ ++ will_become_local = 1; ++ } ++ else ++ { ++ h = sym_hashes[r_symndx - symtab_hdr->sh_info]; ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ sym_name = h->root.root.string; ++ ++ /* Can this relocation be resolved immediately? */ ++ will_become_local = SYMBOL_REFERENCES_LOCAL (info, h); ++ ++ if (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ { ++ sec = h->root.u.def.section; ++ if (((r_type == R_PPC_PLT32 ++ || r_type == R_PPC_PLTREL24) ++ && splt != NULL ++ && h->plt.offset != (bfd_vma) -1) ++ || (r_type == R_PPC_LOCAL24PC ++ && sec->output_section == NULL) ++ || ((r_type == R_PPC_GOT16 ++ || r_type == R_PPC_GOT16_LO ++ || r_type == R_PPC_GOT16_HI ++ || r_type == R_PPC_GOT16_HA) ++ && elf_hash_table (info)->dynamic_sections_created ++ && (! info->shared || ! will_become_local)) ++ || (info->shared ++ && ! will_become_local ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ /* Testing SEC_DEBUGGING here may be wrong. ++ It's here to avoid a crash when ++ generating a shared library with DWARF ++ debugging information. */ ++ || ((input_section->flags & SEC_DEBUGGING) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_DYNAMIC) != 0)) ++ && (r_type == R_PPC_ADDR32 ++ || r_type == R_PPC_ADDR24 ++ || r_type == R_PPC_ADDR16 ++ || r_type == R_PPC_ADDR16_LO ++ || r_type == R_PPC_ADDR16_HI ++ || r_type == R_PPC_ADDR16_HA ++ || r_type == R_PPC_ADDR14 ++ || r_type == R_PPC_ADDR14_BRTAKEN ++ || r_type == R_PPC_ADDR14_BRNTAKEN ++ || r_type == R_PPC_COPY ++ || r_type == R_PPC_GLOB_DAT ++ || r_type == R_PPC_JMP_SLOT ++ || r_type == R_PPC_UADDR32 ++ || r_type == R_PPC_UADDR16 ++ || r_type == R_PPC_SDAREL16 ++ || r_type == R_PPC_EMB_NADDR32 ++ || r_type == R_PPC_EMB_NADDR16 ++ || r_type == R_PPC_EMB_NADDR16_LO ++ || r_type == R_PPC_EMB_NADDR16_HI ++ || r_type == R_PPC_EMB_NADDR16_HA ++ || r_type == R_PPC_EMB_SDAI16 ++ || r_type == R_PPC_EMB_SDA2I16 ++ || r_type == R_PPC_EMB_SDA2REL ++ || r_type == R_PPC_EMB_SDA21 ++ || r_type == R_PPC_EMB_MRKREF ++ || r_type == R_PPC_EMB_BIT_FLD ++ || r_type == R_PPC_EMB_RELSDA ++ || ((r_type == R_PPC_REL24 ++ || r_type == R_PPC_REL32 ++ || r_type == R_PPC_REL14 ++ || r_type == R_PPC_REL14_BRTAKEN ++ || r_type == R_PPC_REL14_BRNTAKEN ++ || r_type == R_PPC_RELATIVE) ++ && strcmp (h->root.root.string, ++ "_GLOBAL_OFFSET_TABLE_") != 0)))) ++ { ++ /* In these cases, we don't need the relocation ++ value. We check specially because in some ++ obscure cases sec->output_section will be NULL. */ ++ relocation = 0; ++ } ++ else if (sec->output_section == NULL) ++ { ++ (*_bfd_error_handler) ++ (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"), ++ bfd_archive_filename (input_bfd), h->root.root.string, ++ bfd_get_section_name (input_bfd, input_section)); ++ relocation = 0; ++ } ++ else ++ relocation = (h->root.u.def.value ++ + sec->output_section->vma ++ + sec->output_offset); ++ } ++ else if (h->root.type == bfd_link_hash_undefweak) ++ relocation = 0; ++ else if (info->shared ++ && (!info->symbolic || info->allow_shlib_undefined) ++ && !info->no_undefined ++ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) ++ relocation = 0; ++ else ++ { ++ if (! (*info->callbacks->undefined_symbol) (info, ++ h->root.root.string, ++ input_bfd, ++ input_section, ++ rel->r_offset, ++ (!info->shared ++ || info->no_undefined ++ || ELF_ST_VISIBILITY (h->other)))) ++ return false; ++ relocation = 0; ++ } ++ } ++ ++ switch ((int) r_type) ++ { ++ default: ++ (*_bfd_error_handler) (_("%s: unknown relocation type %d for symbol %s"), ++ bfd_archive_filename (input_bfd), ++ (int) r_type, sym_name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ ++ case (int) R_PPC_NONE: ++ continue; ++ ++ /* Relocations that need no special processing. */ ++ case (int) R_PPC_LOCAL24PC: ++ /* It makes no sense to point a local relocation ++ at a symbol not in this object. */ ++ if (h != NULL ++ && (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && sec->output_section == NULL) ++ { ++ if (! (*info->callbacks->undefined_symbol) (info, ++ h->root.root.string, ++ input_bfd, ++ input_section, ++ rel->r_offset, ++ true)) ++ return false; ++ continue; ++ } ++ break; ++ ++ /* Relocations that may need to be propagated if this is a shared ++ object. */ ++ case (int) R_PPC_REL24: ++ case (int) R_PPC_REL32: ++ case (int) R_PPC_REL14: ++ /* If these relocations are not to a named symbol, they can be ++ handled right here, no need to bother the dynamic linker. */ ++ if (info->shared && (h == NULL ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 ++ || SYMBOL_REFERENCES_LOCAL (info, h))) ++ break; ++ /* fall through */ ++ ++ /* Relocations that always need to be propagated if this is a shared ++ object. */ ++ case (int) R_PPC_ADDR32: ++ case (int) R_PPC_ADDR24: ++ case (int) R_PPC_ADDR16: ++ case (int) R_PPC_ADDR16_LO: ++ case (int) R_PPC_ADDR16_HI: ++ case (int) R_PPC_ADDR16_HA: ++ case (int) R_PPC_ADDR14: ++ case (int) R_PPC_UADDR32: ++ case (int) R_PPC_UADDR16: ++ if (info->shared && r_symndx != 0) ++ { ++ Elf_Internal_Rela outrel; ++ int skip; ++ ++#ifdef DEBUG ++ fprintf (stderr, "ppc_elf_relocate_section need to create relocation for %s\n", ++ (h && h->root.root.string) ? h->root.root.string : "<unknown>"); ++#endif ++ ++ /* When generating a shared object, these relocations ++ are copied into the output file to be resolved at run ++ time. */ ++ ++ if (sreloc == NULL) ++ { ++ const char *name; ++ ++ name = (bfd_elf_string_from_elf_section ++ (input_bfd, ++ elf_elfheader (input_bfd)->e_shstrndx, ++ elf_section_data (input_section)->rel_hdr.sh_name)); ++ if (name == NULL) ++ return false; ++ ++ BFD_ASSERT (strncmp (name, ".rela", 5) == 0 ++ && strcmp (bfd_get_section_name (input_bfd, ++ input_section), ++ name + 5) == 0); ++ ++ sreloc = bfd_get_section_by_name (dynobj, name); ++ BFD_ASSERT (sreloc != NULL); ++ } ++ ++ skip = 0; ++ ++ outrel.r_offset = ++ _bfd_elf_section_offset (output_bfd, info, input_section, ++ rel->r_offset); ++ if (outrel.r_offset == (bfd_vma) -1 ++ || outrel.r_offset == (bfd_vma) -2) ++ skip = (int) outrel.r_offset; ++ outrel.r_offset += (input_section->output_section->vma ++ + input_section->output_offset); ++ ++ if (skip) ++ memset (&outrel, 0, sizeof outrel); ++ /* h->dynindx may be -1 if this symbol was marked to ++ become local. */ ++ else if (! will_become_local) ++ { ++ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); ++ outrel.r_addend = rel->r_addend; ++ } ++ else ++ { ++ if (r_type == R_PPC_ADDR32) ++ { ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ outrel.r_addend = relocation + rel->r_addend; ++ } ++ else ++ { ++ long indx; ++ ++ if (h == NULL) ++ sec = local_sections[r_symndx]; ++ else ++ { ++ BFD_ASSERT (h->root.type == bfd_link_hash_defined ++ || (h->root.type ++ == bfd_link_hash_defweak)); ++ sec = h->root.u.def.section; ++ } ++ if (sec != NULL && bfd_is_abs_section (sec)) ++ indx = 0; ++ else if (sec == NULL || sec->owner == NULL) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ else ++ { ++ asection *osec; ++ ++ osec = sec->output_section; ++ indx = elf_section_data (osec)->dynindx; ++ BFD_ASSERT (indx > 0); ++#ifdef DEBUG ++ if (indx <= 0) ++ { ++ printf ("indx=%d section=%s flags=%08x name=%s\n", ++ indx, osec->name, osec->flags, ++ h->root.root.string); ++ } ++#endif ++ } ++ ++ outrel.r_info = ELF32_R_INFO (indx, r_type); ++ outrel.r_addend = relocation + rel->r_addend; ++ } ++ } ++ ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, ++ (((Elf32_External_Rela *) ++ sreloc->contents) ++ + sreloc->reloc_count)); ++ ++sreloc->reloc_count; ++ ++ if (skip == -1) ++ continue; ++ ++ /* This reloc will be computed at runtime. We clear the memory ++ so that it contains predictable value. */ ++ if (! skip ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ || ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE)) ++ { ++ relocation = howto->pc_relative ? outrel.r_offset : 0; ++ addend = 0; ++ break; ++ } ++ } ++ else if (r_type == R_PPC_REL24 || r_type == R_PPC_REL14) ++ { ++ if (sec->output_section != input_section->output_section) ++ { ++ (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)", ++ bfd_get_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[ (int)r_type ]->name, ++ bfd_get_section_name (abfd, sec)); ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ break; ++ } ++ else if (r_type == R_PPC_REL32) ++ { ++ if (sec->output_section != input_section->output_section) ++ copy = true; ++ else ++ break; ++ } ++ else if (ddr_ptr && sec && r_type == R_PPC_ADDR32 && ++ (sec->output_section == sdata_sec || ++ sec->output_section == sbss_sec || ++ !strcmp(bfd_get_section_name(abfd, sec), "COMMON") || ++ !strcmp(bfd_get_section_name(abfd, sec), ".data") || ++ !strcmp(bfd_get_section_name(abfd, sec), ".bss")) && ++ (input_section->output_section == sdata_sec || ++ input_section->output_section == sbss_sec || ++ !strcmp(bfd_get_section_name(abfd, input_section), "COMMON") || ++ !strcmp(bfd_get_section_name(abfd, input_section), ".data") || ++ !strcmp(bfd_get_section_name(abfd, input_section), ".bss"))) ++ { ++ ++ddr_count; ++ *ddr_ptr++ = input_section->output_offset + offset; ++ copy = true; ++ break; ++ } ++ else if (sec && !bfd_is_abs_section(sec)) ++ { ++ copy = true; ++ break; ++ } ++ ++ if (copy && ddr_ptr && sec && ++ (sec->output_section == sdata_sec || ++ sec->output_section == sbss_sec || ++ !strcmp(bfd_get_section_name(abfd, sec), "COMMON") || ++ !strcmp(bfd_get_section_name(abfd, sec), ".data") || ++ !strcmp(bfd_get_section_name(abfd, sec), ".bss")) /*&& ++ (r_type != R_PPC_ADDR32 || ++ !(input_section->output_section == sdata_sec->output_section || ++ input_section->output_section == sbss_sec->output_section || ++ !strcmp(bfd_get_section_name(abfd, input_section), "COMMON") || ++ !strcmp(bfd_get_section_name(abfd, input_section), ".data") || ++ !strcmp(bfd_get_section_name(abfd, input_section), ".bss")))*/) ++ { ++ (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)", ++ bfd_get_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[ (int)r_type ]->name, ++ bfd_get_section_name (abfd, sec)); ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ ++ /* Arithmetic adjust relocations that aren't going into a ++ shared object. */ ++ if (r_type == R_PPC_ADDR16_HA ++ /* It's just possible that this symbol is a weak symbol ++ that's not actually defined anywhere. In that case, ++ 'sec' would be NULL, and we should leave the symbol ++ alone (it will be set to zero elsewhere in the link). */ ++ && sec != NULL) ++ { ++ addend += ((relocation + addend) & 0x8000) << 1; ++ } ++ break; ++ ++ /* branch taken prediction relocations */ ++ case (int) R_PPC_ADDR14_BRTAKEN: ++ case (int) R_PPC_REL14_BRTAKEN: ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ if ((relocation - offset) & 0x8000) ++ insn &= ~BRANCH_PREDICT_BIT; ++ else ++ insn |= BRANCH_PREDICT_BIT; ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ break; ++ ++ /* branch not taken predicition relocations */ ++ case (int) R_PPC_ADDR14_BRNTAKEN: ++ case (int) R_PPC_REL14_BRNTAKEN: ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ if ((relocation - offset) & 0x8000) ++ insn |= BRANCH_PREDICT_BIT; ++ else ++ insn &= ~BRANCH_PREDICT_BIT; ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ break; ++ ++ /* GOT16 relocations */ ++ case (int) R_PPC_GOT16: ++ case (int) R_PPC_GOT16_LO: ++ case (int) R_PPC_GOT16_HI: ++ case (int) R_PPC_GOT16_HA: ++ /* Relocation is to the entry for this symbol in the global ++ offset table. */ ++ BFD_ASSERT (sgot != NULL); ++ ++ if (h != NULL) ++ { ++ bfd_vma off; ++ ++ off = h->got.offset; ++ BFD_ASSERT (off != (bfd_vma) -1); ++ ++ if (! elf_hash_table (info)->dynamic_sections_created ++ || (info->shared ++ && SYMBOL_REFERENCES_LOCAL (info, h))) ++ { ++ /* This is actually a static link, or it is a ++ -Bsymbolic link and the symbol is defined ++ locally. We must initialize this entry in the ++ global offset table. Since the offset must ++ always be a multiple of 4, we use the least ++ significant bit to record whether we have ++ initialized it already. ++ ++ When doing a dynamic link, we create a .rela.got ++ relocation entry to initialize the value. This ++ is done in the finish_dynamic_symbol routine. */ ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ bfd_put_32 (output_bfd, relocation, ++ sgot->contents + off); ++ h->got.offset |= 1; ++ } ++ } ++ ++ relocation = sgot->output_offset + off - 4; ++ } ++ else ++ { ++ bfd_vma off; ++ ++ BFD_ASSERT (local_got_offsets != NULL ++ && local_got_offsets[r_symndx] != (bfd_vma) -1); ++ ++ off = local_got_offsets[r_symndx]; ++ ++ /* The offset must always be a multiple of 4. We use ++ the least significant bit to record whether we have ++ already processed this entry. */ ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ ++ if (info->shared) ++ { ++ asection *srelgot; ++ Elf_Internal_Rela outrel; ++ ++ /* We need to generate a R_PPC_RELATIVE reloc ++ for the dynamic linker. */ ++ srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); ++ BFD_ASSERT (srelgot != NULL); ++ ++ outrel.r_offset = (sgot->output_section->vma ++ + sgot->output_offset ++ + off); ++ outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); ++ outrel.r_addend = relocation; ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, ++ (((Elf32_External_Rela *) ++ srelgot->contents) ++ + srelgot->reloc_count)); ++ ++srelgot->reloc_count; ++ relocation = 0; ++ } ++ ++ bfd_put_32 (output_bfd, relocation, sgot->contents + off); ++ local_got_offsets[r_symndx] |= 1; ++ } ++ ++ relocation = sgot->output_offset + off - 4; ++ } ++ break; ++ ++ /* Indirect .sdata relocation */ ++ case (int) R_PPC_EMB_SDAI16: ++ BFD_ASSERT (sdata != NULL); ++ relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, ++ sdata, h, relocation, rel, ++ R_PPC_RELATIVE); ++ break; ++ ++ /* Indirect .sdata2 relocation */ ++ case (int) R_PPC_EMB_SDA2I16: ++ BFD_ASSERT (sdata2 != NULL); ++ relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, ++ sdata2, h, relocation, rel, ++ R_PPC_RELATIVE); ++ break; ++ ++ /* Handle the TOC16 reloc. We want to use the offset within the .got ++ section, not the actual VMA. This is appropriate when generating ++ an embedded ELF object, for which the .got section acts like the ++ AIX .toc section. */ ++ case (int) R_PPC_TOC16: /* phony GOT16 relocations */ ++ BFD_ASSERT (sec != (asection *) 0); ++ BFD_ASSERT (bfd_is_und_section (sec) ++ || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 ++ || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0) ++ ++ addend -= sec->output_section->vma + sec->output_offset + 0x8000; ++ break; ++ ++ case (int) R_PPC_PLTREL24: ++ /* Relocation is to the entry for this symbol in the ++ procedure linkage table. */ ++ BFD_ASSERT (h != NULL); ++ ++ if (h->plt.offset == (bfd_vma) -1 ++ || splt == NULL) ++ { ++ /* We didn't make a PLT entry for this symbol. This ++ happens when statically linking PIC code, or when ++ using -Bsymbolic. */ ++ break; ++ } ++ ++ relocation = (splt->output_section->vma ++ + splt->output_offset ++ + h->plt.offset); ++ break; ++ ++ /* relocate against _SDA_BASE_ */ ++ case (int) R_PPC_SDAREL16: ++ { ++ const char *name; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") != 0 ++ && strcmp (name, ".sbss") != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ } ++ addend -= (sdata->sym_hash->root.u.def.value ++ + sdata->sym_hash->root.u.def.section->output_section->vma ++ /*+ sdata->sym_hash->root.u.def.section->output_offset*/); ++ } ++ break; ++ ++ /* relocate against _SDA_BASE_, in large data mode */ ++ case (int)R_PPC_MORPHOS_DREL: ++ case (int)R_PPC_MORPHOS_DREL_LO: ++ case (int)R_PPC_MORPHOS_DREL_HI: ++ case (int)R_PPC_MORPHOS_DREL_HA: ++ BFD_ASSERT (sec != (asection *)0); ++ if (strcmp (bfd_get_section_name (abfd, sec), ".sdata") != 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ".data") != 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ".bss") != 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ".sbss") != 0 ++ && strcmp (bfd_get_section_name (abfd, sec), "COMMON") != 0) ++ { ++ (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)", ++ bfd_get_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[ (int)r_type ]->name, ++ bfd_get_section_name (abfd, sec)); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ /*printf("DREL: addend = %x, sdata->val = %x, vma = %x, output_offset = %x\n", ++ addend, sdata->sym_hash->root.u.def.value, ++ sdata->sym_hash->root.u.def.section->output_section->vma, ++ sdata->sym_hash->root.u.def.section->output_offset);*/ ++ addend -= (sdata->sym_hash->root.u.def.value ++ + sdata->sym_hash->root.u.def.section->output_section->vma ++ /*+ sdata->sym_hash->root.u.def.section->output_offset*/); ++ if (r_type == R_PPC_MORPHOS_DREL_HA) ++ addend += ((relocation + addend) & 0x8000) << 1; ++ break; ++ ++ /* relocate against _SDA2_BASE_ */ ++ case (int) R_PPC_EMB_SDA2REL: ++ { ++ const char *name; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata2") != 0 && strcmp (name, ".sbss2") != 0) ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ addend -= (sdata2->sym_hash->root.u.def.value ++ + sdata2->sym_hash->root.u.def.section->output_section->vma ++ + sdata2->sym_hash->root.u.def.section->output_offset); ++ } ++ break; ++ ++ /* relocate against either _SDA_BASE_, _SDA2_BASE_, or 0 */ ++ case (int) R_PPC_EMB_SDA21: ++ case (int) R_PPC_EMB_RELSDA: ++ { ++ const char *name; ++ int reg; ++ ++ BFD_ASSERT (sec != (asection *) 0); ++ name = bfd_get_section_name (abfd, sec->output_section); ++ if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0) ++ { ++ reg = 13; ++ addend -= (sdata->sym_hash->root.u.def.value ++ + sdata->sym_hash->root.u.def.section->output_section->vma ++ + sdata->sym_hash->root.u.def.section->output_offset); ++ } ++ ++ else if (strcmp (name, ".sdata2") == 0 ++ || strcmp (name, ".sbss2") == 0) ++ { ++ reg = 2; ++ addend -= (sdata2->sym_hash->root.u.def.value ++ + sdata2->sym_hash->root.u.def.section->output_section->vma ++ + sdata2->sym_hash->root.u.def.section->output_offset); ++ } ++ ++ else if (strcmp (name, ".PPC.EMB.sdata0") == 0 ++ || strcmp (name, ".PPC.EMB.sbss0") == 0) ++ { ++ reg = 0; ++ } ++ ++ else ++ { ++ (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"), ++ bfd_archive_filename (input_bfd), ++ sym_name, ++ ppc_elf_howto_table[(int) r_type]->name, ++ name); ++ ++ bfd_set_error (bfd_error_bad_value); ++ ret = false; ++ continue; ++ } ++ ++ if (r_type == R_PPC_EMB_SDA21) ++ { /* fill in register field */ ++ insn = bfd_get_32 (output_bfd, contents + offset); ++ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); ++ bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset); ++ } ++ } ++ break; ++ ++ /* Relocate against the beginning of the section */ ++ case (int) R_PPC_SECTOFF: ++ case (int) R_PPC_SECTOFF_LO: ++ case (int) R_PPC_SECTOFF_HI: ++ BFD_ASSERT (sec != (asection *) 0); ++ addend -= sec->output_section->vma; ++ break; ++ ++ case (int) R_PPC_SECTOFF_HA: ++ BFD_ASSERT (sec != (asection *) 0); ++ addend -= sec->output_section->vma; ++ addend += ((relocation + addend) & 0x8000) << 1; ++ break; ++ ++ /* Negative relocations */ ++ case (int) R_PPC_EMB_NADDR32: ++ case (int) R_PPC_EMB_NADDR16: ++ case (int) R_PPC_EMB_NADDR16_LO: ++ case (int) R_PPC_EMB_NADDR16_HI: ++ addend -= 2 * relocation; ++ break; ++ ++ case (int) R_PPC_EMB_NADDR16_HA: ++ addend -= 2 * relocation; ++ addend += ((relocation + addend) & 0x8000) << 1; ++ break; ++ ++ /* NOP relocation that prevents garbage collecting linkers from omitting a ++ reference. */ ++ case (int) R_PPC_EMB_MRKREF: ++ continue; ++ ++ case (int) R_PPC_COPY: ++ case (int) R_PPC_GLOB_DAT: ++ case (int) R_PPC_JMP_SLOT: ++ case (int) R_PPC_RELATIVE: ++ case (int) R_PPC_PLT32: ++ case (int) R_PPC_PLTREL32: ++ case (int) R_PPC_PLT16_LO: ++ case (int) R_PPC_PLT16_HI: ++ case (int) R_PPC_PLT16_HA: ++ case (int) R_PPC_EMB_RELSEC16: ++ case (int) R_PPC_EMB_RELST_LO: ++ case (int) R_PPC_EMB_RELST_HI: ++ case (int) R_PPC_EMB_RELST_HA: ++ case (int) R_PPC_EMB_BIT_FLD: ++ (*_bfd_error_handler) (_("%s: Relocation %s is not yet supported for symbol %s."), ++ bfd_archive_filename (input_bfd), ++ ppc_elf_howto_table[(int) r_type]->name, ++ sym_name); ++ ++ bfd_set_error (bfd_error_invalid_operation); ++ ret = false; ++ continue; ++ ++ case (int) R_PPC_GNU_VTINHERIT: ++ case (int) R_PPC_GNU_VTENTRY: ++ /* These are no-ops in the end. */ ++ continue; ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, offset = %ld, addend = %ld\n", ++ howto->name, ++ (int) r_type, ++ sym_name, ++ r_symndx, ++ (long) offset, ++ (long) addend); ++#endif ++ if (copy) ++ { ++ Elf_Internal_Rela outrel; ++ ++ if (sec == NULL) /* Don't know if it is possible... */ ++ abort(); ++ ++ /*printf("copying reloc %d, addend=%x, rel=%x, indx=%d, offset=%x, sec_vma=%x\n", ++ r_type,addend,relocation,sec->output_section->target_index, ++ sec->output_offset,sec->output_section->vma);*/ ++ ++ outrel.r_info = ELF32_R_INFO(sec->output_section->target_index, r_type); ++ outrel.r_addend = relocation + addend - sec->output_section->vma; ++ outrel.r_offset = input_section->output_offset + offset; ++ ++ bfd_elf32_swap_reloca_out (output_bfd, &outrel, ++ (((Elf32_External_Rela *) ++ elf_section_data(input_section->output_section)-> ++ rel_hdr.contents) ++ + input_section->output_section->reloc_count)); ++ ++input_section->output_section->reloc_count; ++ } ++ else ++ { ++ /*printf("applying reloc %d, sym=%s addend=%x, rel=%x, indx=%d, offset=%x, sec_vma=%x\n", ++ r_type,sym_name,addend,relocation,sec->output_section->target_index, ++ sec->output_offset,sec->output_section->vma);*/ ++ ++ r = _bfd_final_link_relocate (howto, ++ input_bfd, ++ input_section, ++ contents, ++ offset, ++ relocation, ++ addend); ++ ++ if (r == bfd_reloc_ok) ++ ; ++ else if (r == bfd_reloc_overflow) ++ { ++ const char *name; ++ ++ if (h != NULL) ++ { ++ if (h->root.type == bfd_link_hash_undefweak ++ && howto->pc_relative) ++ { ++ /* Assume this is a call protected by other code that ++ detect the symbol is undefined. If this is the case, ++ we can safely ignore the overflow. If not, the ++ program is hosed anyway, and a little warning isn't ++ going to help. */ ++ ++ continue; ++ } ++ ++ name = h->root.root.string; ++ } ++ else ++ { ++ name = bfd_elf_string_from_elf_section (input_bfd, ++ symtab_hdr->sh_link, ++ sym->st_name); ++ if (name == NULL) ++ continue; ++ if (*name == '\0') ++ name = bfd_section_name (input_bfd, sec); ++ } ++ ++ if (! (*info->callbacks->reloc_overflow) (info, ++ name, ++ howto->name, ++ (bfd_vma) 0, ++ input_bfd, ++ input_section, ++ offset)) ++ return false; ++ } ++ else ++ ret = false; ++ } ++ } ++ ++#ifdef DEBUG ++ fprintf (stderr, "\n"); ++#endif ++ ++ return ret; ++} ++ ++static enum elf_reloc_type_class ++ppc_elf_reloc_type_class (rela) ++ const Elf_Internal_Rela *rela; ++{ ++ switch ((int) ELF32_R_TYPE (rela->r_info)) ++ { ++ case R_PPC_RELATIVE: ++ return reloc_class_relative; ++ case R_PPC_REL24: ++ case R_PPC_ADDR24: ++ case R_PPC_JMP_SLOT: ++ return reloc_class_plt; ++ case R_PPC_COPY: ++ return reloc_class_copy; ++ default: ++ return reloc_class_normal; ++ } ++} ++ ++/* Support for core dump NOTE sections */ ++static boolean ++ppc_elf_grok_prstatus (abfd, note) ++ bfd *abfd; ++ Elf_Internal_Note *note; ++{ ++ int offset; ++ unsigned int raw_size; ++ ++ switch (note->descsz) ++ { ++ default: ++ return false; ++ ++ case 268: /* Linux/PPC */ ++ /* pr_cursig */ ++ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); ++ ++ /* pr_pid */ ++ elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); ++ ++ /* pr_reg */ ++ offset = 72; ++ raw_size = 192; ++ ++ break; ++ } ++ ++ /* Make a ".reg/999" section. */ ++ return _bfd_elfcore_make_pseudosection (abfd, ".reg", ++ raw_size, note->descpos + offset); ++} ++ ++static boolean ++ppc_elf_grok_psinfo (abfd, note) ++ bfd *abfd; ++ Elf_Internal_Note *note; ++{ ++ switch (note->descsz) ++ { ++ default: ++ return false; ++ ++ case 128: /* Linux/PPC elf_prpsinfo */ ++ elf_tdata (abfd)->core_program ++ = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); ++ elf_tdata (abfd)->core_command ++ = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); ++ } ++ ++ /* Note that for some reason, a spurious space is tacked ++ onto the end of the args in some (at least one anyway) ++ implementations, so strip it off if it exists. */ ++ ++ { ++ char *command = elf_tdata (abfd)->core_command; ++ int n = strlen (command); ++ ++ if (0 < n && command[n - 1] == ' ') ++ command[n - 1] = '\0'; ++ } ++ ++ return true; ++} ++ ++/* Special MorphOS final link routine. */ ++/* This is almost the same as the elf one, except for the hanling of relocations */ ++ ++/* A structure we use to avoid passing large numbers of arguments. */ ++ ++struct elf_final_link_info ++{ ++ /* General link information. */ ++ struct bfd_link_info *info; ++ /* Output BFD. */ ++ bfd *output_bfd; ++ /* Symbol string table. */ ++ struct bfd_strtab_hash *symstrtab; ++ /* .dynsym section. */ ++ asection *dynsym_sec; ++ /* .hash section. */ ++ asection *hash_sec; ++ /* symbol version section (.gnu.version). */ ++ asection *symver_sec; ++ /* first SHF_TLS section (if any). */ ++ asection *first_tls_sec; ++ /* Buffer large enough to hold contents of any section. */ ++ bfd_byte *contents; ++ /* Buffer large enough to hold external relocs of any section. */ ++ PTR external_relocs; ++ /* Buffer large enough to hold internal relocs of any section. */ ++ Elf_Internal_Rela *internal_relocs; ++ /* Buffer large enough to hold external local symbols of any input ++ BFD. */ ++ Elf_External_Sym *external_syms; ++ /* And a buffer for symbol section indices. */ ++ Elf_External_Sym_Shndx *locsym_shndx; ++ /* Buffer large enough to hold internal local symbols of any input ++ BFD. */ ++ Elf_Internal_Sym *internal_syms; ++ /* Array large enough to hold a symbol index for each local symbol ++ of any input BFD. */ ++ long *indices; ++ /* Array large enough to hold a section pointer for each local ++ symbol of any input BFD. */ ++ asection **sections; ++ /* Buffer to hold swapped out symbols. */ ++ Elf_External_Sym *symbuf; ++ /* And one for symbol section indices. */ ++ Elf_External_Sym_Shndx *symshndxbuf; ++ /* Number of swapped out symbols in buffer. */ ++ size_t symbuf_count; ++ /* Number of symbols which fit in symbuf. */ ++ size_t symbuf_size; ++}; ++ ++static boolean elf_link_output_sym ++ PARAMS ((struct elf_final_link_info *, const char *, ++ Elf_Internal_Sym *, asection *)); ++static boolean elf_link_flush_output_syms ++ PARAMS ((struct elf_final_link_info *)); ++static boolean elf_link_output_extsym ++ PARAMS ((struct elf_link_hash_entry *, PTR)); ++static boolean elf_link_sec_merge_syms ++ PARAMS ((struct elf_link_hash_entry *, PTR)); ++static boolean elf_link_check_versioned_symbol ++ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); ++static boolean elf_link_input_bfd ++ PARAMS ((struct elf_final_link_info *, bfd *)); ++static boolean elf_reloc_link_order ++ PARAMS ((bfd *, struct bfd_link_info *, asection *, ++ struct bfd_link_order *)); ++ ++static boolean elf_section_ignore_discarded_relocs ++ PARAMS ((asection *)); ++ ++/* This struct is used to pass information to elf_link_output_extsym. */ ++ ++struct elf_outext_info ++{ ++ boolean failed; ++ boolean localsyms; ++ struct elf_final_link_info *finfo; ++}; ++ ++/* Compute the size of, and allocate space for, REL_HDR which is the ++ section header for a section containing relocations for O. */ ++ ++static boolean ++elf_link_size_reloc_section (abfd, rel_hdr, o) ++ bfd *abfd; ++ Elf_Internal_Shdr *rel_hdr; ++ asection *o; ++{ ++ bfd_size_type reloc_count; ++ bfd_size_type num_rel_hashes; ++ ++ /* Figure out how many relocations there will be. */ ++ if (rel_hdr == &elf_section_data (o)->rel_hdr) ++ reloc_count = elf_section_data (o)->rel_count; ++ else ++ reloc_count = elf_section_data (o)->rel_count2; ++ ++ num_rel_hashes = o->reloc_count; ++ if (num_rel_hashes < reloc_count) ++ num_rel_hashes = reloc_count; ++ ++ /* That allows us to calculate the size of the section. */ ++ rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count; ++ ++ /* The contents field must last into write_object_contents, so we ++ allocate it with bfd_alloc rather than malloc. Also since we ++ cannot be sure that the contents will actually be filled in, ++ we zero the allocated space. */ ++ rel_hdr->contents = (PTR) bfd_zalloc (abfd, rel_hdr->sh_size); ++ if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0) ++ return false; ++ ++ /* We only allocate one set of hash entries, so we only do it the ++ first time we are called. */ ++ if (elf_section_data (o)->rel_hashes == NULL ++ && num_rel_hashes) ++ { ++ struct elf_link_hash_entry **p; ++ ++ p = ((struct elf_link_hash_entry **) ++ bfd_zmalloc (num_rel_hashes ++ * sizeof (struct elf_link_hash_entry *))); ++ if (p == NULL) ++ return false; ++ ++ elf_section_data (o)->rel_hashes = p; ++ } ++ ++ return true; ++} ++ ++/* When performing a relocateable link, the input relocations are ++ preserved. But, if they reference global symbols, the indices ++ referenced must be updated. Update all the relocations in ++ REL_HDR (there are COUNT of them), using the data in REL_HASH. */ ++ ++static void ++elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash) ++ bfd *abfd; ++ Elf_Internal_Shdr *rel_hdr; ++ unsigned int count; ++ struct elf_link_hash_entry **rel_hash; ++{ ++ unsigned int i; ++ struct elf_backend_data *bed = get_elf_backend_data (abfd); ++ Elf_Internal_Rel *irel; ++ Elf_Internal_Rela *irela; ++ bfd_size_type amt = sizeof (Elf_Internal_Rel) * bed->s->int_rels_per_ext_rel; ++ ++ irel = (Elf_Internal_Rel *) bfd_zmalloc (amt); ++ if (irel == NULL) ++ { ++ (*_bfd_error_handler) (_("Error: out of memory")); ++ abort (); ++ } ++ ++ amt = sizeof (Elf_Internal_Rela) * bed->s->int_rels_per_ext_rel; ++ irela = (Elf_Internal_Rela *) bfd_zmalloc (amt); ++ if (irela == NULL) ++ { ++ (*_bfd_error_handler) (_("Error: out of memory")); ++ abort (); ++ } ++ ++ for (i = 0; i < count; i++, rel_hash++) ++ { ++ if (*rel_hash == NULL) ++ continue; ++ ++ BFD_ASSERT ((*rel_hash)->indx >= 0); ++ ++ if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) ++ { ++ Elf_External_Rel *erel; ++ unsigned int j; ++ ++ erel = (Elf_External_Rel *) rel_hdr->contents + i; ++ if (bed->s->swap_reloc_in) ++ (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, irel); ++ else ++ elf_swap_reloc_in (abfd, erel, irel); ++ ++ for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) ++ irel[j].r_info = ELF_R_INFO ((*rel_hash)->indx, ++ ELF_R_TYPE (irel[j].r_info)); ++ ++ if (bed->s->swap_reloc_out) ++ (*bed->s->swap_reloc_out) (abfd, irel, (bfd_byte *) erel); ++ else ++ elf_swap_reloc_out (abfd, irel, erel); ++ } ++ else ++ { ++ Elf_External_Rela *erela; ++ unsigned int j; ++ ++ BFD_ASSERT (rel_hdr->sh_entsize ++ == sizeof (Elf_External_Rela)); ++ ++ erela = (Elf_External_Rela *) rel_hdr->contents + i; ++ if (bed->s->swap_reloca_in) ++ (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, irela); ++ else ++ elf_swap_reloca_in (abfd, erela, irela); ++ ++ for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) ++ irela[j].r_info = ELF_R_INFO ((*rel_hash)->indx, ++ ELF_R_TYPE (irela[j].r_info)); ++ ++ if (bed->s->swap_reloca_out) ++ (*bed->s->swap_reloca_out) (abfd, irela, (bfd_byte *) erela); ++ else ++ elf_swap_reloca_out (abfd, irela, erela); ++ } ++ } ++ ++ free (irel); ++ free (irela); ++} ++ ++struct elf_link_sort_rela ++{ ++ bfd_vma offset; ++ enum elf_reloc_type_class type; ++ union ++ { ++ Elf_Internal_Rel rel; ++ Elf_Internal_Rela rela; ++ } u; ++}; ++ ++static int ++elf_link_sort_cmp1 (A, B) ++ const PTR A; ++ const PTR B; ++{ ++ struct elf_link_sort_rela *a = (struct elf_link_sort_rela *) A; ++ struct elf_link_sort_rela *b = (struct elf_link_sort_rela *) B; ++ int relativea, relativeb; ++ ++ relativea = a->type == reloc_class_relative; ++ relativeb = b->type == reloc_class_relative; ++ ++ if (relativea < relativeb) ++ return 1; ++ if (relativea > relativeb) ++ return -1; ++ if (ELF_R_SYM (a->u.rel.r_info) < ELF_R_SYM (b->u.rel.r_info)) ++ return -1; ++ if (ELF_R_SYM (a->u.rel.r_info) > ELF_R_SYM (b->u.rel.r_info)) ++ return 1; ++ if (a->u.rel.r_offset < b->u.rel.r_offset) ++ return -1; ++ if (a->u.rel.r_offset > b->u.rel.r_offset) ++ return 1; ++ return 0; ++} ++ ++static int ++elf_link_sort_cmp2 (A, B) ++ const PTR A; ++ const PTR B; ++{ ++ struct elf_link_sort_rela *a = (struct elf_link_sort_rela *) A; ++ struct elf_link_sort_rela *b = (struct elf_link_sort_rela *) B; ++ int copya, copyb; ++ ++ if (a->offset < b->offset) ++ return -1; ++ if (a->offset > b->offset) ++ return 1; ++ copya = (a->type == reloc_class_copy) * 2 + (a->type == reloc_class_plt); ++ copyb = (b->type == reloc_class_copy) * 2 + (b->type == reloc_class_plt); ++ if (copya < copyb) ++ return -1; ++ if (copya > copyb) ++ return 1; ++ if (a->u.rel.r_offset < b->u.rel.r_offset) ++ return -1; ++ if (a->u.rel.r_offset > b->u.rel.r_offset) ++ return 1; ++ return 0; ++} ++ ++static size_t ++elf_link_sort_relocs (abfd, info, psec) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ asection **psec; ++{ ++ bfd *dynobj = elf_hash_table (info)->dynobj; ++ asection *reldyn, *o; ++ boolean rel = false; ++ bfd_size_type count, size; ++ size_t i, j, ret; ++ struct elf_link_sort_rela *rela; ++ struct elf_backend_data *bed = get_elf_backend_data (abfd); ++ ++ reldyn = bfd_get_section_by_name (abfd, ".rela.dyn"); ++ if (reldyn == NULL || reldyn->_raw_size == 0) ++ { ++ reldyn = bfd_get_section_by_name (abfd, ".rel.dyn"); ++ if (reldyn == NULL || reldyn->_raw_size == 0) ++ return 0; ++ rel = true; ++ count = reldyn->_raw_size / sizeof (Elf_External_Rel); ++ } ++ else ++ count = reldyn->_raw_size / sizeof (Elf_External_Rela); ++ ++ size = 0; ++ for (o = dynobj->sections; o != NULL; o = o->next) ++ if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)) ++ == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED) ++ && o->output_section == reldyn) ++ size += o->_raw_size; ++ ++ if (size != reldyn->_raw_size) ++ return 0; ++ ++ rela = (struct elf_link_sort_rela *) bfd_zmalloc (sizeof (*rela) * count); ++ if (rela == NULL) ++ { ++ (*info->callbacks->warning) ++ (info, _("Not enough memory to sort relocations"), 0, abfd, 0, ++ (bfd_vma) 0); ++ return 0; ++ } ++ ++ for (o = dynobj->sections; o != NULL; o = o->next) ++ if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)) ++ == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED) ++ && o->output_section == reldyn) ++ { ++ if (rel) ++ { ++ Elf_External_Rel *erel, *erelend; ++ struct elf_link_sort_rela *s; ++ ++ erel = (Elf_External_Rel *) o->contents; ++ erelend = (Elf_External_Rel *) (o->contents + o->_raw_size); ++ s = rela + o->output_offset / sizeof (Elf_External_Rel); ++ for (; erel < erelend; erel++, s++) ++ { ++ if (bed->s->swap_reloc_in) ++ (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &s->u.rel); ++ else ++ elf_swap_reloc_in (abfd, erel, &s->u.rel); ++ ++ s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela); ++ } ++ } ++ else ++ { ++ Elf_External_Rela *erela, *erelaend; ++ struct elf_link_sort_rela *s; ++ ++ erela = (Elf_External_Rela *) o->contents; ++ erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size); ++ s = rela + o->output_offset / sizeof (Elf_External_Rela); ++ for (; erela < erelaend; erela++, s++) ++ { ++ if (bed->s->swap_reloca_in) ++ (*bed->s->swap_reloca_in) (dynobj, (bfd_byte *) erela, ++ &s->u.rela); ++ else ++ elf_swap_reloca_in (dynobj, erela, &s->u.rela); ++ ++ s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela); ++ } ++ } ++ } ++ ++ qsort (rela, (size_t) count, sizeof (*rela), elf_link_sort_cmp1); ++ for (ret = 0; ret < count && rela[ret].type == reloc_class_relative; ret++) ++ ; ++ for (i = ret, j = ret; i < count; i++) ++ { ++ if (ELF_R_SYM (rela[i].u.rel.r_info) != ELF_R_SYM (rela[j].u.rel.r_info)) ++ j = i; ++ rela[i].offset = rela[j].u.rel.r_offset; ++ } ++ qsort (rela + ret, (size_t) count - ret, sizeof (*rela), elf_link_sort_cmp2); ++ ++ for (o = dynobj->sections; o != NULL; o = o->next) ++ if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)) ++ == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED) ++ && o->output_section == reldyn) ++ { ++ if (rel) ++ { ++ Elf_External_Rel *erel, *erelend; ++ struct elf_link_sort_rela *s; ++ ++ erel = (Elf_External_Rel *) o->contents; ++ erelend = (Elf_External_Rel *) (o->contents + o->_raw_size); ++ s = rela + o->output_offset / sizeof (Elf_External_Rel); ++ for (; erel < erelend; erel++, s++) ++ { ++ if (bed->s->swap_reloc_out) ++ (*bed->s->swap_reloc_out) (abfd, &s->u.rel, ++ (bfd_byte *) erel); ++ else ++ elf_swap_reloc_out (abfd, &s->u.rel, erel); ++ } ++ } ++ else ++ { ++ Elf_External_Rela *erela, *erelaend; ++ struct elf_link_sort_rela *s; ++ ++ erela = (Elf_External_Rela *) o->contents; ++ erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size); ++ s = rela + o->output_offset / sizeof (Elf_External_Rela); ++ for (; erela < erelaend; erela++, s++) ++ { ++ if (bed->s->swap_reloca_out) ++ (*bed->s->swap_reloca_out) (dynobj, &s->u.rela, ++ (bfd_byte *) erela); ++ else ++ elf_swap_reloca_out (dynobj, &s->u.rela, erela); ++ } ++ } ++ } ++ ++ free (rela); ++ *psec = reldyn; ++ return ret; ++} ++ ++/* Do the final step of an ELF link. */ ++ ++boolean ++ppc_elf_final_link (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ boolean dynamic; ++ boolean emit_relocs; ++ bfd *dynobj; ++ struct elf_final_link_info finfo; ++ register asection *o; ++ register struct bfd_link_order *p; ++ register bfd *sub; ++ bfd_size_type max_contents_size; ++ bfd_size_type max_external_reloc_size; ++ bfd_size_type max_internal_reloc_count; ++ bfd_size_type max_sym_count; ++ bfd_size_type max_sym_shndx_count; ++ bfd_size_type max_datadata_reloc_count; ++ file_ptr off; ++ Elf_Internal_Sym elfsym; ++ unsigned int i; ++ Elf_Internal_Shdr *symtab_hdr; ++ Elf_Internal_Shdr *symstrtab_hdr; ++ struct elf_backend_data *bed = get_elf_backend_data (abfd); ++ struct elf_outext_info eoinfo; ++ boolean merged; ++ size_t relativecount = 0; ++ asection *reldyn = 0; ++ bfd_size_type amt; ++ asection *ddr_sec; ++ asection *sdata_sec = NULL; ++ asection *sbss_sec = NULL; ++ ++ if (! is_elf_hash_table (info)) ++ return false; ++ ++ if (info->shared) ++ abfd->flags |= DYNAMIC; ++ ++ bfd_set_start_address(abfd, 0); ++ ++ dynamic = elf_hash_table (info)->dynamic_sections_created; ++ dynobj = elf_hash_table (info)->dynobj; ++ ++ emit_relocs = (info->relocateable ++ || info->emitrelocations ++ || bed->elf_backend_emit_relocs); ++ ++ finfo.info = info; ++ finfo.output_bfd = abfd; ++ finfo.symstrtab = elf_stringtab_init (); ++ if (finfo.symstrtab == NULL) ++ return false; ++ ++ if (! dynamic) ++ { ++ finfo.dynsym_sec = NULL; ++ finfo.hash_sec = NULL; ++ finfo.symver_sec = NULL; ++ } ++ else ++ { ++ finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym"); ++ finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash"); ++ BFD_ASSERT (finfo.dynsym_sec != NULL && finfo.hash_sec != NULL); ++ finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version"); ++ /* Note that it is OK if symver_sec is NULL. */ ++ } ++ ++ finfo.contents = NULL; ++ finfo.external_relocs = NULL; ++ finfo.internal_relocs = NULL; ++ finfo.external_syms = NULL; ++ finfo.locsym_shndx = NULL; ++ finfo.internal_syms = NULL; ++ finfo.indices = NULL; ++ finfo.sections = NULL; ++ finfo.symbuf = NULL; ++ finfo.symshndxbuf = NULL; ++ finfo.symbuf_count = 0; ++ finfo.first_tls_sec = NULL; ++ for (o = abfd->sections; o != (asection *) NULL; o = o->next) ++ if ((o->flags & SEC_THREAD_LOCAL) != 0 ++ && (o->flags & SEC_LOAD) != 0) ++ { ++ finfo.first_tls_sec = o; ++ break; ++ } ++ ++ ddr_sec = bfd_get_section_by_name(abfd, "ddrelocs"); ++ ++ /* Count up the number of relocations we will output for each output ++ section, so that we know the sizes of the reloc sections. We ++ also figure out some maximum sizes. */ ++ max_contents_size = 0; ++ max_external_reloc_size = 0; ++ max_internal_reloc_count = 0; ++ max_sym_count = 0; ++ max_sym_shndx_count = 0; ++ max_datadata_reloc_count = 0; ++ merged = false; ++ for (o = abfd->sections; o != (asection *) NULL; o = o->next) ++ { ++ o->reloc_count = 0; ++ ++ for (p = o->link_order_head; p != NULL; p = p->next) ++ { ++ if (p->type == bfd_section_reloc_link_order ++ || p->type == bfd_symbol_reloc_link_order) ++ ++o->reloc_count; ++ else if (p->type == bfd_indirect_link_order) ++ { ++ asection *sec; ++ ++ sec = p->u.indirect.section; ++ ++ /* Mark all sections which are to be included in the ++ link. This will normally be every section. We need ++ to do this so that we can identify any sections which ++ the linker has decided to not include. */ ++ sec->linker_mark = true; ++ ++ if (sec->flags & SEC_MERGE) ++ merged = true; ++ ++ /* Maximum number of relocations */ ++ if (1 || info->relocateable || info->emitrelocations) ++ o->reloc_count += sec->reloc_count; ++ else if (bed->elf_backend_count_relocs) ++ { ++ Elf_Internal_Rela * relocs; ++ ++ relocs = (NAME(_bfd_elf,link_read_relocs) ++ (abfd, sec, (PTR) NULL, ++ (Elf_Internal_Rela *) NULL, info->keep_memory)); ++ ++ o->reloc_count ++ += (*bed->elf_backend_count_relocs) (sec, relocs); ++ ++ if (elf_section_data (o)->relocs != relocs) ++ free (relocs); ++ } ++ ++ if (sec->_raw_size > max_contents_size) ++ max_contents_size = sec->_raw_size; ++ if (sec->_cooked_size > max_contents_size) ++ max_contents_size = sec->_cooked_size; ++ ++ /* We are interested in just local symbols, not all ++ symbols. */ ++ if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour ++ && (sec->owner->flags & DYNAMIC) == 0) ++ { ++ size_t sym_count; ++ ++ if (elf_bad_symtab (sec->owner)) ++ sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size ++ / sizeof (Elf_External_Sym)); ++ else ++ sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info; ++ ++ if (sym_count > max_sym_count) ++ max_sym_count = sym_count; ++ ++ if (sym_count > max_sym_shndx_count ++ && elf_symtab_shndx (sec->owner) != 0) ++ max_sym_shndx_count = sym_count; ++ ++ if ((sec->flags & SEC_RELOC) != 0) ++ { ++ size_t ext_size; ++ ++ ext_size = elf_section_data (sec)->rel_hdr.sh_size; ++ if (ext_size > max_external_reloc_size) ++ max_external_reloc_size = ext_size; ++ if (sec->reloc_count > max_internal_reloc_count) ++ max_internal_reloc_count = sec->reloc_count; ++ } ++ } ++ } ++ } ++ ++ if (!strcmp(bfd_section_name(abfd, o), ".sdata")) ++ sdata_sec = o; ++ else if(!strcmp(bfd_section_name(abfd, o), ".sbss")) ++ sbss_sec = o; ++ else ++ bfd_set_section_vma(abfd, o, 0); ++ ++ if (o->reloc_count > 0) ++ { ++ o->flags |= SEC_RELOC; ++ if (o == sdata_sec || o == sbss_sec) ++ max_datadata_reloc_count += o->reloc_count; ++ } ++ else ++ { ++ /* Explicitly clear the SEC_RELOC flag. The linker tends to ++ set it (this is probably a bug) and if it is set ++ assign_section_numbers will create a reloc section. */ ++ o->flags &=~ SEC_RELOC; ++ } ++ ++ /* If the SEC_ALLOC flag is not set, force the section VMA to ++ zero. This is done in elf_fake_sections as well, but forcing ++ the VMA to 0 here will ensure that relocs against these ++ sections are handled correctly. */ ++ if ((o->flags & SEC_ALLOC) == 0 ++ && ! o->user_set_vma) ++ o->vma = 0; ++ } ++ ++ if (sdata_sec) ++ { ++ if (sbss_sec) ++ bfd_set_section_vma(abfd, sbss_sec, sbss_sec->vma - sdata_sec->vma); ++ bfd_set_section_vma(abfd, sdata_sec, 0); ++ } ++ ++ if (! info->relocateable && merged) ++ elf_link_hash_traverse (elf_hash_table (info), ++ elf_link_sec_merge_syms, (PTR) abfd); ++ ++ /* Figure out the file positions for everything but the symbol table ++ and the relocs. We set symcount to force assign_section_numbers ++ to create a symbol table. */ ++ bfd_get_symcount (abfd) = 1; ++ BFD_ASSERT (! abfd->output_has_begun); ++ if (! _bfd_elf_compute_section_file_positions (abfd, info)) ++ goto error_return; ++ ++ /* Figure out how many relocations we will have in each section. ++ Just using RELOC_COUNT isn't good enough since that doesn't ++ maintain a separate value for REL vs. RELA relocations. */ ++ if (emit_relocs) ++ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) ++ for (o = sub->sections; o != NULL; o = o->next) ++ { ++ asection *output_section; ++ ++ if (! o->linker_mark) ++ { ++ /* This section was omitted from the link. */ ++ continue; ++ } ++ ++ output_section = o->output_section; ++ ++ if (output_section != NULL ++ && (o->flags & SEC_RELOC) != 0) ++ { ++ struct bfd_elf_section_data *esdi ++ = elf_section_data (o); ++ struct bfd_elf_section_data *esdo ++ = elf_section_data (output_section); ++ unsigned int *rel_count; ++ unsigned int *rel_count2; ++ bfd_size_type entsize; ++ bfd_size_type entsize2; ++ ++ /* We must be careful to add the relocations from the ++ input section to the right output count. */ ++ entsize = esdi->rel_hdr.sh_entsize; ++ entsize2 = esdi->rel_hdr2 ? esdi->rel_hdr2->sh_entsize : 0; ++ BFD_ASSERT ((entsize == sizeof (Elf_External_Rel) ++ || entsize == sizeof (Elf_External_Rela)) ++ && entsize2 != entsize ++ && (entsize2 == 0 ++ || entsize2 == sizeof (Elf_External_Rel) ++ || entsize2 == sizeof (Elf_External_Rela))); ++ if (entsize == esdo->rel_hdr.sh_entsize) ++ { ++ rel_count = &esdo->rel_count; ++ rel_count2 = &esdo->rel_count2; ++ } ++ else ++ { ++ rel_count = &esdo->rel_count2; ++ rel_count2 = &esdo->rel_count; ++ } ++ ++ *rel_count += NUM_SHDR_ENTRIES (& esdi->rel_hdr); ++ if (esdi->rel_hdr2) ++ *rel_count2 += NUM_SHDR_ENTRIES (esdi->rel_hdr2); ++ output_section->flags |= SEC_RELOC; ++ } ++ } ++ ++ /* That created the reloc sections. Set their sizes, and assign ++ them file positions, and allocate some buffers. */ ++ for (o = abfd->sections; o != NULL; o = o->next) ++ { ++ if ((o->flags & SEC_RELOC) != 0) ++ { ++ if (!elf_link_size_reloc_section (abfd, ++ &elf_section_data (o)->rel_hdr, ++ o)) ++ goto error_return; ++ ++ if (elf_section_data (o)->rel_hdr2 ++ && !elf_link_size_reloc_section (abfd, ++ elf_section_data (o)->rel_hdr2, ++ o)) ++ goto error_return; ++ } ++ ++ /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them ++ to count upwards while actually outputting the relocations. */ ++ elf_section_data (o)->rel_count = 0; ++ elf_section_data (o)->rel_count2 = 0; ++ } ++ ++ /* We have now assigned file positions for all the sections except ++ relocations, .symtab, and .strtab. We start the .symtab section ++ at the current file position, and write directly to it. We build ++ the .strtab section in memory. */ ++ bfd_get_symcount (abfd) = 0; ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ /* sh_name is set in prep_headers. */ ++ symtab_hdr->sh_type = SHT_SYMTAB; ++ symtab_hdr->sh_flags = 0; ++ symtab_hdr->sh_addr = 0; ++ symtab_hdr->sh_size = 0; ++ symtab_hdr->sh_entsize = sizeof (Elf_External_Sym); ++ /* sh_link is set in assign_section_numbers. */ ++ /* sh_info is set below. */ ++ /* sh_offset is set just below. */ ++ symtab_hdr->sh_addralign = bed->s->file_align; ++ ++ off = elf_tdata (abfd)->next_file_pos; ++ off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, true); ++ ++ /* Note that at this point elf_tdata (abfd)->next_file_pos is ++ incorrect. We do not yet know the size of the .symtab section. ++ We correct next_file_pos below, after we do know the size. */ ++ ++ /* Allocate a buffer to hold swapped out symbols. This is to avoid ++ continuously seeking to the right position in the file. */ ++ if (! info->keep_memory || max_sym_count < 20) ++ finfo.symbuf_size = 20; ++ else ++ finfo.symbuf_size = max_sym_count; ++ amt = finfo.symbuf_size; ++ amt *= sizeof (Elf_External_Sym); ++ finfo.symbuf = (Elf_External_Sym *) bfd_malloc (amt); ++ if (finfo.symbuf == NULL) ++ goto error_return; ++ if (elf_numsections (abfd) > SHN_LORESERVE) ++ { ++ amt = finfo.symbuf_size; ++ amt *= sizeof (Elf_External_Sym_Shndx); ++ finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_malloc (amt); ++ if (finfo.symshndxbuf == NULL) ++ goto error_return; ++ } ++ ++ /* Start writing out the symbol table. The first symbol is always a ++ dummy symbol. */ ++ elfsym.st_value = 0; ++ elfsym.st_size = 0; ++ elfsym.st_info = 0; ++ elfsym.st_other = 0; ++ elfsym.st_shndx = SHN_UNDEF; ++ if (! elf_link_output_sym (&finfo, (const char *) NULL, ++ &elfsym, bfd_und_section_ptr)) ++ goto error_return; ++ ++#if 0 ++ /* Some standard ELF linkers do this, but we don't because it causes ++ bootstrap comparison failures. */ ++ /* Output a file symbol for the output file as the second symbol. ++ We output this even if we are discarding local symbols, although ++ I'm not sure if this is correct. */ ++ elfsym.st_value = 0; ++ elfsym.st_size = 0; ++ elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); ++ elfsym.st_other = 0; ++ elfsym.st_shndx = SHN_ABS; ++ if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd), ++ &elfsym, bfd_abs_section_ptr)) ++ goto error_return; ++#endif ++ ++ /* Output a symbol for each section. We output these even if we are ++ discarding local symbols, since they are used for relocs. These ++ symbols have no names. We store the index of each one in the ++ index field of the section, so that we can find it again when ++ outputting relocs. */ ++ elfsym.st_size = 0; ++ elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); ++ elfsym.st_other = 0; ++ for (i = 1; i < elf_numsections (abfd); i++) ++ { ++ o = section_from_elf_index (abfd, i); ++ if (o != NULL) ++ o->target_index = bfd_get_symcount (abfd); ++ elfsym.st_shndx = i; ++ elfsym.st_value = 0; ++ if (! elf_link_output_sym (&finfo, (const char *) NULL, ++ &elfsym, o)) ++ goto error_return; ++ if (i == SHN_LORESERVE) ++ i += SHN_HIRESERVE + 1 - SHN_LORESERVE; ++ } ++ ++ /* Allocate some memory to hold information read in from the input ++ files. */ ++ if (max_contents_size != 0) ++ { ++ finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); ++ if (finfo.contents == NULL) ++ goto error_return; ++ } ++ ++ if (max_external_reloc_size != 0) ++ { ++ finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size); ++ if (finfo.external_relocs == NULL) ++ goto error_return; ++ } ++ ++ if (max_internal_reloc_count != 0) ++ { ++ amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel; ++ amt *= sizeof (Elf_Internal_Rela); ++ finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt); ++ if (finfo.internal_relocs == NULL) ++ goto error_return; ++ } ++ ++ if (max_sym_count != 0) ++ { ++ amt = max_sym_count * sizeof (Elf_External_Sym); ++ finfo.external_syms = (Elf_External_Sym *) bfd_malloc (amt); ++ if (finfo.external_syms == NULL) ++ goto error_return; ++ ++ amt = max_sym_count * sizeof (Elf_Internal_Sym); ++ finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt); ++ if (finfo.internal_syms == NULL) ++ goto error_return; ++ ++ amt = max_sym_count * sizeof (long); ++ finfo.indices = (long *) bfd_malloc (amt); ++ if (finfo.indices == NULL) ++ goto error_return; ++ ++ amt = max_sym_count * sizeof (asection *); ++ finfo.sections = (asection **) bfd_malloc (amt); ++ if (finfo.sections == NULL) ++ goto error_return; ++ } ++ ++ if (max_sym_shndx_count != 0) ++ { ++ amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx); ++ finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt); ++ if (finfo.locsym_shndx == NULL) ++ goto error_return; ++ } ++ ++ if (finfo.first_tls_sec) ++ { ++ unsigned int align = 0; ++ bfd_vma base = finfo.first_tls_sec->vma, end = 0; ++ asection *sec; ++ ++ for (sec = finfo.first_tls_sec; ++ sec && (sec->flags & SEC_THREAD_LOCAL); ++ sec = sec->next) ++ { ++ bfd_vma size = sec->_raw_size; ++ ++ if (bfd_get_section_alignment (abfd, sec) > align) ++ align = bfd_get_section_alignment (abfd, sec); ++ if (sec->_raw_size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0) ++ { ++ struct bfd_link_order *o; ++ ++ size = 0; ++ for (o = sec->link_order_head; o != NULL; o = o->next) ++ if (size < o->offset + o->size) ++ size = o->offset + o->size; ++ } ++ end = sec->vma + size; ++ } ++ elf_hash_table (info)->tls_segment ++ = bfd_zalloc (abfd, sizeof (struct elf_link_tls_segment)); ++ if (elf_hash_table (info)->tls_segment == NULL) ++ goto error_return; ++ elf_hash_table (info)->tls_segment->start = base; ++ elf_hash_table (info)->tls_segment->size = end - base; ++ elf_hash_table (info)->tls_segment->align = align; ++ } ++ ++ if (ddr_sec) ++ { ++ ddr_count = 0; ++ ddr_ptr = (unsigned *)bfd_alloc(abfd, 4 * max_datadata_reloc_count + 4); ++ if (ddr_ptr) ++ ++ddr_ptr; ++ else ++ goto error_return; ++ } ++ else ++ ddr_ptr = NULL; ++ ++ /* Since ELF permits relocations to be against local symbols, we ++ must have the local symbols available when we do the relocations. ++ Since we would rather only read the local symbols once, and we ++ would rather not keep them in memory, we handle all the ++ relocations for a single input file at the same time. ++ ++ Unfortunately, there is no way to know the total number of local ++ symbols until we have seen all of them, and the local symbol ++ indices precede the global symbol indices. This means that when ++ we are generating relocateable output, and we see a reloc against ++ a global symbol, we can not know the symbol index until we have ++ finished examining all the local symbols to see which ones we are ++ going to output. To deal with this, we keep the relocations in ++ memory, and don't output them until the end of the link. This is ++ an unfortunate waste of memory, but I don't see a good way around ++ it. Fortunately, it only happens when performing a relocateable ++ link, which is not the common case. FIXME: If keep_memory is set ++ we could write the relocs out and then read them again; I don't ++ know how bad the memory loss will be. */ ++ ++ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) ++ sub->output_has_begun = false; ++ for (o = abfd->sections; o != NULL; o = o->next) ++ { ++ for (p = o->link_order_head; p != NULL; p = p->next) ++ { ++ if (p->type == bfd_indirect_link_order ++ && (bfd_get_flavour ((sub = p->u.indirect.section->owner)) ++ == bfd_target_elf_flavour) ++ && elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass) ++ { ++ if (! sub->output_has_begun) ++ { ++ if (! elf_link_input_bfd (&finfo, sub)) ++ goto error_return; ++ sub->output_has_begun = true; ++ } ++ } ++ else if (p->type == bfd_section_reloc_link_order ++ || p->type == bfd_symbol_reloc_link_order) ++ { ++ if (! elf_reloc_link_order (abfd, info, o, p)) ++ goto error_return; ++ } ++ else ++ { ++ if (! _bfd_default_link_order (abfd, info, o, p)) ++ goto error_return; ++ } ++ } ++ } ++ ++ /* Output any global symbols that got converted to local in a ++ version script or due to symbol visibility. We do this in a ++ separate step since ELF requires all local symbols to appear ++ prior to any global symbols. FIXME: We should only do this if ++ some global symbols were, in fact, converted to become local. ++ FIXME: Will this work correctly with the Irix 5 linker? */ ++ eoinfo.failed = false; ++ eoinfo.finfo = &finfo; ++ eoinfo.localsyms = true; ++ elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym, ++ (PTR) &eoinfo); ++ if (eoinfo.failed) ++ return false; ++ ++ /* Set the vma of the sections to 0. We can't do that before, otherwise the ++ relocation doesn't work properly for .sbss. */ ++ { ++ int n = elf_elfheader(abfd)->e_shnum; ++ Elf_Internal_Shdr **hdr = elf_elfsections(abfd); ++ for (i = 1; i < n; ++i, ++hdr) ++ (*hdr)->sh_addr = 0; ++ } ++ ++ /* That wrote out all the local symbols. Finish up the symbol table ++ with the global symbols. Even if we want to strip everything we ++ can, we still need to deal with those global symbols that got ++ converted to local in a version script. */ ++ ++ /* The sh_info field records the index of the first non local symbol. */ ++ symtab_hdr->sh_info = bfd_get_symcount (abfd); ++ ++ if (dynamic ++ && finfo.dynsym_sec->output_section != bfd_abs_section_ptr) ++ { ++ Elf_Internal_Sym sym; ++ Elf_External_Sym *dynsym = ++ (Elf_External_Sym *) finfo.dynsym_sec->contents; ++ long last_local = 0; ++ ++ /* Write out the section symbols for the output sections. */ ++ if (info->shared) ++ { ++ asection *s; ++ ++ sym.st_size = 0; ++ sym.st_name = 0; ++ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); ++ sym.st_other = 0; ++ ++ for (s = abfd->sections; s != NULL; s = s->next) ++ { ++ int indx; ++ Elf_External_Sym *dest; ++ ++ indx = elf_section_data (s)->this_idx; ++ BFD_ASSERT (indx > 0); ++ sym.st_shndx = indx; ++ sym.st_value = s->vma; ++ dest = dynsym + elf_section_data (s)->dynindx; ++ elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0); ++ } ++ ++ last_local = bfd_count_sections (abfd); ++ } ++ ++ /* Write out the local dynsyms. */ ++ if (elf_hash_table (info)->dynlocal) ++ { ++ struct elf_link_local_dynamic_entry *e; ++ for (e = elf_hash_table (info)->dynlocal; e ; e = e->next) ++ { ++ asection *s; ++ Elf_External_Sym *dest; ++ ++ sym.st_size = e->isym.st_size; ++ sym.st_other = e->isym.st_other; ++ ++ /* Copy the internal symbol as is. ++ Note that we saved a word of storage and overwrote ++ the original st_name with the dynstr_index. */ ++ sym = e->isym; ++ ++ if (e->isym.st_shndx != SHN_UNDEF ++ && (e->isym.st_shndx < SHN_LORESERVE ++ || e->isym.st_shndx > SHN_HIRESERVE)) ++ { ++ s = bfd_section_from_elf_index (e->input_bfd, ++ e->isym.st_shndx); ++ ++ sym.st_shndx = ++ elf_section_data (s->output_section)->this_idx; ++ sym.st_value = (s->output_section->vma ++ + s->output_offset ++ + e->isym.st_value); ++ } ++ ++ if (last_local < e->dynindx) ++ last_local = e->dynindx; ++ ++ dest = dynsym + e->dynindx; ++ elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0); ++ } ++ } ++ ++ elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = ++ last_local + 1; ++ } ++ ++ /* We get the global symbols from the hash table. */ ++ eoinfo.failed = false; ++ eoinfo.localsyms = false; ++ eoinfo.finfo = &finfo; ++ elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym, ++ (PTR) &eoinfo); ++ if (eoinfo.failed) ++ return false; ++ ++ /* If backend needs to output some symbols not present in the hash ++ table, do it now. */ ++ if (bed->elf_backend_output_arch_syms) ++ { ++ typedef boolean (*out_sym_func) PARAMS ((PTR, const char *, ++ Elf_Internal_Sym *, ++ asection *)); ++ ++ if (! ((*bed->elf_backend_output_arch_syms) ++ (abfd, info, (PTR) &finfo, (out_sym_func) elf_link_output_sym))) ++ return false; ++ } ++ ++ /* Flush all symbols to the file. */ ++ if (! elf_link_flush_output_syms (&finfo)) ++ return false; ++ ++ /* Now we know the size of the symtab section. */ ++ off += symtab_hdr->sh_size; ++ ++ /* Add the __datadata_relocs table. */ ++ if (ddr_sec) ++ { ++ Elf_Internal_Shdr *hdr = elf_elfsections(abfd)[_bfd_elf_section_from_bfd_section(abfd, ddr_sec)]; ++ ddr_sec->_cooked_size = ddr_sec->_raw_size = hdr->sh_size = 4 * ddr_count + 4; ++ hdr->sh_addralign = 2; ++ off = _bfd_elf_assign_file_position_for_section (hdr, off, true); ++ ddr_ptr -= ddr_count + 1; ++ *ddr_ptr = ddr_count ? ddr_count : -1; ++ bfd_set_section_contents(abfd, ddr_sec, ddr_ptr, 0, hdr->sh_size); ++ } ++ ++ /* Finish up and write out the symbol string table (.strtab) ++ section. */ ++ symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; ++ /* sh_name was set in prep_headers. */ ++ symstrtab_hdr->sh_type = SHT_STRTAB; ++ symstrtab_hdr->sh_flags = 0; ++ symstrtab_hdr->sh_addr = 0; ++ symstrtab_hdr->sh_size = _bfd_stringtab_size (finfo.symstrtab); ++ symstrtab_hdr->sh_entsize = 0; ++ symstrtab_hdr->sh_link = 0; ++ symstrtab_hdr->sh_info = 0; ++ /* sh_offset is set just below. */ ++ symstrtab_hdr->sh_addralign = 1; ++ ++ off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, true); ++ elf_tdata (abfd)->next_file_pos = off; ++ ++ if (bfd_get_symcount (abfd) > 0) ++ { ++ if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0 ++ || ! _bfd_stringtab_emit (abfd, finfo.symstrtab)) ++ return false; ++ } ++ ++ /* Adjust the relocs to have the correct symbol indices. */ ++ for (o = abfd->sections; o != NULL; o = o->next) ++ { ++ if ((o->flags & SEC_RELOC) == 0) ++ continue; ++ ++ elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr, ++ elf_section_data (o)->rel_count, ++ elf_section_data (o)->rel_hashes); ++ if (elf_section_data (o)->rel_hdr2 != NULL) ++ elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2, ++ elf_section_data (o)->rel_count2, ++ (elf_section_data (o)->rel_hashes ++ + elf_section_data (o)->rel_count)); ++ ++ elf_section_data (o)->rel_hdr.sh_size = ++ o->reloc_count * elf_section_data (o)->rel_hdr.sh_entsize; ++ ++ /* Set the reloc_count field to 0 to prevent write_relocs from ++ trying to swap the relocs out itself. */ ++ o->reloc_count = 0; ++ } ++ ++ _bfd_elf_assign_file_positions_for_relocs (abfd); ++ ++ if (dynamic && info->combreloc && dynobj != NULL) ++ relativecount = elf_link_sort_relocs (abfd, info, &reldyn); ++ ++ /* If we are linking against a dynamic object, or generating a ++ shared library, finish up the dynamic linking information. */ ++ if (dynamic) ++ { ++ Elf_External_Dyn *dyncon, *dynconend; ++ ++ /* Fix up .dynamic entries. */ ++ o = bfd_get_section_by_name (dynobj, ".dynamic"); ++ BFD_ASSERT (o != NULL); ++ ++ dyncon = (Elf_External_Dyn *) o->contents; ++ dynconend = (Elf_External_Dyn *) (o->contents + o->_raw_size); ++ for (; dyncon < dynconend; dyncon++) ++ { ++ Elf_Internal_Dyn dyn; ++ const char *name; ++ unsigned int type; ++ ++ elf_swap_dyn_in (dynobj, dyncon, &dyn); ++ ++ switch (dyn.d_tag) ++ { ++ default: ++ break; ++ case DT_NULL: ++ if (relativecount > 0 && dyncon + 1 < dynconend) ++ { ++ switch (elf_section_data (reldyn)->this_hdr.sh_type) ++ { ++ case SHT_REL: dyn.d_tag = DT_RELCOUNT; break; ++ case SHT_RELA: dyn.d_tag = DT_RELACOUNT; break; ++ default: break; ++ } ++ if (dyn.d_tag != DT_NULL) ++ { ++ dyn.d_un.d_val = relativecount; ++ elf_swap_dyn_out (dynobj, &dyn, dyncon); ++ relativecount = 0; ++ } ++ } ++ break; ++ case DT_INIT: ++ name = info->init_function; ++ goto get_sym; ++ case DT_FINI: ++ name = info->fini_function; ++ get_sym: ++ { ++ struct elf_link_hash_entry *h; ++ ++ h = elf_link_hash_lookup (elf_hash_table (info), name, ++ false, false, true); ++ if (h != NULL ++ && (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak)) ++ { ++ dyn.d_un.d_val = h->root.u.def.value; ++ o = h->root.u.def.section; ++ if (o->output_section != NULL) ++ dyn.d_un.d_val += (o->output_section->vma ++ + o->output_offset); ++ else ++ { ++ /* The symbol is imported from another shared ++ library and does not apply to this one. */ ++ dyn.d_un.d_val = 0; ++ } ++ ++ elf_swap_dyn_out (dynobj, &dyn, dyncon); ++ } ++ } ++ break; ++ ++ case DT_PREINIT_ARRAYSZ: ++ name = ".preinit_array"; ++ goto get_size; ++ case DT_INIT_ARRAYSZ: ++ name = ".init_array"; ++ goto get_size; ++ case DT_FINI_ARRAYSZ: ++ name = ".fini_array"; ++ get_size: ++ o = bfd_get_section_by_name (abfd, name); ++ if (o == NULL) ++ { ++ (*_bfd_error_handler) ++ (_("%s: could not find output section %s"), ++ bfd_get_filename (abfd), name); ++ goto error_return; ++ } ++ if (o->_raw_size == 0) ++ (*_bfd_error_handler) ++ (_("warning: %s section has zero size"), name); ++ dyn.d_un.d_val = o->_raw_size; ++ elf_swap_dyn_out (dynobj, &dyn, dyncon); ++ break; ++ ++ case DT_PREINIT_ARRAY: ++ name = ".preinit_array"; ++ goto get_vma; ++ case DT_INIT_ARRAY: ++ name = ".init_array"; ++ goto get_vma; ++ case DT_FINI_ARRAY: ++ name = ".fini_array"; ++ goto get_vma; ++ ++ case DT_HASH: ++ name = ".hash"; ++ goto get_vma; ++ case DT_STRTAB: ++ name = ".dynstr"; ++ goto get_vma; ++ case DT_SYMTAB: ++ name = ".dynsym"; ++ goto get_vma; ++ case DT_VERDEF: ++ name = ".gnu.version_d"; ++ goto get_vma; ++ case DT_VERNEED: ++ name = ".gnu.version_r"; ++ goto get_vma; ++ case DT_VERSYM: ++ name = ".gnu.version"; ++ get_vma: ++ o = bfd_get_section_by_name (abfd, name); ++ if (o == NULL) ++ { ++ (*_bfd_error_handler) ++ (_("%s: could not find output section %s"), ++ bfd_get_filename (abfd), name); ++ goto error_return; ++ } ++ dyn.d_un.d_ptr = o->vma; ++ elf_swap_dyn_out (dynobj, &dyn, dyncon); ++ break; ++ ++ case DT_REL: ++ case DT_RELA: ++ case DT_RELSZ: ++ case DT_RELASZ: ++ if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ) ++ type = SHT_REL; ++ else ++ type = SHT_RELA; ++ dyn.d_un.d_val = 0; ++ for (i = 1; i < elf_numsections (abfd); i++) ++ { ++ Elf_Internal_Shdr *hdr; ++ ++ hdr = elf_elfsections (abfd)[i]; ++ if (hdr->sh_type == type ++ && (hdr->sh_flags & SHF_ALLOC) != 0) ++ { ++ if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) ++ dyn.d_un.d_val += hdr->sh_size; ++ else ++ { ++ if (dyn.d_un.d_val == 0 ++ || hdr->sh_addr < dyn.d_un.d_val) ++ dyn.d_un.d_val = hdr->sh_addr; ++ } ++ } ++ } ++ elf_swap_dyn_out (dynobj, &dyn, dyncon); ++ break; ++ } ++ } ++ } ++ ++ /* If we have created any dynamic sections, then output them. */ ++ if (dynobj != NULL) ++ { ++ if (! (*bed->elf_backend_finish_dynamic_sections) (abfd, info)) ++ goto error_return; ++ ++ for (o = dynobj->sections; o != NULL; o = o->next) ++ { ++ if ((o->flags & SEC_HAS_CONTENTS) == 0 ++ || o->_raw_size == 0 ++ || o->output_section == bfd_abs_section_ptr) ++ continue; ++ if ((o->flags & SEC_LINKER_CREATED) == 0) ++ { ++ /* At this point, we are only interested in sections ++ created by elf_link_create_dynamic_sections. */ ++ continue; ++ } ++ if ((elf_section_data (o->output_section)->this_hdr.sh_type ++ != SHT_STRTAB) ++ || strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0) ++ { ++ if (! bfd_set_section_contents (abfd, o->output_section, ++ o->contents, ++ (file_ptr) o->output_offset, ++ o->_raw_size)) ++ goto error_return; ++ } ++ else ++ { ++ /* The contents of the .dynstr section are actually in a ++ stringtab. */ ++ off = elf_section_data (o->output_section)->this_hdr.sh_offset; ++ if (bfd_seek (abfd, off, SEEK_SET) != 0 ++ || ! _bfd_elf_strtab_emit (abfd, ++ elf_hash_table (info)->dynstr)) ++ goto error_return; ++ } ++ } ++ } ++ ++ if (info->relocateable) ++ { ++ boolean failed = false; ++ ++ bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed); ++ if (failed) ++ goto error_return; ++ } ++ ++ /* If we have optimized stabs strings, output them. */ ++ if (elf_hash_table (info)->stab_info != NULL) ++ { ++ if (! _bfd_write_stab_strings (abfd, &elf_hash_table (info)->stab_info)) ++ goto error_return; ++ } ++ ++ if (info->eh_frame_hdr && elf_hash_table (info)->dynobj) ++ { ++ o = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ++ ".eh_frame_hdr"); ++ if (o ++ && (elf_section_data (o)->sec_info_type ++ == ELF_INFO_TYPE_EH_FRAME_HDR)) ++ { ++ if (! _bfd_elf_write_section_eh_frame_hdr (abfd, o)) ++ goto error_return; ++ } ++ } ++ ++ if (finfo.symstrtab != NULL) ++ _bfd_stringtab_free (finfo.symstrtab); ++ if (finfo.contents != NULL) ++ free (finfo.contents); ++ if (finfo.external_relocs != NULL) ++ free (finfo.external_relocs); ++ if (finfo.internal_relocs != NULL) ++ free (finfo.internal_relocs); ++ if (finfo.external_syms != NULL) ++ free (finfo.external_syms); ++ if (finfo.locsym_shndx != NULL) ++ free (finfo.locsym_shndx); ++ if (finfo.internal_syms != NULL) ++ free (finfo.internal_syms); ++ if (finfo.indices != NULL) ++ free (finfo.indices); ++ if (finfo.sections != NULL) ++ free (finfo.sections); ++ if (finfo.symbuf != NULL) ++ free (finfo.symbuf); ++ if (finfo.symshndxbuf != NULL) ++ free (finfo.symbuf); ++ for (o = abfd->sections; o != NULL; o = o->next) ++ { ++ if ((o->flags & SEC_RELOC) != 0 ++ && elf_section_data (o)->rel_hashes != NULL) ++ free (elf_section_data (o)->rel_hashes); ++ } ++ ++ elf_tdata (abfd)->linker = true; ++ ++ return true; ++ ++ error_return: ++ if (finfo.symstrtab != NULL) ++ _bfd_stringtab_free (finfo.symstrtab); ++ if (finfo.contents != NULL) ++ free (finfo.contents); ++ if (finfo.external_relocs != NULL) ++ free (finfo.external_relocs); ++ if (finfo.internal_relocs != NULL) ++ free (finfo.internal_relocs); ++ if (finfo.external_syms != NULL) ++ free (finfo.external_syms); ++ if (finfo.locsym_shndx != NULL) ++ free (finfo.locsym_shndx); ++ if (finfo.internal_syms != NULL) ++ free (finfo.internal_syms); ++ if (finfo.indices != NULL) ++ free (finfo.indices); ++ if (finfo.sections != NULL) ++ free (finfo.sections); ++ if (finfo.symbuf != NULL) ++ free (finfo.symbuf); ++ if (finfo.symshndxbuf != NULL) ++ free (finfo.symbuf); ++ for (o = abfd->sections; o != NULL; o = o->next) ++ { ++ if ((o->flags & SEC_RELOC) != 0 ++ && elf_section_data (o)->rel_hashes != NULL) ++ free (elf_section_data (o)->rel_hashes); ++ } ++ ++ return false; ++} ++ ++/* Add a symbol to the output symbol table. */ ++ ++static boolean ++elf_link_output_sym (finfo, name, elfsym, input_sec) ++ struct elf_final_link_info *finfo; ++ const char *name; ++ Elf_Internal_Sym *elfsym; ++ asection *input_sec; ++{ ++ Elf_External_Sym *dest; ++ Elf_External_Sym_Shndx *destshndx; ++ ++ boolean (*output_symbol_hook) PARAMS ((bfd *, ++ struct bfd_link_info *info, ++ const char *, ++ Elf_Internal_Sym *, ++ asection *)); ++ ++ output_symbol_hook = get_elf_backend_data (finfo->output_bfd)-> ++ elf_backend_link_output_symbol_hook; ++ if (output_symbol_hook != NULL) ++ { ++ if (! ((*output_symbol_hook) ++ (finfo->output_bfd, finfo->info, name, elfsym, input_sec))) ++ return false; ++ } ++ ++ if (name == (const char *) NULL || *name == '\0') ++ elfsym->st_name = 0; ++ else if (input_sec->flags & SEC_EXCLUDE) ++ elfsym->st_name = 0; ++ else ++ { ++ elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab, ++ name, true, false); ++ if (elfsym->st_name == (unsigned long) -1) ++ return false; ++ } ++ ++ if (finfo->symbuf_count >= finfo->symbuf_size) ++ { ++ if (! elf_link_flush_output_syms (finfo)) ++ return false; ++ } ++ ++ dest = finfo->symbuf + finfo->symbuf_count; ++ destshndx = finfo->symshndxbuf; ++ if (destshndx != NULL) ++ destshndx += finfo->symbuf_count; ++ elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx); ++ ++finfo->symbuf_count; ++ ++ ++ bfd_get_symcount (finfo->output_bfd); ++ ++ return true; ++} ++ ++/* Flush the output symbols to the file. */ ++ ++static boolean ++elf_link_flush_output_syms (finfo) ++ struct elf_final_link_info *finfo; ++{ ++ if (finfo->symbuf_count > 0) ++ { ++ Elf_Internal_Shdr *hdr; ++ file_ptr pos; ++ bfd_size_type amt; ++ ++ hdr = &elf_tdata (finfo->output_bfd)->symtab_hdr; ++ pos = hdr->sh_offset + hdr->sh_size; ++ amt = finfo->symbuf_count * sizeof (Elf_External_Sym); ++ if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0 ++ || bfd_bwrite ((PTR) finfo->symbuf, amt, finfo->output_bfd) != amt) ++ return false; ++ ++ hdr->sh_size += amt; ++ ++ if (finfo->symshndxbuf != NULL) ++ { ++ hdr = &elf_tdata (finfo->output_bfd)->symtab_shndx_hdr; ++ pos = hdr->sh_offset + hdr->sh_size; ++ amt = finfo->symbuf_count * sizeof (Elf_External_Sym_Shndx); ++ if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0 ++ || (bfd_bwrite ((PTR) finfo->symshndxbuf, amt, finfo->output_bfd) ++ != amt)) ++ return false; ++ ++ hdr->sh_size += amt; ++ } ++ ++ finfo->symbuf_count = 0; ++ } ++ ++ return true; ++} ++ ++/* Adjust all external symbols pointing into SEC_MERGE sections ++ to reflect the object merging within the sections. */ ++ ++static boolean ++elf_link_sec_merge_syms (h, data) ++ struct elf_link_hash_entry *h; ++ PTR data; ++{ ++ asection *sec; ++ ++ if (h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ ++ if ((h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && ((sec = h->root.u.def.section)->flags & SEC_MERGE) ++ && elf_section_data (sec)->sec_info_type == ELF_INFO_TYPE_MERGE) ++ { ++ bfd *output_bfd = (bfd *) data; ++ ++ h->root.u.def.value = ++ _bfd_merged_section_offset (output_bfd, ++ &h->root.u.def.section, ++ elf_section_data (sec)->sec_info, ++ h->root.u.def.value, (bfd_vma) 0); ++ } ++ ++ return true; ++} ++ ++/* For DSOs loaded in via a DT_NEEDED entry, emulate ld.so in ++ allowing an unsatisfied unversioned symbol in the DSO to match a ++ versioned symbol that would normally require an explicit version. */ ++ ++static boolean ++elf_link_check_versioned_symbol (info, h) ++ struct bfd_link_info *info; ++ struct elf_link_hash_entry *h; ++{ ++ bfd *undef_bfd = h->root.u.undef.abfd; ++ struct elf_link_loaded_list *loaded; ++ ++ if ((undef_bfd->flags & DYNAMIC) == 0 ++ || info->hash->creator->flavour != bfd_target_elf_flavour ++ || elf_dt_soname (h->root.u.undef.abfd) == NULL) ++ return false; ++ ++ for (loaded = elf_hash_table (info)->loaded; ++ loaded != NULL; ++ loaded = loaded->next) ++ { ++ bfd *input; ++ Elf_Internal_Shdr *hdr; ++ bfd_size_type symcount; ++ bfd_size_type extsymcount; ++ bfd_size_type extsymoff; ++ Elf_Internal_Shdr *versymhdr; ++ Elf_Internal_Sym *isym; ++ Elf_Internal_Sym *isymend; ++ Elf_Internal_Sym *isymbuf; ++ Elf_External_Versym *ever; ++ Elf_External_Versym *extversym; ++ ++ input = loaded->abfd; ++ ++ /* We check each DSO for a possible hidden versioned definition. */ ++ if (input == undef_bfd ++ || (input->flags & DYNAMIC) == 0 ++ || elf_dynversym (input) == 0) ++ continue; ++ ++ hdr = &elf_tdata (input)->dynsymtab_hdr; ++ ++ symcount = hdr->sh_size / sizeof (Elf_External_Sym); ++ if (elf_bad_symtab (input)) ++ { ++ extsymcount = symcount; ++ extsymoff = 0; ++ } ++ else ++ { ++ extsymcount = symcount - hdr->sh_info; ++ extsymoff = hdr->sh_info; ++ } ++ ++ if (extsymcount == 0) ++ continue; ++ ++ isymbuf = bfd_elf_get_elf_syms (input, hdr, extsymcount, extsymoff, ++ NULL, NULL, NULL); ++ if (isymbuf == NULL) ++ return false; ++ ++ /* Read in any version definitions. */ ++ versymhdr = &elf_tdata (input)->dynversym_hdr; ++ extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size); ++ if (extversym == NULL) ++ goto error_ret; ++ ++ if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0 ++ || (bfd_bread ((PTR) extversym, versymhdr->sh_size, input) ++ != versymhdr->sh_size)) ++ { ++ free (extversym); ++ error_ret: ++ free (isymbuf); ++ return false; ++ } ++ ++ ever = extversym + extsymoff; ++ isymend = isymbuf + extsymcount; ++ for (isym = isymbuf; isym < isymend; isym++, ever++) ++ { ++ const char *name; ++ Elf_Internal_Versym iver; ++ ++ if (ELF_ST_BIND (isym->st_info) == STB_LOCAL ++ || isym->st_shndx == SHN_UNDEF) ++ continue; ++ ++ name = bfd_elf_string_from_elf_section (input, ++ hdr->sh_link, ++ isym->st_name); ++ if (strcmp (name, h->root.root.string) != 0) ++ continue; ++ ++ _bfd_elf_swap_versym_in (input, ever, &iver); ++ ++ if ((iver.vs_vers & VERSYM_HIDDEN) == 0) ++ { ++ /* If we have a non-hidden versioned sym, then it should ++ have provided a definition for the undefined sym. */ ++ abort (); ++ } ++ ++ if ((iver.vs_vers & VERSYM_VERSION) == 2) ++ { ++ /* This is the oldest (default) sym. We can use it. */ ++ free (extversym); ++ free (isymbuf); ++ return true; ++ } ++ } ++ ++ free (extversym); ++ free (isymbuf); ++ } ++ ++ return false; ++} ++ ++/* Add an external symbol to the symbol table. This is called from ++ the hash table traversal routine. When generating a shared object, ++ we go through the symbol table twice. The first time we output ++ anything that might have been forced to local scope in a version ++ script. The second time we output the symbols that are still ++ global symbols. */ ++ ++static boolean ++elf_link_output_extsym (h, data) ++ struct elf_link_hash_entry *h; ++ PTR data; ++{ ++ struct elf_outext_info *eoinfo = (struct elf_outext_info *) data; ++ struct elf_final_link_info *finfo = eoinfo->finfo; ++ boolean strip; ++ Elf_Internal_Sym sym; ++ asection *input_sec; ++ ++ if (h->root.type == bfd_link_hash_warning) ++ { ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ if (h->root.type == bfd_link_hash_new) ++ return true; ++ } ++ ++ /* Decide whether to output this symbol in this pass. */ ++ if (eoinfo->localsyms) ++ { ++ if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) ++ return true; ++ } ++ else ++ { ++ if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) ++ return true; ++ } ++ ++ /* If we are not creating a shared library, and this symbol is ++ referenced by a shared library but is not defined anywhere, then ++ warn that it is undefined. If we do not do this, the runtime ++ linker will complain that the symbol is undefined when the ++ program is run. We don't have to worry about symbols that are ++ referenced by regular files, because we will already have issued ++ warnings for them. */ ++ if (! finfo->info->relocateable ++ && ! finfo->info->allow_shlib_undefined ++ && ! finfo->info->shared ++ && h->root.type == bfd_link_hash_undefined ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0 ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0 ++ && ! elf_link_check_versioned_symbol (finfo->info, h)) ++ { ++ if (! ((*finfo->info->callbacks->undefined_symbol) ++ (finfo->info, h->root.root.string, h->root.u.undef.abfd, ++ (asection *) NULL, (bfd_vma) 0, true))) ++ { ++ eoinfo->failed = true; ++ return false; ++ } ++ } ++ ++ /* We don't want to output symbols that have never been mentioned by ++ a regular file, or that we have been told to strip. However, if ++ h->indx is set to -2, the symbol is used by a reloc and we must ++ output it. */ ++ if (h->indx == -2) ++ strip = false; ++ else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 ++ || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) ++ strip = true; ++ else if (finfo->info->strip == strip_all ++ || (finfo->info->strip == strip_some ++ && bfd_hash_lookup (finfo->info->keep_hash, ++ h->root.root.string, ++ false, false) == NULL)) ++ strip = true; ++ else ++ strip = false; ++ ++ /* If we're stripping it, and it's not a dynamic symbol, there's ++ nothing else to do unless it is a forced local symbol. */ ++ if (strip ++ && h->dynindx == -1 ++ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) ++ return true; ++ ++ sym.st_value = 0; ++ sym.st_size = h->size; ++ sym.st_other = h->other; ++ if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) ++ sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type); ++ else if (h->root.type == bfd_link_hash_undefweak ++ || h->root.type == bfd_link_hash_defweak) ++ sym.st_info = ELF_ST_INFO (STB_WEAK, h->type); ++ else ++ sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type); ++ ++ switch (h->root.type) ++ { ++ default: ++ case bfd_link_hash_new: ++ case bfd_link_hash_warning: ++ abort (); ++ return false; ++ ++ case bfd_link_hash_undefined: ++ case bfd_link_hash_undefweak: ++ input_sec = bfd_und_section_ptr; ++ sym.st_shndx = SHN_UNDEF; ++ break; ++ ++ case bfd_link_hash_defined: ++ case bfd_link_hash_defweak: ++ { ++ input_sec = h->root.u.def.section; ++ if (input_sec->output_section != NULL) ++ { ++ sym.st_shndx = ++ _bfd_elf_section_from_bfd_section (finfo->output_bfd, ++ input_sec->output_section); ++ if (sym.st_shndx == SHN_BAD) ++ { ++ (*_bfd_error_handler) ++ (_("%s: could not find output section %s for input section %s"), ++ bfd_get_filename (finfo->output_bfd), ++ input_sec->output_section->name, ++ input_sec->name); ++ eoinfo->failed = true; ++ return false; ++ } ++ ++ /* ELF symbols in relocateable files are section relative, ++ but in nonrelocateable files they are virtual ++ addresses. */ ++ sym.st_value = h->root.u.def.value + input_sec->output_offset; ++#if 0 ++ if (! finfo->info->relocateable) ++ { ++ sym.st_value += input_sec->output_section->vma; ++ if (h->type == STT_TLS) ++ { ++ /* STT_TLS symbols are relative to PT_TLS segment ++ base. */ ++ BFD_ASSERT (finfo->first_tls_sec != NULL); ++ sym.st_value -= finfo->first_tls_sec->vma; ++ } ++ } ++#endif ++ } ++ else ++ { ++ BFD_ASSERT (input_sec->owner == NULL ++ || (input_sec->owner->flags & DYNAMIC) != 0); ++ sym.st_shndx = SHN_UNDEF; ++ input_sec = bfd_und_section_ptr; ++ } ++ } ++ break; ++ ++ case bfd_link_hash_common: ++ input_sec = h->root.u.c.p->section; ++ sym.st_shndx = SHN_COMMON; ++ sym.st_value = 1 << h->root.u.c.p->alignment_power; ++ break; ++ ++ case bfd_link_hash_indirect: ++ /* These symbols are created by symbol versioning. They point ++ to the decorated version of the name. For example, if the ++ symbol foo@@GNU_1.2 is the default, which should be used when ++ foo is used with no version, then we add an indirect symbol ++ foo which points to foo@@GNU_1.2. We ignore these symbols, ++ since the indirected symbol is already in the hash table. */ ++ return true; ++ } ++ ++ /* Give the processor backend a chance to tweak the symbol value, ++ and also to finish up anything that needs to be done for this ++ symbol. FIXME: Not calling elf_backend_finish_dynamic_symbol for ++ forced local syms when non-shared is due to a historical quirk. */ ++ if ((h->dynindx != -1 ++ || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) ++ && (finfo->info->shared ++ || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) ++ && elf_hash_table (finfo->info)->dynamic_sections_created) ++ { ++ struct elf_backend_data *bed; ++ ++ bed = get_elf_backend_data (finfo->output_bfd); ++ if (! ((*bed->elf_backend_finish_dynamic_symbol) ++ (finfo->output_bfd, finfo->info, h, &sym))) ++ { ++ eoinfo->failed = true; ++ return false; ++ } ++ } ++ ++ /* If we are marking the symbol as undefined, and there are no ++ non-weak references to this symbol from a regular object, then ++ mark the symbol as weak undefined; if there are non-weak ++ references, mark the symbol as strong. We can't do this earlier, ++ because it might not be marked as undefined until the ++ finish_dynamic_symbol routine gets through with it. */ ++ if (sym.st_shndx == SHN_UNDEF ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0 ++ && (ELF_ST_BIND (sym.st_info) == STB_GLOBAL ++ || ELF_ST_BIND (sym.st_info) == STB_WEAK)) ++ { ++ int bindtype; ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) != 0) ++ bindtype = STB_GLOBAL; ++ else ++ bindtype = STB_WEAK; ++ sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info)); ++ } ++ ++ /* If a symbol is not defined locally, we clear the visibility ++ field. */ ++ if (! finfo->info->relocateable ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ sym.st_other ^= ELF_ST_VISIBILITY (sym.st_other); ++ ++ /* If this symbol should be put in the .dynsym section, then put it ++ there now. We already know the symbol index. We also fill in ++ the entry in the .hash section. */ ++ if (h->dynindx != -1 ++ && elf_hash_table (finfo->info)->dynamic_sections_created) ++ { ++ size_t bucketcount; ++ size_t bucket; ++ size_t hash_entry_size; ++ bfd_byte *bucketpos; ++ bfd_vma chain; ++ Elf_External_Sym *esym; ++ ++ sym.st_name = h->dynstr_index; ++ esym = (Elf_External_Sym *) finfo->dynsym_sec->contents + h->dynindx; ++ elf_swap_symbol_out (finfo->output_bfd, &sym, (PTR) esym, (PTR) 0); ++ ++ bucketcount = elf_hash_table (finfo->info)->bucketcount; ++ bucket = h->elf_hash_value % bucketcount; ++ hash_entry_size ++ = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize; ++ bucketpos = ((bfd_byte *) finfo->hash_sec->contents ++ + (bucket + 2) * hash_entry_size); ++ chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos); ++ bfd_put (8 * hash_entry_size, finfo->output_bfd, (bfd_vma) h->dynindx, ++ bucketpos); ++ bfd_put (8 * hash_entry_size, finfo->output_bfd, chain, ++ ((bfd_byte *) finfo->hash_sec->contents ++ + (bucketcount + 2 + h->dynindx) * hash_entry_size)); ++ ++ if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL) ++ { ++ Elf_Internal_Versym iversym; ++ Elf_External_Versym *eversym; ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ { ++ if (h->verinfo.verdef == NULL) ++ iversym.vs_vers = 0; ++ else ++ iversym.vs_vers = h->verinfo.verdef->vd_exp_refno + 1; ++ } ++ else ++ { ++ if (h->verinfo.vertree == NULL) ++ iversym.vs_vers = 1; ++ else ++ iversym.vs_vers = h->verinfo.vertree->vernum + 1; ++ } ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HIDDEN) != 0) ++ iversym.vs_vers |= VERSYM_HIDDEN; ++ ++ eversym = (Elf_External_Versym *) finfo->symver_sec->contents; ++ eversym += h->dynindx; ++ _bfd_elf_swap_versym_out (finfo->output_bfd, &iversym, eversym); ++ } ++ } ++ ++ /* If we're stripping it, then it was just a dynamic symbol, and ++ there's nothing else to do. */ ++ if (strip || (input_sec->flags & SEC_EXCLUDE) != 0) ++ return true; ++ ++ h->indx = bfd_get_symcount (finfo->output_bfd); ++ ++ if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec)) ++ { ++ eoinfo->failed = true; ++ return false; ++ } ++ ++ return true; ++} ++ ++/* Copy the relocations indicated by the INTERNAL_RELOCS (which ++ originated from the section given by INPUT_REL_HDR) to the ++ OUTPUT_BFD. */ ++ ++static boolean ++elf_link_output_relocs (output_bfd, input_section, input_rel_hdr, ++ internal_relocs) ++ bfd *output_bfd; ++ asection *input_section; ++ Elf_Internal_Shdr *input_rel_hdr; ++ Elf_Internal_Rela *internal_relocs; ++{ ++ Elf_Internal_Rela *irela; ++ Elf_Internal_Rela *irelaend; ++ Elf_Internal_Shdr *output_rel_hdr; ++ asection *output_section; ++ unsigned int *rel_countp = NULL; ++ struct elf_backend_data *bed; ++ bfd_size_type amt; ++ ++ output_section = input_section->output_section; ++ output_rel_hdr = NULL; ++ ++ if (elf_section_data (output_section)->rel_hdr.sh_entsize ++ == input_rel_hdr->sh_entsize) ++ { ++ output_rel_hdr = &elf_section_data (output_section)->rel_hdr; ++ rel_countp = &elf_section_data (output_section)->rel_count; ++ } ++ else if (elf_section_data (output_section)->rel_hdr2 ++ && (elf_section_data (output_section)->rel_hdr2->sh_entsize ++ == input_rel_hdr->sh_entsize)) ++ { ++ output_rel_hdr = elf_section_data (output_section)->rel_hdr2; ++ rel_countp = &elf_section_data (output_section)->rel_count2; ++ } ++ else ++ { ++ (*_bfd_error_handler) ++ (_("%s: relocation size mismatch in %s section %s"), ++ bfd_get_filename (output_bfd), ++ bfd_archive_filename (input_section->owner), ++ input_section->name); ++ bfd_set_error (bfd_error_wrong_object_format); ++ return false; ++ } ++ ++ bed = get_elf_backend_data (output_bfd); ++ irela = internal_relocs; ++ irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) ++ * bed->s->int_rels_per_ext_rel); ++ ++ if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) ++ { ++ Elf_External_Rel *erel; ++ Elf_Internal_Rel *irel; ++ ++ amt = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rel); ++ irel = (Elf_Internal_Rel *) bfd_zmalloc (amt); ++ if (irel == NULL) ++ { ++ (*_bfd_error_handler) (_("Error: out of memory")); ++ abort (); ++ } ++ ++ erel = ((Elf_External_Rel *) output_rel_hdr->contents + *rel_countp); ++ for (; irela < irelaend; irela += bed->s->int_rels_per_ext_rel, erel++) ++ { ++ unsigned int i; ++ ++ for (i = 0; i < bed->s->int_rels_per_ext_rel; i++) ++ { ++ irel[i].r_offset = irela[i].r_offset; ++ irel[i].r_info = irela[i].r_info; ++ BFD_ASSERT (irela[i].r_addend == 0); ++ } ++ ++ if (bed->s->swap_reloc_out) ++ (*bed->s->swap_reloc_out) (output_bfd, irel, (PTR) erel); ++ else ++ elf_swap_reloc_out (output_bfd, irel, erel); ++ } ++ ++ free (irel); ++ } ++ else ++ { ++ Elf_External_Rela *erela; ++ ++ BFD_ASSERT (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rela)); ++ ++ erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp); ++ for (; irela < irelaend; irela += bed->s->int_rels_per_ext_rel, erela++) ++ if (bed->s->swap_reloca_out) ++ (*bed->s->swap_reloca_out) (output_bfd, irela, (PTR) erela); ++ else ++ elf_swap_reloca_out (output_bfd, irela, erela); ++ } ++ ++ /* Bump the counter, so that we know where to add the next set of ++ relocations. */ ++ *rel_countp += NUM_SHDR_ENTRIES (input_rel_hdr); ++ ++ return true; ++} ++ ++/* Link an input file into the linker output file. This function ++ handles all the sections and relocations of the input file at once. ++ This is so that we only have to read the local symbols once, and ++ don't have to keep them in memory. */ ++ ++static boolean ++elf_link_input_bfd (finfo, input_bfd) ++ struct elf_final_link_info *finfo; ++ bfd *input_bfd; ++{ ++ boolean (*relocate_section) PARAMS ((bfd *, struct bfd_link_info *, ++ bfd *, asection *, bfd_byte *, ++ Elf_Internal_Rela *, ++ Elf_Internal_Sym *, asection **)); ++ bfd *output_bfd; ++ Elf_Internal_Shdr *symtab_hdr; ++ size_t locsymcount; ++ size_t extsymoff; ++ Elf_Internal_Sym *isymbuf; ++ Elf_Internal_Sym *isym; ++ Elf_Internal_Sym *isymend; ++ long *pindex; ++ asection **ppsection; ++ asection *o; ++ struct elf_backend_data *bed; ++ boolean emit_relocs; ++ struct elf_link_hash_entry **sym_hashes; ++ ++ output_bfd = finfo->output_bfd; ++ bed = get_elf_backend_data (output_bfd); ++ relocate_section = bed->elf_backend_relocate_section; ++ ++ /* If this is a dynamic object, we don't want to do anything here: ++ we don't want the local symbols, and we don't want the section ++ contents. */ ++ if ((input_bfd->flags & DYNAMIC) != 0) ++ return true; ++ ++ emit_relocs = (finfo->info->relocateable ++ || finfo->info->emitrelocations ++ || bed->elf_backend_emit_relocs); ++ ++ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; ++ if (elf_bad_symtab (input_bfd)) ++ { ++ locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym); ++ extsymoff = 0; ++ } ++ else ++ { ++ locsymcount = symtab_hdr->sh_info; ++ extsymoff = symtab_hdr->sh_info; ++ } ++ ++ /* Read the local symbols. */ ++ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; ++ if (isymbuf == NULL && locsymcount != 0) ++ { ++ isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0, ++ finfo->internal_syms, ++ finfo->external_syms, ++ finfo->locsym_shndx); ++ if (isymbuf == NULL) ++ return false; ++ } ++ ++ /* Find local symbol sections and adjust values of symbols in ++ SEC_MERGE sections. Write out those local symbols we know are ++ going into the output file. */ ++ isymend = isymbuf + locsymcount; ++ for (isym = isymbuf, pindex = finfo->indices, ppsection = finfo->sections; ++ isym < isymend; ++ isym++, pindex++, ppsection++) ++ { ++ asection *isec; ++ const char *name; ++ Elf_Internal_Sym osym; ++ ++ *pindex = -1; ++ ++ if (elf_bad_symtab (input_bfd)) ++ { ++ if (ELF_ST_BIND (isym->st_info) != STB_LOCAL) ++ { ++ *ppsection = NULL; ++ continue; ++ } ++ } ++ ++ if (isym->st_shndx == SHN_UNDEF) ++ isec = bfd_und_section_ptr; ++ else if (isym->st_shndx < SHN_LORESERVE ++ || isym->st_shndx > SHN_HIRESERVE) ++ { ++ isec = section_from_elf_index (input_bfd, isym->st_shndx); ++ if (isec ++ && elf_section_data (isec)->sec_info_type == ELF_INFO_TYPE_MERGE ++ && ELF_ST_TYPE (isym->st_info) != STT_SECTION) ++ isym->st_value = ++ _bfd_merged_section_offset (output_bfd, &isec, ++ elf_section_data (isec)->sec_info, ++ isym->st_value, (bfd_vma) 0); ++ } ++ else if (isym->st_shndx == SHN_ABS) ++ isec = bfd_abs_section_ptr; ++ else if (isym->st_shndx == SHN_COMMON) ++ isec = bfd_com_section_ptr; ++ else ++ { ++ /* Who knows? */ ++ isec = NULL; ++ } ++ ++ *ppsection = isec; ++ ++ /* Don't output the first, undefined, symbol. */ ++ if (ppsection == finfo->sections) ++ continue; ++ ++ if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) ++ { ++ /* We never output section symbols. Instead, we use the ++ section symbol of the corresponding section in the output ++ file. */ ++ continue; ++ } ++ ++ /* If we are stripping all symbols, we don't want to output this ++ one. */ ++ if (finfo->info->strip == strip_all) ++ continue; ++ ++ /* If we are discarding all local symbols, we don't want to ++ output this one. If we are generating a relocateable output ++ file, then some of the local symbols may be required by ++ relocs; we output them below as we discover that they are ++ needed. */ ++ if (finfo->info->discard == discard_all) ++ continue; ++ ++ /* If this symbol is defined in a section which we are ++ discarding, we don't need to keep it, but note that ++ linker_mark is only reliable for sections that have contents. ++ For the benefit of the MIPS ELF linker, we check SEC_EXCLUDE ++ as well as linker_mark. */ ++ if ((isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE) ++ && isec != NULL ++ && ((! isec->linker_mark && (isec->flags & SEC_HAS_CONTENTS) != 0) ++ || (! finfo->info->relocateable ++ && (isec->flags & SEC_EXCLUDE) != 0))) ++ continue; ++ ++ /* Get the name of the symbol. */ ++ name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, ++ isym->st_name); ++ if (name == NULL) ++ return false; ++ ++ /* See if we are discarding symbols with this name. */ ++ if ((finfo->info->strip == strip_some ++ && (bfd_hash_lookup (finfo->info->keep_hash, name, false, false) ++ == NULL)) ++ || (((finfo->info->discard == discard_sec_merge ++ && (isec->flags & SEC_MERGE) && ! finfo->info->relocateable) ++ || finfo->info->discard == discard_l) ++ && bfd_is_local_label_name (input_bfd, name))) ++ continue; ++ ++ /* If we get here, we are going to output this symbol. */ ++ ++ osym = *isym; ++ ++ /* Adjust the section index for the output file. */ ++ osym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd, ++ isec->output_section); ++ if (osym.st_shndx == SHN_BAD) ++ return false; ++ ++ *pindex = bfd_get_symcount (output_bfd); ++ ++ /* ELF symbols in relocateable files are section relative, but ++ in executable files they are virtual addresses. Note that ++ this code assumes that all ELF sections have an associated ++ BFD section with a reasonable value for output_offset; below ++ we assume that they also have a reasonable value for ++ output_section. Any special sections must be set up to meet ++ these requirements. */ ++ osym.st_value += isec->output_offset; ++ if (! finfo->info->relocateable) ++ { ++ osym.st_value += isec->output_section->vma; ++ if (ELF_ST_TYPE (osym.st_info) == STT_TLS) ++ { ++ /* STT_TLS symbols are relative to PT_TLS segment base. */ ++ BFD_ASSERT (finfo->first_tls_sec != NULL); ++ osym.st_value -= finfo->first_tls_sec->vma; ++ } ++ } ++ ++ if (! elf_link_output_sym (finfo, name, &osym, isec)) ++ return false; ++ } ++ ++ /* Relocate the contents of each section. */ ++ sym_hashes = elf_sym_hashes (input_bfd); ++ for (o = input_bfd->sections; o != NULL; o = o->next) ++ { ++ bfd_byte *contents; ++ ++ if (! o->linker_mark) ++ { ++ /* This section was omitted from the link. */ ++ continue; ++ } ++ ++ if ((o->flags & SEC_HAS_CONTENTS) == 0 ++ || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0)) ++ continue; ++ ++ if ((o->flags & SEC_LINKER_CREATED) != 0) ++ { ++ /* Section was created by elf_link_create_dynamic_sections ++ or somesuch. */ ++ continue; ++ } ++ ++ /* Get the contents of the section. They have been cached by a ++ relaxation routine. Note that o is a section in an input ++ file, so the contents field will not have been set by any of ++ the routines which work on output files. */ ++ if (elf_section_data (o)->this_hdr.contents != NULL) ++ contents = elf_section_data (o)->this_hdr.contents; ++ else ++ { ++ contents = finfo->contents; ++ if (! bfd_get_section_contents (input_bfd, o, contents, ++ (file_ptr) 0, o->_raw_size)) ++ return false; ++ } ++ ++ if ((o->flags & SEC_RELOC) != 0) ++ { ++ Elf_Internal_Rela *internal_relocs; ++ ++ /* Get the swapped relocs. */ ++ internal_relocs = (NAME(_bfd_elf,link_read_relocs) ++ (input_bfd, o, finfo->external_relocs, ++ finfo->internal_relocs, false)); ++ if (internal_relocs == NULL ++ && o->reloc_count > 0) ++ return false; ++ ++ /* Run through the relocs looking for any against symbols ++ from discarded sections and section symbols from ++ removed link-once sections. Complain about relocs ++ against discarded sections. Zero relocs against removed ++ link-once sections. We should really complain if ++ anything in the final link tries to use it, but ++ DWARF-based exception handling might have an entry in ++ .eh_frame to describe a routine in the linkonce section, ++ and it turns out to be hard to remove the .eh_frame ++ entry too. FIXME. */ ++ if (!finfo->info->relocateable ++ && !elf_section_ignore_discarded_relocs (o)) ++ { ++ Elf_Internal_Rela *rel, *relend; ++ ++ rel = internal_relocs; ++ relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel; ++ for ( ; rel < relend; rel++) ++ { ++ unsigned long r_symndx = ELF_R_SYM (rel->r_info); ++ ++ if (r_symndx >= locsymcount ++ || (elf_bad_symtab (input_bfd) ++ && finfo->sections[r_symndx] == NULL)) ++ { ++ struct elf_link_hash_entry *h; ++ ++ h = sym_hashes[r_symndx - extsymoff]; ++ while (h->root.type == bfd_link_hash_indirect ++ || h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ ++ /* Complain if the definition comes from a ++ discarded section. */ ++ if ((h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && elf_discarded_section (h->root.u.def.section)) ++ { ++ if ((o->flags & SEC_DEBUGGING) != 0) ++ { ++ BFD_ASSERT (r_symndx != 0); ++ memset (rel, 0, sizeof (*rel)); ++ } ++ else ++ { ++ if (! ((*finfo->info->callbacks->undefined_symbol) ++ (finfo->info, h->root.root.string, ++ input_bfd, o, rel->r_offset, ++ true))) ++ return false; ++ } ++ } ++ } ++ else ++ { ++ asection *sec = finfo->sections[r_symndx]; ++ ++ if (sec != NULL && elf_discarded_section (sec)) ++ { ++ if ((o->flags & SEC_DEBUGGING) != 0 ++ || (sec->flags & SEC_LINK_ONCE) != 0) ++ { ++ BFD_ASSERT (r_symndx != 0); ++ rel->r_info ++ = ELF_R_INFO (0, ELF_R_TYPE (rel->r_info)); ++ rel->r_addend = 0; ++ } ++ else ++ { ++ boolean ok; ++ const char *msg ++ = _("local symbols in discarded section %s"); ++ bfd_size_type amt ++ = strlen (sec->name) + strlen (msg) - 1; ++ char *buf = (char *) bfd_malloc (amt); ++ ++ if (buf != NULL) ++ sprintf (buf, msg, sec->name); ++ else ++ buf = (char *) sec->name; ++ ok = (*finfo->info->callbacks ++ ->undefined_symbol) (finfo->info, buf, ++ input_bfd, o, ++ rel->r_offset, ++ true); ++ if (buf != sec->name) ++ free (buf); ++ if (!ok) ++ return false; ++ } ++ } ++ } ++ } ++ } ++ ++ /* Relocate the section by invoking a back end routine. ++ ++ The back end routine is responsible for adjusting the ++ section contents as necessary, and (if using Rela relocs ++ and generating a relocateable output file) adjusting the ++ reloc addend as necessary. ++ ++ The back end routine does not have to worry about setting ++ the reloc address or the reloc symbol index. ++ ++ The back end routine is given a pointer to the swapped in ++ internal symbols, and can access the hash table entries ++ for the external symbols via elf_sym_hashes (input_bfd). ++ ++ When generating relocateable output, the back end routine ++ must handle STB_LOCAL/STT_SECTION symbols specially. The ++ output symbol is going to be a section symbol ++ corresponding to the output section, which will require ++ the addend to be adjusted. */ ++ ++ if (! (*relocate_section) (output_bfd, finfo->info, ++ input_bfd, o, contents, ++ internal_relocs, ++ isymbuf, ++ finfo->sections)) ++ return false; ++ ++ if (emit_relocs) ++ { ++ Elf_Internal_Rela *irela; ++ Elf_Internal_Rela *irelaend; ++ struct elf_link_hash_entry **rel_hash; ++ Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2; ++ unsigned int next_erel; ++ boolean (*reloc_emitter) PARAMS ((bfd *, asection *, ++ Elf_Internal_Shdr *, ++ Elf_Internal_Rela *)); ++ boolean rela_normal; ++ ++ input_rel_hdr = &elf_section_data (o)->rel_hdr; ++ rela_normal = (bed->rela_normal ++ && (input_rel_hdr->sh_entsize ++ == sizeof (Elf_External_Rela))); ++ ++ /* Adjust the reloc addresses and symbol indices. */ ++ ++ irela = internal_relocs; ++ irelaend = irela + o->reloc_count * bed->s->int_rels_per_ext_rel; ++ rel_hash = (elf_section_data (o->output_section)->rel_hashes ++ + elf_section_data (o->output_section)->rel_count ++ + elf_section_data (o->output_section)->rel_count2); ++ for (next_erel = 0; irela < irelaend; irela++, next_erel++) ++ { ++ unsigned long r_symndx; ++ asection *sec; ++ Elf_Internal_Sym sym; ++ ++ if (next_erel == bed->s->int_rels_per_ext_rel) ++ { ++ rel_hash++; ++ next_erel = 0; ++ } ++ ++ irela->r_offset += o->output_offset; ++ ++ /* Relocs in an executable have to be virtual addresses. */ ++ if (!finfo->info->relocateable) ++ irela->r_offset += o->output_section->vma; ++ ++ r_symndx = ELF_R_SYM (irela->r_info); ++ ++ if (r_symndx == 0) ++ continue; ++ ++ if (r_symndx >= locsymcount ++ || (elf_bad_symtab (input_bfd) ++ && finfo->sections[r_symndx] == NULL)) ++ { ++ struct elf_link_hash_entry *rh; ++ unsigned long indx; ++ ++ /* This is a reloc against a global symbol. We ++ have not yet output all the local symbols, so ++ we do not know the symbol index of any global ++ symbol. We set the rel_hash entry for this ++ reloc to point to the global hash table entry ++ for this symbol. The symbol index is then ++ set at the end of elf_bfd_final_link. */ ++ indx = r_symndx - extsymoff; ++ rh = elf_sym_hashes (input_bfd)[indx]; ++ while (rh->root.type == bfd_link_hash_indirect ++ || rh->root.type == bfd_link_hash_warning) ++ rh = (struct elf_link_hash_entry *) rh->root.u.i.link; ++ ++ /* Setting the index to -2 tells ++ elf_link_output_extsym that this symbol is ++ used by a reloc. */ ++ BFD_ASSERT (rh->indx < 0); ++ rh->indx = -2; ++ ++ *rel_hash = rh; ++ ++ continue; ++ } ++ ++ /* This is a reloc against a local symbol. */ ++ ++ *rel_hash = NULL; ++ sym = isymbuf[r_symndx]; ++ sec = finfo->sections[r_symndx]; ++ if (ELF_ST_TYPE (sym.st_info) == STT_SECTION) ++ { ++ /* I suppose the backend ought to fill in the ++ section of any STT_SECTION symbol against a ++ processor specific section. If we have ++ discarded a section, the output_section will ++ be the absolute section. */ ++ if (bfd_is_abs_section (sec) ++ || (sec != NULL ++ && bfd_is_abs_section (sec->output_section))) ++ r_symndx = 0; ++ else if (sec == NULL || sec->owner == NULL) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ else ++ { ++ r_symndx = sec->output_section->target_index; ++ BFD_ASSERT (r_symndx != 0); ++ } ++ ++ /* Adjust the addend according to where the ++ section winds up in the output section. */ ++ if (rela_normal) ++ irela->r_addend += sec->output_offset; ++ } ++ else ++ { ++ if (finfo->indices[r_symndx] == -1) ++ { ++ unsigned long shlink; ++ const char *name; ++ asection *osec; ++ ++ if (finfo->info->strip == strip_all) ++ { ++ /* You can't do ld -r -s. */ ++ bfd_set_error (bfd_error_invalid_operation); ++ return false; ++ } ++ ++ /* This symbol was skipped earlier, but ++ since it is needed by a reloc, we ++ must output it now. */ ++ shlink = symtab_hdr->sh_link; ++ name = (bfd_elf_string_from_elf_section ++ (input_bfd, shlink, sym.st_name)); ++ if (name == NULL) ++ return false; ++ ++ osec = sec->output_section; ++ sym.st_shndx = ++ _bfd_elf_section_from_bfd_section (output_bfd, ++ osec); ++ if (sym.st_shndx == SHN_BAD) ++ return false; ++ ++ sym.st_value += sec->output_offset; ++#if 0 ++ if (! finfo->info->relocateable) ++ { ++ sym.st_value += osec->vma; ++ if (ELF_ST_TYPE (sym.st_info) == STT_TLS) ++ { ++ /* STT_TLS symbols are relative to PT_TLS ++ segment base. */ ++ BFD_ASSERT (finfo->first_tls_sec != NULL); ++ sym.st_value -= finfo->first_tls_sec->vma; ++ } ++ } ++#endif ++ ++ finfo->indices[r_symndx] ++ = bfd_get_symcount (output_bfd); ++ ++ if (! elf_link_output_sym (finfo, name, &sym, sec)) ++ return false; ++ } ++ ++ r_symndx = finfo->indices[r_symndx]; ++ } ++ ++ irela->r_info = ELF_R_INFO (r_symndx, ++ ELF_R_TYPE (irela->r_info)); ++ } ++ ++ /* Swap out the relocs. */ ++ if (bed->elf_backend_emit_relocs ++ && !(finfo->info->relocateable ++ || finfo->info->emitrelocations)) ++ reloc_emitter = bed->elf_backend_emit_relocs; ++ else ++ reloc_emitter = elf_link_output_relocs; ++ ++ if (input_rel_hdr->sh_size != 0 ++ && ! (*reloc_emitter) (output_bfd, o, input_rel_hdr, ++ internal_relocs)) ++ return false; ++ ++ input_rel_hdr2 = elf_section_data (o)->rel_hdr2; ++ if (input_rel_hdr2 && input_rel_hdr2->sh_size != 0) ++ { ++ internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr) ++ * bed->s->int_rels_per_ext_rel); ++ if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr2, ++ internal_relocs)) ++ return false; ++ } ++ } ++ } ++ ++ /* Write out the modified section contents. */ ++ if (bed->elf_backend_write_section ++ && (*bed->elf_backend_write_section) (output_bfd, o, contents)) ++ { ++ /* Section written out. */ ++ } ++ else switch (elf_section_data (o)->sec_info_type) ++ { ++ case ELF_INFO_TYPE_STABS: ++ if (! (_bfd_write_section_stabs ++ (output_bfd, ++ &elf_hash_table (finfo->info)->stab_info, ++ o, &elf_section_data (o)->sec_info, contents))) ++ return false; ++ break; ++ case ELF_INFO_TYPE_MERGE: ++ if (! (_bfd_write_merged_section ++ (output_bfd, o, elf_section_data (o)->sec_info))) ++ return false; ++ break; ++ case ELF_INFO_TYPE_EH_FRAME: ++ { ++ asection *ehdrsec; ++ ++ ehdrsec ++ = bfd_get_section_by_name (elf_hash_table (finfo->info)->dynobj, ++ ".eh_frame_hdr"); ++ if (! (_bfd_elf_write_section_eh_frame (output_bfd, o, ehdrsec, ++ contents))) ++ return false; ++ } ++ break; ++ default: ++ { ++ bfd_size_type sec_size; ++ ++ sec_size = (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size); ++ if (! (o->flags & SEC_EXCLUDE) ++ && ! bfd_set_section_contents (output_bfd, o->output_section, ++ contents, ++ (file_ptr) o->output_offset, ++ sec_size)) ++ return false; ++ } ++ break; ++ } ++ } ++ ++ return true; ++} ++ ++/* Generate a reloc when linking an ELF file. This is a reloc ++ requested by the linker, and does come from any input file. This ++ is used to build constructor and destructor tables when linking ++ with -Ur. */ ++ ++static boolean ++elf_reloc_link_order (output_bfd, info, output_section, link_order) ++ bfd *output_bfd; ++ struct bfd_link_info *info; ++ asection *output_section; ++ struct bfd_link_order *link_order; ++{ ++ reloc_howto_type *howto; ++ long indx; ++ bfd_vma offset; ++ bfd_vma addend; ++ struct elf_link_hash_entry **rel_hash_ptr; ++ Elf_Internal_Shdr *rel_hdr; ++ struct elf_backend_data *bed = get_elf_backend_data (output_bfd); ++ ++ howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); ++ if (howto == NULL) ++ { ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } ++ ++ addend = link_order->u.reloc.p->addend; ++ ++ /* Figure out the symbol index. */ ++ rel_hash_ptr = (elf_section_data (output_section)->rel_hashes ++ + elf_section_data (output_section)->rel_count ++ + elf_section_data (output_section)->rel_count2); ++ if (link_order->type == bfd_section_reloc_link_order) ++ { ++ indx = link_order->u.reloc.p->u.section->target_index; ++ BFD_ASSERT (indx != 0); ++ *rel_hash_ptr = NULL; ++ } ++ else ++ { ++ struct elf_link_hash_entry *h; ++ ++ /* Treat a reloc against a defined symbol as though it were ++ actually against the section. */ ++ h = ((struct elf_link_hash_entry *) ++ bfd_wrapped_link_hash_lookup (output_bfd, info, ++ link_order->u.reloc.p->u.name, ++ false, false, true)); ++ if (h != NULL ++ && (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak)) ++ { ++ asection *section; ++ ++ section = h->root.u.def.section; ++ indx = section->output_section->target_index; ++ *rel_hash_ptr = NULL; ++ /* It seems that we ought to add the symbol value to the ++ addend here, but in practice it has already been added ++ because it was passed to constructor_callback. */ ++ addend += section->output_section->vma + section->output_offset; ++ } ++ else if (h != NULL) ++ { ++ /* Setting the index to -2 tells elf_link_output_extsym that ++ this symbol is used by a reloc. */ ++ h->indx = -2; ++ *rel_hash_ptr = h; ++ indx = 0; ++ } ++ else ++ { ++ if (! ((*info->callbacks->unattached_reloc) ++ (info, link_order->u.reloc.p->u.name, (bfd *) NULL, ++ (asection *) NULL, (bfd_vma) 0))) ++ return false; ++ indx = 0; ++ } ++ } ++ ++ /* If this is an inplace reloc, we must write the addend into the ++ object file. */ ++ if (howto->partial_inplace && addend != 0) ++ { ++ bfd_size_type size; ++ bfd_reloc_status_type rstat; ++ bfd_byte *buf; ++ boolean ok; ++ const char *sym_name; ++ ++ size = bfd_get_reloc_size (howto); ++ buf = (bfd_byte *) bfd_zmalloc (size); ++ if (buf == (bfd_byte *) NULL) ++ return false; ++ rstat = _bfd_relocate_contents (howto, output_bfd, (bfd_vma) addend, buf); ++ switch (rstat) ++ { ++ case bfd_reloc_ok: ++ break; ++ ++ default: ++ case bfd_reloc_outofrange: ++ abort (); ++ ++ case bfd_reloc_overflow: ++ if (link_order->type == bfd_section_reloc_link_order) ++ sym_name = bfd_section_name (output_bfd, ++ link_order->u.reloc.p->u.section); ++ else ++ sym_name = link_order->u.reloc.p->u.name; ++ if (! ((*info->callbacks->reloc_overflow) ++ (info, sym_name, howto->name, addend, ++ (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) ++ { ++ free (buf); ++ return false; ++ } ++ break; ++ } ++ ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, ++ (file_ptr) link_order->offset, size); ++ free (buf); ++ if (! ok) ++ return false; ++ } ++ ++ /* The address of a reloc is relative to the section in a ++ relocateable file, and is a virtual address in an executable ++ file. */ ++ offset = link_order->offset; ++ if (! info->relocateable) ++ offset += output_section->vma; ++ ++ rel_hdr = &elf_section_data (output_section)->rel_hdr; ++ ++ if (rel_hdr->sh_type == SHT_REL) ++ { ++ bfd_size_type size; ++ Elf_Internal_Rel *irel; ++ Elf_External_Rel *erel; ++ unsigned int i; ++ ++ size = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rel); ++ irel = (Elf_Internal_Rel *) bfd_zmalloc (size); ++ if (irel == NULL) ++ return false; ++ ++ for (i = 0; i < bed->s->int_rels_per_ext_rel; i++) ++ irel[i].r_offset = offset; ++ irel[0].r_info = ELF_R_INFO (indx, howto->type); ++ ++ erel = ((Elf_External_Rel *) rel_hdr->contents ++ + elf_section_data (output_section)->rel_count); ++ ++ if (bed->s->swap_reloc_out) ++ (*bed->s->swap_reloc_out) (output_bfd, irel, (bfd_byte *) erel); ++ else ++ elf_swap_reloc_out (output_bfd, irel, erel); ++ ++ free (irel); ++ } ++ else ++ { ++ bfd_size_type size; ++ Elf_Internal_Rela *irela; ++ Elf_External_Rela *erela; ++ unsigned int i; ++ ++ size = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela); ++ irela = (Elf_Internal_Rela *) bfd_zmalloc (size); ++ if (irela == NULL) ++ return false; ++ ++ for (i = 0; i < bed->s->int_rels_per_ext_rel; i++) ++ irela[i].r_offset = offset; ++ irela[0].r_info = ELF_R_INFO (indx, howto->type); ++ irela[0].r_addend = addend; ++ ++ erela = ((Elf_External_Rela *) rel_hdr->contents ++ + elf_section_data (output_section)->rel_count); ++ ++ if (bed->s->swap_reloca_out) ++ (*bed->s->swap_reloca_out) (output_bfd, irela, (bfd_byte *) erela); ++ else ++ elf_swap_reloca_out (output_bfd, irela, erela); ++ } ++ ++ ++elf_section_data (output_section)->rel_count; ++ ++ return true; ++} ++ ++static boolean ++elf_section_ignore_discarded_relocs (sec) ++ asection *sec; ++{ ++ struct elf_backend_data *bed; ++ ++ switch (elf_section_data (sec)->sec_info_type) ++ { ++ case ELF_INFO_TYPE_STABS: ++ case ELF_INFO_TYPE_EH_FRAME: ++ return true; ++ default: ++ break; ++ } ++ ++ bed = get_elf_backend_data (sec->owner); ++ if (bed->elf_backend_ignore_discarded_relocs != NULL ++ && (*bed->elf_backend_ignore_discarded_relocs) (sec)) ++ return true; ++ ++ return false; ++} ++ ++#define TARGET_BIG_SYM bfd_elf32_morphos_vec ++#define TARGET_BIG_NAME "elf32-morphos" ++#define ELF_ARCH bfd_arch_powerpc ++#define ELF_MACHINE_CODE EM_PPC ++#define ELF_MAXPAGESIZE 0x10000 ++#define elf_info_to_howto ppc_elf_info_to_howto ++ ++#ifdef EM_CYGNUS_POWERPC ++#define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC ++#endif ++ ++#ifdef EM_PPC_OLD ++#define ELF_MACHINE_ALT2 EM_PPC_OLD ++#endif ++ ++#define elf_backend_plt_not_loaded 1 ++#define elf_backend_got_symbol_offset 4 ++#define elf_backend_can_gc_sections 1 ++#define elf_backend_can_refcount 1 ++#define elf_backend_got_header_size 12 ++#define elf_backend_plt_header_size PLT_INITIAL_ENTRY_SIZE ++#define elf_backend_rela_normal 1 ++ ++#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data ++#define bfd_elf32_bfd_relax_section ppc_elf_relax_section ++#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup ++#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags ++/*#define bfd_elf32_bfd_final_link _bfd_elf32_gc_common_final_link*/ ++#define bfd_elf32_bfd_final_link ppc_elf_final_link ++ ++#define elf_backend_object_p ppc_elf_object_p ++#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook ++#define elf_backend_gc_sweep_hook ppc_elf_gc_sweep_hook ++#define elf_backend_section_from_shdr ppc_elf_section_from_shdr ++#define elf_backend_relocate_section ppc_elf_relocate_section ++#define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections ++#define elf_backend_check_relocs ppc_elf_check_relocs ++#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol ++/*#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook*/ ++#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections ++#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol ++#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections ++#define elf_backend_fake_sections ppc_elf_fake_sections ++#define elf_backend_additional_program_headers ppc_elf_additional_program_headers ++#define elf_backend_modify_segment_map ppc_elf_modify_segment_map ++#define elf_backend_grok_prstatus ppc_elf_grok_prstatus ++#define elf_backend_grok_psinfo ppc_elf_grok_psinfo ++#define elf_backend_reloc_type_class ppc_elf_reloc_type_class ++ ++#include "elf32-target.h" +diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c +index 6454a8350da35adf6ed1e2209d9e4774ab7c50e3..5c92c53da7b3dec8f85a0a0b930190635f89dcfb 100644 +--- a/bfd/elf32-ppc.c ++++ b/bfd/elf32-ppc.c +@@ -4412,12 +4412,16 @@ ppc_elf_check_relocs (bfd *abfd, + p->count += 1; + if (!must_be_dyn_reloc (info, r_type)) + p->pc_count += 1; + } + + break; ++ ++ default: ++ fprintf(stderr,"Switch case not handled!\n"); ++ break; + } + } + + return TRUE; + } + +diff --git a/bfd/hosts/amigaos.h b/bfd/hosts/amigaos.h +new file mode 100644 +index 0000000000000000000000000000000000000000..dc62d7f837f333ae8d2c5b47d01144cb0d3625f2 +--- /dev/null ++++ b/bfd/hosts/amigaos.h +@@ -0,0 +1,5 @@ ++/* Host configuration for AmigaOS */ ++#ifndef hosts_amigaos_h ++#define hosts_amigaos_h ++#include "hosts/std-host.h" ++#endif /* hosts_amigaos_h */ +diff --git a/bfd/hosts/morphos.h b/bfd/hosts/morphos.h +new file mode 100644 +index 0000000000000000000000000000000000000000..d3c60ea9f5767ad0bfa22ba2c8c1e5ed9d94d481 +--- /dev/null ++++ b/bfd/hosts/morphos.h +@@ -0,0 +1,5 @@ ++/* Host configuration for MorphOS */ ++#ifndef hosts_morphos_h ++#define hosts_morphos_h ++#include "hosts/std-host.h" ++#endif /* hosts_morphos_h */ +diff --git a/bfd/libamiga.h b/bfd/libamiga.h +new file mode 100644 +index 0000000000000000000000000000000000000000..351f0fa16a45680982f5b5807c8ba756defe1764 +--- /dev/null ++++ b/bfd/libamiga.h +@@ -0,0 +1,187 @@ ++/* BFD back-end for Commodore-Amiga AmigaOS binaries. Data structures. ++ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998 ++ Free Software Foundation, Inc. ++ Contributed by Leonard Norrgard. ++ Extended by Stephan Thesing 11/1994. ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++ ++/* Hunk ID numbers. */ ++ ++#define HUNK_UNIT 999 ++#define HUNK_NAME 1000 ++#define HUNK_CODE 1001 ++#define HUNK_DATA 1002 ++#define HUNK_BSS 1003 ++#define HUNK_RELOC32 1004 ++#define HUNK_ABSRELOC32 HUNK_RELOC32 ++#define HUNK_RELOC16 1005 ++#define HUNK_RELRELOC16 HUNK_RELOC16 ++#define HUNK_RELOC8 1006 ++#define HUNK_RELRELOC8 HUNK_RELOC8 ++#define HUNK_EXT 1007 ++#define HUNK_SYMBOL 1008 ++#define HUNK_DEBUG 1009 ++#define HUNK_END 1010 ++#define HUNK_HEADER 1011 ++#define HUNK_OVERLAY 1013 ++#define HUNK_BREAK 1014 ++#define HUNK_DREL32 1015 ++#define HUNK_DREL16 1016 ++#define HUNK_DREL8 1017 ++#define HUNK_LIB 1018 ++#define HUNK_INDEX 1019 ++#define HUNK_RELOC32SHORT 1020 ++#define HUNK_RELRELOC32 1021 ++#define HUNK_ABSRELOC16 1022 ++/* EHF extensions */ ++#define HUNK_PPC_CODE 1257 ++#define HUNK_RELRELOC26 1260 ++ ++/* The hunk ID part. */ ++ ++#define HUNK_VALUE(hunk_id) ((hunk_id) & 0x3fffffff) ++ ++/* Attributes of a hunk. */ ++ ++#define HUNK_ATTRIBUTE(hunk_id) ((hunk_id) >> 30) ++#define HUNK_ATTR_CHIP 0x01 /* hunk content must go into chip ram */ ++#define HUNK_ATTR_FAST 0x02 /* fast */ ++#define HUNK_ATTR_FOLLOWS 0x03 /* mem id follows */ ++ ++/* HUNK_EXT subtypes. */ ++ ++#define EXT_SYMB 0 ++#define EXT_DEF 1 ++#define EXT_ABS 2 ++#define EXT_RES 3 ++#define EXT_REF32 129 ++#define EXT_ABSREF32 EXT_REF32 ++#define EXT_COMMON 130 ++#define EXT_ABSCOMMON EXT_COMMON ++#define EXT_REF16 131 ++#define EXT_RELREF16 EXT_REF16 ++#define EXT_REF8 132 ++#define EXT_RELREF8 EXT_REF8 ++#define EXT_DEXT32 133 ++#define EXT_DEXT16 134 ++#define EXT_DEXT8 135 ++#define EXT_RELREF32 136 ++#define EXT_RELCOMMON 137 ++#define EXT_ABSREF16 138 ++#define EXT_ABSREF8 139 ++/* VBCC extensions */ ++#define EXT_DEXT32COMMON 208 ++#define EXT_DEXT16COMMON 209 ++#define EXT_DEXT8COMMON 210 ++/* EHF extensions */ ++#define EXT_RELREF26 229 ++ ++/* HOWTO types almost matching aoutx.h/howto_table_std. */ ++ ++enum { ++ H_ABS8=0,H_ABS16,H_ABS32,H_ABS32SHORT,H_PC8,H_PC16,H_PC32,H_PC26,H_SD8,H_SD16,H_SD32 ++}; ++ ++/* Various structures. */ ++ ++typedef struct amiga_reloc { ++ arelent relent; ++ struct amiga_reloc *next; ++ asymbol *symbol; ++} amiga_reloc_type; ++ ++/* Structure layout *must* match libaout.h/struct aout_symbol. */ ++ ++typedef struct amiga_symbol { ++ asymbol symbol; ++ short desc; ++ char other; ++ unsigned char type; ++ /* amiga data */ ++ unsigned long index,refnum; ++} amiga_symbol_type; ++ ++/* We take the address of the first element of an asymbol to ensure that the ++ macro is only ever applied to an asymbol. */ ++#define amiga_symbol(asymbol) ((amiga_symbol_type *)(&(asymbol)->the_bfd)) ++ ++typedef struct raw_reloc { ++ unsigned long num,pos; ++ struct raw_reloc *next; ++} raw_reloc_type; ++ ++typedef struct amiga_per_section { ++ amiga_reloc_type *reloc_tail; /* last reloc, first is in section->relocation */ ++ int attribute; /* Memory type required by this section */ ++ unsigned long disk_size; /* Section size on disk, _raw_size may be larger than this */ ++ amiga_symbol_type *amiga_symbols; /* the symbols for this section */ ++ unsigned long hunk_ext_pos; /* offset of hunk_ext in the bfd file */ ++ unsigned long hunk_symbol_pos; /* offset of hunk_symbol in the bfd file */ ++ raw_reloc_type *relocs; ++} amiga_per_section_type; ++ ++#define amiga_per_section(x) ((amiga_per_section_type *)((x)->used_by_bfd)) ++ ++/* Structure layout *must* match libaout.h/struct aoutdata. */ ++ ++struct amiga_data { ++ char *dummy[2]; ++ sec_ptr textsec; ++ sec_ptr datasec; ++ sec_ptr bsssec; ++ file_ptr sym_filepos; ++ file_ptr str_filepos; ++ /* rest intentionally omitted */ ++}; ++ ++typedef struct amiga_data_struct { ++ struct amiga_data a; ++ unsigned long symtab_size; ++ unsigned long stringtab_size; ++ amiga_symbol_type *symbols; ++ bfd_boolean IsLoadFile; /* If true, this is a load file (for output bfd only) */ ++ unsigned int nb_hunks; ++ /* The next two fields are set at final_link time (for the output bfd only) */ ++ bfd_boolean baserel;/* true if there is ___init_a4 in the global hash table */ ++ bfd_vma a4init; /* cache the value for efficiency */ ++} amiga_data_type; ++ ++#define adata(bfd) ((bfd)->tdata.amiga_data->a) ++#define AMIGA_DATA(bfd) ((bfd)->tdata.amiga_data) ++ ++#define HUNKB_ADVISORY 29 ++#define HUNKB_CHIP 30 ++#define HUNKB_FAST 31 ++#define HUNKF_ADVISORY (1L << HUNKB_ADVISORY) ++#define HUNKF_CHIP (1L << HUNKB_CHIP) ++#define HUNKF_FAST (1L << HUNKB_FAST) ++ ++#ifndef MEMF_ANY ++#define MEMF_ANY (0L) ++#define MEMF_PUBLIC (1L << 0) ++#define MEMF_CHIP (1L << 1) ++#define MEMF_FAST (1L << 2) ++#define MEMF_LOCAL (1L << 8) ++#define MEMF_24BITDMA (1L << 9) ++#define MEMF_KICK (1L << 10) ++#define MEMF_CLEAR (1L << 16) ++#define MEMF_LARGEST (1L << 17) ++#define MEMF_REVERSE (1L << 18) ++#define MEMF_TOTAL (1L << 19) ++#define MEMF_NO_EXPUNGE (1L << 31) ++#endif /* MEMF_ANY */ +diff --git a/bfd/libbfd.h b/bfd/libbfd.h +index 6c48d641f606b9ed6158b4567021769bacfbd54a..3cb9b36fe2379a5d7f118472e106c151d6153aea 100644 +--- a/bfd/libbfd.h ++++ b/bfd/libbfd.h +@@ -1345,12 +1345,16 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", + "BFD_RELOC_PPC_EMB_RELSEC16", + "BFD_RELOC_PPC_EMB_RELST_LO", + "BFD_RELOC_PPC_EMB_RELST_HI", + "BFD_RELOC_PPC_EMB_RELST_HA", + "BFD_RELOC_PPC_EMB_BIT_FLD", + "BFD_RELOC_PPC_EMB_RELSDA", ++ "BFD_RELOC_PPC_MORPHOS_DREL", ++ "BFD_RELOC_PPC_MORPHOS_DREL_LO", ++ "BFD_RELOC_PPC_MORPHOS_DREL_HI", ++ "BFD_RELOC_PPC_MORPHOS_DREL_HA", + "BFD_RELOC_PPC_VLE_REL8", + "BFD_RELOC_PPC_VLE_REL15", + "BFD_RELOC_PPC_VLE_REL24", + "BFD_RELOC_PPC_VLE_LO16A", + "BFD_RELOC_PPC_VLE_LO16D", + "BFD_RELOC_PPC_VLE_HI16A", +@@ -1427,12 +1431,16 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", + "BFD_RELOC_PPC64_DTPREL16_DS", + "BFD_RELOC_PPC64_DTPREL16_LO_DS", + "BFD_RELOC_PPC64_DTPREL16_HIGHER", + "BFD_RELOC_PPC64_DTPREL16_HIGHERA", + "BFD_RELOC_PPC64_DTPREL16_HIGHEST", + "BFD_RELOC_PPC64_DTPREL16_HIGHESTA", ++ "BFD_RELOC_PPC_AMIGAOS_BREL", ++ "BFD_RELOC_PPC_AMIGAOS_BREL_LO", ++ "BFD_RELOC_PPC_AMIGAOS_BREL_HI", ++ "BFD_RELOC_PPC_AMIGAOS_BREL_HA", + "BFD_RELOC_I370_D12", + "BFD_RELOC_CTOR", + "BFD_RELOC_ARM_PCREL_BRANCH", + "BFD_RELOC_ARM_PCREL_BLX", + "BFD_RELOC_THUMB_PCREL_BLX", + "BFD_RELOC_ARM_PCREL_CALL", +diff --git a/bfd/linker.c b/bfd/linker.c +index d3ef9a43a5bca8096221870248daf58007c6ef78..4f0aa188f5017ea68023530f6ae9eaa6b98b5b11 100644 +--- a/bfd/linker.c ++++ b/bfd/linker.c +@@ -430,13 +430,14 @@ static bfd_boolean generic_link_add_symbol_list + (bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **, + bfd_boolean); + static bfd_boolean generic_add_output_symbol + (bfd *, size_t *psymalloc, asymbol *); + static bfd_boolean default_data_link_order + (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *); +-static bfd_boolean default_indirect_link_order ++/*Amiga hack - used in amigaoslink.c so must be global */ ++/*static*/ bfd_boolean default_indirect_link_order + (bfd *, struct bfd_link_info *, asection *, struct bfd_link_order *, + bfd_boolean); + + /* The link hash table structure is defined in bfdlink.h. It provides + a base hash table which the backend specific hash tables are built + upon. */ +@@ -1294,12 +1295,19 @@ generic_link_check_archive_element (bfd *abfd, + return FALSE; + + size = bfd_asymbol_value (p); + h->u.c.size = size; + + power = bfd_log2 (size); ++ /* For the amiga, we don't want an alignment bigger than 2**2. ++ Doing this here is horrible kludgy, but IMHO the maximal ++ power alignment really should be target-dependant so that ++ we wouldn't have to do this -- daniel */ ++ if (info->output_bfd->xvec->flavour == bfd_target_amiga_flavour ++ && power > 2) ++ power = 2; + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + + if (p->section == bfd_com_section_ptr) + h->u.c.p->section = bfd_make_section_old_way (symbfd, "COMMON"); +@@ -1746,12 +1754,19 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, + /* Select a default alignment based on the size. This may + be overridden by the caller. */ + { + unsigned int power; + + power = bfd_log2 (value); ++ /* For the amiga, we don't want an alignment bigger than 2**2. ++ Doing this here is horrible kludgy, but IMHO the maximal ++ power alignment really should be target-dependant so that ++ we wouldn't have to do this -- daniel */ ++ if (info->output_bfd->xvec->flavour == bfd_target_amiga_flavour ++ && power > 2) ++ power = 2; + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + } + + /* The section of a common symbol is only used if the common +@@ -1799,12 +1814,19 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, + + h->u.c.size = value; + + /* Select a default alignment based on the size. This may + be overridden by the caller. */ + power = bfd_log2 (value); ++ /* For the amiga, we don't want an alignment bigger than 2**2. ++ Doing this here is horrible kludgy, but IMHO the maximal ++ power alignment really should be target-dependant so that ++ we wouldn't have to do this -- daniel */ ++ if (info->output_bfd->xvec->flavour == bfd_target_amiga_flavour ++ && power > 2) ++ power = 2; + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + + /* Some systems have special treatment for small commons, + hence we want to select the section used by the larger +@@ -2709,13 +2731,13 @@ default_data_link_order (bfd *abfd, + free (fill); + return result; + } + + /* Default routine to handle a bfd_indirect_link_order. */ + +-static bfd_boolean ++/*static*/ bfd_boolean + default_indirect_link_order (bfd *output_bfd, + struct bfd_link_info *info, + asection *output_section, + struct bfd_link_order *link_order, + bfd_boolean generic_linker) + { +diff --git a/bfd/reloc.c b/bfd/reloc.c +index 47d052d1345847a7178f4c7ebe4f529396ae0a4f..6c3bb68f2da65b201b6288b8709fd60d9b0d5b2c 100644 +--- a/bfd/reloc.c ++++ b/bfd/reloc.c +@@ -2803,12 +2803,20 @@ ENUMX + BFD_RELOC_PPC_EMB_RELST_HA + ENUMX + BFD_RELOC_PPC_EMB_BIT_FLD + ENUMX + BFD_RELOC_PPC_EMB_RELSDA + ENUMX ++ BFD_RELOC_PPC_MORPHOS_DREL ++ENUMX ++ BFD_RELOC_PPC_MORPHOS_DREL_LO ++ENUMX ++ BFD_RELOC_PPC_MORPHOS_DREL_HI ++ENUMX ++ BFD_RELOC_PPC_MORPHOS_DREL_HA ++ENUMX + BFD_RELOC_PPC_VLE_REL8 + ENUMX + BFD_RELOC_PPC_VLE_REL15 + ENUMX + BFD_RELOC_PPC_VLE_REL24 + ENUMX +@@ -2973,12 +2981,23 @@ ENUMX + ENUMX + BFD_RELOC_PPC64_DTPREL16_HIGHESTA + ENUMDOC + PowerPC and PowerPC64 thread-local storage relocations. + + ENUM ++ BFD_RELOC_PPC_AMIGAOS_BREL ++ENUMX ++ BFD_RELOC_PPC_AMIGAOS_BREL_LO ++ENUMX ++ BFD_RELOC_PPC_AMIGAOS_BREL_HI ++ENUMX ++ BFD_RELOC_PPC_AMIGAOS_BREL_HA ++ENUMDOC ++ AmigaOS4 PowerPC specific base-relative relocations. ++ ++ENUM + BFD_RELOC_I370_D12 + ENUMDOC + IBM 370/390 relocations + + ENUM + BFD_RELOC_CTOR +diff --git a/bfd/targets.c b/bfd/targets.c +index fa206d24bef3a22255f6be42221647db3142eb06..9df24504bab564048f724fbbb641ca13c5805602 100644 +--- a/bfd/targets.c ++++ b/bfd/targets.c +@@ -144,12 +144,13 @@ DESCRIPTION + the entry points which call them. Too bad we can't have one + macro to define them both! + + .enum bfd_flavour + .{ + . bfd_target_unknown_flavour, ++. bfd_target_amiga_flavour, + . bfd_target_aout_flavour, + . bfd_target_coff_flavour, + . bfd_target_ecoff_flavour, + . bfd_target_xcoff_flavour, + . bfd_target_elf_flavour, + . bfd_target_ieee_flavour, +@@ -568,12 +569,14 @@ to find an alternative output format that is suitable. + /* All known xvecs (even those that don't compile on all systems). + Alphabetized for easy reference. + They are listed a second time below, since + we can't intermix extern's and initializers. */ + extern const bfd_target a_out_adobe_vec; + extern const bfd_target aix5coff64_vec; ++extern const bfd_target amiga_vec; ++extern const bfd_target aout_amiga_vec; + extern const bfd_target aout0_big_vec; + extern const bfd_target aout_arm_big_vec; + extern const bfd_target aout_arm_little_vec; + extern const bfd_target aout_mips_big_vec; + extern const bfd_target aout_mips_little_vec; + extern const bfd_target apollocoff_vec; +@@ -592,12 +595,13 @@ extern const bfd_target armpe_big_vec; + extern const bfd_target armpe_little_vec; + extern const bfd_target armpei_big_vec; + extern const bfd_target armpei_little_vec; + extern const bfd_target b_out_vec_big_host; + extern const bfd_target b_out_vec_little_host; + extern const bfd_target bfd_pei_ia64_vec; ++extern const bfd_target bfd_elf32_amigaos_vec; + extern const bfd_target bfd_elf32_avr_vec; + extern const bfd_target bfd_elf32_bfin_vec; + extern const bfd_target bfd_elf32_bfinfdpic_vec; + extern const bfd_target bfd_elf32_big_generic_vec; + extern const bfd_target bfd_elf32_bigarc_vec; + extern const bfd_target bfd_elf32_bigarm_vec; +@@ -625,12 +629,13 @@ extern const bfd_target bfd_elf32_hppa_vec; + extern const bfd_target bfd_elf32_i370_vec; + extern const bfd_target bfd_elf32_i386_freebsd_vec; + extern const bfd_target bfd_elf32_i386_nacl_vec; + extern const bfd_target bfd_elf32_i386_sol2_vec; + extern const bfd_target bfd_elf32_i386_vxworks_vec; + extern const bfd_target bfd_elf32_i386_vec; ++extern const bfd_target bfd_elf32_i386be_amithlon_vec; + extern const bfd_target bfd_elf32_i860_little_vec; + extern const bfd_target bfd_elf32_i860_vec; + extern const bfd_target bfd_elf32_i960_vec; + extern const bfd_target bfd_elf32_ia64_big_vec; + extern const bfd_target bfd_elf32_ia64_hpux_big_vec; + extern const bfd_target bfd_elf32_ip2k_vec; +@@ -658,12 +663,13 @@ extern const bfd_target bfd_elf32_mcore_big_vec; + extern const bfd_target bfd_elf32_mcore_little_vec; + extern const bfd_target bfd_elf32_mep_vec; + extern const bfd_target bfd_elf32_mep_little_vec; + extern const bfd_target bfd_elf32_microblaze_vec; + extern const bfd_target bfd_elf32_mn10200_vec; + extern const bfd_target bfd_elf32_mn10300_vec; ++extern const bfd_target bfd_elf32_morphos_vec; + extern const bfd_target bfd_elf32_mt_vec; + extern const bfd_target bfd_elf32_msp430_vec; + extern const bfd_target bfd_elf32_nbigmips_vec; + extern const bfd_target bfd_elf32_nlittlemips_vec; + extern const bfd_target bfd_elf32_ntradbigmips_vec; + extern const bfd_target bfd_elf32_ntradlittlemips_vec; +@@ -929,12 +935,14 @@ static const bfd_target * const _bfd_target_vector[] = + should have an entry here with #if 0 around it, to show that + it wasn't omitted by mistake. */ + &a_out_adobe_vec, + #ifdef BFD64 + &aix5coff64_vec, + #endif ++ &amiga_vec, ++ &aout_amiga_vec, + &aout0_big_vec, + #if 0 + /* We have no way of distinguishing these from other a.out variants. */ + &aout_arm_big_vec, + &aout_arm_little_vec, + /* No one seems to use this. */ +@@ -961,12 +969,13 @@ static const bfd_target * const _bfd_target_vector[] = + &armpei_little_vec, + &b_out_vec_big_host, + &b_out_vec_little_host, + #ifdef BFD64 + &bfd_pei_ia64_vec, + #endif ++ &bfd_elf32_amigaos_vec, + &bfd_elf32_avr_vec, + &bfd_elf32_bfin_vec, + &bfd_elf32_bfinfdpic_vec, + + /* This, and other vectors, may not be used in any *.mt configuration. + But that does not mean they are unnecessary. If configured with +@@ -998,12 +1007,13 @@ static const bfd_target * const _bfd_target_vector[] = + &bfd_elf32_i370_vec, + &bfd_elf32_i386_freebsd_vec, + &bfd_elf32_i386_nacl_vec, + &bfd_elf32_i386_sol2_vec, + &bfd_elf32_i386_vxworks_vec, + &bfd_elf32_i386_vec, ++ &bfd_elf32_i386be_amithlon_vec, + &bfd_elf32_i860_little_vec, + &bfd_elf32_i860_vec, + &bfd_elf32_i960_vec, + #if 0 + &bfd_elf32_ia64_big_vec, + #endif +@@ -1032,12 +1042,13 @@ static const bfd_target * const _bfd_target_vector[] = + &bfd_elf32_mcore_big_vec, + &bfd_elf32_mcore_little_vec, + &bfd_elf32_mep_vec, + &bfd_elf32_microblaze_vec, + &bfd_elf32_mn10200_vec, + &bfd_elf32_mn10300_vec, ++ &bfd_elf32_morphos_vec, + &bfd_elf32_mt_vec, + &bfd_elf32_msp430_vec, + #ifdef BFD64 + &bfd_elf32_nbigmips_vec, + &bfd_elf32_nlittlemips_vec, + &bfd_elf32_ntradbigmips_vec, +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index 020d54d6fbe27a5c90600e1d034a93e8fade0ff6..88bd071eefa8b5426eaadfd6431e9de5d4a4591b 100644 +--- a/binutils/objcopy.c ++++ b/binutils/objcopy.c +@@ -1101,12 +1101,17 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, + bfd_boolean undefined; + bfd_boolean rem_leading_char; + bfd_boolean add_leading_char; + + undefined = bfd_is_und_section (bfd_get_section (sym)); + ++ if (strip_symbols == STRIP_ALL && undefined) ++ { ++ add_specific_symbol(name, keep_specific_htab); ++ } ++ + if (redefine_sym_list) + { + char *old_name, *new_name; + + old_name = (char *) bfd_asymbol_name (sym); + new_name = (char *) lookup_sym_redefinition (old_name); +@@ -1162,13 +1167,18 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, + strcpy (ptr, name); + bfd_asymbol_name (sym) = n; + name = n; + } + + if (strip_symbols == STRIP_ALL) +- keep = FALSE; ++ { ++ if (strcmp(name, "_start") == 0 || strcmp(name, "__amigaos4__") == 0 || strcmp(name, "_SDA_BASE_") == 0) ++ keep = TRUE; ++ else ++ keep = FALSE; ++ } + else if ((flags & BSF_KEEP) != 0 /* Used in relocation. */ + || ((flags & BSF_SECTION_SYM) != 0 + && ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags + & BSF_KEEP) != 0)) + { + keep = TRUE; +@@ -1925,13 +1935,13 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) + + Note we iterate over the input sections examining their + relocations since the relocations for the output sections + haven't been set yet. mark_symbols_used_in_relocations will + ignore input sections which have no corresponding output + section. */ +- if (strip_symbols != STRIP_ALL) ++// if (strip_symbols != STRIP_ALL) + bfd_map_over_sections (ibfd, + mark_symbols_used_in_relocations, + isympp); + osympp = (asymbol **) xmalloc ((symcount + 1) * sizeof (asymbol *)); + symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount); + } +@@ -2745,25 +2755,48 @@ copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg) + status = 1; + bfd_nonfatal_message (NULL, ibfd, isection, + _("relocation count is negative")); + return; + } + +- if (strip_symbols == STRIP_ALL) ++ /* Never, ever, strip reloc data on the Amiga! */ ++ if (strip_symbols == STRIP_ALL && ++ bfd_get_flavour(obfd) != bfd_target_amiga_flavour) + { + /* Remove relocations which are not in + keep_strip_specific_list. */ + arelent **temp_relpp; + long temp_relcount = 0; + long i; + + temp_relpp = (arelent **) xmalloc (relsize); + for (i = 0; i < relcount; i++) ++ { ++ asection *sec; ++ sec = bfd_get_section(*relpp[i]->sym_ptr_ptr); ++ ++// printf("%d: %s (0x%lx + 0x%lx) value 0x%lx (in section %s)\n", ++// i, bfd_asymbol_name (*relpp [i]->sym_ptr_ptr), relpp [i]->address, relpp [i]->addend, ++// bfd_asymbol_value(*relpp [i]->sym_ptr_ptr), ++// bfd_section_name(ibfd, sec)); ++ ++ /* Keep the symbol */ + if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr), + keep_specific_htab)) + temp_relpp [temp_relcount++] = relpp [i]; ++ else ++ { ++ /* Don't keep the symbol, but keep the reloc */ ++ temp_relpp [temp_relcount] = relpp[i]; ++ temp_relpp [temp_relcount]->addend = bfd_asymbol_value(*relpp [i]->sym_ptr_ptr) ++ - sec->vma ++ + relpp[i]->addend; ++ temp_relpp [temp_relcount]->sym_ptr_ptr = sec->symbol_ptr_ptr; ++ temp_relcount++; ++ } ++ } + relcount = temp_relcount; + free (relpp); + relpp = temp_relpp; + } + + bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount); +@@ -3155,13 +3188,17 @@ strip_main (int argc, char *argv[]) + + if (show_version) + print_version ("strip"); + + default_deterministic (); + +- /* Default is to strip all symbols. */ ++ add_specific_symbol("__amigaos4__", keep_specific_htab); ++ add_specific_symbol("_start", keep_specific_htab); ++ add_specific_symbol("_SDA_BASE_", keep_specific_htab); ++ ++ /* Default is to strip all unnecessary symbols. */ + if (strip_symbols == STRIP_UNDEF + && discard_locals == LOCALS_UNDEF + && htab_elements (strip_specific_htab) == 0) + strip_symbols = STRIP_ALL; + + if (output_target == NULL) +@@ -3992,12 +4029,17 @@ copy_main (int argc, char *argv[]) + if (show_version) + print_version ("objcopy"); + + if (interleave && copy_byte == -1) + fatal (_("interleave start byte must be set with --byte")); + ++ add_specific_symbol("__amigappc__", keep_specific_htab); ++ add_specific_symbol("__amigaos4__", keep_specific_htab); ++ add_specific_symbol("_start", keep_specific_htab); ++ add_specific_symbol("_SDA_BASE_", keep_specific_htab); ++ + if (copy_byte >= interleave) + fatal (_("byte number must be less than interleave")); + + if (copy_width > interleave - copy_byte) + fatal (_("interleave width must be less than or equal to interleave - byte`")); + +diff --git a/binutils/readelf.c b/binutils/readelf.c +index d9ec436af6fbea0bbc3dfa8e9cd40fcf9be140cf..f52d7168af3bc6559bd2483ff1fc126da385b38d 100644 +--- a/binutils/readelf.c ++++ b/binutils/readelf.c +@@ -150,12 +150,13 @@ + #include "elf/vax.h" + #include "elf/x86-64.h" + #include "elf/xc16x.h" + #include "elf/xgate.h" + #include "elf/xstormy16.h" + #include "elf/xtensa.h" ++#include "elf/amigaos.h" + + #include "getopt.h" + #include "libiberty.h" + #include "safe-ctype.h" + #include "filenames.h" + +@@ -1520,12 +1521,13 @@ static const char * + get_ppc_dynamic_type (unsigned long type) + { + 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 +--- a/binutils/rename.c ++++ b/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 +--- a/config.sub ++++ b/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 ++++ b/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 ++++ b/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 +--- a/configure ++++ b/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 +--- a/configure.ac ++++ b/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 +--- a/gas/ChangeLog-9697 ++++ b/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 +--- a/gas/ChangeLog-9899 ++++ b/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 +--- a/gas/Makefile.am ++++ b/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 +--- a/gas/Makefile.in ++++ b/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 +--- a/gas/as.c ++++ b/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 +--- a/gas/config/m68k-parse.h ++++ b/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 +--- a/gas/config/m68k-parse.y ++++ b/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 ++++ b/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 ++++ b/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 +--- a/gas/config/obj-elf.c ++++ b/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 +--- a/gas/config/tc-i386.h ++++ b/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 +--- a/gas/config/tc-m68k.c ++++ b/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 +--- a/gas/config/tc-m68k.h ++++ b/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 +--- a/gas/config/tc-ppc.c ++++ b/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 +--- a/gas/config/tc-sh.c ++++ b/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 ++++ b/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 ++++ b/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 +--- a/gas/config/te-nbsd.h ++++ b/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 ++++ b/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 +--- a/gas/configure ++++ b/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 +--- a/gas/configure.in ++++ b/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 +--- a/gas/configure.tgt ++++ b/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 +--- a/gas/read.c ++++ b/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 +--- a/gas/read.h ++++ b/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 +--- a/gas/write.c ++++ b/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 +--- a/gas/write.h ++++ b/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 +--- a/gprof/Makefile.am ++++ b/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 +--- a/gprof/Makefile.in ++++ b/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 +--- a/gprof/configure ++++ b/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 +--- a/gprof/configure.in ++++ b/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 +--- a/gprof/gconfig.in ++++ b/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 ++++ b/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 +--- a/include/elf/ppc.h ++++ b/include/elf/ppc.h +@@ -128,12 +128,24 @@ 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) + ++/* Special MorphOS relocs. */ ++ RELOC_NUMBER (R_PPC_MORPHOS_DREL, 200) ++ RELOC_NUMBER (R_PPC_MORPHOS_DREL_LO, 201) ++ RELOC_NUMBER (R_PPC_MORPHOS_DREL_HI, 202) ++ RELOC_NUMBER (R_PPC_MORPHOS_DREL_HA, 203) ++ ++/* AmigaOS4 relocs */ ++ RELOC_NUMBER (R_PPC_AMIGAOS_BREL, 210) ++ RELOC_NUMBER (R_PPC_AMIGAOS_BREL_LO, 211) ++ RELOC_NUMBER (R_PPC_AMIGAOS_BREL_HI, 212) ++ RELOC_NUMBER (R_PPC_AMIGAOS_BREL_HA, 213) ++ + /* PowerPC VLE relocations. */ + RELOC_NUMBER (R_PPC_VLE_REL8, 216) + RELOC_NUMBER (R_PPC_VLE_REL15, 217) + 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 +--- a/include/libiberty.h ++++ b/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 +--- a/ld/ChangeLog-9197 ++++ b/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 +--- a/ld/ChangeLog-9899 ++++ b/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 +--- a/ld/Makefile.am ++++ b/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 +--- a/ld/Makefile.in ++++ b/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 +--- a/ld/configure.host ++++ b/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 +--- a/ld/configure.tgt ++++ b/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 ++++ b/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 ++++ b/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 ++++ b/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 ++++ b/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 ++++ b/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 ++++ b/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 ++++ b/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 ++++ b/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 ++++ b/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 ++++ b/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 ++++ b/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 +--- a/ld/emultempl/ppc32elf.em ++++ b/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 +--- a/ld/ldctor.c ++++ b/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 +--- a/ld/ldfile.c ++++ b/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 +--- a/ld/ldfile.h ++++ b/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 +--- a/ld/ldlang.c ++++ b/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 +--- a/ld/ldlang.h ++++ b/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 +--- a/ld/ldlex.c ++++ b/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 +--- a/ld/ldmain.c ++++ b/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 ++++ b/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 ++++ b/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 +--- a/ld/scripttempl/elf64hppa.sc ++++ b/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 +--- a/ld/scripttempl/mep.sc ++++ b/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/ld/scripttempl/elfi370.sc b/ld/scripttempl/morphos.sc +similarity index 88% +copy from ld/scripttempl/elfi370.sc +copy to ld/scripttempl/morphos.sc +index a845b2980105fa8504b5bf8a83aeb6fc086caa6e..469a8f5f2cad237c9317faf5d23db7f2b7a63eee 100644 +--- a/ld/scripttempl/elfi370.sc ++++ b/ld/scripttempl/morphos.sc +@@ -1,17 +1,14 @@ + # +-# This is just a raw copy of elfppc.sc and has not been otherwise modified +-# + # Unusual variables checked by this code: +-# NOP - four byte opcode for no-op (defaults to 0) ++# NOP - two byte opcode for no-op (defaults to 0) + # DATA_ADDR - if end-of-text-plus-one-page isn't right for data start + # OTHER_READONLY_SECTIONS - other than .text .init .rodata ... + # (e.g., .PARISC.milli) + # OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ... + # (e.g., .PARISC.global) +-# 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_SYMBOLS - symbols that appear at the start of the + # .text section. + # DATA_START_SYMBOLS - symbols that appear at the start of the +@@ -19,37 +16,35 @@ + # OTHER_BSS_SYMBOLS - symbols that appear at the start of the + # .bss section besides __bss_start. + # + # When adding sections, do note that the names of some sections are used + # when specifying the start address of the next. + # +-test -z "$ENTRY" && ENTRY=_start + test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT} + test -z "${LITTLE_OUTPUT_FORMAT}" && LITTLE_OUTPUT_FORMAT=${OUTPUT_FORMAT} +-test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }" + test "$LD_FLAG" = "N" && DATA_ADDR=. + SBSS2=".sbss2 ${RELOCATING-0} : { *(.sbss2) }" + SDATA2=".sdata2 ${RELOCATING-0} : { *(.sdata2) }" + INTERP=".interp ${RELOCATING-0} : { *(.interp) }" + PLT=".plt ${RELOCATING-0} : { *(.plt) }" + cat <<EOF + OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}", + "${LITTLE_OUTPUT_FORMAT}") + OUTPUT_ARCH(${ARCH}) +-${RELOCATING+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- /* For some reason, the Solaris linker makes bad executables + if gld -r is used and the intermediate file has sections starting + at non-zero addresses. Could be a Solaris ld bug, could be a GNU ld + bug. But for now assigning the zero vmas works. */} + + ${RELOCATING+PROVIDE (__stack = 0);} ++PROVIDE (__machtype = 0x1); + SECTIONS + { + /* Read-only sections, merged into text segment: */ + ${CREATE_SHLIB-${RELOCATING+. = ${TEXT_START_ADDR} + SIZEOF_HEADERS;}} + ${CREATE_SHLIB+${RELOCATING+. = SIZEOF_HEADERS;}} + ${CREATE_SHLIB-${INTERP}} +@@ -77,27 +72,30 @@ SECTIONS + .rela.sdata ${RELOCATING-0} : { *(.rela.sdata) } + .rela.sbss ${RELOCATING-0} : { *(.rela.sbss) } + .rela.sdata2 ${RELOCATING-0} : { *(.rela.sdata2) } + .rela.sbss2 ${RELOCATING-0} : { *(.rela.sbss2) } + .text ${RELOCATING-0} : + { ++ PROVIDE (__text_start = .); + ${RELOCATING+${TEXT_START_SYMBOLS}} + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) ++ PROVIDE (__text_end = .); + } =${NOP-0} ++ PROVIDE (__text_size = SIZEOF(.text)); + .init ${RELOCATING-0} : { *(.init) } =${NOP-0} + .fini ${RELOCATING-0} : { *(.fini) } =${NOP-0} + .rodata ${RELOCATING-0} : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 ${RELOCATING-0} : { *(.rodata1) } + ${RELOCATING+_etext = .;} + ${RELOCATING+PROVIDE (etext = .);} + ${CREATE_SHLIB-${SDATA2}} + ${CREATE_SHLIB-${SBSS2}} +- ${OTHER_READONLY_SECTIONS} ++ ${RELOCATING+${OTHER_READONLY_SECTIONS}} + + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. It would + be more correct to do this: + ${RELOCATING+. = ${DATA_ADDR-ALIGN(${MAXPAGESIZE}) + (ALIGN(8) & (${MAXPAGESIZE} - 1))};} + The current expression does not correctly handle the case of a +@@ -111,19 +109,22 @@ SECTIONS + that no actual memory is lost; the page which is skipped can not + be referenced). */ + ${RELOCATING+. = ${DATA_ADDR- ALIGN(8) + ${MAXPAGESIZE}};} + + .data ${RELOCATING-0} : + { ++ PROVIDE (__data_start = .); + ${RELOCATING+${DATA_START_SYMBOLS}} + *(.data) + *(.gnu.linkonce.d*) + ${CONSTRUCTING+CONSTRUCTORS} ++ PROVIDE (__data_end = .); + } ++ PROVIDE (__data_size = SIZEOF(.data)); + .data1 ${RELOCATING-0} : { *(.data1) } +- ${OTHER_READWRITE_SECTIONS} ++ ${RELOCATING+${OTHER_READWRITE_SECTIONS}} + + .got1 ${RELOCATING-0} : { *(.got1) } + .dynamic ${RELOCATING-0} : { *(.dynamic) } + + /* Put .ctors and .dtors next to the .got2 section, so that the pointers + get relocated with -mrelocatable. Also put in the .fixup pointers. +@@ -152,32 +153,43 @@ SECTIONS + ${CREATE_SHLIB+${SBSS2}} + ${RELOCATING+PROVIDE (_GOT_END_ = .);} + + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ +- .sdata ${RELOCATING-0} : { *(.sdata) } ++ .sdata ${RELOCATING-0} : ++ { ++ PROVIDE (__sdata_start = .); ++ *(.sdata) ++ PROVIDE (__r13_init = 0x8000); ++ PROVIDE (__sdata_end = .); ++ } ++ PROVIDE (__sdata_size = SIZEOF(.sdata)); + ${RELOCATING+_edata = .;} + ${RELOCATING+PROVIDE (edata = .);} + .sbss ${RELOCATING-0} : + { +- ${RELOCATING+PROVIDE (__sbss_start = .);} ++ PROVIDE (__sbss_start = .); + *(.sbss) + *(.scommon) + *(.dynsbss) +- ${RELOCATING+PROVIDE (__sbss_end = .);} ++ PROVIDE (__sbss_end = .); + } ++ PROVIDE (__sbss_size = SIZEOF(.sbss)); + ${PLT} + .bss ${RELOCATING-0} : + { +- ${RELOCATING+${OTHER_BSS_SYMBOLS}} +- ${RELOCATING+PROVIDE (__bss_start = .);} +- *(.dynbss) +- *(.bss) +- *(COMMON) ++ PROVIDE (__bss_start = .); ++ ${RELOCATING+${OTHER_BSS_SYMBOLS}} ++ ${RELOCATING+PROVIDE (__bss_start = .);} ++ *(.dynbss) ++ *(.bss) ++ *(COMMON) ++ PROVIDE (__bss_end = .); + } ++ PROVIDE (__bss_size = SIZEOF(.bss)); + ${RELOCATING+_end = . ;} + ${RELOCATING+PROVIDE (end = .);} + + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } +@@ -197,13 +209,13 @@ SECTIONS + + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + + /* DWARF 2 */ +- .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) } ++ .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } +@@ -211,17 +223,10 @@ SECTIONS + /* 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) } +- +- ${ATTRS_SECTIONS} ++ /* These must appear regardless of ${RELOCATING}. */ + ${OTHER_SECTIONS} + } + EOF +diff --git a/ld/scripttempl/elfi370.sc b/ld/scripttempl/morphos_baserel.sc +similarity index 69% +copy from ld/scripttempl/elfi370.sc +copy to ld/scripttempl/morphos_baserel.sc +index a845b2980105fa8504b5bf8a83aeb6fc086caa6e..4f0f4aba86bddb4e76a9405c0da04df4c0091d9e 100644 +--- a/ld/scripttempl/elfi370.sc ++++ b/ld/scripttempl/morphos_baserel.sc +@@ -1,17 +1,14 @@ + # +-# This is just a raw copy of elfppc.sc and has not been otherwise modified +-# + # Unusual variables checked by this code: +-# NOP - four byte opcode for no-op (defaults to 0) ++# NOP - two byte opcode for no-op (defaults to 0) + # DATA_ADDR - if end-of-text-plus-one-page isn't right for data start + # OTHER_READONLY_SECTIONS - other than .text .init .rodata ... + # (e.g., .PARISC.milli) + # OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ... + # (e.g., .PARISC.global) +-# 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_SYMBOLS - symbols that appear at the start of the + # .text section. + # DATA_START_SYMBOLS - symbols that appear at the start of the +@@ -19,37 +16,35 @@ + # OTHER_BSS_SYMBOLS - symbols that appear at the start of the + # .bss section besides __bss_start. + # + # When adding sections, do note that the names of some sections are used + # when specifying the start address of the next. + # +-test -z "$ENTRY" && ENTRY=_start + test -z "${BIG_OUTPUT_FORMAT}" && BIG_OUTPUT_FORMAT=${OUTPUT_FORMAT} + test -z "${LITTLE_OUTPUT_FORMAT}" && LITTLE_OUTPUT_FORMAT=${OUTPUT_FORMAT} +-test -z "$ATTRS_SECTIONS" && ATTRS_SECTIONS=".gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }" + test "$LD_FLAG" = "N" && DATA_ADDR=. + SBSS2=".sbss2 ${RELOCATING-0} : { *(.sbss2) }" + SDATA2=".sdata2 ${RELOCATING-0} : { *(.sdata2) }" + INTERP=".interp ${RELOCATING-0} : { *(.interp) }" + PLT=".plt ${RELOCATING-0} : { *(.plt) }" + cat <<EOF + OUTPUT_FORMAT("${OUTPUT_FORMAT}", "${BIG_OUTPUT_FORMAT}", + "${LITTLE_OUTPUT_FORMAT}") + OUTPUT_ARCH(${ARCH}) +-${RELOCATING+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- /* For some reason, the Solaris linker makes bad executables + if gld -r is used and the intermediate file has sections starting + at non-zero addresses. Could be a Solaris ld bug, could be a GNU ld + bug. But for now assigning the zero vmas works. */} + + ${RELOCATING+PROVIDE (__stack = 0);} ++PROVIDE (__machtype = 0x1); + SECTIONS + { + /* Read-only sections, merged into text segment: */ + ${CREATE_SHLIB-${RELOCATING+. = ${TEXT_START_ADDR} + SIZEOF_HEADERS;}} + ${CREATE_SHLIB+${RELOCATING+. = SIZEOF_HEADERS;}} + ${CREATE_SHLIB-${INTERP}} +@@ -58,72 +53,53 @@ SECTIONS + .dynstr ${RELOCATING-0} : { *(.dynstr) } + .gnu.version ${RELOCATING-0} : { *(.gnu.version) } + .gnu.version_d ${RELOCATING-0} : { *(.gnu.version_d) } + .gnu.version_r ${RELOCATING-0} : { *(.gnu.version_r) } + .rela.text ${RELOCATING-0} : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } +- .rela.data ${RELOCATING-0} : +- { *(.rela.data) *(.rela.gnu.linkonce.d*) } +- .rela.rodata ${RELOCATING-0} : +- { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rela.got ${RELOCATING-0} : { *(.rela.got) } + .rela.got1 ${RELOCATING-0} : { *(.rela.got1) } + .rela.got2 ${RELOCATING-0} : { *(.rela.got2) } + .rela.ctors ${RELOCATING-0} : { *(.rela.ctors) } + .rela.dtors ${RELOCATING-0} : { *(.rela.dtors) } + .rela.init ${RELOCATING-0} : { *(.rela.init) } + .rela.fini ${RELOCATING-0} : { *(.rela.fini) } +- .rela.bss ${RELOCATING-0} : { *(.rela.bss) } + .rela.plt ${RELOCATING-0} : { *(.rela.plt) } +- .rela.sdata ${RELOCATING-0} : { *(.rela.sdata) } +- .rela.sbss ${RELOCATING-0} : { *(.rela.sbss) } ++ .rela.rodata ${RELOCATING-0} : ++ { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } ++ .rela.sdata ${RELOCATING-0} : ++ { ++ *(.rela.data) ++ *(.rela.gnu.linkonce.d*) ++ *(.rela.sdata) ++ } ++ .rela.sbss ${RELOCATING-0} : ++ { ++ *(.rela.sbss) ++ *(.rela.bss) ++ } + .rela.sdata2 ${RELOCATING-0} : { *(.rela.sdata2) } + .rela.sbss2 ${RELOCATING-0} : { *(.rela.sbss2) } + .text ${RELOCATING-0} : + { ++ PROVIDE (__text_start = .); + ${RELOCATING+${TEXT_START_SYMBOLS}} + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) ++ PROVIDE (__text_end = .); + } =${NOP-0} ++ PROVIDE (__text_size = SIZEOF(.text)); + .init ${RELOCATING-0} : { *(.init) } =${NOP-0} + .fini ${RELOCATING-0} : { *(.fini) } =${NOP-0} +- .rodata ${RELOCATING-0} : { *(.rodata) *(.gnu.linkonce.r*) } +- .rodata1 ${RELOCATING-0} : { *(.rodata1) } + ${RELOCATING+_etext = .;} + ${RELOCATING+PROVIDE (etext = .);} + ${CREATE_SHLIB-${SDATA2}} + ${CREATE_SHLIB-${SBSS2}} +- ${OTHER_READONLY_SECTIONS} +- +- /* Adjust the address for the data segment. We want to adjust up to +- the same address within the page on the next page up. It would +- be more correct to do this: +- ${RELOCATING+. = ${DATA_ADDR-ALIGN(${MAXPAGESIZE}) + (ALIGN(8) & (${MAXPAGESIZE} - 1))};} +- The current expression does not correctly handle the case of a +- text segment ending precisely at the end of a page; it causes the +- data segment to skip a page. The above expression does not have +- this problem, but it will currently (2/95) cause BFD to allocate +- a single segment, combining both text and data, for this case. +- This will prevent the text segment from being shared among +- multiple executions of the program; I think that is more +- important than losing a page of the virtual address space (note +- that no actual memory is lost; the page which is skipped can not +- be referenced). */ +- ${RELOCATING+. = ${DATA_ADDR- ALIGN(8) + ${MAXPAGESIZE}};} +- +- .data ${RELOCATING-0} : +- { +- ${RELOCATING+${DATA_START_SYMBOLS}} +- *(.data) +- *(.gnu.linkonce.d*) +- ${CONSTRUCTING+CONSTRUCTORS} +- } +- .data1 ${RELOCATING-0} : { *(.data1) } +- ${OTHER_READWRITE_SECTIONS} ++ ${RELOCATING+${OTHER_READONLY_SECTIONS}} + + .got1 ${RELOCATING-0} : { *(.got1) } + .dynamic ${RELOCATING-0} : { *(.dynamic) } + + /* Put .ctors and .dtors next to the .got2 section, so that the pointers + get relocated with -mrelocatable. Also put in the .fixup pointers. +@@ -148,38 +124,41 @@ SECTIONS + ${RELOCATING+PROVIDE (_GOT_START_ = .);} + .got ${RELOCATING-0} : { *(.got) } + .got.plt ${RELOCATING-0} : { *(.got.plt) } + ${CREATE_SHLIB+${SDATA2}} + ${CREATE_SHLIB+${SBSS2}} + ${RELOCATING+PROVIDE (_GOT_END_ = .);} +- +- /* We want the small data sections together, so single-instruction offsets ++ .rodata ${RELOCATING-0} : { *(.rodata) } ++ /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ +- .sdata ${RELOCATING-0} : { *(.sdata) } ++ .sdata ${RELOCATING-0} : ++ { ++ /*PROVIDE (__sdata_start = .);*/ ++ __sdata_start = .; ++ *(.data) ++ *(.data1) ++ __small_start = .; ++ *(.sdata) ++ PROVIDE (__r13_init = /*__small_start*/ __sdata_start + 0x8000); ++ PROVIDE (__sdata_end = .); ++ } ++ PROVIDE (__sdata_size = SIZEOF(.sdata)); + ${RELOCATING+_edata = .;} + ${RELOCATING+PROVIDE (edata = .);} + .sbss ${RELOCATING-0} : + { +- ${RELOCATING+PROVIDE (__sbss_start = .);} ++ PROVIDE (__sbss_start = .); + *(.sbss) + *(.scommon) + *(.dynsbss) +- ${RELOCATING+PROVIDE (__sbss_end = .);} +- } +- ${PLT} +- .bss ${RELOCATING-0} : +- { +- ${RELOCATING+${OTHER_BSS_SYMBOLS}} +- ${RELOCATING+PROVIDE (__bss_start = .);} +- *(.dynbss) +- *(.bss) +- *(COMMON) ++ *(.bss) ++ *(COMMON) ++ PROVIDE (__sbss_end = .); + } +- ${RELOCATING+_end = . ;} +- ${RELOCATING+PROVIDE (end = .);} ++ PROVIDE (__sbss_size = SIZEOF(.sbss)); + + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + +@@ -197,13 +176,13 @@ SECTIONS + + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + + /* DWARF 2 */ +- .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) } ++ .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } +@@ -211,17 +190,10 @@ SECTIONS + /* 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) } +- +- ${ATTRS_SECTIONS} ++ /* These must appear regardless of ${RELOCATING}. */ + ${OTHER_SECTIONS} + } + EOF +diff --git a/libiberty/config/mh-amigaos b/libiberty/config/mh-amigaos +new file mode 100644 +index 0000000000000000000000000000000000000000..495fa7e35897000efe600c9f1dd844b086731fcd +--- /dev/null ++++ b/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 ++++ b/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 +--- a/libiberty/lrealpath.c ++++ b/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 +--- a/opcodes/m68k-dis.c ++++ b/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..eab630d --- /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 +--- a/bfd/doc/bfd.texinfo ++++ b/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 +--- a/binutils/doc/binutils.texi ++++ b/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 +--- a/gas/doc/c-arc.texi ++++ b/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 +--- a/gas/doc/c-arm.texi ++++ b/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 +--- a/gas/doc/c-cr16.texi ++++ b/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 +--- a/gas/doc/c-mips.texi ++++ b/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 +--- a/gas/doc/c-score.texi ++++ b/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 +--- a/gas/doc/c-tic54x.texi ++++ b/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 +--- a/ld/ld.texinfo ++++ b/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..f244e21 --- /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 +--- a/gas/config/tc-m68k.c ++++ b/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..5c6c8c4 --- /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 +--- a/bfd/elflink.c ++++ b/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..2375145 --- /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 +--- a/ld/emulparams/amigaos.sh ++++ b/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..7477e49 --- /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 +--- a/binutils/objcopy.c ++++ b/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..8246392 --- /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 +--- a/binutils/objcopy.c ++++ b/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/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; |