diff options
author | Luca Barbato <lu_zero@gentoo.org> | 2003-11-07 01:22:24 +0000 |
---|---|---|
committer | Luca Barbato <lu_zero@gentoo.org> | 2003-11-07 01:22:24 +0000 |
commit | 652ff9e206c4c71cc78af68d306742f271099de3 (patch) | |
tree | 88eb06a70325661fd463aca9f3a521c44fc8b9ad /sys-devel | |
parent | ~ppc, fix #32755 (diff) | |
download | gentoo-2-652ff9e206c4c71cc78af68d306742f271099de3.tar.gz gentoo-2-652ff9e206c4c71cc78af68d306742f271099de3.tar.bz2 gentoo-2-652ff9e206c4c71cc78af68d306742f271099de3.zip |
~ppc, fix #32755
Diffstat (limited to 'sys-devel')
-rw-r--r-- | sys-devel/binutils/ChangeLog | 11 | ||||
-rw-r--r-- | sys-devel/binutils/Manifest | 4 | ||||
-rw-r--r-- | sys-devel/binutils/binutils-2.14.90.0.7-r1.ebuild | 199 | ||||
-rw-r--r-- | sys-devel/binutils/files/2.14/binutils-2.14.90.0.7-ppc-reloc.patch | 6673 | ||||
-rw-r--r-- | sys-devel/binutils/files/digest-binutils-2.14.90.0.7-r1 | 1 |
5 files changed, 6883 insertions, 5 deletions
diff --git a/sys-devel/binutils/ChangeLog b/sys-devel/binutils/ChangeLog index 90e006542ba0..d2d3683b7163 100644 --- a/sys-devel/binutils/ChangeLog +++ b/sys-devel/binutils/ChangeLog @@ -1,6 +1,11 @@ # ChangeLog for sys-devel/binutils # Copyright 2002-2003 Gentoo Technologies, Inc.; Distributed under the GPL v2 -# $Header: /var/cvsroot/gentoo-x86/sys-devel/binutils/ChangeLog,v 1.86 2003/11/05 22:23:21 lu_zero Exp $ +# $Header: /var/cvsroot/gentoo-x86/sys-devel/binutils/ChangeLog,v 1.87 2003/11/07 01:21:05 lu_zero Exp $ + + 07 Nov 2003; Luca Barbato <lu_zero@gentoo.org> + binutils-2.14.90.0.7-r1.ebuild, + files/2.14/binutils-2.14.90.0.7-ppc-reloc.patch: + Fix to bug #32755 05 Nov 2003; Luca Barbato <lu_zero@gentoo.org> binutils-2.14.90.0.7.ebuild: Maked -ppc :seems to have too many issues @@ -12,8 +17,8 @@ 04 Nov 2003; Martin Schlemmer <azarah@gentoo.org> binutils-2.14.90.0.2.ebuild, binutils-2.14.90.0.4.1-r1.ebuild, binutils-2.14.90.0.6-r7.ebuild, binutils-2.14.90.0.7.ebuild: - Enable building of 64bit apps on Sparc and Mips, closing bug #24631. Fix is an - modified one from Jason Wever <weeve@gentoo.org>. + Enable building of 64bit apps on Sparc and Mips, closing bug #24631. + Fix is an modified one from Jason Wever <weeve@gentoo.org>. *binutils-2.14.90.0.7 (01 Nov 2003) diff --git a/sys-devel/binutils/Manifest b/sys-devel/binutils/Manifest index b008d3285200..669b2f16df8a 100644 --- a/sys-devel/binutils/Manifest +++ b/sys-devel/binutils/Manifest @@ -3,8 +3,8 @@ MD5 0605cad192892662d9ab7bcf4292a278 binutils-2.11.92.0.12.3-r2.ebuild 3047 MD5 b7ddfee30d6b7884c1b9088c6fde759d binutils-2.13.90.0.16-r1.ebuild 4661 MD5 d7774659828753b66eedf647ed63a6f6 binutils-2.14.90.0.7.ebuild 5482 MD5 1b11085f74185bfe7061a6fb01d62ebd binutils-2.12.90.0.15.ebuild 3501 -MD5 df6b75234c842e371111bfab0437d01f ChangeLog 19248 -MD5 e741e83d7f9e62eba31eb62ba61d5901 binutils-2.14.90.0.7-r1.ebuild 5522 +MD5 743f2087155d5bd2768bd5f00f6775e7 ChangeLog 19248 +MD5 de7af19f48e189e180aaf0542dda06e5 binutils-2.14.90.0.7-r1.ebuild 5525 MD5 81a6c0292284ac5066b7c452dba54b57 binutils-2.14.90.0.2.ebuild 5583 MD5 e56840c0286c1b40a114e80ced64dc45 binutils-2.13.90.0.18.ebuild 4572 MD5 92e0fa5133dbba4ffefc25a217f28686 binutils-2.14.90.0.5-r1.ebuild 5781 diff --git a/sys-devel/binutils/binutils-2.14.90.0.7-r1.ebuild b/sys-devel/binutils/binutils-2.14.90.0.7-r1.ebuild new file mode 100644 index 000000000000..ba3b5a3cf6cf --- /dev/null +++ b/sys-devel/binutils/binutils-2.14.90.0.7-r1.ebuild @@ -0,0 +1,199 @@ +# Copyright 1999-2003 Gentoo Technologies, Inc. +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-x86/sys-devel/binutils/binutils-2.14.90.0.7-r1.ebuild,v 1.1 2003/11/07 01:21:05 lu_zero Exp $ + +IUSE="nls bootstrap build" + +# NOTE to Maintainer: ChangeLog states that it no longer use perl to build +# the manpages, but seems this is incorrect .... + +inherit eutils libtool flag-o-matic + +# Generate borked binaries. Bug #6730 +filter-flags "-fomit-frame-pointer -fssa" + +S="${WORKDIR}/${P}" +DESCRIPTION="Tools necessary to build programs" +SRC_URI="mirror://kernel/linux/devel/binutils/${P}.tar.bz2 + mirror://kernel/linux/devel/binutils/test/${P}.tar.bz2" +HOMEPAGE="http://sources.redhat.com/binutils/" + +SLOT="0" +LICENSE="GPL-2 | LGPL-2" +KEYWORDS="~ppc" + +DEPEND="virtual/glibc + nls? ( sys-devel/gettext ) + !build? ( !bootstrap? ( dev-lang/perl ) )" + + +src_unpack() { + + unpack ${A} + + cd ${S} + epatch ${FILESDIR}/2.13/${PN}-2.13.90.0.10-glibc21.patch + epatch ${FILESDIR}/2.14/${PN}-2.14.90.0.4-sparc-nonpic.patch + epatch ${FILESDIR}/2.14/${PN}-2.14.90.0.6-eh-frame-ro-2.patch + epatch ${FILESDIR}/2.14/${PN}-2.14.90.0.4-ltconfig-multilib.patch +# Might think of adding the Prescott stuff later on +# epatch ${FILESDIR}/2.14/${PN}-2.14.90.0.4-pni.patch + epatch ${FILESDIR}/2.14/${PN}-2.14.90.0.5-s390-pie.patch + epatch ${FILESDIR}/2.14/${PN}-2.14.90.0.5-ppc64-pie.patch + epatch ${FILESDIR}/2.13/${PN}-2.13.90.0.10-x86_64-testsuite.patch + epatch ${FILESDIR}/2.13/${PN}-2.13.90.0.10-x86_64-gotpcrel.patch + epatch ${FILESDIR}/2.13/${PN}-2.13.90.0.18-testsuite-Wall-fixes.patch + +# This one seems to be partly merged, will need to check later on why +# some bits to bfd/elf-strtab.c was not merged ... + # This increase c++ linking 2 to 3 times, bug #27540. +# epatch ${FILESDIR}/2.14/${PN}-2.14.90.0.6-merge-speedup.patch + + # Some IA64 patches + epatch ${FILESDIR}/2.14/${PN}-2.14.90.0.6-ia64-speedup.patch + + if [ "${ARCH}" = "amd64" ] + then + epatch ${FILESDIR}/${PN}-2.14.amd64-32bit-path-fix.patch + fi + + use x86 &> /dev/null \ + && epatch ${FILESDIR}/2.13/${PN}-2.13.90.0.20-array-sects-compat.patch + + use ppc &> /dev/null \ + && epatch ${FILESDIR}/2.14/${PN}-2.14.90.0.7-ppc-reloc.patch + + + # Libtool is broken (Redhat). + for x in ${S}/opcodes/Makefile.{am,in} + do + cp ${x} ${x}.orig + gawk ' + { + if ($0 ~ /LIBADD/) + gsub("../bfd/libbfd.la", "-L../bfd/.libs ../bfd/libbfd.la") + + print + }' ${x}.orig > ${x} + rm -rf ${x}.orig + done +} + +src_compile() { + local myconf= + + use nls && \ + myconf="${myconf} --without-included-gettext" || \ + myconf="${myconf} --disable-nls" + + # Filter CFLAGS=".. -O2 .." on arm + if [ "${ARCH}" = "arm" ] + then + CFLAGS="$(echo "${CFLAGS}" | sed -e 's,-O[2-9] ,-O1 ,')" + fi + + # Fix /usr/lib/libbfd.la + elibtoolize --portage + + ./configure --enable-shared \ + --enable-64-bit-bfd \ + --prefix=/usr \ + --mandir=/usr/share/man \ + --infodir=/usr/share/info \ + --host=${CHOST} \ + ${myconf} || die + + make configure-bfd || die + make headers -C bfd || die + emake tooldir="${ROOT}/usr/bin" \ + all || die + + if [ -z "`use build`" ] + then + if [ -z "`use bootstrap`" ] + then + # Nuke the manpages to recreate them (only use this if we have perl) + find . -name '*.1' -exec rm -f {} \; || : + fi + # Make the info pages (makeinfo included with gcc is used) + make info || die + fi +} + +src_install() { + + make prefix=${D}/usr \ + mandir=${D}/usr/share/man \ + infodir=${D}/usr/share/info \ + install || die + + insinto /usr/include + doins include/libiberty.h + + # c++filt is included with gcc -- what are these GNU people thinking? + # but not the manpage, so leave that! +# We install it now, as gcc-3.3 do not have it any longer ... +# rm -f ${D}/usr/bin/c++filt #${D}/usr/share/man/man1/c++filt* + + # By default strip has a symlink going from /usr/${CHOST}/bin/strip to + # /usr/bin/strip we should reverse it: + + rm ${D}/usr/${CHOST}/bin/strip; mv ${D}/usr/bin/strip ${D}/usr/${CHOST}/bin/strip + # The strip symlink gets created in the loop below + + # By default ar, as, ld, nm, ranlib and strip are in two places; create + # symlinks. This will reduce the size of the tbz2 significantly. We also + # move all the stuff in /usr/bin to /usr/${CHOST}/bin and create the + # appropriate symlinks. Things are cleaner that way. + cd ${D}/usr/bin + local x= + for x in * strip + do + if [ ! -e ../${CHOST}/bin/${x} ] + then + mv ${x} ../${CHOST}/bin/${x} + else + rm -f ${x} + fi + ln -s ../${CHOST}/bin/${x} ${x} + done + + if [ -n "${PROFILE_ARCH}" ] && \ + [ "${PROFILE_ARCH/64}" != "${PROFILE_ARCH}" ] + then + dosym ${CHOST} /usr/${CHOST/-/64-} + + for x in `ls ${D}/usr/${CHOST/-/64-}/bin/` + do + dosym ../${CHOST/-/64-}/bin/${x} /usr/bin/${CHOST/-/64-}-${x} + done + fi + + cd ${S} + if [ -z "`use build`" ] + then + make prefix=${D}/usr \ + mandir=${D}/usr/share/man \ + infodir=${D}/usr/share/info \ + install-info || die + + dodoc COPYING* README + docinto bfd + dodoc bfd/ChangeLog* bfd/COPYING bfd/README bfd/PORTING bfd/TODO + docinto binutils + dodoc binutils/ChangeLog binutils/NEWS binutils/README + docinto gas + dodoc gas/ChangeLog* gas/CONTRIBUTORS gas/COPYING gas/NEWS gas/README* + docinto gprof + dodoc gprof/ChangeLog* gprof/TEST gprof/TODO + docinto ld + dodoc ld/ChangeLog* ld/README ld/NEWS ld/TODO + docinto libiberty + dodoc libiberty/ChangeLog* libiberty/COPYING.LIB libiberty/README + docinto opcodes + dodoc opcodes/ChangeLog* + # Install pre-generated manpages .. currently we do not ... + else + rm -rf ${D}/usr/share/man + fi +} diff --git a/sys-devel/binutils/files/2.14/binutils-2.14.90.0.7-ppc-reloc.patch b/sys-devel/binutils/files/2.14/binutils-2.14.90.0.7-ppc-reloc.patch new file mode 100644 index 000000000000..6c14a3708128 --- /dev/null +++ b/sys-devel/binutils/files/2.14/binutils-2.14.90.0.7-ppc-reloc.patch @@ -0,0 +1,6673 @@ +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf-bfd.h binutils-2.14.90.0.7/bfd/elf-bfd.h +--- binutils-2.14.90.0.7.orig/bfd/elf-bfd.h 2003-11-07 00:11:22.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf-bfd.h 2003-11-07 00:21:15.000000000 +0100 +@@ -1303,7 +1303,7 @@ + extern enum elf_reloc_type_class _bfd_elf_reloc_type_class + (const Elf_Internal_Rela *); + extern bfd_vma _bfd_elf_rela_local_sym +- (bfd *, Elf_Internal_Sym *, asection *, Elf_Internal_Rela *); ++ (bfd *, Elf_Internal_Sym *, asection **, Elf_Internal_Rela *); + extern bfd_vma _bfd_elf_rel_local_sym + (bfd *, Elf_Internal_Sym *, asection **, bfd_vma); + extern bfd_vma _bfd_elf_section_offset +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf-bfd.h.orig binutils-2.14.90.0.7/bfd/elf-bfd.h.orig +--- binutils-2.14.90.0.7.orig/bfd/elf-bfd.h.orig 1970-01-01 01:00:00.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf-bfd.h.orig 2003-11-07 00:20:18.000000000 +0100 +@@ -0,0 +1,1751 @@ ++/* BFD back-end data structures for ELF files. ++ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, ++ 2002, 2003 Free Software Foundation, Inc. ++ Written by 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. */ ++ ++#ifndef _LIBELF_H_ ++#define _LIBELF_H_ 1 ++ ++#include "elf/common.h" ++#include "elf/internal.h" ++#include "elf/external.h" ++#include "bfdlink.h" ++ ++/* The number of entries in a section is its size divided by the size ++ of a single entry. This is normally only applicable to reloc and ++ symbol table sections. */ ++#define NUM_SHDR_ENTRIES(shdr) ((shdr)->sh_size / (shdr)->sh_entsize) ++ ++/* If size isn't specified as 64 or 32, NAME macro should fail. */ ++#ifndef NAME ++#if ARCH_SIZE == 64 ++#define NAME(x, y) x ## 64 ## _ ## y ++#endif ++#if ARCH_SIZE == 32 ++#define NAME(x, y) x ## 32 ## _ ## y ++#endif ++#endif ++ ++#ifndef NAME ++#define NAME(x, y) x ## NOSIZE ## _ ## y ++#endif ++ ++#define ElfNAME(X) NAME(Elf,X) ++#define elfNAME(X) NAME(elf,X) ++ ++/* Information held for an ELF symbol. The first field is the ++ corresponding asymbol. Every symbol is an ELF file is actually a ++ pointer to this structure, although it is often handled as a ++ pointer to an asymbol. */ ++ ++typedef struct ++{ ++ /* The BFD symbol. */ ++ asymbol symbol; ++ /* ELF symbol information. */ ++ Elf_Internal_Sym internal_elf_sym; ++ /* Backend specific information. */ ++ union ++ { ++ unsigned int hppa_arg_reloc; ++ void *mips_extr; ++ void *any; ++ } ++ tc_data; ++ ++ /* Version information. This is from an Elf_Internal_Versym ++ structure in a SHT_GNU_versym section. It is zero if there is no ++ version information. */ ++ unsigned short version; ++ ++} elf_symbol_type; ++ ++struct elf_strtab_hash; ++struct got_entry; ++struct plt_entry; ++ ++/* ELF linker hash table entries. */ ++ ++struct elf_link_hash_entry ++{ ++ struct bfd_link_hash_entry root; ++ ++ /* Symbol index in output file. This is initialized to -1. It is ++ set to -2 if the symbol is used by a reloc. */ ++ long indx; ++ ++ /* Symbol index as a dynamic symbol. Initialized to -1, and remains ++ -1 if this is not a dynamic symbol. */ ++ /* ??? Note that this is consistently used as a synonym for tests ++ against whether we can perform various simplifying transformations ++ to the code. (E.g. changing a pc-relative jump to a PLT entry ++ into a pc-relative jump to the target function.) That test, which ++ is often relatively complex, and someplaces wrong or incomplete, ++ should really be replaced by a predicate in elflink.c. ++ ++ End result: this field -1 does not indicate that the symbol is ++ not in the dynamic symbol table, but rather that the symbol is ++ not visible outside this DSO. */ ++ long dynindx; ++ ++ /* String table index in .dynstr if this is a dynamic symbol. */ ++ unsigned long dynstr_index; ++ ++ /* Hash value of the name computed using the ELF hash function. */ ++ unsigned long elf_hash_value; ++ ++ /* If this is a weak defined symbol from a dynamic object, this ++ field points to a defined symbol with the same value, if there is ++ one. Otherwise it is NULL. */ ++ struct elf_link_hash_entry *weakdef; ++ ++ /* Version information. */ ++ union ++ { ++ /* This field is used for a symbol which is not defined in a ++ regular object. It points to the version information read in ++ from the dynamic object. */ ++ Elf_Internal_Verdef *verdef; ++ /* This field is used for a symbol which is defined in a regular ++ object. It is set up in size_dynamic_sections. It points to ++ the version information we should write out for this symbol. */ ++ struct bfd_elf_version_tree *vertree; ++ } verinfo; ++ ++ /* Virtual table entry use information. This array is nominally of size ++ size/sizeof(target_void_pointer), though we have to be able to assume ++ and track a size while the symbol is still undefined. It is indexed ++ via offset/sizeof(target_void_pointer). */ ++ size_t vtable_entries_size; ++ bfd_boolean *vtable_entries_used; ++ ++ /* Virtual table derivation info. */ ++ struct elf_link_hash_entry *vtable_parent; ++ ++ /* If this symbol requires an entry in the global offset table, the ++ processor specific backend uses this field to track usage and ++ final offset. Two schemes are supported: The first assumes that ++ a symbol may only have one GOT entry, and uses REFCOUNT until ++ size_dynamic_sections, at which point the contents of the .got is ++ fixed. Afterward, if OFFSET is -1, then the symbol does not ++ require a global offset table entry. The second scheme allows ++ multiple GOT entries per symbol, managed via a linked list ++ pointed to by GLIST. */ ++ union gotplt_union ++ { ++ bfd_signed_vma refcount; ++ bfd_vma offset; ++ struct got_entry *glist; ++ struct plt_entry *plist; ++ } got; ++ ++ /* Same, but tracks a procedure linkage table entry. */ ++ union gotplt_union plt; ++ ++ /* Symbol size. */ ++ bfd_size_type size; ++ ++ /* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */ ++ char type; ++ ++ /* Symbol st_other value, symbol visibility. */ ++ unsigned char other; ++ ++ /* Some flags; legal values follow. */ ++ unsigned short elf_link_hash_flags; ++ /* Symbol is referenced by a non-shared object. */ ++#define ELF_LINK_HASH_REF_REGULAR 01 ++ /* Symbol is defined by a non-shared object. */ ++#define ELF_LINK_HASH_DEF_REGULAR 02 ++ /* Symbol is referenced by a shared object. */ ++#define ELF_LINK_HASH_REF_DYNAMIC 04 ++ /* Symbol is defined by a shared object. */ ++#define ELF_LINK_HASH_DEF_DYNAMIC 010 ++ /* Symbol has a non-weak reference from a non-shared object. */ ++#define ELF_LINK_HASH_REF_REGULAR_NONWEAK 020 ++ /* Dynamic symbol has been adjustd. */ ++#define ELF_LINK_HASH_DYNAMIC_ADJUSTED 040 ++ /* Symbol needs a copy reloc. */ ++#define ELF_LINK_HASH_NEEDS_COPY 0100 ++ /* Symbol needs a procedure linkage table entry. */ ++#define ELF_LINK_HASH_NEEDS_PLT 0200 ++ /* Symbol appears in a non-ELF input file. */ ++#define ELF_LINK_NON_ELF 0400 ++ /* Symbol should be marked as hidden in the version information. */ ++#define ELF_LINK_HIDDEN 01000 ++ /* Symbol was forced to local scope due to a version script file. */ ++#define ELF_LINK_FORCED_LOCAL 02000 ++ /* Symbol was marked during garbage collection. */ ++#define ELF_LINK_HASH_MARK 04000 ++ /* Symbol is referenced by a non-GOT/non-PLT relocation. This is ++ not currently set by all the backends. */ ++#define ELF_LINK_NON_GOT_REF 010000 ++ /* Symbol has a definition in a shared object. */ ++#define ELF_LINK_DYNAMIC_DEF 020000 ++ /* Symbol is weak in all shared objects. */ ++#define ELF_LINK_DYNAMIC_WEAK 040000 ++}; ++ ++/* Will references to this symbol always reference the symbol ++ in this object? STV_PROTECTED is excluded from the visibility test ++ here so that function pointer comparisons work properly. Since ++ function symbols not defined in an app are set to their .plt entry, ++ it's necessary for shared libs to also reference the .plt even ++ though the symbol is really local to the shared lib. */ ++#define SYMBOL_REFERENCES_LOCAL(INFO, H) \ ++ _bfd_elf_symbol_refs_local_p (H, INFO, 0) ++ ++/* Will _calls_ to this symbol always call the version in this object? */ ++#define SYMBOL_CALLS_LOCAL(INFO, H) \ ++ _bfd_elf_symbol_refs_local_p (H, INFO, 1) ++ ++/* Records local symbols to be emitted in the dynamic symbol table. */ ++ ++struct elf_link_local_dynamic_entry ++{ ++ struct elf_link_local_dynamic_entry *next; ++ ++ /* The input bfd this symbol came from. */ ++ bfd *input_bfd; ++ ++ /* The index of the local symbol being copied. */ ++ long input_indx; ++ ++ /* The index in the outgoing dynamic symbol table. */ ++ long dynindx; ++ ++ /* A copy of the input symbol. */ ++ Elf_Internal_Sym isym; ++}; ++ ++struct elf_link_loaded_list ++{ ++ struct elf_link_loaded_list *next; ++ bfd *abfd; ++}; ++ ++/* Structures used by the eh_frame optimization code. */ ++struct cie_header ++{ ++ unsigned int length; ++ unsigned int id; ++}; ++ ++struct cie ++{ ++ struct cie_header hdr; ++ unsigned char version; ++ unsigned char augmentation[20]; ++ unsigned int code_align; ++ int data_align; ++ unsigned int ra_column; ++ unsigned int augmentation_size; ++ struct elf_link_hash_entry *personality; ++ unsigned char per_encoding; ++ unsigned char lsda_encoding; ++ unsigned char fde_encoding; ++ unsigned char initial_insn_length; ++ unsigned char make_relative; ++ unsigned char make_lsda_relative; ++ unsigned char initial_instructions[50]; ++}; ++ ++struct eh_cie_fde ++{ ++ unsigned int offset; ++ unsigned int size; ++ asection *sec; ++ unsigned int new_offset; ++ unsigned char fde_encoding; ++ unsigned char lsda_encoding; ++ unsigned char lsda_offset; ++ unsigned char cie : 1; ++ unsigned char removed : 1; ++ unsigned char make_relative : 1; ++ unsigned char make_lsda_relative : 1; ++ unsigned char per_encoding_relative : 1; ++}; ++ ++struct eh_frame_sec_info ++{ ++ unsigned int count; ++ unsigned int alloced; ++ struct eh_cie_fde entry[1]; ++}; ++ ++struct eh_frame_array_ent ++{ ++ bfd_vma initial_loc; ++ bfd_vma fde; ++}; ++ ++struct eh_frame_hdr_info ++{ ++ struct cie last_cie; ++ asection *last_cie_sec; ++ asection *hdr_sec; ++ unsigned int last_cie_offset; ++ unsigned int fde_count, array_count; ++ struct eh_frame_array_ent *array; ++ /* TRUE if .eh_frame_hdr should contain the sorted search table. ++ We build it if we successfully read all .eh_frame input sections ++ and recognize them. */ ++ bfd_boolean table; ++}; ++ ++/* Cached start, size and alignment of PT_TLS segment. */ ++struct elf_link_tls_segment ++{ ++ bfd_vma start; ++ bfd_size_type size; ++ unsigned int align; ++}; ++ ++/* ELF linker hash table. */ ++ ++struct elf_link_hash_table ++{ ++ struct bfd_link_hash_table root; ++ ++ /* Whether we have created the special dynamic sections required ++ when linking against or generating a shared object. */ ++ bfd_boolean dynamic_sections_created; ++ ++ /* The BFD used to hold special sections created by the linker. ++ This will be the first BFD found which requires these sections to ++ be created. */ ++ bfd *dynobj; ++ ++ /* The value to use when initialising got.refcount/offset and ++ plt.refcount/offset in an elf_link_hash_entry. Set to zero when ++ the values are refcounts. Set to init_offset in ++ size_dynamic_sections when the values may be offsets. */ ++ union gotplt_union init_refcount; ++ ++ /* The value to use for got.refcount/offset and plt.refcount/offset ++ when the values may be offsets. Normally (bfd_vma) -1. */ ++ union gotplt_union init_offset; ++ ++ /* The number of symbols found in the link which must be put into ++ the .dynsym section. */ ++ bfd_size_type dynsymcount; ++ ++ /* The string table of dynamic symbols, which becomes the .dynstr ++ section. */ ++ struct elf_strtab_hash *dynstr; ++ ++ /* The number of buckets in the hash table in the .hash section. ++ This is based on the number of dynamic symbols. */ ++ bfd_size_type bucketcount; ++ ++ /* A linked list of DT_NEEDED names found in dynamic objects ++ included in the link. */ ++ struct bfd_link_needed_list *needed; ++ ++ /* The _GLOBAL_OFFSET_TABLE_ symbol. */ ++ struct elf_link_hash_entry *hgot; ++ ++ /* A pointer to information used to link stabs in sections. */ ++ void *stab_info; ++ ++ /* A pointer to information used to merge SEC_MERGE sections. */ ++ void *merge_info; ++ ++ /* Used by eh_frame code when editing .eh_frame. */ ++ struct eh_frame_hdr_info eh_info; ++ ++ /* A linked list of local symbols to be added to .dynsym. */ ++ struct elf_link_local_dynamic_entry *dynlocal; ++ ++ /* A linked list of DT_RPATH/DT_RUNPATH names found in dynamic ++ objects included in the link. */ ++ struct bfd_link_needed_list *runpath; ++ ++ /* Cached start, size and alignment of PT_TLS segment. */ ++ struct elf_link_tls_segment *tls_segment; ++ ++ /* A linked list of BFD's loaded in the link. */ ++ struct elf_link_loaded_list *loaded; ++}; ++ ++/* Look up an entry in an ELF linker hash table. */ ++ ++#define elf_link_hash_lookup(table, string, create, copy, follow) \ ++ ((struct elf_link_hash_entry *) \ ++ bfd_link_hash_lookup (&(table)->root, (string), (create), \ ++ (copy), (follow))) ++ ++/* Traverse an ELF linker hash table. */ ++ ++#define elf_link_hash_traverse(table, func, info) \ ++ (bfd_link_hash_traverse \ ++ (&(table)->root, \ ++ (bfd_boolean (*) (struct bfd_link_hash_entry *, void *)) (func), \ ++ (info))) ++ ++/* Get the ELF linker hash table from a link_info structure. */ ++ ++#define elf_hash_table(p) ((struct elf_link_hash_table *) ((p)->hash)) ++ ++/* Returns TRUE if the hash table is a struct elf_link_hash_table. */ ++#define is_elf_hash_table(p) \ ++ ((p)->hash->type == bfd_link_elf_hash_table) ++ ++/* Used by bfd_section_from_r_symndx to cache a small number of local ++ symbol to section mappings. */ ++#define LOCAL_SYM_CACHE_SIZE 32 ++struct sym_sec_cache ++{ ++ bfd *abfd; ++ unsigned long indx[LOCAL_SYM_CACHE_SIZE]; ++ asection *sec[LOCAL_SYM_CACHE_SIZE]; ++}; ++ ++/* Constant information held for an ELF backend. */ ++ ++struct elf_size_info { ++ unsigned char sizeof_ehdr, sizeof_phdr, sizeof_shdr; ++ unsigned char sizeof_rel, sizeof_rela, sizeof_sym, sizeof_dyn, sizeof_note; ++ ++ /* The size of entries in the .hash section. */ ++ unsigned char sizeof_hash_entry; ++ ++ /* The number of internal relocations to allocate per external ++ relocation entry. */ ++ unsigned char int_rels_per_ext_rel; ++ /* We use some fixed size arrays. This should be large enough to ++ handle all back-ends. */ ++#define MAX_INT_RELS_PER_EXT_REL 3 ++ ++ unsigned char arch_size, log_file_align; ++ unsigned char elfclass, ev_current; ++ int (*write_out_phdrs) ++ (bfd *, const Elf_Internal_Phdr *, unsigned int); ++ bfd_boolean ++ (*write_shdrs_and_ehdr) (bfd *); ++ void (*write_relocs) ++ (bfd *, asection *, void *); ++ void (*swap_symbol_in) ++ (bfd *, const void *, const void *, Elf_Internal_Sym *); ++ void (*swap_symbol_out) ++ (bfd *, const Elf_Internal_Sym *, void *, void *); ++ bfd_boolean (*slurp_reloc_table) ++ (bfd *, asection *, asymbol **, bfd_boolean); ++ long (*slurp_symbol_table) ++ (bfd *, asymbol **, bfd_boolean); ++ void (*swap_dyn_in) ++ (bfd *, const void *, Elf_Internal_Dyn *); ++ void (*swap_dyn_out) ++ (bfd *, const Elf_Internal_Dyn *, void *); ++ ++ /* This function is called to swap in a REL relocation. If an ++ external relocation corresponds to more than one internal ++ relocation, then all relocations are swapped in at once. */ ++ void (*swap_reloc_in) ++ (bfd *, const bfd_byte *, Elf_Internal_Rela *); ++ ++ /* This function is called to swap out a REL relocation. */ ++ void (*swap_reloc_out) ++ (bfd *, const Elf_Internal_Rela *, bfd_byte *); ++ ++ /* This function is called to swap in a RELA relocation. If an ++ external relocation corresponds to more than one internal ++ relocation, then all relocations are swapped in at once. */ ++ void (*swap_reloca_in) ++ (bfd *, const bfd_byte *, Elf_Internal_Rela *); ++ ++ /* This function is called to swap out a RELA relocation. */ ++ void (*swap_reloca_out) ++ (bfd *, const Elf_Internal_Rela *, bfd_byte *); ++}; ++ ++#define elf_symbol_from(ABFD,S) \ ++ (((S)->the_bfd->xvec->flavour == bfd_target_elf_flavour \ ++ && (S)->the_bfd->tdata.elf_obj_data != 0) \ ++ ? (elf_symbol_type *) (S) \ ++ : 0) ++ ++enum elf_reloc_type_class { ++ reloc_class_normal, ++ reloc_class_relative, ++ reloc_class_plt, ++ reloc_class_copy ++}; ++ ++struct elf_reloc_cookie ++{ ++ Elf_Internal_Rela *rels, *rel, *relend; ++ Elf_Internal_Sym *locsyms; ++ bfd *abfd; ++ size_t locsymcount; ++ size_t extsymoff; ++ struct elf_link_hash_entry **sym_hashes; ++ bfd_boolean bad_symtab; ++}; ++ ++/* The level of IRIX compatibility we're striving for. */ ++ ++typedef enum { ++ ict_none, ++ ict_irix5, ++ ict_irix6 ++} irix_compat_t; ++ ++/* Mapping of ELF section names and types. */ ++struct bfd_elf_special_section ++{ ++ const char *prefix; ++ int prefix_length; ++ /* 0 means name must match PREFIX exactly. ++ -1 means name must start with PREFIX followed by an arbitrary string. ++ -2 means name must match PREFIX exactly or consist of PREFIX followed ++ by a dot then anything. ++ > 0 means name must start with the first PREFIX_LENGTH chars of ++ PREFIX and finish with the last SUFFIX_LENGTH chars of PREFIX. */ ++ int suffix_length; ++ int type; ++ int attr; ++}; ++ ++struct elf_backend_data ++{ ++ /* The architecture for this backend. */ ++ enum bfd_architecture arch; ++ ++ /* The ELF machine code (EM_xxxx) for this backend. */ ++ int elf_machine_code; ++ ++ /* The maximum page size for this backend. */ ++ bfd_vma maxpagesize; ++ ++ /* A function to translate an ELF RELA relocation to a BFD arelent ++ structure. */ ++ void (*elf_info_to_howto) ++ (bfd *, arelent *, Elf_Internal_Rela *); ++ ++ /* A function to translate an ELF REL relocation to a BFD arelent ++ structure. */ ++ void (*elf_info_to_howto_rel) ++ (bfd *, arelent *, Elf_Internal_Rela *); ++ ++ /* A function to determine whether a symbol is global when ++ partitioning the symbol table into local and global symbols. ++ This should be NULL for most targets, in which case the correct ++ thing will be done. MIPS ELF, at least on the Irix 5, has ++ special requirements. */ ++ bfd_boolean (*elf_backend_sym_is_global) ++ (bfd *, asymbol *); ++ ++ /* The remaining functions are hooks which are called only if they ++ are not NULL. */ ++ ++ /* A function to permit a backend specific check on whether a ++ particular BFD format is relevant for an object file, and to ++ permit the backend to set any global information it wishes. When ++ this is called elf_elfheader is set, but anything else should be ++ used with caution. If this returns FALSE, the check_format ++ routine will return a bfd_error_wrong_format error. */ ++ bfd_boolean (*elf_backend_object_p) ++ (bfd *); ++ ++ /* A function to do additional symbol processing when reading the ++ ELF symbol table. This is where any processor-specific special ++ section indices are handled. */ ++ void (*elf_backend_symbol_processing) ++ (bfd *, asymbol *); ++ ++ /* A function to do additional symbol processing after reading the ++ entire ELF symbol table. */ ++ bfd_boolean (*elf_backend_symbol_table_processing) ++ (bfd *, elf_symbol_type *, unsigned int); ++ ++ /* A function to set the type of the info field. Processor-specific ++ types should be handled here. */ ++ int (*elf_backend_get_symbol_type) ++ (Elf_Internal_Sym *, int); ++ ++ /* A function to do additional processing on the ELF section header ++ just before writing it out. This is used to set the flags and ++ type fields for some sections, or to actually write out data for ++ unusual sections. */ ++ bfd_boolean (*elf_backend_section_processing) ++ (bfd *, Elf_Internal_Shdr *); ++ ++ /* A function to handle unusual section types when creating BFD ++ sections from ELF sections. */ ++ bfd_boolean (*elf_backend_section_from_shdr) ++ (bfd *, Elf_Internal_Shdr *, const char *); ++ ++ /* A function to convert machine dependent section header flags to ++ BFD internal section header flags. */ ++ bfd_boolean (*elf_backend_section_flags) ++ (flagword *, Elf_Internal_Shdr *); ++ ++ /* A function to handle unusual program segment types when creating BFD ++ sections from ELF program segments. */ ++ bfd_boolean (*elf_backend_section_from_phdr) ++ (bfd *, Elf_Internal_Phdr *, int); ++ ++ /* A function to set up the ELF section header for a BFD section in ++ preparation for writing it out. This is where the flags and type ++ fields are set for unusual sections. */ ++ bfd_boolean (*elf_backend_fake_sections) ++ (bfd *, Elf_Internal_Shdr *, asection *); ++ ++ /* A function to get the ELF section index for a BFD section. If ++ this returns TRUE, the section was found. If it is a normal ELF ++ section, *RETVAL should be left unchanged. If it is not a normal ++ ELF section *RETVAL should be set to the SHN_xxxx index. */ ++ bfd_boolean (*elf_backend_section_from_bfd_section) ++ (bfd *, asection *, int *retval); ++ ++ /* If this field is not NULL, it is called by the add_symbols phase ++ of a link just before adding a symbol to the global linker hash ++ table. It may modify any of the fields as it wishes. If *NAME ++ is set to NULL, the symbol will be skipped rather than being ++ added to the hash table. This function is responsible for ++ handling all processor dependent symbol bindings and section ++ indices, and must set at least *FLAGS and *SEC for each processor ++ dependent case; failure to do so will cause a link error. */ ++ bfd_boolean (*elf_add_symbol_hook) ++ (bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Sym *, ++ const char **name, flagword *flags, asection **sec, bfd_vma *value); ++ ++ /* If this field is not NULL, it is called by the elf_link_output_sym ++ phase of a link for each symbol which will appear in the object file. */ ++ bfd_boolean (*elf_backend_link_output_symbol_hook) ++ (bfd *, struct bfd_link_info *info, const char *, Elf_Internal_Sym *, ++ asection *); ++ ++ /* The CREATE_DYNAMIC_SECTIONS function is called by the ELF backend ++ linker the first time it encounters a dynamic object in the link. ++ This function must create any sections required for dynamic ++ linking. The ABFD argument is a dynamic object. The .interp, ++ .dynamic, .dynsym, .dynstr, and .hash functions have already been ++ created, and this function may modify the section flags if ++ desired. This function will normally create the .got and .plt ++ sections, but different backends have different requirements. */ ++ bfd_boolean (*elf_backend_create_dynamic_sections) ++ (bfd *abfd, struct bfd_link_info *info); ++ ++ /* The CHECK_RELOCS function is called by the add_symbols phase of ++ the ELF backend linker. It is called once for each section with ++ relocs of an object file, just after the symbols for the object ++ file have been added to the global linker hash table. The ++ function must look through the relocs and do any special handling ++ required. This generally means allocating space in the global ++ offset table, and perhaps allocating space for a reloc. The ++ relocs are always passed as Rela structures; if the section ++ actually uses Rel structures, the r_addend field will always be ++ zero. */ ++ bfd_boolean (*check_relocs) ++ (bfd *abfd, struct bfd_link_info *info, asection *o, ++ const Elf_Internal_Rela *relocs); ++ ++ /* The ADJUST_DYNAMIC_SYMBOL function is called by the ELF backend ++ linker for every symbol which is defined by a dynamic object and ++ referenced by a regular object. This is called after all the ++ input files have been seen, but before the SIZE_DYNAMIC_SECTIONS ++ function has been called. The hash table entry should be ++ bfd_link_hash_defined ore bfd_link_hash_defweak, and it should be ++ defined in a section from a dynamic object. Dynamic object ++ sections are not included in the final link, and this function is ++ responsible for changing the value to something which the rest of ++ the link can deal with. This will normally involve adding an ++ entry to the .plt or .got or some such section, and setting the ++ symbol to point to that. */ ++ bfd_boolean (*elf_backend_adjust_dynamic_symbol) ++ (struct bfd_link_info *info, struct elf_link_hash_entry *h); ++ ++ /* The ALWAYS_SIZE_SECTIONS function is called by the backend linker ++ after all the linker input files have been seen but before the ++ section sizes have been set. This is called after ++ ADJUST_DYNAMIC_SYMBOL, but before SIZE_DYNAMIC_SECTIONS. */ ++ bfd_boolean (*elf_backend_always_size_sections) ++ (bfd *output_bfd, struct bfd_link_info *info); ++ ++ /* The SIZE_DYNAMIC_SECTIONS function is called by the ELF backend ++ linker after all the linker input files have been seen but before ++ the sections sizes have been set. This is called after ++ ADJUST_DYNAMIC_SYMBOL has been called on all appropriate symbols. ++ It is only called when linking against a dynamic object. It must ++ set the sizes of the dynamic sections, and may fill in their ++ contents as well. The generic ELF linker can handle the .dynsym, ++ .dynstr and .hash sections. This function must handle the ++ .interp section and any sections created by the ++ CREATE_DYNAMIC_SECTIONS entry point. */ ++ bfd_boolean (*elf_backend_size_dynamic_sections) ++ (bfd *output_bfd, struct bfd_link_info *info); ++ ++ /* The RELOCATE_SECTION function is called by the ELF backend linker ++ to handle the relocations for a section. ++ ++ The relocs are always passed as Rela structures; if the section ++ actually uses Rel structures, the r_addend field will always be ++ zero. ++ ++ This function is responsible for adjust the section contents as ++ necessary, and (if using Rela relocs and generating a ++ relocatable output file) adjusting the reloc addend as ++ necessary. ++ ++ This function does not have to worry about setting the reloc ++ address or the reloc symbol index. ++ ++ LOCAL_SYMS is a pointer to the swapped in local symbols. ++ ++ LOCAL_SECTIONS is an array giving the section in the input file ++ corresponding to the st_shndx field of each local symbol. ++ ++ The global hash table entry for the global symbols can be found ++ via elf_sym_hashes (input_bfd). ++ ++ When generating relocatable output, this function must handle ++ STB_LOCAL/STT_SECTION symbols specially. The output symbol is ++ going to be the section symbol corresponding to the output ++ section, which means that the addend must be adjusted ++ accordingly. */ ++ bfd_boolean (*elf_backend_relocate_section) ++ (bfd *output_bfd, struct bfd_link_info *info, bfd *input_bfd, ++ asection *input_section, bfd_byte *contents, Elf_Internal_Rela *relocs, ++ Elf_Internal_Sym *local_syms, asection **local_sections); ++ ++ /* The FINISH_DYNAMIC_SYMBOL function is called by the ELF backend ++ linker just before it writes a symbol out to the .dynsym section. ++ The processor backend may make any required adjustment to the ++ symbol. It may also take the opportunity to set contents of the ++ dynamic sections. Note that FINISH_DYNAMIC_SYMBOL is called on ++ all .dynsym symbols, while ADJUST_DYNAMIC_SYMBOL is only called ++ on those symbols which are defined by a dynamic object. */ ++ bfd_boolean (*elf_backend_finish_dynamic_symbol) ++ (bfd *output_bfd, struct bfd_link_info *info, ++ struct elf_link_hash_entry *h, Elf_Internal_Sym *sym); ++ ++ /* The FINISH_DYNAMIC_SECTIONS function is called by the ELF backend ++ linker just before it writes all the dynamic sections out to the ++ output file. The FINISH_DYNAMIC_SYMBOL will have been called on ++ all dynamic symbols. */ ++ bfd_boolean (*elf_backend_finish_dynamic_sections) ++ (bfd *output_bfd, struct bfd_link_info *info); ++ ++ /* A function to do any beginning processing needed for the ELF file ++ before building the ELF headers and computing file positions. */ ++ void (*elf_backend_begin_write_processing) ++ (bfd *, struct bfd_link_info *); ++ ++ /* A function to do any final processing needed for the ELF file ++ before writing it out. The LINKER argument is TRUE if this BFD ++ was created by the ELF backend linker. */ ++ void (*elf_backend_final_write_processing) ++ (bfd *, bfd_boolean linker); ++ ++ /* This function is called by get_program_header_size. It should ++ return the number of additional program segments which this BFD ++ will need. It should return -1 on error. */ ++ int (*elf_backend_additional_program_headers) ++ (bfd *); ++ ++ /* This function is called to modify an existing segment map in a ++ backend specific fashion. */ ++ bfd_boolean (*elf_backend_modify_segment_map) ++ (bfd *); ++ ++ /* This function is called during section gc to discover the section a ++ particular relocation refers to. */ ++ asection * (*gc_mark_hook) ++ (asection *sec, struct bfd_link_info *, Elf_Internal_Rela *, ++ struct elf_link_hash_entry *h, Elf_Internal_Sym *); ++ ++ /* This function, if defined, is called during the sweep phase of gc ++ in order that a backend might update any data structures it might ++ be maintaining. */ ++ bfd_boolean (*gc_sweep_hook) ++ (bfd *abfd, struct bfd_link_info *info, asection *o, ++ const Elf_Internal_Rela *relocs); ++ ++ /* This function, if defined, is called after the ELF headers have ++ been created. This allows for things like the OS and ABI versions ++ to be changed. */ ++ void (*elf_backend_post_process_headers) ++ (bfd *, struct bfd_link_info *); ++ ++ /* This function, if defined, prints a symbol to file and returns the ++ name of the symbol to be printed. It should return NULL to fall ++ back to default symbol printing. */ ++ const char *(*elf_backend_print_symbol_all) ++ (bfd *, void *, asymbol *); ++ ++ /* This function, if defined, is called after all local symbols and ++ global symbols converted to locals are emited into the symtab ++ section. It allows the backend to emit special global symbols ++ not handled in the hash table. */ ++ bfd_boolean (*elf_backend_output_arch_syms) ++ (bfd *, struct bfd_link_info *, void *, ++ bfd_boolean (*) (void *, const char *, Elf_Internal_Sym *, asection *)); ++ ++ /* Copy any information related to dynamic linking from a pre-existing ++ symbol to a newly created symbol. Also called to copy flags and ++ other back-end info to a weakdef, in which case the symbol is not ++ newly created and plt/got refcounts and dynamic indices should not ++ be copied. */ ++ void (*elf_backend_copy_indirect_symbol) ++ (const struct elf_backend_data *, struct elf_link_hash_entry *, ++ struct elf_link_hash_entry *); ++ ++ /* Modify any information related to dynamic linking such that the ++ symbol is not exported. */ ++ void (*elf_backend_hide_symbol) ++ (struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean); ++ ++ /* Merge the backend specific symbol attribute. */ ++ void (*elf_backend_merge_symbol_attribute) ++ (struct elf_link_hash_entry *, const Elf_Internal_Sym *, bfd_boolean, ++ bfd_boolean); ++ ++ /* Emit relocations. Overrides default routine for emitting relocs, ++ except during a relocatable link, or if all relocs are being emitted. */ ++ bfd_boolean (*elf_backend_emit_relocs) ++ (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *); ++ ++ /* Count relocations. Not called for relocatable links ++ or if all relocs are being preserved in the output. */ ++ unsigned int (*elf_backend_count_relocs) ++ (asection *, Elf_Internal_Rela *); ++ ++ /* This function, if defined, is called when an NT_PRSTATUS note is found ++ in a core file. */ ++ bfd_boolean (*elf_backend_grok_prstatus) ++ (bfd *, Elf_Internal_Note *); ++ ++ /* This function, if defined, is called when an NT_PSINFO or NT_PRPSINFO ++ note is found in a core file. */ ++ bfd_boolean (*elf_backend_grok_psinfo) ++ (bfd *, Elf_Internal_Note *); ++ ++ /* Functions to print VMAs. Special code to handle 64 bit ELF files. */ ++ void (* elf_backend_sprintf_vma) ++ (bfd *, char *, bfd_vma); ++ void (* elf_backend_fprintf_vma) ++ (bfd *, void *, bfd_vma); ++ ++ /* This function returns class of a reloc type. */ ++ enum elf_reloc_type_class (*elf_backend_reloc_type_class) ++ (const Elf_Internal_Rela *); ++ ++ /* This function, if defined, removes information about discarded functions ++ from other sections which mention them. */ ++ bfd_boolean (*elf_backend_discard_info) ++ (bfd *, struct elf_reloc_cookie *, struct bfd_link_info *); ++ ++ /* This function, if defined, signals that the function above has removed ++ the discarded relocations for this section. */ ++ bfd_boolean (*elf_backend_ignore_discarded_relocs) ++ (asection *); ++ ++ /* This function, if defined, may write out the given section. ++ Returns TRUE if it did so and FALSE if the caller should. */ ++ bfd_boolean (*elf_backend_write_section) ++ (bfd *, asection *, bfd_byte *); ++ ++ /* The level of IRIX compatibility we're striving for. ++ MIPS ELF specific function. */ ++ irix_compat_t (*elf_backend_mips_irix_compat) ++ (bfd *); ++ ++ reloc_howto_type *(*elf_backend_mips_rtype_to_howto) ++ (unsigned int, bfd_boolean); ++ ++ /* The swapping table to use when dealing with ECOFF information. ++ Used for the MIPS ELF .mdebug section. */ ++ const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap; ++ ++ /* This function implements `bfd_elf_bfd_from_remote_memory'; ++ see elf.c, elfcode.h. */ ++ bfd *(*elf_backend_bfd_from_remote_memory) ++ (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, ++ int (*target_read_memory) (bfd_vma vma, char *myaddr, int len)); ++ ++ /* Alternate EM_xxxx machine codes for this backend. */ ++ int elf_machine_alt1; ++ int elf_machine_alt2; ++ ++ const struct elf_size_info *s; ++ ++ /* An array of target specific special section map. */ ++ const struct bfd_elf_special_section *special_sections; ++ ++ /* offset of the _GLOBAL_OFFSET_TABLE_ symbol from the start of the ++ .got section */ ++ bfd_vma got_symbol_offset; ++ ++ /* The size in bytes of the headers for the GOT and PLT. This includes ++ the so-called reserved entries on some systems. */ ++ bfd_vma got_header_size; ++ bfd_vma plt_header_size; ++ ++ /* This is TRUE if the linker should act like collect and gather ++ global constructors and destructors by name. This is TRUE for ++ MIPS ELF because the Irix 5 tools can not handle the .init ++ section. */ ++ unsigned collect : 1; ++ ++ /* This is TRUE if the linker should ignore changes to the type of a ++ symbol. This is TRUE for MIPS ELF because some Irix 5 objects ++ record undefined functions as STT_OBJECT although the definitions ++ are STT_FUNC. */ ++ unsigned type_change_ok : 1; ++ ++ /* Whether the backend may use REL relocations. (Some backends use ++ both REL and RELA relocations, and this flag is set for those ++ backends.) */ ++ unsigned may_use_rel_p : 1; ++ ++ /* Whether the backend may use RELA relocations. (Some backends use ++ both REL and RELA relocations, and this flag is set for those ++ backends.) */ ++ unsigned may_use_rela_p : 1; ++ ++ /* Whether the default relocation type is RELA. If a backend with ++ this flag set wants REL relocations for a particular section, ++ it must note that explicitly. Similarly, if this flag is clear, ++ and the backend wants RELA relocations for a particular ++ section. */ ++ unsigned default_use_rela_p : 1; ++ ++ /* Set if RELA relocations for a relocatable link can be handled by ++ generic code. Backends that set this flag need do nothing in the ++ backend relocate_section routine for relocatable linking. */ ++ unsigned rela_normal : 1; ++ ++ /* TRUE if addresses "naturally" sign extend. This is used when ++ swapping in from Elf32 when BFD64. */ ++ unsigned sign_extend_vma : 1; ++ ++ unsigned want_got_plt : 1; ++ unsigned plt_readonly : 1; ++ unsigned want_plt_sym : 1; ++ unsigned plt_not_loaded : 1; ++ unsigned plt_alignment : 4; ++ unsigned can_gc_sections : 1; ++ unsigned can_refcount : 1; ++ unsigned want_got_sym : 1; ++ unsigned want_dynbss : 1; ++ /* Targets which do not support physical addressing often require ++ that the p_paddr field in the section header to be set to zero. ++ This field indicates whether this behavior is required. */ ++ unsigned want_p_paddr_set_to_zero : 1; ++}; ++ ++/* Information stored for each BFD section in an ELF file. This ++ structure is allocated by elf_new_section_hook. */ ++ ++struct bfd_elf_section_data ++{ ++ /* The ELF header for this section. */ ++ Elf_Internal_Shdr this_hdr; ++ ++ /* The ELF header for the reloc section associated with this ++ section, if any. */ ++ Elf_Internal_Shdr rel_hdr; ++ ++ /* If there is a second reloc section associated with this section, ++ as can happen on Irix 6, this field points to the header. */ ++ Elf_Internal_Shdr *rel_hdr2; ++ ++ /* The number of relocations currently assigned to REL_HDR. */ ++ unsigned int rel_count; ++ ++ /* The number of relocations currently assigned to REL_HDR2. */ ++ unsigned int rel_count2; ++ ++ /* The ELF section number of this section. Only used for an output ++ file. */ ++ int this_idx; ++ ++ /* The ELF section number of the reloc section indicated by ++ REL_HDR if any. Only used for an output file. */ ++ int rel_idx; ++ ++ /* The ELF section number of the reloc section indicated by ++ REL_HDR2 if any. Only used for an output file. */ ++ int rel_idx2; ++ ++ /* Used by the backend linker when generating a shared library to ++ record the dynamic symbol index for a section symbol ++ corresponding to this section. A value of 0 means that there is ++ no dynamic symbol for this section. */ ++ int dynindx; ++ ++ /* Used by the backend linker to store the symbol hash table entries ++ associated with relocs against global symbols. */ ++ struct elf_link_hash_entry **rel_hashes; ++ ++ /* A pointer to the swapped relocs. If the section uses REL relocs, ++ rather than RELA, all the r_addend fields will be zero. This ++ pointer may be NULL. It is used by the backend linker. */ ++ Elf_Internal_Rela *relocs; ++ ++ /* A pointer to a linked list tracking dynamic relocs copied for ++ local symbols. */ ++ void *local_dynrel; ++ ++ /* A pointer to the bfd section used for dynamic relocs. */ ++ asection *sreloc; ++ ++ union { ++ /* Group name, if this section is a member of a group. */ ++ const char *name; ++ ++ /* Group signature sym, if this is the SHT_GROUP section. */ ++ struct symbol_cache_entry *id; ++ } group; ++ ++ /* A linked list of sections in the group. Circular when used by ++ the linker. */ ++ asection *next_in_group; ++ ++ /* A pointer used for various section optimizations. */ ++ void *sec_info; ++}; ++ ++#define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd) ++#define elf_section_type(sec) (elf_section_data(sec)->this_hdr.sh_type) ++#define elf_section_flags(sec) (elf_section_data(sec)->this_hdr.sh_flags) ++#define elf_group_name(sec) (elf_section_data(sec)->group.name) ++#define elf_group_id(sec) (elf_section_data(sec)->group.id) ++#define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group) ++ ++/* Return TRUE if section has been discarded. */ ++#define elf_discarded_section(sec) \ ++ (!bfd_is_abs_section (sec) \ ++ && bfd_is_abs_section ((sec)->output_section) \ ++ && sec->sec_info_type != ELF_INFO_TYPE_MERGE \ ++ && sec->sec_info_type != ELF_INFO_TYPE_JUST_SYMS) ++ ++#define get_elf_backend_data(abfd) \ ++ ((const struct elf_backend_data *) (abfd)->xvec->backend_data) ++ ++/* This struct is used to pass information to routines called via ++ elf_link_hash_traverse which must return failure. */ ++ ++struct elf_info_failed ++{ ++ bfd_boolean failed; ++ struct bfd_link_info *info; ++ struct bfd_elf_version_tree *verdefs; ++}; ++ ++/* This structure is used to pass information to ++ _bfd_elf_link_assign_sym_version. */ ++ ++struct elf_assign_sym_version_info ++{ ++ /* Output BFD. */ ++ bfd *output_bfd; ++ /* General link information. */ ++ struct bfd_link_info *info; ++ /* Version tree. */ ++ struct bfd_elf_version_tree *verdefs; ++ /* Whether we had a failure. */ ++ bfd_boolean failed; ++}; ++ ++/* This structure is used to pass information to ++ _bfd_elf_link_find_version_dependencies. */ ++ ++struct elf_find_verdep_info ++{ ++ /* Output BFD. */ ++ bfd *output_bfd; ++ /* General link information. */ ++ struct bfd_link_info *info; ++ /* The number of dependencies. */ ++ unsigned int vers; ++ /* Whether we had a failure. */ ++ bfd_boolean failed; ++}; ++ ++/* Some private data is stashed away for future use using the tdata pointer ++ in the bfd structure. */ ++ ++struct elf_obj_tdata ++{ ++ Elf_Internal_Ehdr elf_header[1]; /* Actual data, but ref like ptr */ ++ Elf_Internal_Shdr **elf_sect_ptr; ++ Elf_Internal_Phdr *phdr; ++ struct elf_segment_map *segment_map; ++ struct elf_strtab_hash *strtab_ptr; ++ int num_locals; ++ int num_globals; ++ unsigned int num_elf_sections; /* elf_sect_ptr size */ ++ int num_section_syms; ++ asymbol **section_syms; /* STT_SECTION symbols for each section */ ++ Elf_Internal_Shdr symtab_hdr; ++ Elf_Internal_Shdr shstrtab_hdr; ++ Elf_Internal_Shdr strtab_hdr; ++ Elf_Internal_Shdr dynsymtab_hdr; ++ Elf_Internal_Shdr dynstrtab_hdr; ++ Elf_Internal_Shdr dynversym_hdr; ++ Elf_Internal_Shdr dynverref_hdr; ++ Elf_Internal_Shdr dynverdef_hdr; ++ Elf_Internal_Shdr symtab_shndx_hdr; ++ unsigned int symtab_section, shstrtab_section; ++ unsigned int strtab_section, dynsymtab_section; ++ unsigned int symtab_shndx_section; ++ unsigned int dynversym_section, dynverdef_section, dynverref_section; ++ file_ptr next_file_pos; ++ bfd_vma gp; /* The gp value */ ++ unsigned int gp_size; /* The gp size */ ++ ++ Elf_Internal_Shdr **group_sect_ptr; ++ int num_group; ++ ++ /* Information grabbed from an elf core file. */ ++ int core_signal; ++ int core_pid; ++ int core_lwpid; ++ char* core_program; ++ char* core_command; ++ ++ /* This is set to TRUE if the object was created by the backend ++ linker. */ ++ bfd_boolean linker; ++ ++ /* A mapping from external symbols to entries in the linker hash ++ table, used when linking. This is indexed by the symbol index ++ minus the sh_info field of the symbol table header. */ ++ struct elf_link_hash_entry **sym_hashes; ++ ++ /* Track usage and final offsets of GOT entries for local symbols. ++ This array is indexed by symbol index. Elements are used ++ identically to "got" in struct elf_link_hash_entry. */ ++ union ++ { ++ bfd_signed_vma *refcounts; ++ bfd_vma *offsets; ++ struct got_entry **ents; ++ } local_got; ++ ++ /* The linker ELF emulation code needs to let the backend ELF linker ++ know what filename should be used for a dynamic object if the ++ dynamic object is found using a search. The emulation code then ++ sometimes needs to know what name was actually used. Until the ++ file has been added to the linker symbol table, this field holds ++ the name the linker wants. After it has been added, it holds the ++ name actually used, which will be the DT_SONAME entry if there is ++ one. */ ++ const char *dt_name; ++ ++ /* When a reference in a regular object is resolved by a shared ++ object is loaded into via the DT_NEEDED entries by the linker ++ ELF emulation code, we need to add the shared object to the ++ DT_NEEDED list of the resulting binary to indicate the dependency ++ as if the -l option is passed to the linker. This field holds the ++ name of the loaded shared object. */ ++ const char *dt_soname; ++ ++ /* Irix 5 often screws up the symbol table, sorting local symbols ++ after global symbols. This flag is set if the symbol table in ++ this BFD appears to be screwed up. If it is, we ignore the ++ sh_info field in the symbol table header, and always read all the ++ symbols. */ ++ bfd_boolean bad_symtab; ++ ++ /* Records the result of `get_program_header_size'. */ ++ bfd_size_type program_header_size; ++ ++ /* Used by find_nearest_line entry point. */ ++ void *line_info; ++ ++ /* Used by MIPS ELF find_nearest_line entry point. The structure ++ could be included directly in this one, but there's no point to ++ wasting the memory just for the infrequently called ++ find_nearest_line. */ ++ struct mips_elf_find_line *find_line_info; ++ ++ /* A place to stash dwarf1 info for this bfd. */ ++ struct dwarf1_debug *dwarf1_find_line_info; ++ ++ /* A place to stash dwarf2 info for this bfd. */ ++ void *dwarf2_find_line_info; ++ ++ /* An array of stub sections indexed by symbol number, used by the ++ MIPS ELF linker. FIXME: We should figure out some way to only ++ include this field for a MIPS ELF target. */ ++ asection **local_stubs; ++ ++ /* Used to determine if PT_GNU_EH_FRAME segment header should be ++ created. */ ++ asection *eh_frame_hdr; ++ ++ /* Used to determine if the e_flags field has been initialized */ ++ bfd_boolean flags_init; ++ ++ /* Number of symbol version definitions we are about to emit. */ ++ unsigned int cverdefs; ++ ++ /* Number of symbol version references we are about to emit. */ ++ unsigned int cverrefs; ++ ++ /* Segment flags for the PT_GNU_STACK segment. */ ++ unsigned int stack_flags; ++ ++ /* Symbol version definitions in external objects. */ ++ Elf_Internal_Verdef *verdef; ++ ++ /* Symbol version references to external objects. */ ++ Elf_Internal_Verneed *verref; ++ ++ /* The Irix 5 support uses two virtual sections, which represent ++ text/data symbols defined in dynamic objects. */ ++ asymbol *elf_data_symbol; ++ asymbol *elf_text_symbol; ++ asection *elf_data_section; ++ asection *elf_text_section; ++}; ++ ++#define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) ++#define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header) ++#define elf_elfsections(bfd) (elf_tdata(bfd) -> elf_sect_ptr) ++#define elf_numsections(bfd) (elf_tdata(bfd) -> num_elf_sections) ++#define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr) ++#define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section) ++#define elf_symtab_shndx(bfd) (elf_tdata(bfd) -> symtab_shndx_section) ++#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section) ++#define elf_dynversym(bfd) (elf_tdata(bfd) -> dynversym_section) ++#define elf_dynverdef(bfd) (elf_tdata(bfd) -> dynverdef_section) ++#define elf_dynverref(bfd) (elf_tdata(bfd) -> dynverref_section) ++#define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals) ++#define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals) ++#define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms) ++#define elf_num_section_syms(bfd) (elf_tdata(bfd) -> num_section_syms) ++#define core_prpsinfo(bfd) (elf_tdata(bfd) -> prpsinfo) ++#define core_prstatus(bfd) (elf_tdata(bfd) -> prstatus) ++#define elf_gp(bfd) (elf_tdata(bfd) -> gp) ++#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size) ++#define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes) ++#define elf_local_got_refcounts(bfd) (elf_tdata(bfd) -> local_got.refcounts) ++#define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got.offsets) ++#define elf_local_got_ents(bfd) (elf_tdata(bfd) -> local_got.ents) ++#define elf_dt_name(bfd) (elf_tdata(bfd) -> dt_name) ++#define elf_dt_soname(bfd) (elf_tdata(bfd) -> dt_soname) ++#define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) ++#define elf_flags_init(bfd) (elf_tdata(bfd) -> flags_init) ++ ++extern void _bfd_elf_swap_verdef_in ++ (bfd *, const Elf_External_Verdef *, Elf_Internal_Verdef *); ++extern void _bfd_elf_swap_verdef_out ++ (bfd *, const Elf_Internal_Verdef *, Elf_External_Verdef *); ++extern void _bfd_elf_swap_verdaux_in ++ (bfd *, const Elf_External_Verdaux *, Elf_Internal_Verdaux *); ++extern void _bfd_elf_swap_verdaux_out ++ (bfd *, const Elf_Internal_Verdaux *, Elf_External_Verdaux *); ++extern void _bfd_elf_swap_verneed_in ++ (bfd *, const Elf_External_Verneed *, Elf_Internal_Verneed *); ++extern void _bfd_elf_swap_verneed_out ++ (bfd *, const Elf_Internal_Verneed *, Elf_External_Verneed *); ++extern void _bfd_elf_swap_vernaux_in ++ (bfd *, const Elf_External_Vernaux *, Elf_Internal_Vernaux *); ++extern void _bfd_elf_swap_vernaux_out ++ (bfd *, const Elf_Internal_Vernaux *, Elf_External_Vernaux *); ++extern void _bfd_elf_swap_versym_in ++ (bfd *, const Elf_External_Versym *, Elf_Internal_Versym *); ++extern void _bfd_elf_swap_versym_out ++ (bfd *, const Elf_Internal_Versym *, Elf_External_Versym *); ++ ++extern int _bfd_elf_section_from_bfd_section ++ (bfd *, asection *); ++extern char *bfd_elf_string_from_elf_section ++ (bfd *, unsigned, unsigned); ++extern char *bfd_elf_get_str_section ++ (bfd *, unsigned); ++extern Elf_Internal_Sym *bfd_elf_get_elf_syms ++ (bfd *, Elf_Internal_Shdr *, size_t, size_t, Elf_Internal_Sym *, void *, ++ Elf_External_Sym_Shndx *); ++extern const char *bfd_elf_local_sym_name ++ (bfd *, Elf_Internal_Sym *); ++ ++extern bfd_boolean _bfd_elf_copy_private_bfd_data ++ (bfd *, bfd *); ++extern bfd_boolean _bfd_elf_print_private_bfd_data ++ (bfd *, void *); ++extern void bfd_elf_print_symbol ++ (bfd *, void *, asymbol *, bfd_print_symbol_type); ++ ++#define elf_string_from_elf_strtab(abfd, strindex) \ ++ bfd_elf_string_from_elf_section (abfd, elf_elfheader(abfd)->e_shstrndx, \ ++ strindex) ++ ++#define bfd_elf32_print_symbol bfd_elf_print_symbol ++#define bfd_elf64_print_symbol bfd_elf_print_symbol ++ ++extern void _bfd_elf_sprintf_vma ++ (bfd *, char *, bfd_vma); ++extern void _bfd_elf_fprintf_vma ++ (bfd *, void *, bfd_vma); ++ ++extern enum elf_reloc_type_class _bfd_elf_reloc_type_class ++ (const Elf_Internal_Rela *); ++extern bfd_vma _bfd_elf_rela_local_sym ++ (bfd *, Elf_Internal_Sym *, asection *, Elf_Internal_Rela *); ++extern bfd_vma _bfd_elf_rel_local_sym ++ (bfd *, Elf_Internal_Sym *, asection **, bfd_vma); ++extern bfd_vma _bfd_elf_section_offset ++ (bfd *, struct bfd_link_info *, asection *, bfd_vma); ++ ++extern unsigned long bfd_elf_hash ++ (const char *); ++ ++extern bfd_reloc_status_type bfd_elf_generic_reloc ++ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); ++extern bfd_boolean bfd_elf_mkobject ++ (bfd *); ++extern bfd_boolean bfd_elf_mkcorefile ++ (bfd *); ++extern Elf_Internal_Shdr *bfd_elf_find_section ++ (bfd *, char *); ++extern bfd_boolean _bfd_elf_make_section_from_shdr ++ (bfd *, Elf_Internal_Shdr *, const char *); ++extern bfd_boolean _bfd_elf_make_section_from_phdr ++ (bfd *, Elf_Internal_Phdr *, int, const char *); ++extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc ++ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); ++extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create ++ (bfd *); ++extern void _bfd_elf_link_hash_copy_indirect ++ (const struct elf_backend_data *, struct elf_link_hash_entry *, ++ struct elf_link_hash_entry *); ++extern void _bfd_elf_link_hash_hide_symbol ++ (struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean); ++extern bfd_boolean _bfd_elf_link_hash_table_init ++ (struct elf_link_hash_table *, bfd *, ++ struct bfd_hash_entry *(*) ++ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); ++extern bfd_boolean _bfd_elf_slurp_version_tables ++ (bfd *); ++extern bfd_boolean _bfd_elf_merge_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_elf_discard_group ++ (bfd *, struct bfd_section *); ++extern void bfd_elf_set_group_contents ++ (bfd *, asection *, void *); ++extern void _bfd_elf_link_just_syms ++ (asection *, struct bfd_link_info *); ++extern bfd_boolean _bfd_elf_copy_private_symbol_data ++ (bfd *, asymbol *, bfd *, asymbol *); ++extern bfd_boolean _bfd_elf_copy_private_section_data ++ (bfd *, asection *, bfd *, asection *); ++extern bfd_boolean _bfd_elf_write_object_contents ++ (bfd *); ++extern bfd_boolean _bfd_elf_write_corefile_contents ++ (bfd *); ++extern bfd_boolean _bfd_elf_set_section_contents ++ (bfd *, sec_ptr, void *, file_ptr, bfd_size_type); ++extern long _bfd_elf_get_symtab_upper_bound ++ (bfd *); ++extern long _bfd_elf_canonicalize_symtab ++ (bfd *, asymbol **); ++extern long _bfd_elf_get_dynamic_symtab_upper_bound ++ (bfd *); ++extern long _bfd_elf_canonicalize_dynamic_symtab ++ (bfd *, asymbol **); ++extern long _bfd_elf_get_reloc_upper_bound ++ (bfd *, sec_ptr); ++extern long _bfd_elf_canonicalize_reloc ++ (bfd *, sec_ptr, arelent **, asymbol **); ++extern long _bfd_elf_get_dynamic_reloc_upper_bound ++ (bfd *); ++extern long _bfd_elf_canonicalize_dynamic_reloc ++ (bfd *, arelent **, asymbol **); ++extern asymbol *_bfd_elf_make_empty_symbol ++ (bfd *); ++extern void _bfd_elf_get_symbol_info ++ (bfd *, asymbol *, symbol_info *); ++extern bfd_boolean _bfd_elf_is_local_label_name ++ (bfd *, const char *); ++extern alent *_bfd_elf_get_lineno ++ (bfd *, asymbol *); ++extern bfd_boolean _bfd_elf_set_arch_mach ++ (bfd *, enum bfd_architecture, unsigned long); ++extern bfd_boolean _bfd_elf_find_nearest_line ++ (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, ++ unsigned int *); ++#define _bfd_elf_read_minisymbols _bfd_generic_read_minisymbols ++#define _bfd_elf_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol ++extern int _bfd_elf_sizeof_headers ++ (bfd *, bfd_boolean); ++extern bfd_boolean _bfd_elf_new_section_hook ++ (bfd *, asection *); ++extern bfd_boolean _bfd_elf_init_reloc_shdr ++ (bfd *, Elf_Internal_Shdr *, asection *, bfd_boolean); ++extern const struct bfd_elf_special_section *_bfd_elf_get_sec_type_attr ++ (bfd *, const char *); ++ ++/* If the target doesn't have reloc handling written yet: */ ++extern void _bfd_elf_no_info_to_howto ++ (bfd *, arelent *, Elf_Internal_Rela *); ++ ++extern bfd_boolean bfd_section_from_shdr ++ (bfd *, unsigned int shindex); ++extern bfd_boolean bfd_section_from_phdr ++ (bfd *, Elf_Internal_Phdr *, int); ++ ++extern int _bfd_elf_symbol_from_bfd_symbol ++ (bfd *, asymbol **); ++ ++extern asection *bfd_section_from_r_symndx ++ (bfd *, struct sym_sec_cache *, asection *, unsigned long); ++extern asection *bfd_section_from_elf_index ++ (bfd *, unsigned int); ++extern struct bfd_strtab_hash *_bfd_elf_stringtab_init ++ (void); ++ ++extern struct elf_strtab_hash * _bfd_elf_strtab_init ++ (void); ++extern void _bfd_elf_strtab_free ++ (struct elf_strtab_hash *); ++extern bfd_size_type _bfd_elf_strtab_add ++ (struct elf_strtab_hash *, const char *, bfd_boolean); ++extern void _bfd_elf_strtab_addref ++ (struct elf_strtab_hash *, bfd_size_type); ++extern void _bfd_elf_strtab_delref ++ (struct elf_strtab_hash *, bfd_size_type); ++extern void _bfd_elf_strtab_clear_all_refs ++ (struct elf_strtab_hash *); ++extern bfd_size_type _bfd_elf_strtab_size ++ (struct elf_strtab_hash *); ++extern bfd_size_type _bfd_elf_strtab_offset ++ (struct elf_strtab_hash *, bfd_size_type); ++extern bfd_boolean _bfd_elf_strtab_emit ++ (bfd *, struct elf_strtab_hash *); ++extern void _bfd_elf_strtab_finalize ++ (struct elf_strtab_hash *); ++ ++extern bfd_boolean _bfd_elf_discard_section_eh_frame ++ (bfd *, struct bfd_link_info *, asection *, ++ bfd_boolean (*) (bfd_vma, void *), struct elf_reloc_cookie *); ++extern bfd_boolean _bfd_elf_discard_section_eh_frame_hdr ++ (bfd *, struct bfd_link_info *); ++extern bfd_vma _bfd_elf_eh_frame_section_offset ++ (bfd *, asection *, bfd_vma); ++extern bfd_boolean _bfd_elf_write_section_eh_frame ++ (bfd *, struct bfd_link_info *, asection *, bfd_byte *); ++extern bfd_boolean _bfd_elf_write_section_eh_frame_hdr ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean _bfd_elf_maybe_strip_eh_frame_hdr ++ (struct bfd_link_info *); ++ ++extern bfd_boolean _bfd_elf_merge_symbol ++ (bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *, ++ asection **, bfd_vma *, struct elf_link_hash_entry **, bfd_boolean *, ++ bfd_boolean *, bfd_boolean *, bfd_boolean *, bfd_boolean); ++ ++extern bfd_boolean _bfd_elf_add_default_symbol ++ (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, ++ const char *, Elf_Internal_Sym *, asection **, bfd_vma *, ++ bfd_boolean *, bfd_boolean, bfd_boolean); ++ ++extern bfd_boolean _bfd_elf_export_symbol ++ (struct elf_link_hash_entry *, void *); ++ ++extern bfd_boolean _bfd_elf_link_find_version_dependencies ++ (struct elf_link_hash_entry *, void *); ++ ++extern bfd_boolean _bfd_elf_link_assign_sym_version ++ (struct elf_link_hash_entry *, void *); ++ ++extern bfd_boolean _bfd_elf_link_record_dynamic_symbol ++ (struct bfd_link_info *, struct elf_link_hash_entry *); ++extern long _bfd_elf_link_lookup_local_dynindx ++ (struct bfd_link_info *, bfd *, long); ++extern bfd_boolean _bfd_elf_compute_section_file_positions ++ (bfd *, struct bfd_link_info *); ++extern void _bfd_elf_assign_file_positions_for_relocs ++ (bfd *); ++extern file_ptr _bfd_elf_assign_file_position_for_section ++ (Elf_Internal_Shdr *, file_ptr, bfd_boolean); ++ ++extern bfd_boolean _bfd_elf_validate_reloc ++ (bfd *, arelent *); ++ ++extern bfd_boolean _bfd_elf_link_create_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean _bfd_elf_create_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean _bfd_elf_create_got_section ++ (bfd *, struct bfd_link_info *); ++extern unsigned long _bfd_elf_link_renumber_dynsyms ++ (bfd *, struct bfd_link_info *); ++ ++extern bfd_boolean _bfd_elfcore_make_pseudosection ++ (bfd *, char *, size_t, ufile_ptr); ++extern char *_bfd_elfcore_strndup ++ (bfd *, char *, size_t); ++ ++extern Elf_Internal_Rela *_bfd_elf_link_read_relocs ++ (bfd *, asection *, void *, Elf_Internal_Rela *, bfd_boolean); ++ ++extern bfd_boolean _bfd_elf_link_size_reloc_section ++ (bfd *, Elf_Internal_Shdr *, asection *); ++ ++extern bfd_boolean _bfd_elf_link_output_relocs ++ (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *); ++ ++extern bfd_boolean _bfd_elf_fix_symbol_flags ++ (struct elf_link_hash_entry *, struct elf_info_failed *); ++ ++extern bfd_boolean _bfd_elf_adjust_dynamic_symbol ++ (struct elf_link_hash_entry *, void *); ++ ++extern bfd_boolean _bfd_elf_link_sec_merge_syms ++ (struct elf_link_hash_entry *, void *); ++ ++extern bfd_boolean _bfd_elf_dynamic_symbol_p ++ (struct elf_link_hash_entry *, struct bfd_link_info *, bfd_boolean); ++ ++extern bfd_boolean _bfd_elf_symbol_refs_local_p ++ (struct elf_link_hash_entry *, struct bfd_link_info *, bfd_boolean); ++ ++extern const bfd_target *bfd_elf32_object_p ++ (bfd *); ++extern const bfd_target *bfd_elf32_core_file_p ++ (bfd *); ++extern char *bfd_elf32_core_file_failing_command ++ (bfd *); ++extern int bfd_elf32_core_file_failing_signal ++ (bfd *); ++extern bfd_boolean bfd_elf32_core_file_matches_executable_p ++ (bfd *, bfd *); ++ ++extern bfd_boolean bfd_elf32_bfd_link_add_symbols ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_elf32_bfd_final_link ++ (bfd *, struct bfd_link_info *); ++ ++extern void bfd_elf32_swap_symbol_in ++ (bfd *, const void *, const void *, Elf_Internal_Sym *); ++extern void bfd_elf32_swap_symbol_out ++ (bfd *, const Elf_Internal_Sym *, void *, void *); ++extern void bfd_elf32_swap_reloc_in ++ (bfd *, const bfd_byte *, Elf_Internal_Rela *); ++extern void bfd_elf32_swap_reloc_out ++ (bfd *, const Elf_Internal_Rela *, bfd_byte *); ++extern void bfd_elf32_swap_reloca_in ++ (bfd *, const bfd_byte *, Elf_Internal_Rela *); ++extern void bfd_elf32_swap_reloca_out ++ (bfd *, const Elf_Internal_Rela *, bfd_byte *); ++extern void bfd_elf32_swap_phdr_in ++ (bfd *, const Elf32_External_Phdr *, Elf_Internal_Phdr *); ++extern void bfd_elf32_swap_phdr_out ++ (bfd *, const Elf_Internal_Phdr *, Elf32_External_Phdr *); ++extern void bfd_elf32_swap_dyn_in ++ (bfd *, const void *, Elf_Internal_Dyn *); ++extern void bfd_elf32_swap_dyn_out ++ (bfd *, const Elf_Internal_Dyn *, void *); ++extern long bfd_elf32_slurp_symbol_table ++ (bfd *, asymbol **, bfd_boolean); ++extern bfd_boolean bfd_elf32_write_shdrs_and_ehdr ++ (bfd *); ++extern int bfd_elf32_write_out_phdrs ++ (bfd *, const Elf_Internal_Phdr *, unsigned int); ++extern void bfd_elf32_write_relocs ++ (bfd *, asection *, void *); ++extern bfd_boolean bfd_elf32_slurp_reloc_table ++ (bfd *, asection *, asymbol **, bfd_boolean); ++extern bfd_boolean bfd_elf32_add_dynamic_entry ++ (struct bfd_link_info *, bfd_vma, bfd_vma); ++ ++extern const bfd_target *bfd_elf64_object_p ++ (bfd *); ++extern const bfd_target *bfd_elf64_core_file_p ++ (bfd *); ++extern char *bfd_elf64_core_file_failing_command ++ (bfd *); ++extern int bfd_elf64_core_file_failing_signal ++ (bfd *); ++extern bfd_boolean bfd_elf64_core_file_matches_executable_p ++ (bfd *, bfd *); ++extern bfd_boolean bfd_elf64_bfd_link_add_symbols ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_elf64_bfd_final_link ++ (bfd *, struct bfd_link_info *); ++ ++extern void bfd_elf64_swap_symbol_in ++ (bfd *, const void *, const void *, Elf_Internal_Sym *); ++extern void bfd_elf64_swap_symbol_out ++ (bfd *, const Elf_Internal_Sym *, void *, void *); ++extern void bfd_elf64_swap_reloc_in ++ (bfd *, const bfd_byte *, Elf_Internal_Rela *); ++extern void bfd_elf64_swap_reloc_out ++ (bfd *, const Elf_Internal_Rela *, bfd_byte *); ++extern void bfd_elf64_swap_reloca_in ++ (bfd *, const bfd_byte *, Elf_Internal_Rela *); ++extern void bfd_elf64_swap_reloca_out ++ (bfd *, const Elf_Internal_Rela *, bfd_byte *); ++extern void bfd_elf64_swap_phdr_in ++ (bfd *, const Elf64_External_Phdr *, Elf_Internal_Phdr *); ++extern void bfd_elf64_swap_phdr_out ++ (bfd *, const Elf_Internal_Phdr *, Elf64_External_Phdr *); ++extern void bfd_elf64_swap_dyn_in ++ (bfd *, const void *, Elf_Internal_Dyn *); ++extern void bfd_elf64_swap_dyn_out ++ (bfd *, const Elf_Internal_Dyn *, void *); ++extern long bfd_elf64_slurp_symbol_table ++ (bfd *, asymbol **, bfd_boolean); ++extern bfd_boolean bfd_elf64_write_shdrs_and_ehdr ++ (bfd *); ++extern int bfd_elf64_write_out_phdrs ++ (bfd *, const Elf_Internal_Phdr *, unsigned int); ++extern void bfd_elf64_write_relocs ++ (bfd *, asection *, void *); ++extern bfd_boolean bfd_elf64_slurp_reloc_table ++ (bfd *, asection *, asymbol **, bfd_boolean); ++extern bfd_boolean bfd_elf64_add_dynamic_entry ++ (struct bfd_link_info *, bfd_vma, bfd_vma); ++ ++#define bfd_elf32_link_record_dynamic_symbol \ ++ _bfd_elf_link_record_dynamic_symbol ++#define bfd_elf64_link_record_dynamic_symbol \ ++ _bfd_elf_link_record_dynamic_symbol ++ ++extern int elf_link_record_local_dynamic_symbol ++ (struct bfd_link_info *, bfd *, long); ++#define _bfd_elf32_link_record_local_dynamic_symbol \ ++ elf_link_record_local_dynamic_symbol ++#define _bfd_elf64_link_record_local_dynamic_symbol \ ++ elf_link_record_local_dynamic_symbol ++ ++extern bfd_boolean _bfd_elf_close_and_cleanup ++ (bfd *); ++extern bfd_reloc_status_type _bfd_elf_rel_vtable_reloc_fn ++ (bfd *, arelent *, struct symbol_cache_entry *, void *, ++ asection *, bfd *, char **); ++ ++extern bfd_boolean _bfd_elf32_gc_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean _bfd_elf32_gc_common_finalize_got_offsets ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean _bfd_elf32_gc_common_final_link ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean _bfd_elf32_gc_record_vtinherit ++ (bfd *, asection *, struct elf_link_hash_entry *, bfd_vma); ++extern bfd_boolean _bfd_elf32_gc_record_vtentry ++ (bfd *, asection *, struct elf_link_hash_entry *, bfd_vma); ++ ++extern bfd_boolean _bfd_elf64_gc_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean _bfd_elf64_gc_common_finalize_got_offsets ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean _bfd_elf64_gc_common_final_link ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean _bfd_elf64_gc_record_vtinherit ++ (bfd *, asection *, struct elf_link_hash_entry *, bfd_vma); ++extern bfd_boolean _bfd_elf64_gc_record_vtentry ++ (bfd *, asection *, struct elf_link_hash_entry *, bfd_vma); ++ ++extern bfd_boolean _bfd_elf32_reloc_symbol_deleted_p ++ (bfd_vma, void *); ++extern bfd_boolean _bfd_elf64_reloc_symbol_deleted_p ++ (bfd_vma, void *); ++ ++/* Exported interface for writing elf corefile notes. */ ++extern char *elfcore_write_note ++ (bfd *, char *, int *, const char *, int, const void *, int); ++extern char *elfcore_write_prpsinfo ++ (bfd *, char *, int *, const char *, const char *); ++extern char *elfcore_write_prstatus ++ (bfd *, char *, int *, long, int, const void *); ++extern char * elfcore_write_pstatus ++ (bfd *, char *, int *, long, int, const void *); ++extern char *elfcore_write_prfpreg ++ (bfd *, char *, int *, const void *, int); ++extern char *elfcore_write_prxfpreg ++ (bfd *, char *, int *, const void *, int); ++extern char *elfcore_write_lwpstatus ++ (bfd *, char *, int *, long, int, const void *); ++ ++extern bfd *_bfd_elf32_bfd_from_remote_memory ++ (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, ++ int (*target_read_memory) (bfd_vma, char *, int)); ++extern bfd *_bfd_elf64_bfd_from_remote_memory ++ (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, ++ int (*target_read_memory) (bfd_vma, char *, int)); ++ ++/* SH ELF specific routine. */ ++ ++extern bfd_boolean _sh_elf_set_mach_from_flags ++ (bfd *); ++ ++/* This macro is to avoid lots of duplicated code in the body ++ of xxx_relocate_section() in the various elfxx-xxxx.c files. */ ++#define RELOC_FOR_GLOBAL_SYMBOL(h, sym_hashes, r_symndx, symtab_hdr, relocation, sec, unresolved_reloc, info, warned) \ ++ do \ ++ { \ ++ /* It seems this can happen with erroneous or unsupported \ ++ input (mixing a.out and elf in an archive, for example.) */ \ ++ if (sym_hashes == NULL) \ ++ return FALSE; \ ++ \ ++ 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; \ ++ \ ++ warned = FALSE; \ ++ unresolved_reloc = FALSE; \ ++ relocation = 0; \ ++ if (h->root.type == bfd_link_hash_defined \ ++ || h->root.type == bfd_link_hash_defweak) \ ++ { \ ++ sec = h->root.u.def.section; \ ++ if (sec == NULL \ ++ || sec->output_section == NULL) \ ++ /* Set a flag that will be cleared later if we find a \ ++ relocation value for this symbol. output_section \ ++ is typically NULL for symbols satisfied by a shared \ ++ library. */ \ ++ unresolved_reloc = TRUE; \ ++ else \ ++ relocation = (h->root.u.def.value \ ++ + sec->output_section->vma \ ++ + sec->output_offset); \ ++ } \ ++ else if (h->root.type == bfd_link_hash_undefweak) \ ++ ; \ ++ else if (!info->executable \ ++ && info->unresolved_syms_in_objects == RM_IGNORE \ ++ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) \ ++ ; \ ++ else \ ++ { \ ++ if (! info->callbacks->undefined_symbol \ ++ (info, h->root.root.string, input_bfd, \ ++ input_section, rel->r_offset, \ ++ ((info->shared && info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR) \ ++ || (!info->shared && info->unresolved_syms_in_objects == RM_GENERATE_ERROR) \ ++ || ELF_ST_VISIBILITY (h->other)) \ ++ )) \ ++ return FALSE; \ ++ warned = TRUE; \ ++ } \ ++ } \ ++ while (0) ++ ++#endif /* _LIBELF_H_ */ +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf-hppa.h binutils-2.14.90.0.7/bfd/elf-hppa.h +--- binutils-2.14.90.0.7.orig/bfd/elf-hppa.h 2003-11-07 00:11:17.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf-hppa.h 2003-11-07 00:21:15.000000000 +0100 +@@ -1346,7 +1346,7 @@ + /* This is a local symbol. */ + sym = local_syms + r_symndx; + sym_sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sym_sec, rel); + + /* If this symbol has an entry in the PA64 dynamic hash + table, then get it. */ +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf-m10200.c binutils-2.14.90.0.7/bfd/elf-m10200.c +--- binutils-2.14.90.0.7.orig/bfd/elf-m10200.c 2003-11-07 00:11:14.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf-m10200.c 2003-11-07 00:21:15.000000000 +0100 +@@ -373,7 +373,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf-m10300.c binutils-2.14.90.0.7/bfd/elf-m10300.c +--- binutils-2.14.90.0.7.orig/bfd/elf-m10300.c 2003-11-07 00:11:15.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf-m10300.c 2003-11-07 00:21:15.000000000 +0100 +@@ -1574,7 +1574,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf.c binutils-2.14.90.0.7/bfd/elf.c +--- binutils-2.14.90.0.7.orig/bfd/elf.c 2003-11-07 00:11:20.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf.c 2003-11-07 00:21:15.000000000 +0100 +@@ -7367,9 +7367,10 @@ + bfd_vma + _bfd_elf_rela_local_sym (bfd *abfd, + Elf_Internal_Sym *sym, +- asection *sec, ++ asection **psec, + Elf_Internal_Rela *rel) + { ++ asection *sec = *psec; + bfd_vma relocation; + + relocation = (sec->output_section->vma +@@ -7379,16 +7380,14 @@ + && ELF_ST_TYPE (sym->st_info) == STT_SECTION + && sec->sec_info_type == ELF_INFO_TYPE_MERGE) + { +- asection *msec; +- +- msec = sec; + rel->r_addend = +- _bfd_merged_section_offset (abfd, &msec, ++ _bfd_merged_section_offset (abfd, psec, + elf_section_data (sec)->sec_info, + sym->st_value + rel->r_addend, +- 0) +- - relocation; +- rel->r_addend += msec->output_section->vma + msec->output_offset; ++ 0); ++ sec = *psec; ++ rel->r_addend -= relocation; ++ rel->r_addend += sec->output_section->vma + sec->output_offset; + } + return relocation; + } +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-arm.h binutils-2.14.90.0.7/bfd/elf32-arm.h +--- binutils-2.14.90.0.7.orig/bfd/elf32-arm.h 2003-11-07 00:11:24.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-arm.h 2003-11-07 00:21:15.000000000 +0100 +@@ -1958,7 +1958,7 @@ + bfd_put_32 (input_bfd, value, contents + rel->r_offset); + } + #else +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + #endif + } + else +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-arm.h.orig binutils-2.14.90.0.7/bfd/elf32-arm.h.orig +--- binutils-2.14.90.0.7.orig/bfd/elf32-arm.h.orig 1970-01-01 01:00:00.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-arm.h.orig 2003-11-07 00:20:18.000000000 +0100 +@@ -0,0 +1,3739 @@ ++/* 32-bit ELF support for ARM ++ Copyright 1998, 1999, 2000, 2001, 2002, 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ++ ++#ifndef USE_REL ++#define USE_REL 0 ++#endif ++ ++typedef unsigned long int insn32; ++typedef unsigned short int insn16; ++ ++static bfd_boolean elf32_arm_set_private_flags ++ PARAMS ((bfd *, flagword)); ++static bfd_boolean elf32_arm_copy_private_bfd_data ++ PARAMS ((bfd *, bfd *)); ++static bfd_boolean elf32_arm_merge_private_bfd_data ++ PARAMS ((bfd *, bfd *)); ++static bfd_boolean elf32_arm_print_private_bfd_data ++ PARAMS ((bfd *, PTR)); ++static int elf32_arm_get_symbol_type ++ PARAMS (( Elf_Internal_Sym *, int)); ++static struct bfd_link_hash_table *elf32_arm_link_hash_table_create ++ PARAMS ((bfd *)); ++static bfd_reloc_status_type elf32_arm_final_link_relocate ++ PARAMS ((reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *, ++ Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *, ++ const char *, int, struct elf_link_hash_entry *)); ++static insn32 insert_thumb_branch ++ PARAMS ((insn32, int)); ++static struct elf_link_hash_entry *find_thumb_glue ++ PARAMS ((struct bfd_link_info *, const char *, bfd *)); ++static struct elf_link_hash_entry *find_arm_glue ++ PARAMS ((struct bfd_link_info *, const char *, bfd *)); ++static void elf32_arm_post_process_headers ++ PARAMS ((bfd *, struct bfd_link_info *)); ++static int elf32_arm_to_thumb_stub ++ PARAMS ((struct bfd_link_info *, const char *, bfd *, bfd *, asection *, ++ bfd_byte *, asection *, bfd_vma, bfd_signed_vma, bfd_vma)); ++static int elf32_thumb_to_arm_stub ++ PARAMS ((struct bfd_link_info *, const char *, bfd *, bfd *, asection *, ++ bfd_byte *, asection *, bfd_vma, bfd_signed_vma, bfd_vma)); ++static bfd_boolean elf32_arm_relocate_section ++ PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, ++ Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); ++static asection * elf32_arm_gc_mark_hook ++ PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, ++ struct elf_link_hash_entry *, Elf_Internal_Sym *)); ++static bfd_boolean elf32_arm_gc_sweep_hook ++ PARAMS ((bfd *, struct bfd_link_info *, asection *, ++ const Elf_Internal_Rela *)); ++static bfd_boolean elf32_arm_check_relocs ++ PARAMS ((bfd *, struct bfd_link_info *, asection *, ++ const Elf_Internal_Rela *)); ++static bfd_boolean elf32_arm_find_nearest_line ++ PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, ++ const char **, unsigned int *)); ++static bfd_boolean elf32_arm_adjust_dynamic_symbol ++ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); ++static bfd_boolean elf32_arm_size_dynamic_sections ++ PARAMS ((bfd *, struct bfd_link_info *)); ++static bfd_boolean elf32_arm_finish_dynamic_symbol ++ PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, ++ Elf_Internal_Sym *)); ++static bfd_boolean elf32_arm_finish_dynamic_sections ++ PARAMS ((bfd *, struct bfd_link_info *)); ++static struct bfd_hash_entry * elf32_arm_link_hash_newfunc ++ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); ++#if USE_REL ++static void arm_add_to_rel ++ PARAMS ((bfd *, bfd_byte *, reloc_howto_type *, bfd_signed_vma)); ++#endif ++static enum elf_reloc_type_class elf32_arm_reloc_type_class ++ PARAMS ((const Elf_Internal_Rela *)); ++static bfd_boolean elf32_arm_object_p ++ PARAMS ((bfd *)); ++ ++#ifndef ELFARM_NABI_C_INCLUDED ++static void record_arm_to_thumb_glue ++ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); ++static void record_thumb_to_arm_glue ++ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); ++bfd_boolean bfd_elf32_arm_allocate_interworking_sections ++ PARAMS ((struct bfd_link_info *)); ++bfd_boolean bfd_elf32_arm_get_bfd_for_interworking ++ PARAMS ((bfd *, struct bfd_link_info *)); ++bfd_boolean bfd_elf32_arm_process_before_allocation ++ PARAMS ((bfd *, struct bfd_link_info *, int)); ++#endif ++ ++ ++#define INTERWORK_FLAG(abfd) (elf_elfheader (abfd)->e_flags & EF_ARM_INTERWORK) ++ ++/* The linker script knows the section names for placement. ++ The entry_names are used to do simple name mangling on the stubs. ++ Given a function name, and its type, the stub can be found. The ++ name can be changed. The only requirement is the %s be present. */ ++#define THUMB2ARM_GLUE_SECTION_NAME ".glue_7t" ++#define THUMB2ARM_GLUE_ENTRY_NAME "__%s_from_thumb" ++ ++#define ARM2THUMB_GLUE_SECTION_NAME ".glue_7" ++#define ARM2THUMB_GLUE_ENTRY_NAME "__%s_from_arm" ++ ++/* 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 16 ++ ++/* The first entry in a procedure linkage table looks like ++ this. It is set up so that any shared library function that is ++ called before the relocation has been set up calls the dynamic ++ linker first. */ ++static const bfd_vma elf32_arm_plt0_entry [PLT_ENTRY_SIZE / 4] = ++ { ++ 0xe52de004, /* str lr, [sp, #-4]! */ ++ 0xe59fe010, /* ldr lr, [pc, #16] */ ++ 0xe08fe00e, /* add lr, pc, lr */ ++ 0xe5bef008 /* ldr pc, [lr, #8]! */ ++ }; ++ ++/* Subsequent entries in a procedure linkage table look like ++ this. */ ++static const bfd_vma elf32_arm_plt_entry [PLT_ENTRY_SIZE / 4] = ++ { ++ 0xe59fc004, /* ldr ip, [pc, #4] */ ++ 0xe08fc00c, /* add ip, pc, ip */ ++ 0xe59cf000, /* ldr pc, [ip] */ ++ 0x00000000 /* offset to symbol in got */ ++ }; ++ ++/* The ARM linker needs to keep track of the number of relocs that it ++ decides to copy in check_relocs for each symbol. This is so that ++ it can discard PC relative relocs if it doesn't need them when ++ linking with -Bsymbolic. We store the information in a field ++ extending the regular ELF linker hash table. */ ++ ++/* This structure keeps track of the number of PC relative relocs we ++ have copied for a given symbol. */ ++struct elf32_arm_pcrel_relocs_copied ++ { ++ /* Next section. */ ++ struct elf32_arm_pcrel_relocs_copied * next; ++ /* A section in dynobj. */ ++ asection * section; ++ /* Number of relocs copied in this section. */ ++ bfd_size_type count; ++ }; ++ ++/* Arm ELF linker hash entry. */ ++struct elf32_arm_link_hash_entry ++ { ++ struct elf_link_hash_entry root; ++ ++ /* Number of PC relative relocs copied for this symbol. */ ++ struct elf32_arm_pcrel_relocs_copied * pcrel_relocs_copied; ++ }; ++ ++/* Declare this now that the above structures are defined. */ ++static bfd_boolean elf32_arm_discard_copies ++ PARAMS ((struct elf32_arm_link_hash_entry *, PTR)); ++ ++/* Traverse an arm ELF linker hash table. */ ++#define elf32_arm_link_hash_traverse(table, func, info) \ ++ (elf_link_hash_traverse \ ++ (&(table)->root, \ ++ (bfd_boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \ ++ (info))) ++ ++/* Get the ARM elf linker hash table from a link_info structure. */ ++#define elf32_arm_hash_table(info) \ ++ ((struct elf32_arm_link_hash_table *) ((info)->hash)) ++ ++/* ARM ELF linker hash table. */ ++struct elf32_arm_link_hash_table ++ { ++ /* The main hash table. */ ++ struct elf_link_hash_table root; ++ ++ /* The size in bytes of the section containg the Thumb-to-ARM glue. */ ++ bfd_size_type thumb_glue_size; ++ ++ /* The size in bytes of the section containg the ARM-to-Thumb glue. */ ++ bfd_size_type arm_glue_size; ++ ++ /* An arbitary input BFD chosen to hold the glue sections. */ ++ bfd * bfd_of_glue_owner; ++ ++ /* A boolean indicating whether knowledge of the ARM's pipeline ++ length should be applied by the linker. */ ++ int no_pipeline_knowledge; ++ }; ++ ++/* Create an entry in an ARM ELF linker hash table. */ ++ ++static struct bfd_hash_entry * ++elf32_arm_link_hash_newfunc (entry, table, string) ++ struct bfd_hash_entry * entry; ++ struct bfd_hash_table * table; ++ const char * string; ++{ ++ struct elf32_arm_link_hash_entry * ret = ++ (struct elf32_arm_link_hash_entry *) entry; ++ ++ /* Allocate the structure if it has not already been allocated by a ++ subclass. */ ++ if (ret == (struct elf32_arm_link_hash_entry *) NULL) ++ ret = ((struct elf32_arm_link_hash_entry *) ++ bfd_hash_allocate (table, ++ sizeof (struct elf32_arm_link_hash_entry))); ++ if (ret == (struct elf32_arm_link_hash_entry *) NULL) ++ return (struct bfd_hash_entry *) ret; ++ ++ /* Call the allocation method of the superclass. */ ++ ret = ((struct elf32_arm_link_hash_entry *) ++ _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, ++ table, string)); ++ if (ret != (struct elf32_arm_link_hash_entry *) NULL) ++ ret->pcrel_relocs_copied = NULL; ++ ++ return (struct bfd_hash_entry *) ret; ++} ++ ++/* Create an ARM elf linker hash table. */ ++ ++static struct bfd_link_hash_table * ++elf32_arm_link_hash_table_create (abfd) ++ bfd *abfd; ++{ ++ struct elf32_arm_link_hash_table *ret; ++ bfd_size_type amt = sizeof (struct elf32_arm_link_hash_table); ++ ++ ret = (struct elf32_arm_link_hash_table *) bfd_malloc (amt); ++ if (ret == (struct elf32_arm_link_hash_table *) NULL) ++ return NULL; ++ ++ if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, ++ elf32_arm_link_hash_newfunc)) ++ { ++ free (ret); ++ return NULL; ++ } ++ ++ ret->thumb_glue_size = 0; ++ ret->arm_glue_size = 0; ++ ret->bfd_of_glue_owner = NULL; ++ ret->no_pipeline_knowledge = 0; ++ ++ return &ret->root.root; ++} ++ ++/* Locate the Thumb encoded calling stub for NAME. */ ++ ++static struct elf_link_hash_entry * ++find_thumb_glue (link_info, name, input_bfd) ++ struct bfd_link_info *link_info; ++ const char *name; ++ bfd *input_bfd; ++{ ++ char *tmp_name; ++ struct elf_link_hash_entry *hash; ++ struct elf32_arm_link_hash_table *hash_table; ++ ++ /* We need a pointer to the armelf specific hash table. */ ++ hash_table = elf32_arm_hash_table (link_info); ++ ++ tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) ++ + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1); ++ ++ BFD_ASSERT (tmp_name); ++ ++ sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name); ++ ++ hash = elf_link_hash_lookup ++ (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE); ++ ++ if (hash == NULL) ++ /* xgettext:c-format */ ++ (*_bfd_error_handler) (_("%s: unable to find THUMB glue '%s' for `%s'"), ++ bfd_archive_filename (input_bfd), tmp_name, name); ++ ++ free (tmp_name); ++ ++ return hash; ++} ++ ++/* Locate the ARM encoded calling stub for NAME. */ ++ ++static struct elf_link_hash_entry * ++find_arm_glue (link_info, name, input_bfd) ++ struct bfd_link_info *link_info; ++ const char *name; ++ bfd *input_bfd; ++{ ++ char *tmp_name; ++ struct elf_link_hash_entry *myh; ++ struct elf32_arm_link_hash_table *hash_table; ++ ++ /* We need a pointer to the elfarm specific hash table. */ ++ hash_table = elf32_arm_hash_table (link_info); ++ ++ tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) ++ + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1); ++ ++ BFD_ASSERT (tmp_name); ++ ++ sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name); ++ ++ myh = elf_link_hash_lookup ++ (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE); ++ ++ if (myh == NULL) ++ /* xgettext:c-format */ ++ (*_bfd_error_handler) (_("%s: unable to find ARM glue '%s' for `%s'"), ++ bfd_archive_filename (input_bfd), tmp_name, name); ++ ++ free (tmp_name); ++ ++ return myh; ++} ++ ++/* ARM->Thumb glue: ++ ++ .arm ++ __func_from_arm: ++ ldr r12, __func_addr ++ bx r12 ++ __func_addr: ++ .word func @ behave as if you saw a ARM_32 reloc. */ ++ ++#define ARM2THUMB_GLUE_SIZE 12 ++static const insn32 a2t1_ldr_insn = 0xe59fc000; ++static const insn32 a2t2_bx_r12_insn = 0xe12fff1c; ++static const insn32 a2t3_func_addr_insn = 0x00000001; ++ ++/* Thumb->ARM: Thumb->(non-interworking aware) ARM ++ ++ .thumb .thumb ++ .align 2 .align 2 ++ __func_from_thumb: __func_from_thumb: ++ bx pc push {r6, lr} ++ nop ldr r6, __func_addr ++ .arm mov lr, pc ++ __func_change_to_arm: bx r6 ++ b func .arm ++ __func_back_to_thumb: ++ ldmia r13! {r6, lr} ++ bx lr ++ __func_addr: ++ .word func */ ++ ++#define THUMB2ARM_GLUE_SIZE 8 ++static const insn16 t2a1_bx_pc_insn = 0x4778; ++static const insn16 t2a2_noop_insn = 0x46c0; ++static const insn32 t2a3_b_insn = 0xea000000; ++ ++#ifndef ELFARM_NABI_C_INCLUDED ++bfd_boolean ++bfd_elf32_arm_allocate_interworking_sections (info) ++ struct bfd_link_info * info; ++{ ++ asection * s; ++ bfd_byte * foo; ++ struct elf32_arm_link_hash_table * globals; ++ ++ globals = elf32_arm_hash_table (info); ++ ++ BFD_ASSERT (globals != NULL); ++ ++ if (globals->arm_glue_size != 0) ++ { ++ BFD_ASSERT (globals->bfd_of_glue_owner != NULL); ++ ++ s = bfd_get_section_by_name (globals->bfd_of_glue_owner, ++ ARM2THUMB_GLUE_SECTION_NAME); ++ ++ BFD_ASSERT (s != NULL); ++ ++ foo = (bfd_byte *) bfd_alloc (globals->bfd_of_glue_owner, ++ globals->arm_glue_size); ++ ++ s->_raw_size = s->_cooked_size = globals->arm_glue_size; ++ s->contents = foo; ++ } ++ ++ if (globals->thumb_glue_size != 0) ++ { ++ BFD_ASSERT (globals->bfd_of_glue_owner != NULL); ++ ++ s = bfd_get_section_by_name ++ (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME); ++ ++ BFD_ASSERT (s != NULL); ++ ++ foo = (bfd_byte *) bfd_alloc (globals->bfd_of_glue_owner, ++ globals->thumb_glue_size); ++ ++ s->_raw_size = s->_cooked_size = globals->thumb_glue_size; ++ s->contents = foo; ++ } ++ ++ return TRUE; ++} ++ ++static void ++record_arm_to_thumb_glue (link_info, h) ++ struct bfd_link_info * link_info; ++ struct elf_link_hash_entry * h; ++{ ++ const char * name = h->root.root.string; ++ asection * s; ++ char * tmp_name; ++ struct elf_link_hash_entry * myh; ++ struct bfd_link_hash_entry * bh; ++ struct elf32_arm_link_hash_table * globals; ++ bfd_vma val; ++ ++ globals = elf32_arm_hash_table (link_info); ++ ++ BFD_ASSERT (globals != NULL); ++ BFD_ASSERT (globals->bfd_of_glue_owner != NULL); ++ ++ s = bfd_get_section_by_name ++ (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME); ++ ++ BFD_ASSERT (s != NULL); ++ ++ tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) ++ + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1); ++ ++ BFD_ASSERT (tmp_name); ++ ++ sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name); ++ ++ myh = elf_link_hash_lookup ++ (&(globals)->root, tmp_name, FALSE, FALSE, TRUE); ++ ++ if (myh != NULL) ++ { ++ /* We've already seen this guy. */ ++ free (tmp_name); ++ return; ++ } ++ ++ /* The only trick here is using hash_table->arm_glue_size as the value. Even ++ though the section isn't allocated yet, this is where we will be putting ++ it. */ ++ bh = NULL; ++ val = globals->arm_glue_size + 1; ++ _bfd_generic_link_add_one_symbol (link_info, globals->bfd_of_glue_owner, ++ tmp_name, BSF_GLOBAL, s, val, ++ NULL, TRUE, FALSE, &bh); ++ ++ free (tmp_name); ++ ++ globals->arm_glue_size += ARM2THUMB_GLUE_SIZE; ++ ++ return; ++} ++ ++static void ++record_thumb_to_arm_glue (link_info, h) ++ struct bfd_link_info *link_info; ++ struct elf_link_hash_entry *h; ++{ ++ const char *name = h->root.root.string; ++ asection *s; ++ char *tmp_name; ++ struct elf_link_hash_entry *myh; ++ struct bfd_link_hash_entry *bh; ++ struct elf32_arm_link_hash_table *hash_table; ++ char bind; ++ bfd_vma val; ++ ++ hash_table = elf32_arm_hash_table (link_info); ++ ++ BFD_ASSERT (hash_table != NULL); ++ BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL); ++ ++ s = bfd_get_section_by_name ++ (hash_table->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME); ++ ++ BFD_ASSERT (s != NULL); ++ ++ tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) ++ + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1); ++ ++ BFD_ASSERT (tmp_name); ++ ++ sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name); ++ ++ myh = elf_link_hash_lookup ++ (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE); ++ ++ if (myh != NULL) ++ { ++ /* We've already seen this guy. */ ++ free (tmp_name); ++ return; ++ } ++ ++ bh = NULL; ++ val = hash_table->thumb_glue_size + 1; ++ _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner, ++ tmp_name, BSF_GLOBAL, s, val, ++ NULL, TRUE, FALSE, &bh); ++ ++ /* If we mark it 'Thumb', the disassembler will do a better job. */ ++ myh = (struct elf_link_hash_entry *) bh; ++ bind = ELF_ST_BIND (myh->type); ++ myh->type = ELF_ST_INFO (bind, STT_ARM_TFUNC); ++ ++ free (tmp_name); ++ ++#define CHANGE_TO_ARM "__%s_change_to_arm" ++#define BACK_FROM_ARM "__%s_back_from_arm" ++ ++ /* Allocate another symbol to mark where we switch to Arm mode. */ ++ tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) ++ + strlen (CHANGE_TO_ARM) + 1); ++ ++ BFD_ASSERT (tmp_name); ++ ++ sprintf (tmp_name, CHANGE_TO_ARM, name); ++ ++ bh = NULL; ++ val = hash_table->thumb_glue_size + 4, ++ _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner, ++ tmp_name, BSF_LOCAL, s, val, ++ NULL, TRUE, FALSE, &bh); ++ ++ free (tmp_name); ++ ++ hash_table->thumb_glue_size += THUMB2ARM_GLUE_SIZE; ++ ++ return; ++} ++ ++/* Add the glue sections to ABFD. This function is called from the ++ linker scripts in ld/emultempl/{armelf}.em. */ ++ ++bfd_boolean ++bfd_elf32_arm_add_glue_sections_to_bfd (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ flagword flags; ++ asection *sec; ++ ++ /* If we are only performing a partial ++ link do not bother adding the glue. */ ++ if (info->relocatable) ++ return TRUE; ++ ++ sec = bfd_get_section_by_name (abfd, ARM2THUMB_GLUE_SECTION_NAME); ++ ++ if (sec == NULL) ++ { ++ /* Note: we do not include the flag SEC_LINKER_CREATED, as this ++ will prevent elf_link_input_bfd() from processing the contents ++ of this section. */ ++ flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE | SEC_READONLY; ++ ++ sec = bfd_make_section (abfd, ARM2THUMB_GLUE_SECTION_NAME); ++ ++ if (sec == NULL ++ || !bfd_set_section_flags (abfd, sec, flags) ++ || !bfd_set_section_alignment (abfd, sec, 2)) ++ return FALSE; ++ ++ /* Set the gc mark to prevent the section from being removed by garbage ++ collection, despite the fact that no relocs refer to this section. */ ++ sec->gc_mark = 1; ++ } ++ ++ sec = bfd_get_section_by_name (abfd, THUMB2ARM_GLUE_SECTION_NAME); ++ ++ if (sec == NULL) ++ { ++ flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE | SEC_READONLY; ++ ++ sec = bfd_make_section (abfd, THUMB2ARM_GLUE_SECTION_NAME); ++ ++ if (sec == NULL ++ || !bfd_set_section_flags (abfd, sec, flags) ++ || !bfd_set_section_alignment (abfd, sec, 2)) ++ return FALSE; ++ ++ sec->gc_mark = 1; ++ } ++ ++ return TRUE; ++} ++ ++/* Select a BFD to be used to hold the sections used by the glue code. ++ This function is called from the linker scripts in ld/emultempl/ ++ {armelf/pe}.em */ ++ ++bfd_boolean ++bfd_elf32_arm_get_bfd_for_interworking (abfd, info) ++ bfd *abfd; ++ struct bfd_link_info *info; ++{ ++ struct elf32_arm_link_hash_table *globals; ++ ++ /* If we are only performing a partial link ++ do not bother getting a bfd to hold the glue. */ ++ if (info->relocatable) ++ return TRUE; ++ ++ globals = elf32_arm_hash_table (info); ++ ++ BFD_ASSERT (globals != NULL); ++ ++ if (globals->bfd_of_glue_owner != NULL) ++ return TRUE; ++ ++ /* Save the bfd for later use. */ ++ globals->bfd_of_glue_owner = abfd; ++ ++ return TRUE; ++} ++ ++bfd_boolean ++bfd_elf32_arm_process_before_allocation (abfd, link_info, no_pipeline_knowledge) ++ bfd *abfd; ++ struct bfd_link_info *link_info; ++ int no_pipeline_knowledge; ++{ ++ Elf_Internal_Shdr *symtab_hdr; ++ Elf_Internal_Rela *internal_relocs = NULL; ++ Elf_Internal_Rela *irel, *irelend; ++ bfd_byte *contents = NULL; ++ ++ asection *sec; ++ struct elf32_arm_link_hash_table *globals; ++ ++ /* If we are only performing a partial link do not bother ++ to construct any glue. */ ++ if (link_info->relocatable) ++ return TRUE; ++ ++ /* Here we have a bfd that is to be included on the link. We have a hook ++ to do reloc rummaging, before section sizes are nailed down. */ ++ globals = elf32_arm_hash_table (link_info); ++ ++ BFD_ASSERT (globals != NULL); ++ BFD_ASSERT (globals->bfd_of_glue_owner != NULL); ++ ++ globals->no_pipeline_knowledge = no_pipeline_knowledge; ++ ++ /* Rummage around all the relocs and map the glue vectors. */ ++ sec = abfd->sections; ++ ++ if (sec == NULL) ++ return TRUE; ++ ++ for (; sec != NULL; sec = sec->next) ++ { ++ if (sec->reloc_count == 0) ++ continue; ++ ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ ++ /* Load the relocs. */ ++ internal_relocs ++ = _bfd_elf_link_read_relocs (abfd, sec, (PTR) NULL, ++ (Elf_Internal_Rela *) NULL, FALSE); ++ ++ if (internal_relocs == NULL) ++ goto error_return; ++ ++ irelend = internal_relocs + sec->reloc_count; ++ for (irel = internal_relocs; irel < irelend; irel++) ++ { ++ long r_type; ++ unsigned long r_index; ++ ++ struct elf_link_hash_entry *h; ++ ++ r_type = ELF32_R_TYPE (irel->r_info); ++ r_index = ELF32_R_SYM (irel->r_info); ++ ++ /* These are the only relocation types we care about. */ ++ if ( r_type != R_ARM_PC24 ++ && r_type != R_ARM_THM_PC22) ++ continue; ++ ++ /* Get the section contents if we haven't done so already. */ ++ if (contents == NULL) ++ { ++ /* Get cached copy if it exists. */ ++ if (elf_section_data (sec)->this_hdr.contents != NULL) ++ contents = elf_section_data (sec)->this_hdr.contents; ++ else ++ { ++ /* Go get them off disk. */ ++ contents = (bfd_byte *) bfd_malloc (sec->_raw_size); ++ if (contents == NULL) ++ goto error_return; ++ ++ if (!bfd_get_section_contents (abfd, sec, contents, ++ (file_ptr) 0, sec->_raw_size)) ++ goto error_return; ++ } ++ } ++ ++ /* If the relocation is not against a symbol it cannot concern us. */ ++ h = NULL; ++ ++ /* We don't care about local symbols. */ ++ if (r_index < symtab_hdr->sh_info) ++ continue; ++ ++ /* This is an external symbol. */ ++ r_index -= symtab_hdr->sh_info; ++ h = (struct elf_link_hash_entry *) ++ elf_sym_hashes (abfd)[r_index]; ++ ++ /* If the relocation is against a static symbol it must be within ++ the current section and so cannot be a cross ARM/Thumb relocation. */ ++ if (h == NULL) ++ continue; ++ ++ switch (r_type) ++ { ++ case R_ARM_PC24: ++ /* This one is a call from arm code. We need to look up ++ the target of the call. If it is a thumb target, we ++ insert glue. */ ++ if (ELF_ST_TYPE(h->type) == STT_ARM_TFUNC) ++ record_arm_to_thumb_glue (link_info, h); ++ break; ++ ++ case R_ARM_THM_PC22: ++ /* This one is a call from thumb code. We look ++ up the target of the call. If it is not a thumb ++ target, we insert glue. */ ++ if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC) ++ record_thumb_to_arm_glue (link_info, h); ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ if (contents != NULL ++ && elf_section_data (sec)->this_hdr.contents != contents) ++ free (contents); ++ contents = NULL; ++ ++ if (internal_relocs != NULL ++ && elf_section_data (sec)->relocs != internal_relocs) ++ free (internal_relocs); ++ internal_relocs = NULL; ++ } ++ ++ return TRUE; ++ ++error_return: ++ if (contents != NULL ++ && elf_section_data (sec)->this_hdr.contents != contents) ++ free (contents); ++ if (internal_relocs != NULL ++ && elf_section_data (sec)->relocs != internal_relocs) ++ free (internal_relocs); ++ ++ return FALSE; ++} ++#endif ++ ++/* The thumb form of a long branch is a bit finicky, because the offset ++ encoding is split over two fields, each in it's own instruction. They ++ can occur in any order. So given a thumb form of long branch, and an ++ offset, insert the offset into the thumb branch and return finished ++ instruction. ++ ++ It takes two thumb instructions to encode the target address. Each has ++ 11 bits to invest. The upper 11 bits are stored in one (identifed by ++ H-0.. see below), the lower 11 bits are stored in the other (identified ++ by H-1). ++ ++ Combine together and shifted left by 1 (it's a half word address) and ++ there you have it. ++ ++ Op: 1111 = F, ++ H-0, upper address-0 = 000 ++ Op: 1111 = F, ++ H-1, lower address-0 = 800 ++ ++ They can be ordered either way, but the arm tools I've seen always put ++ the lower one first. It probably doesn't matter. krk@cygnus.com ++ ++ XXX: Actually the order does matter. The second instruction (H-1) ++ moves the computed address into the PC, so it must be the second one ++ in the sequence. The problem, however is that whilst little endian code ++ stores the instructions in HI then LOW order, big endian code does the ++ reverse. nickc@cygnus.com. */ ++ ++#define LOW_HI_ORDER 0xF800F000 ++#define HI_LOW_ORDER 0xF000F800 ++ ++static insn32 ++insert_thumb_branch (br_insn, rel_off) ++ insn32 br_insn; ++ int rel_off; ++{ ++ unsigned int low_bits; ++ unsigned int high_bits; ++ ++ BFD_ASSERT ((rel_off & 1) != 1); ++ ++ rel_off >>= 1; /* Half word aligned address. */ ++ low_bits = rel_off & 0x000007FF; /* The bottom 11 bits. */ ++ high_bits = (rel_off >> 11) & 0x000007FF; /* The top 11 bits. */ ++ ++ if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER) ++ br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits; ++ else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER) ++ br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits; ++ else ++ /* FIXME: abort is probably not the right call. krk@cygnus.com */ ++ abort (); /* error - not a valid branch instruction form. */ ++ ++ return br_insn; ++} ++ ++/* Thumb code calling an ARM function. */ ++ ++static int ++elf32_thumb_to_arm_stub (info, name, input_bfd, output_bfd, input_section, ++ hit_data, sym_sec, offset, addend, val) ++ struct bfd_link_info * info; ++ const char * name; ++ bfd * input_bfd; ++ bfd * output_bfd; ++ asection * input_section; ++ bfd_byte * hit_data; ++ asection * sym_sec; ++ bfd_vma offset; ++ bfd_signed_vma addend; ++ bfd_vma val; ++{ ++ asection * s = 0; ++ bfd_vma my_offset; ++ unsigned long int tmp; ++ long int ret_offset; ++ struct elf_link_hash_entry * myh; ++ struct elf32_arm_link_hash_table * globals; ++ ++ myh = find_thumb_glue (info, name, input_bfd); ++ if (myh == NULL) ++ return FALSE; ++ ++ globals = elf32_arm_hash_table (info); ++ ++ BFD_ASSERT (globals != NULL); ++ BFD_ASSERT (globals->bfd_of_glue_owner != NULL); ++ ++ my_offset = myh->root.u.def.value; ++ ++ s = bfd_get_section_by_name (globals->bfd_of_glue_owner, ++ THUMB2ARM_GLUE_SECTION_NAME); ++ ++ BFD_ASSERT (s != NULL); ++ BFD_ASSERT (s->contents != NULL); ++ BFD_ASSERT (s->output_section != NULL); ++ ++ if ((my_offset & 0x01) == 0x01) ++ { ++ if (sym_sec != NULL ++ && sym_sec->owner != NULL ++ && !INTERWORK_FLAG (sym_sec->owner)) ++ { ++ (*_bfd_error_handler) ++ (_("%s(%s): warning: interworking not enabled."), ++ bfd_archive_filename (sym_sec->owner), name); ++ (*_bfd_error_handler) ++ (_(" first occurrence: %s: thumb call to arm"), ++ bfd_archive_filename (input_bfd)); ++ ++ return FALSE; ++ } ++ ++ --my_offset; ++ myh->root.u.def.value = my_offset; ++ ++ bfd_put_16 (output_bfd, (bfd_vma) t2a1_bx_pc_insn, ++ s->contents + my_offset); ++ ++ bfd_put_16 (output_bfd, (bfd_vma) t2a2_noop_insn, ++ s->contents + my_offset + 2); ++ ++ ret_offset = ++ /* Address of destination of the stub. */ ++ ((bfd_signed_vma) val) ++ - ((bfd_signed_vma) ++ /* Offset from the start of the current section to the start of the stubs. */ ++ (s->output_offset ++ /* Offset of the start of this stub from the start of the stubs. */ ++ + my_offset ++ /* Address of the start of the current section. */ ++ + s->output_section->vma) ++ /* The branch instruction is 4 bytes into the stub. */ ++ + 4 ++ /* ARM branches work from the pc of the instruction + 8. */ ++ + 8); ++ ++ bfd_put_32 (output_bfd, ++ (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF), ++ s->contents + my_offset + 4); ++ } ++ ++ BFD_ASSERT (my_offset <= globals->thumb_glue_size); ++ ++ /* Now go back and fix up the original BL insn to point to here. */ ++ ret_offset = ++ /* Address of where the stub is located. */ ++ (s->output_section->vma + s->output_offset + my_offset) ++ /* Address of where the BL is located. */ ++ - (input_section->output_section->vma + input_section->output_offset + offset) ++ /* Addend in the relocation. */ ++ - addend ++ /* Biassing for PC-relative addressing. */ ++ - 8; ++ ++ tmp = bfd_get_32 (input_bfd, hit_data ++ - input_section->vma); ++ ++ bfd_put_32 (output_bfd, ++ (bfd_vma) insert_thumb_branch (tmp, ret_offset), ++ hit_data - input_section->vma); ++ ++ return TRUE; ++} ++ ++/* Arm code calling a Thumb function. */ ++ ++static int ++elf32_arm_to_thumb_stub (info, name, input_bfd, output_bfd, input_section, ++ hit_data, sym_sec, offset, addend, val) ++ struct bfd_link_info * info; ++ const char * name; ++ bfd * input_bfd; ++ bfd * output_bfd; ++ asection * input_section; ++ bfd_byte * hit_data; ++ asection * sym_sec; ++ bfd_vma offset; ++ bfd_signed_vma addend; ++ bfd_vma val; ++{ ++ unsigned long int tmp; ++ bfd_vma my_offset; ++ asection * s; ++ long int ret_offset; ++ struct elf_link_hash_entry * myh; ++ struct elf32_arm_link_hash_table * globals; ++ ++ myh = find_arm_glue (info, name, input_bfd); ++ if (myh == NULL) ++ return FALSE; ++ ++ globals = elf32_arm_hash_table (info); ++ ++ BFD_ASSERT (globals != NULL); ++ BFD_ASSERT (globals->bfd_of_glue_owner != NULL); ++ ++ my_offset = myh->root.u.def.value; ++ s = bfd_get_section_by_name (globals->bfd_of_glue_owner, ++ ARM2THUMB_GLUE_SECTION_NAME); ++ BFD_ASSERT (s != NULL); ++ BFD_ASSERT (s->contents != NULL); ++ BFD_ASSERT (s->output_section != NULL); ++ ++ if ((my_offset & 0x01) == 0x01) ++ { ++ if (sym_sec != NULL ++ && sym_sec->owner != NULL ++ && !INTERWORK_FLAG (sym_sec->owner)) ++ { ++ (*_bfd_error_handler) ++ (_("%s(%s): warning: interworking not enabled."), ++ bfd_archive_filename (sym_sec->owner), name); ++ (*_bfd_error_handler) ++ (_(" first occurrence: %s: arm call to thumb"), ++ bfd_archive_filename (input_bfd)); ++ } ++ ++ --my_offset; ++ myh->root.u.def.value = my_offset; ++ ++ bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn, ++ s->contents + my_offset); ++ ++ bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn, ++ s->contents + my_offset + 4); ++ ++ /* It's a thumb address. Add the low order bit. */ ++ bfd_put_32 (output_bfd, val | a2t3_func_addr_insn, ++ s->contents + my_offset + 8); ++ } ++ ++ BFD_ASSERT (my_offset <= globals->arm_glue_size); ++ ++ tmp = bfd_get_32 (input_bfd, hit_data); ++ tmp = tmp & 0xFF000000; ++ ++ /* Somehow these are both 4 too far, so subtract 8. */ ++ ret_offset = (s->output_offset ++ + my_offset ++ + s->output_section->vma ++ - (input_section->output_offset ++ + input_section->output_section->vma ++ + offset + addend) ++ - 8); ++ ++ tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF); ++ ++ bfd_put_32 (output_bfd, (bfd_vma) tmp, hit_data - input_section->vma); ++ ++ return TRUE; ++} ++ ++/* This is the condition under which elf32_arm_finish_dynamic_symbol ++ will be called from elflink.h. If elflink.h doesn't call our ++ finish_dynamic_symbol routine, we'll need to do something about ++ initializing any .plt and .got entries in elf32_arm_relocate_section ++ and elf32_arm_final_link_relocate. */ ++#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, SHARED, H) \ ++ ((DYN) \ ++ && ((SHARED) \ ++ || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) \ ++ && ((H)->dynindx != -1 \ ++ || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)) ++ ++/* Perform a relocation as part of a final link. */ ++ ++static bfd_reloc_status_type ++elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, ++ input_section, contents, rel, value, ++ info, sym_sec, sym_name, sym_flags, h) ++ reloc_howto_type * howto; ++ bfd * input_bfd; ++ bfd * output_bfd; ++ asection * input_section; ++ bfd_byte * contents; ++ Elf_Internal_Rela * rel; ++ bfd_vma value; ++ struct bfd_link_info * info; ++ asection * sym_sec; ++ const char * sym_name; ++ int sym_flags; ++ struct elf_link_hash_entry * h; ++{ ++ unsigned long r_type = howto->type; ++ unsigned long r_symndx; ++ bfd_byte * hit_data = contents + rel->r_offset; ++ bfd * dynobj = NULL; ++ Elf_Internal_Shdr * symtab_hdr; ++ struct elf_link_hash_entry ** sym_hashes; ++ bfd_vma * local_got_offsets; ++ asection * sgot = NULL; ++ asection * splt = NULL; ++ asection * sreloc = NULL; ++ bfd_vma addend; ++ bfd_signed_vma signed_addend; ++ struct elf32_arm_link_hash_table * globals; ++ ++ /* If the start address has been set, then set the EF_ARM_HASENTRY ++ flag. Setting this more than once is redundant, but the cost is ++ not too high, and it keeps the code simple. ++ ++ The test is done here, rather than somewhere else, because the ++ start address is only set just before the final link commences. ++ ++ Note - if the user deliberately sets a start address of 0, the ++ flag will not be set. */ ++ if (bfd_get_start_address (output_bfd) != 0) ++ elf_elfheader (output_bfd)->e_flags |= EF_ARM_HASENTRY; ++ ++ globals = elf32_arm_hash_table (info); ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ if (dynobj) ++ { ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ splt = bfd_get_section_by_name (dynobj, ".plt"); ++ } ++ symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; ++ sym_hashes = elf_sym_hashes (input_bfd); ++ local_got_offsets = elf_local_got_offsets (input_bfd); ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ ++#if USE_REL ++ addend = bfd_get_32 (input_bfd, hit_data) & howto->src_mask; ++ ++ if (addend & ((howto->src_mask + 1) >> 1)) ++ { ++ signed_addend = -1; ++ signed_addend &= ~ howto->src_mask; ++ signed_addend |= addend; ++ } ++ else ++ signed_addend = addend; ++#else ++ addend = signed_addend = rel->r_addend; ++#endif ++ ++ switch (r_type) ++ { ++ case R_ARM_NONE: ++ return bfd_reloc_ok; ++ ++ case R_ARM_PC24: ++ case R_ARM_ABS32: ++ case R_ARM_REL32: ++#ifndef OLD_ARM_ABI ++ case R_ARM_XPC25: ++#endif ++ /* When generating a shared object, these relocations are copied ++ into the output file to be resolved at run time. */ ++ if (info->shared ++ && r_symndx != 0 ++ && (r_type != R_ARM_PC24 ++ || (h != NULL ++ && h->dynindx != -1 ++ && (! info->symbolic ++ || (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_REGULAR) == 0)))) ++ { ++ Elf_Internal_Rela outrel; ++ bfd_byte *loc; ++ bfd_boolean skip, relocate; ++ ++ 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 bfd_reloc_notsupported; ++ ++ BFD_ASSERT (strncmp (name, ".rel", 4) == 0 ++ && strcmp (bfd_get_section_name (input_bfd, ++ input_section), ++ name + 4) == 0); ++ ++ sreloc = bfd_get_section_by_name (dynobj, name); ++ BFD_ASSERT (sreloc != NULL); ++ } ++ ++ skip = FALSE; ++ relocate = FALSE; ++ ++ outrel.r_offset = ++ _bfd_elf_section_offset (output_bfd, info, input_section, ++ rel->r_offset); ++ if (outrel.r_offset == (bfd_vma) -1) ++ skip = TRUE; ++ else if (outrel.r_offset == (bfd_vma) -2) ++ skip = TRUE, relocate = TRUE; ++ outrel.r_offset += (input_section->output_section->vma ++ + input_section->output_offset); ++ ++ if (skip) ++ memset (&outrel, 0, sizeof outrel); ++ else if (r_type == R_ARM_PC24) ++ { ++ BFD_ASSERT (h != NULL && h->dynindx != -1); ++ if ((input_section->flags & SEC_ALLOC) == 0) ++ relocate = TRUE; ++ outrel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_PC24); ++ } ++ else ++ { ++ if (h == NULL ++ || ((info->symbolic || h->dynindx == -1) ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_REGULAR) != 0)) ++ { ++ relocate = TRUE; ++ outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); ++ } ++ else ++ { ++ BFD_ASSERT (h->dynindx != -1); ++ if ((input_section->flags & SEC_ALLOC) == 0) ++ relocate = TRUE; ++ outrel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_ABS32); ++ } ++ } ++ ++ loc = sreloc->contents; ++ loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); ++ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); ++ ++ /* If this reloc is against an external symbol, we do not want to ++ fiddle with the addend. Otherwise, we need to include the symbol ++ value so that it becomes an addend for the dynamic reloc. */ ++ if (! relocate) ++ return bfd_reloc_ok; ++ ++ return _bfd_final_link_relocate (howto, input_bfd, input_section, ++ contents, rel->r_offset, value, ++ (bfd_vma) 0); ++ } ++ else switch (r_type) ++ { ++#ifndef OLD_ARM_ABI ++ case R_ARM_XPC25: /* Arm BLX instruction. */ ++#endif ++ case R_ARM_PC24: /* Arm B/BL instruction */ ++#ifndef OLD_ARM_ABI ++ if (r_type == R_ARM_XPC25) ++ { ++ /* Check for Arm calling Arm function. */ ++ /* FIXME: Should we translate the instruction into a BL ++ instruction instead ? */ ++ if (sym_flags != STT_ARM_TFUNC) ++ (*_bfd_error_handler) (_("\ ++%s: Warning: Arm BLX instruction targets Arm function '%s'."), ++ bfd_archive_filename (input_bfd), ++ h ? h->root.root.string : "(local)"); ++ } ++ else ++#endif ++ { ++ /* Check for Arm calling Thumb function. */ ++ if (sym_flags == STT_ARM_TFUNC) ++ { ++ elf32_arm_to_thumb_stub (info, sym_name, input_bfd, output_bfd, ++ input_section, hit_data, sym_sec, rel->r_offset, ++ signed_addend, value); ++ return bfd_reloc_ok; ++ } ++ } ++ ++ if ( strcmp (bfd_get_target (input_bfd), "elf32-littlearm-oabi") == 0 ++ || strcmp (bfd_get_target (input_bfd), "elf32-bigarm-oabi") == 0) ++ { ++ /* The old way of doing things. Trearing the addend as a ++ byte sized field and adding in the pipeline offset. */ ++ value -= (input_section->output_section->vma ++ + input_section->output_offset); ++ value -= rel->r_offset; ++ value += addend; ++ ++ if (! globals->no_pipeline_knowledge) ++ value -= 8; ++ } ++ else ++ { ++ /* The ARM ELF ABI says that this reloc is computed as: S - P + A ++ where: ++ S is the address of the symbol in the relocation. ++ P is address of the instruction being relocated. ++ A is the addend (extracted from the instruction) in bytes. ++ ++ S is held in 'value'. ++ P is the base address of the section containing the instruction ++ plus the offset of the reloc into that section, ie: ++ (input_section->output_section->vma + ++ input_section->output_offset + ++ rel->r_offset). ++ A is the addend, converted into bytes, ie: ++ (signed_addend * 4) ++ ++ Note: None of these operations have knowledge of the pipeline ++ size of the processor, thus it is up to the assembler to encode ++ this information into the addend. */ ++ value -= (input_section->output_section->vma ++ + input_section->output_offset); ++ value -= rel->r_offset; ++ value += (signed_addend << howto->size); ++ ++ /* Previous versions of this code also used to add in the pipeline ++ offset here. This is wrong because the linker is not supposed ++ to know about such things, and one day it might change. In order ++ to support old binaries that need the old behaviour however, so ++ we attempt to detect which ABI was used to create the reloc. */ ++ if (! globals->no_pipeline_knowledge) ++ { ++ Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form */ ++ ++ i_ehdrp = elf_elfheader (input_bfd); ++ ++ if (i_ehdrp->e_ident[EI_OSABI] == 0) ++ value -= 8; ++ } ++ } ++ ++ signed_addend = value; ++ signed_addend >>= howto->rightshift; ++ ++ /* It is not an error for an undefined weak reference to be ++ out of range. Any program that branches to such a symbol ++ is going to crash anyway, so there is no point worrying ++ about getting the destination exactly right. */ ++ if (! h || h->root.type != bfd_link_hash_undefweak) ++ { ++ /* Perform a signed range check. */ ++ if ( signed_addend > ((bfd_signed_vma) (howto->dst_mask >> 1)) ++ || signed_addend < - ((bfd_signed_vma) ((howto->dst_mask + 1) >> 1))) ++ return bfd_reloc_overflow; ++ } ++ ++#ifndef OLD_ARM_ABI ++ /* If necessary set the H bit in the BLX instruction. */ ++ if (r_type == R_ARM_XPC25 && ((value & 2) == 2)) ++ value = (signed_addend & howto->dst_mask) ++ | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)) ++ | (1 << 24); ++ else ++#endif ++ value = (signed_addend & howto->dst_mask) ++ | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)); ++ break; ++ ++ case R_ARM_ABS32: ++ value += addend; ++ if (sym_flags == STT_ARM_TFUNC) ++ value |= 1; ++ break; ++ ++ case R_ARM_REL32: ++ value -= (input_section->output_section->vma ++ + input_section->output_offset + rel->r_offset); ++ value += addend; ++ break; ++ } ++ ++ bfd_put_32 (input_bfd, value, hit_data); ++ return bfd_reloc_ok; ++ ++ case R_ARM_ABS8: ++ value += addend; ++ if ((long) value > 0x7f || (long) value < -0x80) ++ return bfd_reloc_overflow; ++ ++ bfd_put_8 (input_bfd, value, hit_data); ++ return bfd_reloc_ok; ++ ++ case R_ARM_ABS16: ++ value += addend; ++ ++ if ((long) value > 0x7fff || (long) value < -0x8000) ++ return bfd_reloc_overflow; ++ ++ bfd_put_16 (input_bfd, value, hit_data); ++ return bfd_reloc_ok; ++ ++ case R_ARM_ABS12: ++ /* Support ldr and str instruction for the arm */ ++ /* Also thumb b (unconditional branch). ??? Really? */ ++ value += addend; ++ ++ if ((long) value > 0x7ff || (long) value < -0x800) ++ return bfd_reloc_overflow; ++ ++ value |= (bfd_get_32 (input_bfd, hit_data) & 0xfffff000); ++ bfd_put_32 (input_bfd, value, hit_data); ++ return bfd_reloc_ok; ++ ++ case R_ARM_THM_ABS5: ++ /* Support ldr and str instructions for the thumb. */ ++#if USE_REL ++ /* Need to refetch addend. */ ++ addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask; ++ /* ??? Need to determine shift amount from operand size. */ ++ addend >>= howto->rightshift; ++#endif ++ value += addend; ++ ++ /* ??? Isn't value unsigned? */ ++ if ((long) value > 0x1f || (long) value < -0x10) ++ return bfd_reloc_overflow; ++ ++ /* ??? Value needs to be properly shifted into place first. */ ++ value |= bfd_get_16 (input_bfd, hit_data) & 0xf83f; ++ bfd_put_16 (input_bfd, value, hit_data); ++ return bfd_reloc_ok; ++ ++#ifndef OLD_ARM_ABI ++ case R_ARM_THM_XPC22: ++#endif ++ case R_ARM_THM_PC22: ++ /* Thumb BL (branch long instruction). */ ++ { ++ bfd_vma relocation; ++ bfd_boolean overflow = FALSE; ++ bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data); ++ bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2); ++ bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift; ++ bfd_signed_vma reloc_signed_min = ~ reloc_signed_max; ++ bfd_vma check; ++ bfd_signed_vma signed_check; ++ ++#if USE_REL ++ /* Need to refetch the addend and squish the two 11 bit pieces ++ together. */ ++ { ++ bfd_vma upper = upper_insn & 0x7ff; ++ bfd_vma lower = lower_insn & 0x7ff; ++ upper = (upper ^ 0x400) - 0x400; /* Sign extend. */ ++ addend = (upper << 12) | (lower << 1); ++ signed_addend = addend; ++ } ++#endif ++#ifndef OLD_ARM_ABI ++ if (r_type == R_ARM_THM_XPC22) ++ { ++ /* Check for Thumb to Thumb call. */ ++ /* FIXME: Should we translate the instruction into a BL ++ instruction instead ? */ ++ if (sym_flags == STT_ARM_TFUNC) ++ (*_bfd_error_handler) (_("\ ++%s: Warning: Thumb BLX instruction targets thumb function '%s'."), ++ bfd_archive_filename (input_bfd), ++ h ? h->root.root.string : "(local)"); ++ } ++ else ++#endif ++ { ++ /* If it is not a call to Thumb, assume call to Arm. ++ If it is a call relative to a section name, then it is not a ++ function call at all, but rather a long jump. */ ++ if (sym_flags != STT_ARM_TFUNC && sym_flags != STT_SECTION) ++ { ++ if (elf32_thumb_to_arm_stub ++ (info, sym_name, input_bfd, output_bfd, input_section, ++ hit_data, sym_sec, rel->r_offset, signed_addend, value)) ++ return bfd_reloc_ok; ++ else ++ return bfd_reloc_dangerous; ++ } ++ } ++ ++ relocation = value + signed_addend; ++ ++ relocation -= (input_section->output_section->vma ++ + input_section->output_offset ++ + rel->r_offset); ++ ++ if (! globals->no_pipeline_knowledge) ++ { ++ Elf_Internal_Ehdr * i_ehdrp; /* Elf file header, internal form. */ ++ ++ i_ehdrp = elf_elfheader (input_bfd); ++ ++ /* Previous versions of this code also used to add in the pipline ++ offset here. This is wrong because the linker is not supposed ++ to know about such things, and one day it might change. In order ++ to support old binaries that need the old behaviour however, so ++ we attempt to detect which ABI was used to create the reloc. */ ++ if ( strcmp (bfd_get_target (input_bfd), "elf32-littlearm-oabi") == 0 ++ || strcmp (bfd_get_target (input_bfd), "elf32-bigarm-oabi") == 0 ++ || i_ehdrp->e_ident[EI_OSABI] == 0) ++ relocation += 4; ++ } ++ ++ check = relocation >> howto->rightshift; ++ ++ /* If this is a signed value, the rightshift just dropped ++ leading 1 bits (assuming twos complement). */ ++ if ((bfd_signed_vma) relocation >= 0) ++ signed_check = check; ++ else ++ signed_check = check | ~((bfd_vma) -1 >> howto->rightshift); ++ ++ /* Assumes two's complement. */ ++ if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) ++ overflow = TRUE; ++ ++#ifndef OLD_ARM_ABI ++ if (r_type == R_ARM_THM_XPC22 ++ && ((lower_insn & 0x1800) == 0x0800)) ++ /* For a BLX instruction, make sure that the relocation is rounded up ++ to a word boundary. This follows the semantics of the instruction ++ which specifies that bit 1 of the target address will come from bit ++ 1 of the base address. */ ++ relocation = (relocation + 2) & ~ 3; ++#endif ++ /* Put RELOCATION back into the insn. */ ++ upper_insn = (upper_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 12) & 0x7ff); ++ lower_insn = (lower_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 1) & 0x7ff); ++ ++ /* Put the relocated value back in the object file: */ ++ bfd_put_16 (input_bfd, upper_insn, hit_data); ++ bfd_put_16 (input_bfd, lower_insn, hit_data + 2); ++ ++ return (overflow ? bfd_reloc_overflow : bfd_reloc_ok); ++ } ++ break; ++ ++ case R_ARM_THM_PC11: ++ /* Thumb B (branch) instruction). */ ++ { ++ bfd_signed_vma relocation; ++ bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; ++ bfd_signed_vma reloc_signed_min = ~ reloc_signed_max; ++ bfd_signed_vma signed_check; ++ ++#if USE_REL ++ /* Need to refetch addend. */ ++ addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask; ++ if (addend & ((howto->src_mask + 1) >> 1)) ++ { ++ signed_addend = -1; ++ signed_addend &= ~ howto->src_mask; ++ signed_addend |= addend; ++ } ++ else ++ signed_addend = addend; ++ /* The value in the insn has been right shifted. We need to ++ undo this, so that we can perform the address calculation ++ in terms of bytes. */ ++ signed_addend <<= howto->rightshift; ++#endif ++ relocation = value + signed_addend; ++ ++ relocation -= (input_section->output_section->vma ++ + input_section->output_offset ++ + rel->r_offset); ++ ++ relocation >>= howto->rightshift; ++ signed_check = relocation; ++ relocation &= howto->dst_mask; ++ relocation |= (bfd_get_16 (input_bfd, hit_data) & (~ howto->dst_mask)); ++ ++ bfd_put_16 (input_bfd, relocation, hit_data); ++ ++ /* Assumes two's complement. */ ++ if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) ++ return bfd_reloc_overflow; ++ ++ return bfd_reloc_ok; ++ } ++ ++ case R_ARM_GNU_VTINHERIT: ++ case R_ARM_GNU_VTENTRY: ++ return bfd_reloc_ok; ++ ++ case R_ARM_COPY: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_GLOB_DAT: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_JUMP_SLOT: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_RELATIVE: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_GOTOFF: ++ /* Relocation is relative to the start of the ++ global offset table. */ ++ ++ BFD_ASSERT (sgot != NULL); ++ if (sgot == NULL) ++ return bfd_reloc_notsupported; ++ ++ /* If we are addressing a Thumb function, we need to adjust the ++ address by one, so that attempts to call the function pointer will ++ correctly interpret it as Thumb code. */ ++ if (sym_flags == STT_ARM_TFUNC) ++ value += 1; ++ ++ /* Note that sgot->output_offset is not involved in this ++ calculation. We always want the start of .got. If we ++ define _GLOBAL_OFFSET_TABLE in a different way, as is ++ permitted by the ABI, we might have to change this ++ calculation. */ ++ value -= sgot->output_section->vma; ++ return _bfd_final_link_relocate (howto, input_bfd, input_section, ++ contents, rel->r_offset, value, ++ (bfd_vma) 0); ++ ++ case R_ARM_GOTPC: ++ /* Use global offset table as symbol value. */ ++ BFD_ASSERT (sgot != NULL); ++ ++ if (sgot == NULL) ++ return bfd_reloc_notsupported; ++ ++ value = sgot->output_section->vma; ++ return _bfd_final_link_relocate (howto, input_bfd, input_section, ++ contents, rel->r_offset, value, ++ (bfd_vma) 0); ++ ++ case R_ARM_GOT32: ++ /* Relocation is to the entry for this symbol in the ++ global offset table. */ ++ if (sgot == NULL) ++ return bfd_reloc_notsupported; ++ ++ if (h != NULL) ++ { ++ bfd_vma off; ++ bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created; ++ ++ off = h->got.offset; ++ BFD_ASSERT (off != (bfd_vma) -1); ++ ++ if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) ++ || (info->shared ++ && (info->symbolic || h->dynindx == -1 ++ || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)) ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) ++ { ++ /* 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 .rel.got relocation ++ entry to initialize the value. This is done in the ++ finish_dynamic_symbol routine. */ ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ /* If we are addressing a Thumb function, we need to ++ adjust the address by one, so that attempts to ++ call the function pointer will correctly ++ interpret it as Thumb code. */ ++ if (sym_flags == STT_ARM_TFUNC) ++ value |= 1; ++ ++ bfd_put_32 (output_bfd, value, sgot->contents + off); ++ h->got.offset |= 1; ++ } ++ } ++ ++ value = sgot->output_offset + off; ++ } ++ 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 ++ generated the necessary reloc. */ ++ if ((off & 1) != 0) ++ off &= ~1; ++ else ++ { ++ bfd_put_32 (output_bfd, value, sgot->contents + off); ++ ++ if (info->shared) ++ { ++ asection * srelgot; ++ Elf_Internal_Rela outrel; ++ bfd_byte *loc; ++ ++ srelgot = bfd_get_section_by_name (dynobj, ".rel.got"); ++ BFD_ASSERT (srelgot != NULL); ++ ++ outrel.r_offset = (sgot->output_section->vma ++ + sgot->output_offset ++ + off); ++ outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); ++ loc = srelgot->contents; ++ loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rel); ++ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); ++ } ++ ++ local_got_offsets[r_symndx] |= 1; ++ } ++ ++ value = sgot->output_offset + off; ++ } ++ ++ return _bfd_final_link_relocate (howto, input_bfd, input_section, ++ contents, rel->r_offset, value, ++ (bfd_vma) 0); ++ ++ case R_ARM_PLT32: ++ /* Relocation is to the entry for this symbol in the ++ procedure linkage table. */ ++ ++ /* Resolve a PLT32 reloc against a local symbol directly, ++ without using the procedure linkage table. */ ++ if (h == NULL) ++ return _bfd_final_link_relocate (howto, input_bfd, input_section, ++ contents, rel->r_offset, value, ++ (bfd_vma) 0); ++ ++ if (h->plt.offset == (bfd_vma) -1) ++ /* We didn't make a PLT entry for this symbol. This ++ happens when statically linking PIC code, or when ++ using -Bsymbolic. */ ++ return _bfd_final_link_relocate (howto, input_bfd, input_section, ++ contents, rel->r_offset, value, ++ (bfd_vma) 0); ++ ++ BFD_ASSERT(splt != NULL); ++ if (splt == NULL) ++ return bfd_reloc_notsupported; ++ ++ value = (splt->output_section->vma ++ + splt->output_offset ++ + h->plt.offset); ++ return _bfd_final_link_relocate (howto, input_bfd, input_section, ++ contents, rel->r_offset, value, ++ (bfd_vma) 0); ++ ++ case R_ARM_SBREL32: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_AMP_VCALL9: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_RSBREL32: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_THM_RPC22: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_RREL32: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_RABS32: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_RPC24: ++ return bfd_reloc_notsupported; ++ ++ case R_ARM_RBASE: ++ return bfd_reloc_notsupported; ++ ++ default: ++ return bfd_reloc_notsupported; ++ } ++} ++ ++#if USE_REL ++/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. */ ++static void ++arm_add_to_rel (abfd, address, howto, increment) ++ bfd * abfd; ++ bfd_byte * address; ++ reloc_howto_type * howto; ++ bfd_signed_vma increment; ++{ ++ bfd_signed_vma addend; ++ ++ if (howto->type == R_ARM_THM_PC22) ++ { ++ int upper_insn, lower_insn; ++ int upper, lower; ++ ++ upper_insn = bfd_get_16 (abfd, address); ++ lower_insn = bfd_get_16 (abfd, address + 2); ++ upper = upper_insn & 0x7ff; ++ lower = lower_insn & 0x7ff; ++ ++ addend = (upper << 12) | (lower << 1); ++ addend += increment; ++ addend >>= 1; ++ ++ upper_insn = (upper_insn & 0xf800) | ((addend >> 11) & 0x7ff); ++ lower_insn = (lower_insn & 0xf800) | (addend & 0x7ff); ++ ++ bfd_put_16 (abfd, (bfd_vma) upper_insn, address); ++ bfd_put_16 (abfd, (bfd_vma) lower_insn, address + 2); ++ } ++ else ++ { ++ bfd_vma contents; ++ ++ contents = bfd_get_32 (abfd, address); ++ ++ /* Get the (signed) value from the instruction. */ ++ addend = contents & howto->src_mask; ++ if (addend & ((howto->src_mask + 1) >> 1)) ++ { ++ bfd_signed_vma mask; ++ ++ mask = -1; ++ mask &= ~ howto->src_mask; ++ addend |= mask; ++ } ++ ++ /* Add in the increment, (which is a byte value). */ ++ switch (howto->type) ++ { ++ default: ++ addend += increment; ++ break; ++ ++ case R_ARM_PC24: ++ addend <<= howto->size; ++ addend += increment; ++ ++ /* Should we check for overflow here ? */ ++ ++ /* Drop any undesired bits. */ ++ addend >>= howto->rightshift; ++ break; ++ } ++ ++ contents = (contents & ~ howto->dst_mask) | (addend & howto->dst_mask); ++ ++ bfd_put_32 (abfd, contents, address); ++ } ++} ++#endif /* USE_REL */ ++ ++/* Relocate an ARM ELF section. */ ++static bfd_boolean ++elf32_arm_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; ++ struct elf_link_hash_entry **sym_hashes; ++ Elf_Internal_Rela *rel; ++ Elf_Internal_Rela *relend; ++ const char *name; ++ ++#if !USE_REL ++ if (info->relocatable) ++ return TRUE; ++#endif ++ ++ symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; ++ sym_hashes = elf_sym_hashes (input_bfd); ++ ++ rel = relocs; ++ relend = relocs + input_section->reloc_count; ++ for (; rel < relend; rel++) ++ { ++ int r_type; ++ reloc_howto_type * howto; ++ unsigned long r_symndx; ++ Elf_Internal_Sym * sym; ++ asection * sec; ++ struct elf_link_hash_entry * h; ++ bfd_vma relocation; ++ bfd_reloc_status_type r; ++ arelent bfd_reloc; ++ ++ r_symndx = ELF32_R_SYM (rel->r_info); ++ r_type = ELF32_R_TYPE (rel->r_info); ++ ++ if ( r_type == R_ARM_GNU_VTENTRY ++ || r_type == R_ARM_GNU_VTINHERIT) ++ continue; ++ ++ elf32_arm_info_to_howto (input_bfd, & bfd_reloc, rel); ++ howto = bfd_reloc.howto; ++ ++#if USE_REL ++ if (info->relocatable) ++ { ++ /* This is a relocatable link. We don't have to change ++ anything, unless the reloc is against a section symbol, ++ in which case we have to adjust according to where the ++ section symbol winds up in the output section. */ ++ if (r_symndx < symtab_hdr->sh_info) ++ { ++ sym = local_syms + r_symndx; ++ if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) ++ { ++ sec = local_sections[r_symndx]; ++ arm_add_to_rel (input_bfd, contents + rel->r_offset, ++ howto, ++ (bfd_signed_vma) (sec->output_offset ++ + sym->st_value)); ++ } ++ } ++ ++ continue; ++ } ++#endif ++ ++ /* This is a final link. */ ++ h = NULL; ++ sym = NULL; ++ sec = NULL; ++ ++ if (r_symndx < symtab_hdr->sh_info) ++ { ++ sym = local_syms + r_symndx; ++ sec = local_sections[r_symndx]; ++#if USE_REL ++ relocation = (sec->output_section->vma ++ + sec->output_offset ++ + sym->st_value); ++ if ((sec->flags & SEC_MERGE) ++ && ELF_ST_TYPE (sym->st_info) == STT_SECTION) ++ { ++ asection *msec; ++ bfd_vma addend, value; ++ ++ if (howto->rightshift) ++ { ++ (*_bfd_error_handler) ++ (_("%s(%s+0x%lx): %s relocation against SEC_MERGE section"), ++ bfd_archive_filename (input_bfd), ++ bfd_get_section_name (input_bfd, input_section), ++ (long) rel->r_offset, howto->name); ++ return FALSE; ++ } ++ ++ value = bfd_get_32 (input_bfd, contents + rel->r_offset); ++ ++ /* Get the (signed) value from the instruction. */ ++ addend = value & howto->src_mask; ++ if (addend & ((howto->src_mask + 1) >> 1)) ++ { ++ bfd_signed_vma mask; ++ ++ mask = -1; ++ mask &= ~ howto->src_mask; ++ addend |= mask; ++ } ++ msec = sec; ++ addend = ++ _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) ++ - relocation; ++ addend += msec->output_section->vma + msec->output_offset; ++ value = (value & ~ howto->dst_mask) | (addend & howto->dst_mask); ++ bfd_put_32 (input_bfd, value, contents + rel->r_offset); ++ } ++#else ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++#endif ++ } ++ else ++ { ++ bfd_boolean warned; ++ bfd_boolean unresolved_reloc; ++ ++ RELOC_FOR_GLOBAL_SYMBOL (h, sym_hashes, r_symndx, ++ symtab_hdr, relocation, ++ sec, unresolved_reloc, info, ++ warned); ++ ++ if (unresolved_reloc || relocation != 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. */ ++ switch (r_type) ++ { ++ case R_ARM_PC24: ++ case R_ARM_ABS32: ++ case R_ARM_THM_PC22: ++ if (info->shared ++ && ( ++ (!info->symbolic && h->dynindx != -1) ++ || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 ++ ) ++ && ((input_section->flags & SEC_ALLOC) != 0 ++ /* DWARF will emit R_ARM_ABS32 relocations in its ++ sections against symbols defined externally ++ in shared libraries. We can't do anything ++ with them here. */ ++ || ((input_section->flags & SEC_DEBUGGING) != 0 ++ && (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_DYNAMIC) != 0)) ++ ) ++ relocation = 0; ++ break; ++ ++ case R_ARM_GOTPC: ++ relocation = 0; ++ break; ++ ++ case R_ARM_GOT32: ++ if ((WILL_CALL_FINISH_DYNAMIC_SYMBOL ++ (elf_hash_table (info)->dynamic_sections_created, ++ info->shared, h)) ++ && (!info->shared ++ || (!info->symbolic && h->dynindx != -1) ++ || (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_REGULAR) == 0)) ++ relocation = 0; ++ break; ++ ++ case R_ARM_PLT32: ++ if (h->plt.offset != (bfd_vma)-1) ++ relocation = 0; ++ break; ++ ++ default: ++ if (unresolved_reloc) ++ _bfd_error_handler ++ (_("%s: warning: unresolvable relocation %d against symbol `%s' from %s section"), ++ bfd_archive_filename (input_bfd), ++ r_type, ++ h->root.root.string, ++ bfd_get_section_name (input_bfd, input_section)); ++ break; ++ } ++ } ++ } ++ ++ if (h != NULL) ++ 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 || *name == '\0') ++ name = bfd_section_name (input_bfd, sec); ++ } ++ ++ r = elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, ++ input_section, contents, rel, ++ relocation, info, sec, name, ++ (h ? ELF_ST_TYPE (h->type) : ++ ELF_ST_TYPE (sym->st_info)), h); ++ ++ if (r != bfd_reloc_ok) ++ { ++ const char * msg = (const char *) 0; ++ ++ switch (r) ++ { ++ case bfd_reloc_overflow: ++ /* If the overflowing reloc was to an undefined symbol, ++ we have already printed one error message and there ++ is no point complaining again. */ ++ if ((! h || ++ h->root.type != bfd_link_hash_undefined) ++ && (!((*info->callbacks->reloc_overflow) ++ (info, name, howto->name, (bfd_vma) 0, ++ input_bfd, input_section, rel->r_offset)))) ++ return FALSE; ++ break; ++ ++ case bfd_reloc_undefined: ++ if (!((*info->callbacks->undefined_symbol) ++ (info, name, input_bfd, input_section, ++ rel->r_offset, TRUE))) ++ return FALSE; ++ break; ++ ++ case bfd_reloc_outofrange: ++ msg = _("internal error: out of range error"); ++ goto common_error; ++ ++ case bfd_reloc_notsupported: ++ msg = _("internal error: unsupported relocation error"); ++ goto common_error; ++ ++ case bfd_reloc_dangerous: ++ msg = _("internal error: dangerous error"); ++ goto common_error; ++ ++ default: ++ msg = _("internal error: unknown error"); ++ /* fall through */ ++ ++ common_error: ++ if (!((*info->callbacks->warning) ++ (info, msg, name, input_bfd, input_section, ++ rel->r_offset))) ++ return FALSE; ++ break; ++ } ++ } ++ } ++ ++ return TRUE; ++} ++ ++/* Set the right machine number. */ ++ ++static bfd_boolean ++elf32_arm_object_p (abfd) ++ bfd *abfd; ++{ ++ unsigned int mach; ++ ++ mach = bfd_arm_get_mach_from_notes (abfd, ARM_NOTE_SECTION); ++ ++ if (mach != bfd_mach_arm_unknown) ++ bfd_default_set_arch_mach (abfd, bfd_arch_arm, mach); ++ ++ else if (elf_elfheader (abfd)->e_flags & EF_ARM_MAVERICK_FLOAT) ++ bfd_default_set_arch_mach (abfd, bfd_arch_arm, bfd_mach_arm_ep9312); ++ ++ else ++ bfd_default_set_arch_mach (abfd, bfd_arch_arm, mach); ++ ++ return TRUE; ++} ++ ++/* Function to keep ARM specific flags in the ELF header. */ ++static bfd_boolean ++elf32_arm_set_private_flags (abfd, flags) ++ bfd *abfd; ++ flagword flags; ++{ ++ if (elf_flags_init (abfd) ++ && elf_elfheader (abfd)->e_flags != flags) ++ { ++ if (EF_ARM_EABI_VERSION (flags) == EF_ARM_EABI_UNKNOWN) ++ { ++ if (flags & EF_ARM_INTERWORK) ++ (*_bfd_error_handler) (_("\ ++Warning: Not setting interworking flag of %s since it has already been specified as non-interworking"), ++ bfd_archive_filename (abfd)); ++ else ++ _bfd_error_handler (_("\ ++Warning: Clearing the interworking flag of %s due to outside request"), ++ bfd_archive_filename (abfd)); ++ } ++ } ++ else ++ { ++ elf_elfheader (abfd)->e_flags = flags; ++ elf_flags_init (abfd) = TRUE; ++ } ++ ++ return TRUE; ++} ++ ++/* Copy backend specific data from one object module to another. */ ++ ++static bfd_boolean ++elf32_arm_copy_private_bfd_data (ibfd, obfd) ++ bfd *ibfd; ++ bfd *obfd; ++{ ++ flagword in_flags; ++ flagword out_flags; ++ ++ if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour ++ || bfd_get_flavour (obfd) != bfd_target_elf_flavour) ++ return TRUE; ++ ++ in_flags = elf_elfheader (ibfd)->e_flags; ++ out_flags = elf_elfheader (obfd)->e_flags; ++ ++ if (elf_flags_init (obfd) ++ && EF_ARM_EABI_VERSION (out_flags) == EF_ARM_EABI_UNKNOWN ++ && in_flags != out_flags) ++ { ++ /* Cannot mix APCS26 and APCS32 code. */ ++ if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26)) ++ return FALSE; ++ ++ /* Cannot mix float APCS and non-float APCS code. */ ++ if ((in_flags & EF_ARM_APCS_FLOAT) != (out_flags & EF_ARM_APCS_FLOAT)) ++ return FALSE; ++ ++ /* If the src and dest have different interworking flags ++ then turn off the interworking bit. */ ++ if ((in_flags & EF_ARM_INTERWORK) != (out_flags & EF_ARM_INTERWORK)) ++ { ++ if (out_flags & EF_ARM_INTERWORK) ++ _bfd_error_handler (_("\ ++Warning: Clearing the interworking flag of %s because non-interworking code in %s has been linked with it"), ++ bfd_get_filename (obfd), ++ bfd_archive_filename (ibfd)); ++ ++ in_flags &= ~EF_ARM_INTERWORK; ++ } ++ ++ /* Likewise for PIC, though don't warn for this case. */ ++ if ((in_flags & EF_ARM_PIC) != (out_flags & EF_ARM_PIC)) ++ in_flags &= ~EF_ARM_PIC; ++ } ++ ++ elf_elfheader (obfd)->e_flags = in_flags; ++ elf_flags_init (obfd) = TRUE; ++ ++ return TRUE; ++} ++ ++/* Merge backend specific data from an object file to the output ++ object file when linking. */ ++ ++static bfd_boolean ++elf32_arm_merge_private_bfd_data (ibfd, obfd) ++ bfd * ibfd; ++ bfd * obfd; ++{ ++ flagword out_flags; ++ flagword in_flags; ++ bfd_boolean flags_compatible = TRUE; ++ asection *sec; ++ ++ /* 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; ++ ++ /* The input BFD must have had its flags initialised. */ ++ /* The following seems bogus to me -- The flags are initialized in ++ the assembler but I don't think an elf_flags_init field is ++ written into the object. */ ++ /* BFD_ASSERT (elf_flags_init (ibfd)); */ ++ ++ in_flags = elf_elfheader (ibfd)->e_flags; ++ out_flags = elf_elfheader (obfd)->e_flags; ++ ++ if (!elf_flags_init (obfd)) ++ { ++ /* If the input is the default architecture and had the default ++ flags then do not bother setting the flags for the output ++ architecture, instead allow future merges to do this. If no ++ future merges ever set these flags then they will retain their ++ uninitialised values, which surprise surprise, correspond ++ to the default values. */ ++ if (bfd_get_arch_info (ibfd)->the_default ++ && elf_elfheader (ibfd)->e_flags == 0) ++ return TRUE; ++ ++ elf_flags_init (obfd) = TRUE; ++ elf_elfheader (obfd)->e_flags = in_flags; ++ ++ if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) ++ && bfd_get_arch_info (obfd)->the_default) ++ return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); ++ ++ return TRUE; ++ } ++ ++ /* Determine what should happen if the input ARM architecture ++ does not match the output ARM architecture. */ ++ if (! bfd_arm_merge_machines (ibfd, obfd)) ++ return FALSE; ++ ++ /* Identical flags must be compatible. */ ++ if (in_flags == out_flags) ++ return TRUE; ++ ++ /* Check to see if the input BFD actually contains any sections. If ++ not, its flags may not have been initialised either, but it ++ cannot actually cause any incompatibility. Do not short-circuit ++ dynamic objects; their section list may be emptied by ++ elf_link_add_object_symbols. */ ++ ++ if (!(ibfd->flags & DYNAMIC)) ++ { ++ bfd_boolean null_input_bfd = TRUE; ++ ++ for (sec = ibfd->sections; sec != NULL; sec = sec->next) ++ { ++ /* Ignore synthetic glue sections. */ ++ if (strcmp (sec->name, ".glue_7") ++ && strcmp (sec->name, ".glue_7t")) ++ { ++ null_input_bfd = FALSE; ++ break; ++ } ++ } ++ if (null_input_bfd) ++ return TRUE; ++ } ++ ++ /* Complain about various flag mismatches. */ ++ if (EF_ARM_EABI_VERSION (in_flags) != EF_ARM_EABI_VERSION (out_flags)) ++ { ++ _bfd_error_handler (_("\ ++ERROR: %s is compiled for EABI version %d, whereas %s is compiled for version %d"), ++ bfd_archive_filename (ibfd), ++ (in_flags & EF_ARM_EABIMASK) >> 24, ++ bfd_get_filename (obfd), ++ (out_flags & EF_ARM_EABIMASK) >> 24); ++ return FALSE; ++ } ++ ++ /* Not sure what needs to be checked for EABI versions >= 1. */ ++ if (EF_ARM_EABI_VERSION (in_flags) == EF_ARM_EABI_UNKNOWN) ++ { ++ if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26)) ++ { ++ _bfd_error_handler (_("\ ++ERROR: %s is compiled for APCS-%d, whereas target %s uses APCS-%d"), ++ bfd_archive_filename (ibfd), ++ in_flags & EF_ARM_APCS_26 ? 26 : 32, ++ bfd_get_filename (obfd), ++ out_flags & EF_ARM_APCS_26 ? 26 : 32); ++ flags_compatible = FALSE; ++ } ++ ++ if ((in_flags & EF_ARM_APCS_FLOAT) != (out_flags & EF_ARM_APCS_FLOAT)) ++ { ++ if (in_flags & EF_ARM_APCS_FLOAT) ++ _bfd_error_handler (_("\ ++ERROR: %s passes floats in float registers, whereas %s passes them in integer registers"), ++ bfd_archive_filename (ibfd), ++ bfd_get_filename (obfd)); ++ else ++ _bfd_error_handler (_("\ ++ERROR: %s passes floats in integer registers, whereas %s passes them in float registers"), ++ bfd_archive_filename (ibfd), ++ bfd_get_filename (obfd)); ++ ++ flags_compatible = FALSE; ++ } ++ ++ if ((in_flags & EF_ARM_VFP_FLOAT) != (out_flags & EF_ARM_VFP_FLOAT)) ++ { ++ if (in_flags & EF_ARM_VFP_FLOAT) ++ _bfd_error_handler (_("\ ++ERROR: %s uses VFP instructions, whereas %s does not"), ++ bfd_archive_filename (ibfd), ++ bfd_get_filename (obfd)); ++ else ++ _bfd_error_handler (_("\ ++ERROR: %s uses FPA instructions, whereas %s does not"), ++ bfd_archive_filename (ibfd), ++ bfd_get_filename (obfd)); ++ ++ flags_compatible = FALSE; ++ } ++ ++ if ((in_flags & EF_ARM_MAVERICK_FLOAT) != (out_flags & EF_ARM_MAVERICK_FLOAT)) ++ { ++ if (in_flags & EF_ARM_MAVERICK_FLOAT) ++ _bfd_error_handler (_("\ ++ERROR: %s uses Maverick instructions, whereas %s does not"), ++ bfd_archive_filename (ibfd), ++ bfd_get_filename (obfd)); ++ else ++ _bfd_error_handler (_("\ ++ERROR: %s does not use Maverick instructions, whereas %s does"), ++ bfd_archive_filename (ibfd), ++ bfd_get_filename (obfd)); ++ ++ flags_compatible = FALSE; ++ } ++ ++#ifdef EF_ARM_SOFT_FLOAT ++ if ((in_flags & EF_ARM_SOFT_FLOAT) != (out_flags & EF_ARM_SOFT_FLOAT)) ++ { ++ /* We can allow interworking between code that is VFP format ++ layout, and uses either soft float or integer regs for ++ passing floating point arguments and results. We already ++ know that the APCS_FLOAT flags match; similarly for VFP ++ flags. */ ++ if ((in_flags & EF_ARM_APCS_FLOAT) != 0 ++ || (in_flags & EF_ARM_VFP_FLOAT) == 0) ++ { ++ if (in_flags & EF_ARM_SOFT_FLOAT) ++ _bfd_error_handler (_("\ ++ERROR: %s uses software FP, whereas %s uses hardware FP"), ++ bfd_archive_filename (ibfd), ++ bfd_get_filename (obfd)); ++ else ++ _bfd_error_handler (_("\ ++ERROR: %s uses hardware FP, whereas %s uses software FP"), ++ bfd_archive_filename (ibfd), ++ bfd_get_filename (obfd)); ++ ++ flags_compatible = FALSE; ++ } ++ } ++#endif ++ ++ /* Interworking mismatch is only a warning. */ ++ if ((in_flags & EF_ARM_INTERWORK) != (out_flags & EF_ARM_INTERWORK)) ++ { ++ if (in_flags & EF_ARM_INTERWORK) ++ { ++ _bfd_error_handler (_("\ ++Warning: %s supports interworking, whereas %s does not"), ++ bfd_archive_filename (ibfd), ++ bfd_get_filename (obfd)); ++ } ++ else ++ { ++ _bfd_error_handler (_("\ ++Warning: %s does not support interworking, whereas %s does"), ++ bfd_archive_filename (ibfd), ++ bfd_get_filename (obfd)); ++ } ++ } ++ } ++ ++ return flags_compatible; ++} ++ ++/* Display the flags field. */ ++ ++static bfd_boolean ++elf32_arm_print_private_bfd_data (abfd, ptr) ++ bfd *abfd; ++ PTR ptr; ++{ ++ FILE * file = (FILE *) ptr; ++ unsigned long flags; ++ ++ BFD_ASSERT (abfd != NULL && ptr != NULL); ++ ++ /* Print normal ELF private data. */ ++ _bfd_elf_print_private_bfd_data (abfd, ptr); ++ ++ flags = elf_elfheader (abfd)->e_flags; ++ /* Ignore init flag - it may not be set, despite the flags field ++ containing valid data. */ ++ ++ /* xgettext:c-format */ ++ fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); ++ ++ switch (EF_ARM_EABI_VERSION (flags)) ++ { ++ case EF_ARM_EABI_UNKNOWN: ++ /* The following flag bits are GNU extenstions and not part of the ++ official ARM ELF extended ABI. Hence they are only decoded if ++ the EABI version is not set. */ ++ if (flags & EF_ARM_INTERWORK) ++ fprintf (file, _(" [interworking enabled]")); ++ ++ if (flags & EF_ARM_APCS_26) ++ fprintf (file, " [APCS-26]"); ++ else ++ fprintf (file, " [APCS-32]"); ++ ++ if (flags & EF_ARM_VFP_FLOAT) ++ fprintf (file, _(" [VFP float format]")); ++ else if (flags & EF_ARM_MAVERICK_FLOAT) ++ fprintf (file, _(" [Maverick float format]")); ++ else ++ fprintf (file, _(" [FPA float format]")); ++ ++ if (flags & EF_ARM_APCS_FLOAT) ++ fprintf (file, _(" [floats passed in float registers]")); ++ ++ if (flags & EF_ARM_PIC) ++ fprintf (file, _(" [position independent]")); ++ ++ if (flags & EF_ARM_NEW_ABI) ++ fprintf (file, _(" [new ABI]")); ++ ++ if (flags & EF_ARM_OLD_ABI) ++ fprintf (file, _(" [old ABI]")); ++ ++ if (flags & EF_ARM_SOFT_FLOAT) ++ fprintf (file, _(" [software FP]")); ++ ++ flags &= ~(EF_ARM_INTERWORK | EF_ARM_APCS_26 | EF_ARM_APCS_FLOAT ++ | EF_ARM_PIC | EF_ARM_NEW_ABI | EF_ARM_OLD_ABI ++ | EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT ++ | EF_ARM_MAVERICK_FLOAT); ++ break; ++ ++ case EF_ARM_EABI_VER1: ++ fprintf (file, _(" [Version1 EABI]")); ++ ++ if (flags & EF_ARM_SYMSARESORTED) ++ fprintf (file, _(" [sorted symbol table]")); ++ else ++ fprintf (file, _(" [unsorted symbol table]")); ++ ++ flags &= ~ EF_ARM_SYMSARESORTED; ++ break; ++ ++ case EF_ARM_EABI_VER2: ++ fprintf (file, _(" [Version2 EABI]")); ++ ++ if (flags & EF_ARM_SYMSARESORTED) ++ fprintf (file, _(" [sorted symbol table]")); ++ else ++ fprintf (file, _(" [unsorted symbol table]")); ++ ++ if (flags & EF_ARM_DYNSYMSUSESEGIDX) ++ fprintf (file, _(" [dynamic symbols use segment index]")); ++ ++ if (flags & EF_ARM_MAPSYMSFIRST) ++ fprintf (file, _(" [mapping symbols precede others]")); ++ ++ flags &= ~(EF_ARM_SYMSARESORTED | EF_ARM_DYNSYMSUSESEGIDX ++ | EF_ARM_MAPSYMSFIRST); ++ break; ++ ++ default: ++ fprintf (file, _(" <EABI version unrecognised>")); ++ break; ++ } ++ ++ flags &= ~ EF_ARM_EABIMASK; ++ ++ if (flags & EF_ARM_RELEXEC) ++ fprintf (file, _(" [relocatable executable]")); ++ ++ if (flags & EF_ARM_HASENTRY) ++ fprintf (file, _(" [has entry point]")); ++ ++ flags &= ~ (EF_ARM_RELEXEC | EF_ARM_HASENTRY); ++ ++ if (flags) ++ fprintf (file, _("<Unrecognised flag bits set>")); ++ ++ fputc ('\n', file); ++ ++ return TRUE; ++} ++ ++static int ++elf32_arm_get_symbol_type (elf_sym, type) ++ Elf_Internal_Sym * elf_sym; ++ int type; ++{ ++ switch (ELF_ST_TYPE (elf_sym->st_info)) ++ { ++ case STT_ARM_TFUNC: ++ return ELF_ST_TYPE (elf_sym->st_info); ++ ++ case STT_ARM_16BIT: ++ /* If the symbol is not an object, return the STT_ARM_16BIT flag. ++ This allows us to distinguish between data used by Thumb instructions ++ and non-data (which is probably code) inside Thumb regions of an ++ executable. */ ++ if (type != STT_OBJECT) ++ return ELF_ST_TYPE (elf_sym->st_info); ++ break; ++ ++ default: ++ break; ++ } ++ ++ return type; ++} ++ ++static asection * ++elf32_arm_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_ARM_GNU_VTINHERIT: ++ case R_ARM_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 bfd_boolean ++elf32_arm_gc_sweep_hook (abfd, info, sec, relocs) ++ bfd *abfd ATTRIBUTE_UNUSED; ++ struct bfd_link_info *info ATTRIBUTE_UNUSED; ++ asection *sec ATTRIBUTE_UNUSED; ++ const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED; ++{ ++ /* We don't support garbage collection of GOT and PLT relocs yet. */ ++ return TRUE; ++} ++ ++/* Look through the relocs for a section during the first phase. */ ++ ++static bfd_boolean ++elf32_arm_check_relocs (abfd, info, sec, relocs) ++ bfd *abfd; ++ struct bfd_link_info *info; ++ asection *sec; ++ const Elf_Internal_Rela *relocs; ++{ ++ Elf_Internal_Shdr *symtab_hdr; ++ struct elf_link_hash_entry **sym_hashes; ++ struct elf_link_hash_entry **sym_hashes_end; ++ const Elf_Internal_Rela *rel; ++ const Elf_Internal_Rela *rel_end; ++ bfd *dynobj; ++ asection *sgot, *srelgot, *sreloc; ++ bfd_vma *local_got_offsets; ++ ++ if (info->relocatable) ++ return TRUE; ++ ++ sgot = srelgot = sreloc = NULL; ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ local_got_offsets = elf_local_got_offsets (abfd); ++ ++ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ++ 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; ++ ++ rel_end = relocs + sec->reloc_count; ++ for (rel = relocs; rel < rel_end; rel++) ++ { ++ struct elf_link_hash_entry *h; ++ unsigned long r_symndx; ++ ++ 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]; ++ ++ /* Some relocs require a global offset table. */ ++ if (dynobj == NULL) ++ { ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_ARM_GOT32: ++ case R_ARM_GOTOFF: ++ case R_ARM_GOTPC: ++ elf_hash_table (info)->dynobj = dynobj = abfd; ++ if (! _bfd_elf_create_got_section (dynobj, info)) ++ return FALSE; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ switch (ELF32_R_TYPE (rel->r_info)) ++ { ++ case R_ARM_GOT32: ++ /* This symbol requires a global offset table entry. */ ++ if (sgot == NULL) ++ { ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ BFD_ASSERT (sgot != NULL); ++ } ++ ++ /* Get the got relocation section if necessary. */ ++ if (srelgot == NULL ++ && (h != NULL || info->shared)) ++ { ++ srelgot = bfd_get_section_by_name (dynobj, ".rel.got"); ++ ++ /* If no got relocation section, make one and initialize. */ ++ if (srelgot == NULL) ++ { ++ srelgot = bfd_make_section (dynobj, ".rel.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.offset != (bfd_vma) -1) ++ /* We have already allocated space in the .got. */ ++ break; ++ ++ h->got.offset = sgot->_raw_size; ++ ++ /* 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; ++ ++ srelgot->_raw_size += sizeof (Elf32_External_Rel); ++ } ++ else ++ { ++ /* This is a global offset table entry for a local ++ symbol. */ ++ if (local_got_offsets == NULL) ++ { ++ bfd_size_type size; ++ unsigned int i; ++ ++ size = symtab_hdr->sh_info; ++ size *= sizeof (bfd_vma); ++ local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size); ++ if (local_got_offsets == NULL) ++ return FALSE; ++ elf_local_got_offsets (abfd) = local_got_offsets; ++ for (i = 0; i < symtab_hdr->sh_info; i++) ++ local_got_offsets[i] = (bfd_vma) -1; ++ } ++ ++ if (local_got_offsets[r_symndx] != (bfd_vma) -1) ++ /* We have already allocated space in the .got. */ ++ break; ++ ++ local_got_offsets[r_symndx] = sgot->_raw_size; ++ ++ if (info->shared) ++ /* If we are generating a shared object, we need to ++ output a R_ARM_RELATIVE reloc so that the dynamic ++ linker can adjust this GOT entry. */ ++ srelgot->_raw_size += sizeof (Elf32_External_Rel); ++ } ++ ++ sgot->_raw_size += 4; ++ break; ++ ++ case R_ARM_PLT32: ++ /* 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 which is ++ never referenced by a dynamic object, in which case we ++ don't need to generate a procedure linkage table entry ++ after all. */ ++ ++ /* If this is a local symbol, we resolve it directly without ++ creating a procedure linkage table entry. */ ++ if (h == NULL) ++ continue; ++ ++ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; ++ break; ++ ++ case R_ARM_ABS32: ++ case R_ARM_REL32: ++ case R_ARM_PC24: ++ /* If we are creating a shared library, and this is a reloc ++ against a global symbol, or a non PC relative reloc ++ against a local symbol, then we need to copy the reloc ++ into the shared library. However, if we are linking with ++ -Bsymbolic, we do not need to copy a reloc against a ++ global symbol which is defined in an object we are ++ including in the link (i.e., DEF_REGULAR is set). At ++ this point we have not seen all the input files, so it is ++ possible that DEF_REGULAR is not set now but will be set ++ later (it is never cleared). We account for that ++ possibility below by storing information in the ++ pcrel_relocs_copied field of the hash table entry. */ ++ if (info->shared ++ && (ELF32_R_TYPE (rel->r_info) != R_ARM_PC24 ++ || (h != NULL ++ && (! info->symbolic ++ || (h->elf_link_hash_flags ++ & ELF_LINK_HASH_DEF_REGULAR) == 0)))) ++ { ++ /* When creating a shared object, we must copy these ++ reloc types into the output file. We create a reloc ++ section in dynobj and make room for this reloc. */ ++ 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, ".rel", 4) == 0 ++ && strcmp (bfd_get_section_name (abfd, sec), ++ name + 4) == 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_Rel); ++ /* If we are linking with -Bsymbolic, and this is a ++ global symbol, we count the number of PC relative ++ relocations we have entered for this symbol, so that ++ we can discard them again if the symbol is later ++ defined by a regular object. Note that this function ++ is only called if we are using an elf_i386 linker ++ hash table, which means that h is really a pointer to ++ an elf_i386_link_hash_entry. */ ++ if (h != NULL && info->symbolic ++ && ELF32_R_TYPE (rel->r_info) == R_ARM_PC24) ++ { ++ struct elf32_arm_link_hash_entry * eh; ++ struct elf32_arm_pcrel_relocs_copied * p; ++ ++ eh = (struct elf32_arm_link_hash_entry *) h; ++ ++ for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next) ++ if (p->section == sreloc) ++ break; ++ ++ if (p == NULL) ++ { ++ p = ((struct elf32_arm_pcrel_relocs_copied *) ++ bfd_alloc (dynobj, (bfd_size_type) sizeof * p)); ++ if (p == NULL) ++ return FALSE; ++ p->next = eh->pcrel_relocs_copied; ++ eh->pcrel_relocs_copied = p; ++ p->section = sreloc; ++ p->count = 0; ++ } ++ ++ ++p->count; ++ } ++ } ++ break; ++ ++ /* This relocation describes the C++ object vtable hierarchy. ++ Reconstruct it for later use during GC. */ ++ case R_ARM_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_ARM_GNU_VTENTRY: ++ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset)) ++ return FALSE; ++ break; ++ } ++ } ++ ++ return TRUE; ++} ++ ++/* Find the nearest line to a particular section and offset, for error ++ reporting. This code is a duplicate of the code in elf.c, except ++ that it also accepts STT_ARM_TFUNC as a symbol that names a function. */ ++ ++static bfd_boolean ++elf32_arm_find_nearest_line ++ (abfd, section, symbols, offset, filename_ptr, functionname_ptr, line_ptr) ++ bfd *abfd; ++ asection *section; ++ asymbol **symbols; ++ bfd_vma offset; ++ const char **filename_ptr; ++ const char **functionname_ptr; ++ unsigned int *line_ptr; ++{ ++ bfd_boolean found; ++ const char *filename; ++ asymbol *func; ++ bfd_vma low_func; ++ asymbol **p; ++ ++ if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, ++ filename_ptr, functionname_ptr, ++ line_ptr, 0, ++ &elf_tdata (abfd)->dwarf2_find_line_info)) ++ return TRUE; ++ ++ if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, ++ &found, filename_ptr, ++ functionname_ptr, line_ptr, ++ &elf_tdata (abfd)->line_info)) ++ return FALSE; ++ ++ if (found) ++ return TRUE; ++ ++ if (symbols == NULL) ++ return FALSE; ++ ++ filename = NULL; ++ func = NULL; ++ low_func = 0; ++ ++ for (p = symbols; *p != NULL; p++) ++ { ++ elf_symbol_type *q; ++ ++ q = (elf_symbol_type *) *p; ++ ++ if (bfd_get_section (&q->symbol) != section) ++ continue; ++ ++ switch (ELF_ST_TYPE (q->internal_elf_sym.st_info)) ++ { ++ default: ++ break; ++ case STT_FILE: ++ filename = bfd_asymbol_name (&q->symbol); ++ break; ++ case STT_NOTYPE: ++ case STT_FUNC: ++ case STT_ARM_TFUNC: ++ if (q->symbol.section == section ++ && q->symbol.value >= low_func ++ && q->symbol.value <= offset) ++ { ++ func = (asymbol *) q; ++ low_func = q->symbol.value; ++ } ++ break; ++ } ++ } ++ ++ if (func == NULL) ++ return FALSE; ++ ++ *filename_ptr = filename; ++ *functionname_ptr = bfd_asymbol_name (func); ++ *line_ptr = 0; ++ ++ return TRUE; ++} ++ ++/* Adjust a symbol defined by a dynamic object and referenced by a ++ regular object. The current definition is in some section of the ++ dynamic object, but we're not including those sections. We have to ++ change the definition to something the rest of the link can ++ understand. */ ++ ++static bfd_boolean ++elf32_arm_adjust_dynamic_symbol (info, h) ++ struct bfd_link_info * info; ++ struct elf_link_hash_entry * h; ++{ ++ bfd * dynobj; ++ asection * s; ++ unsigned int power_of_two; ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ ++ /* 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 we link a program (not a DSO), we'll get rid of unnecessary ++ PLT entries; we point to the actual symbols -- even for pic ++ relocs, because a program built with -fpic should have the same ++ result as one built without -fpic, specifically considering weak ++ symbols. ++ FIXME: m68k and i386 differ here, for unclear reasons. */ ++ if (! info->shared ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0) ++ { ++ /* This case can occur if we saw a PLT32 reloc in an input ++ file, but the symbol was not defined by a dynamic object. ++ In such a case, we don't actually need to build a ++ procedure linkage table, and we can just do a PC32 reloc ++ instead. */ ++ BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0); ++ 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; ++ } ++ ++ 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_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 = s->_raw_size; ++ } ++ ++ h->plt.offset = s->_raw_size; ++ ++ /* Make room for this entry. */ ++ s->_raw_size += PLT_ENTRY_SIZE; ++ ++ /* We also need to make an entry in the .got.plt section, which ++ will be placed in the .got section by the linker script. */ ++ s = bfd_get_section_by_name (dynobj, ".got.plt"); ++ BFD_ASSERT (s != NULL); ++ s->_raw_size += 4; ++ ++ /* We also need to make an entry in the .rel.plt section. */ ++ ++ s = bfd_get_section_by_name (dynobj, ".rel.plt"); ++ BFD_ASSERT (s != NULL); ++ s->_raw_size += sizeof (Elf32_External_Rel); ++ ++ return TRUE; ++ } ++ ++ /* 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. */ ++ s = bfd_get_section_by_name (dynobj, ".dynbss"); ++ BFD_ASSERT (s != NULL); ++ ++ /* We must generate a R_ARM_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 ++ .rel.bss section we are going to use. */ ++ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) ++ { ++ asection *srel; ++ ++ srel = bfd_get_section_by_name (dynobj, ".rel.bss"); ++ BFD_ASSERT (srel != NULL); ++ srel->_raw_size += sizeof (Elf32_External_Rel); ++ 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 > 3) ++ power_of_two = 3; ++ ++ /* 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 bfd_boolean ++elf32_arm_size_dynamic_sections (output_bfd, info) ++ bfd * output_bfd ATTRIBUTE_UNUSED; ++ struct bfd_link_info * info; ++{ ++ bfd * dynobj; ++ asection * s; ++ bfd_boolean plt; ++ bfd_boolean relocs; ++ ++ 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 .rel.got section. ++ However, if we are not creating the dynamic sections, we will ++ not actually use these entries. Reset the size of .rel.got, ++ which will cause it to get stripped from the output file ++ below. */ ++ s = bfd_get_section_by_name (dynobj, ".rel.got"); ++ if (s != NULL) ++ s->_raw_size = 0; ++ } ++ ++ /* If this is a -Bsymbolic shared link, then we need to discard all ++ PC relative relocs against symbols defined in a regular object. ++ We allocated space for them in the check_relocs routine, but we ++ will not fill them in in the relocate_section routine. */ ++ if (info->shared && info->symbolic) ++ elf32_arm_link_hash_traverse (elf32_arm_hash_table (info), ++ elf32_arm_discard_copies, ++ (PTR) NULL); ++ ++ /* 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; ++ bfd_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, ".rel", 4) == 0) ++ { ++ if (s->_raw_size == 0) ++ { ++ /* If we don't need this section, strip it from the ++ output file. This is mostly to handle .rel.bss and ++ .rel.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 reloc sections other ++ than .rel.plt. */ ++ if (strcmp (name, ".rel.plt") != 0) ++ 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 (strncmp (name, ".got", 4) != 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 elf32_arm_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_REL) ++ || !add_dynamic_entry (DT_JMPREL, 0)) ++ return FALSE; ++ } ++ ++ if (relocs) ++ { ++ if ( !add_dynamic_entry (DT_REL, 0) ++ || !add_dynamic_entry (DT_RELSZ, 0) ++ || !add_dynamic_entry (DT_RELENT, sizeof (Elf32_External_Rel))) ++ return FALSE; ++ } ++ ++ if ((info->flags & DF_TEXTREL) != 0) ++ { ++ if (!add_dynamic_entry (DT_TEXTREL, 0)) ++ return FALSE; ++ info->flags |= DF_TEXTREL; ++ } ++ } ++#undef add_synamic_entry ++ ++ return TRUE; ++} ++ ++/* This function is called via elf32_arm_link_hash_traverse if we are ++ creating a shared object with -Bsymbolic. It discards the space ++ allocated to copy PC relative relocs against symbols which are ++ defined in regular objects. We allocated space for them in the ++ check_relocs routine, but we won't fill them in in the ++ relocate_section routine. */ ++ ++static bfd_boolean ++elf32_arm_discard_copies (h, ignore) ++ struct elf32_arm_link_hash_entry * h; ++ PTR ignore ATTRIBUTE_UNUSED; ++{ ++ struct elf32_arm_pcrel_relocs_copied * s; ++ ++ if (h->root.root.type == bfd_link_hash_warning) ++ h = (struct elf32_arm_link_hash_entry *) h->root.root.u.i.link; ++ ++ /* We only discard relocs for symbols defined in a regular object. */ ++ if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) ++ return TRUE; ++ ++ for (s = h->pcrel_relocs_copied; s != NULL; s = s->next) ++ s->section->_raw_size -= s->count * sizeof (Elf32_External_Rel); ++ ++ return TRUE; ++} ++ ++/* Finish up dynamic symbol handling. We set the contents of various ++ dynamic sections here. */ ++ ++static bfd_boolean ++elf32_arm_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; ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ ++ if (h->plt.offset != (bfd_vma) -1) ++ { ++ asection * splt; ++ asection * sgot; ++ asection * srel; ++ bfd_vma plt_index; ++ bfd_vma got_offset; ++ Elf_Internal_Rela rel; ++ bfd_byte *loc; ++ ++ /* 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"); ++ sgot = bfd_get_section_by_name (dynobj, ".got.plt"); ++ srel = bfd_get_section_by_name (dynobj, ".rel.plt"); ++ BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); ++ ++ /* Get the index in the procedure linkage table which ++ corresponds to this symbol. This is the index of this symbol ++ in all the symbols for which we are making plt entries. The ++ first entry in the procedure linkage table is reserved. */ ++ plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; ++ ++ /* Get the offset into the .got table of the entry that ++ corresponds to this function. Each .got entry is 4 bytes. ++ The first three are reserved. */ ++ got_offset = (plt_index + 3) * 4; ++ ++ /* Fill in the entry in the procedure linkage table. */ ++ bfd_put_32 (output_bfd, elf32_arm_plt_entry[0], ++ splt->contents + h->plt.offset + 0); ++ bfd_put_32 (output_bfd, elf32_arm_plt_entry[1], ++ splt->contents + h->plt.offset + 4); ++ bfd_put_32 (output_bfd, elf32_arm_plt_entry[2], ++ splt->contents + h->plt.offset + 8); ++ bfd_put_32 (output_bfd, ++ (sgot->output_section->vma ++ + sgot->output_offset ++ + got_offset ++ - splt->output_section->vma ++ - splt->output_offset ++ - h->plt.offset - 12), ++ splt->contents + h->plt.offset + 12); ++ ++ /* Fill in the entry in the global offset table. */ ++ bfd_put_32 (output_bfd, ++ (splt->output_section->vma ++ + splt->output_offset), ++ sgot->contents + got_offset); ++ ++ /* Fill in the entry in the .rel.plt section. */ ++ rel.r_offset = (sgot->output_section->vma ++ + sgot->output_offset ++ + got_offset); ++ rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_JUMP_SLOT); ++ loc = srel->contents + plt_index * sizeof (Elf32_External_Rel); ++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); ++ ++ 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 * srel; ++ Elf_Internal_Rela rel; ++ bfd_byte *loc; ++ ++ /* This symbol has an entry in the global offset table. Set it ++ up. */ ++ sgot = bfd_get_section_by_name (dynobj, ".got"); ++ srel = bfd_get_section_by_name (dynobj, ".rel.got"); ++ BFD_ASSERT (sgot != NULL && srel != NULL); ++ ++ rel.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 ++ && (info->symbolic || h->dynindx == -1) ++ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) ++ rel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); ++ else ++ { ++ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); ++ rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT); ++ } ++ ++ loc = srel->contents + srel->reloc_count++ * sizeof (Elf32_External_Rel); ++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); ++ } ++ ++ if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) ++ { ++ asection * s; ++ Elf_Internal_Rela rel; ++ bfd_byte *loc; ++ ++ /* This symbol needs a copy reloc. Set it up. */ ++ BFD_ASSERT (h->dynindx != -1 ++ && (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak)); ++ ++ s = bfd_get_section_by_name (h->root.u.def.section->owner, ++ ".rel.bss"); ++ BFD_ASSERT (s != NULL); ++ ++ rel.r_offset = (h->root.u.def.value ++ + h->root.u.def.section->output_section->vma ++ + h->root.u.def.section->output_offset); ++ rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_COPY); ++ loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rel); ++ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); ++ } ++ ++ /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ ++ if (strcmp (h->root.root.string, "_DYNAMIC") == 0 ++ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) ++ sym->st_shndx = SHN_ABS; ++ ++ return TRUE; ++} ++ ++/* Finish up the dynamic sections. */ ++ ++static bfd_boolean ++elf32_arm_finish_dynamic_sections (output_bfd, info) ++ bfd * output_bfd; ++ struct bfd_link_info * info; ++{ ++ bfd * dynobj; ++ asection * sgot; ++ asection * sdyn; ++ ++ dynobj = elf_hash_table (info)->dynobj; ++ ++ sgot = bfd_get_section_by_name (dynobj, ".got.plt"); ++ BFD_ASSERT (sgot != NULL); ++ 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; ++ asection * s; ++ ++ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); ++ ++ switch (dyn.d_tag) ++ { ++ default: ++ break; ++ ++ case DT_PLTGOT: ++ name = ".got"; ++ goto get_vma; ++ case DT_JMPREL: ++ name = ".rel.plt"; ++ get_vma: ++ s = bfd_get_section_by_name (output_bfd, name); ++ BFD_ASSERT (s != NULL); ++ dyn.d_un.d_ptr = s->vma; ++ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); ++ break; ++ ++ case DT_PLTRELSZ: ++ s = bfd_get_section_by_name (output_bfd, ".rel.plt"); ++ BFD_ASSERT (s != NULL); ++ 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); ++ break; ++ ++ case DT_RELSZ: ++ /* My reading of the SVR4 ABI indicates that the ++ procedure linkage table relocs (DT_JMPREL) should be ++ included in the overall relocs (DT_REL). This is ++ what Solaris does. However, UnixWare can not handle ++ that case. Therefore, we override the DT_RELSZ entry ++ here to make it not include the JMPREL relocs. Since ++ the linker script arranges for .rel.plt to follow all ++ other relocation sections, we don't have to worry ++ about changing the DT_REL entry. */ ++ s = bfd_get_section_by_name (output_bfd, ".rel.plt"); ++ if (s != NULL) ++ { ++ 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); ++ break; ++ ++ /* Set the bottom bit of DT_INIT/FINI if the ++ corresponding function is Thumb. */ ++ case DT_INIT: ++ name = info->init_function; ++ goto get_sym; ++ case DT_FINI: ++ name = info->fini_function; ++ get_sym: ++ /* If it wasn't set by elf_bfd_final_link ++ then there is nothing to ajdust. */ ++ if (dyn.d_un.d_val != 0) ++ { ++ struct elf_link_hash_entry * eh; ++ ++ eh = elf_link_hash_lookup (elf_hash_table (info), name, ++ FALSE, FALSE, TRUE); ++ if (eh != (struct elf_link_hash_entry *) NULL ++ && ELF_ST_TYPE (eh->type) == STT_ARM_TFUNC) ++ { ++ dyn.d_un.d_val |= 1; ++ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); ++ } ++ } ++ break; ++ } ++ } ++ ++ /* Fill in the first entry in the procedure linkage table. */ ++ if (splt->_raw_size > 0) ++ { ++ bfd_put_32 (output_bfd, elf32_arm_plt0_entry[0], splt->contents + 0); ++ bfd_put_32 (output_bfd, elf32_arm_plt0_entry[1], splt->contents + 4); ++ bfd_put_32 (output_bfd, elf32_arm_plt0_entry[2], splt->contents + 8); ++ bfd_put_32 (output_bfd, elf32_arm_plt0_entry[3], splt->contents + 12); ++ } ++ ++ /* UnixWare sets the entsize of .plt to 4, although that doesn't ++ really seem like the right value. */ ++ elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; ++ } ++ ++ /* Fill in the first three entries in the global offset table. */ ++ if (sgot->_raw_size > 0) ++ { ++ if (sdyn == NULL) ++ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); ++ else ++ bfd_put_32 (output_bfd, ++ sdyn->output_section->vma + sdyn->output_offset, ++ sgot->contents); ++ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); ++ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); ++ } ++ ++ elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; ++ ++ return TRUE; ++} ++ ++static void ++elf32_arm_post_process_headers (abfd, link_info) ++ bfd * abfd; ++ struct bfd_link_info * link_info ATTRIBUTE_UNUSED; ++{ ++ Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */ ++ ++ i_ehdrp = elf_elfheader (abfd); ++ ++ i_ehdrp->e_ident[EI_OSABI] = ARM_ELF_OS_ABI_VERSION; ++ i_ehdrp->e_ident[EI_ABIVERSION] = ARM_ELF_ABI_VERSION; ++} ++ ++static enum elf_reloc_type_class ++elf32_arm_reloc_type_class (rela) ++ const Elf_Internal_Rela *rela; ++{ ++ switch ((int) ELF32_R_TYPE (rela->r_info)) ++ { ++ case R_ARM_RELATIVE: ++ return reloc_class_relative; ++ case R_ARM_JUMP_SLOT: ++ return reloc_class_plt; ++ case R_ARM_COPY: ++ return reloc_class_copy; ++ default: ++ return reloc_class_normal; ++ } ++} ++ ++static bfd_boolean elf32_arm_section_flags PARAMS ((flagword *, Elf_Internal_Shdr *)); ++static void elf32_arm_final_write_processing PARAMS ((bfd *, bfd_boolean)); ++ ++/* Set the right machine number for an Arm ELF file. */ ++ ++static bfd_boolean ++elf32_arm_section_flags (flags, hdr) ++ flagword *flags; ++ Elf_Internal_Shdr *hdr; ++{ ++ if (hdr->sh_type == SHT_NOTE) ++ *flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_CONTENTS; ++ ++ return TRUE; ++} ++ ++void ++elf32_arm_final_write_processing (abfd, linker) ++ bfd *abfd; ++ bfd_boolean linker ATTRIBUTE_UNUSED; ++{ ++ bfd_arm_update_notes (abfd, ARM_NOTE_SECTION); ++} ++ ++#define ELF_ARCH bfd_arch_arm ++#define ELF_MACHINE_CODE EM_ARM ++#ifdef __QNXTARGET__ ++#define ELF_MAXPAGESIZE 0x1000 ++#else ++#define ELF_MAXPAGESIZE 0x8000 ++#endif ++ ++#define bfd_elf32_bfd_copy_private_bfd_data elf32_arm_copy_private_bfd_data ++#define bfd_elf32_bfd_merge_private_bfd_data elf32_arm_merge_private_bfd_data ++#define bfd_elf32_bfd_set_private_flags elf32_arm_set_private_flags ++#define bfd_elf32_bfd_print_private_bfd_data elf32_arm_print_private_bfd_data ++#define bfd_elf32_bfd_link_hash_table_create elf32_arm_link_hash_table_create ++#define bfd_elf32_bfd_reloc_type_lookup elf32_arm_reloc_type_lookup ++#define bfd_elf32_find_nearest_line elf32_arm_find_nearest_line ++ ++#define elf_backend_get_symbol_type elf32_arm_get_symbol_type ++#define elf_backend_gc_mark_hook elf32_arm_gc_mark_hook ++#define elf_backend_gc_sweep_hook elf32_arm_gc_sweep_hook ++#define elf_backend_check_relocs elf32_arm_check_relocs ++#define elf_backend_relocate_section elf32_arm_relocate_section ++#define elf_backend_adjust_dynamic_symbol elf32_arm_adjust_dynamic_symbol ++#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections ++#define elf_backend_finish_dynamic_symbol elf32_arm_finish_dynamic_symbol ++#define elf_backend_finish_dynamic_sections elf32_arm_finish_dynamic_sections ++#define elf_backend_size_dynamic_sections elf32_arm_size_dynamic_sections ++#define elf_backend_post_process_headers elf32_arm_post_process_headers ++#define elf_backend_reloc_type_class elf32_arm_reloc_type_class ++#define elf_backend_object_p elf32_arm_object_p ++#define elf_backend_section_flags elf32_arm_section_flags ++#define elf_backend_final_write_processing elf32_arm_final_write_processing ++ ++#define elf_backend_can_gc_sections 1 ++#define elf_backend_plt_readonly 1 ++#define elf_backend_want_got_plt 1 ++#define elf_backend_want_plt_sym 0 ++#if !USE_REL ++#define elf_backend_rela_normal 1 ++#endif ++ ++#define elf_backend_got_header_size 12 ++#define elf_backend_plt_header_size PLT_ENTRY_SIZE ++ ++#include "elf32-target.h" ++ +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-avr.c binutils-2.14.90.0.7/bfd/elf32-avr.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-avr.c 2003-11-07 00:11:15.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-avr.c 2003-11-07 00:21:15.000000000 +0100 +@@ -750,7 +750,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections [r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-cris.c binutils-2.14.90.0.7/bfd/elf32-cris.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-cris.c 2003-11-07 00:11:19.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-cris.c 2003-11-07 00:21:15.000000000 +0100 +@@ -847,7 +847,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections [r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + symname = (bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name)); +@@ -1292,16 +1292,7 @@ + { + 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)) ++ if (bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-fr30.c binutils-2.14.90.0.7/bfd/elf32-fr30.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-fr30.c 2003-11-07 00:11:22.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-fr30.c 2003-11-07 00:21:15.000000000 +0100 +@@ -552,7 +552,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections [r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-frv.c binutils-2.14.90.0.7/bfd/elf32-frv.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-frv.c 2003-11-07 00:11:13.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-frv.c 2003-11-07 00:21:15.000000000 +0100 +@@ -724,7 +724,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections [r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-h8300.c binutils-2.14.90.0.7/bfd/elf32-h8300.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-h8300.c 2003-11-07 00:11:18.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-h8300.c 2003-11-07 00:21:15.000000000 +0100 +@@ -435,7 +435,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-hppa.c binutils-2.14.90.0.7/bfd/elf32-hppa.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-hppa.c 2003-11-07 00:11:23.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-hppa.c 2003-11-07 00:21:15.000000000 +0100 +@@ -3408,7 +3408,7 @@ + /* This is a local symbol, h defaults to NULL. */ + sym = local_syms + r_symndx; + sym_sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sym_sec, rel); + } + else + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-i370.c binutils-2.14.90.0.7/bfd/elf32-i370.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-i370.c 2003-11-07 00:11:22.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-i370.c 2003-11-07 00:21:16.000000000 +0100 +@@ -1210,7 +1210,7 @@ + sec = local_sections[r_symndx]; + sym_name = "<local symbol>"; + +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + addend = rel->r_addend; + } + else +@@ -1363,16 +1363,7 @@ + { + 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)) ++ if (bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-i860.c binutils-2.14.90.0.7/bfd/elf32-i860.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-i860.c 2003-11-07 00:11:16.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-i860.c 2003-11-07 00:21:16.000000000 +0100 +@@ -1104,7 +1104,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections [r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-m32r.c binutils-2.14.90.0.7/bfd/elf32-m32r.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-m32r.c 2003-11-07 00:11:22.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-m32r.c 2003-11-07 00:21:16.000000000 +0100 +@@ -1107,7 +1107,7 @@ + sec = local_sections[r_symndx]; + sym_name = "<local symbol>"; + #if !USE_REL +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + addend = rel->r_addend; + #else + /* FIXME: This won't handle local relocations against SEC_MERGE +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-m68k.c binutils-2.14.90.0.7/bfd/elf32-m68k.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-m68k.c 2003-11-07 00:11:22.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-m68k.c 2003-11-07 00:21:16.000000000 +0100 +@@ -1403,7 +1403,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +@@ -1657,16 +1657,7 @@ + { + 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)) ++ if (bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-mcore.c binutils-2.14.90.0.7/bfd/elf32-mcore.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-mcore.c 2003-11-07 00:11:15.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-mcore.c 2003-11-07 00:21:16.000000000 +0100 +@@ -467,7 +467,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections [r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + addend = rel->r_addend; + } + else +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-msp430.c binutils-2.14.90.0.7/bfd/elf32-msp430.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-msp430.c 2003-11-07 00:11:24.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-msp430.c 2003-11-07 00:21:16.000000000 +0100 +@@ -449,7 +449,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-openrisc.c binutils-2.14.90.0.7/bfd/elf32-openrisc.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-openrisc.c 2003-11-07 00:11:23.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-openrisc.c 2003-11-07 00:21:16.000000000 +0100 +@@ -375,7 +375,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-ppc.c binutils-2.14.90.0.7/bfd/elf32-ppc.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-ppc.c 2003-11-07 00:11:21.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-ppc.c 2003-11-07 00:27:00.000000000 +0100 +@@ -1534,7 +1534,7 @@ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + +- /* Phony reloc to handle branch stubs. */ ++ /* Phony relocs to handle branch stubs. */ + HOWTO (R_PPC_RELAX32, /* type */ + 0, /* rightshift */ + 0, /* size */ +@@ -1549,6 +1549,20 @@ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + ++ HOWTO (R_PPC_RELAX32PC, /* type */ ++ 0, /* rightshift */ ++ 0, /* size */ ++ 0, /* bitsize */ ++ FALSE, /* pc_relative */ ++ 0, /* bitpos */ ++ complain_overflow_dont, /* complain_on_overflow */ ++ bfd_elf_generic_reloc, /* special_function */ ++ "R_PPC_RELAX32PC", /* name */ ++ FALSE, /* partial_inplace */ ++ 0, /* src_mask */ ++ 0, /* dst_mask */ ++ FALSE), /* pcrel_offset */ ++ + /* GNU extension to record C++ vtable hierarchy. */ + HOWTO (R_PPC_GNU_VTINHERIT, /* type */ + 0, /* rightshift */ +@@ -1614,90 +1628,26 @@ + } + } + +-static bfd_reloc_status_type +-ppc_elf_install_value (bfd *abfd, +- bfd_byte *hit_addr, +- bfd_vma v, +- unsigned int r_type) +-{ +- bfd_vma t0, t1; +-#ifdef BFD_HOST_U_64_BIT +- BFD_HOST_U_64_BIT val = (BFD_HOST_U_64_BIT) v; +-#else +- bfd_vma val = v; +-#endif +- +- switch (r_type) +- { +- case R_PPC_RELAX32: +- /* Do stuff here. */ +- t0 = bfd_get_32 (abfd, hit_addr); +- t1 = bfd_get_32 (abfd, hit_addr + 4); +- +- /* We're clearing the bits for R_PPC_ADDR16_HA +- and R_PPC_ADDR16_LO here. */ +- t0 &= ~0xffff; +- t1 &= ~0xffff; +- +- /* t0 is HA, t1 is lo */ +- t0 |= ((val + 0x8000) >> 16) & 0xffff; +- t1 |= val & 0xffff; +- +- bfd_put_32 (abfd, t0, hit_addr); +- bfd_put_32 (abfd, t1, hit_addr + 4); +- break; +- +- case R_PPC_REL24: +- t0 = bfd_get_32 (abfd, hit_addr); +- t0 &= ~0x3fffffc; +- t0 |= val & 0x3fffffc; +- bfd_put_32 (abfd, t0, hit_addr); +- break; +- +- case R_PPC_REL14: +- case R_PPC_REL14_BRTAKEN: +- case R_PPC_REL14_BRNTAKEN: +- t0 = bfd_get_32 (abfd, hit_addr); +- t0 &= ~0xfffc; +- t0 |= val & 0xfffc; +- bfd_put_32 (abfd, t0, hit_addr); +- break; +- +- case R_PPC_LOCAL24PC: +- case R_PPC_PLTREL24: +- t0 = bfd_get_32 (abfd, hit_addr); +- t0 &= ~0x3fffffc; +- t0 |= val & 0x3fffffc; +- bfd_put_32 (abfd, t0, hit_addr); +- break; +- +- default: +- return bfd_reloc_notsupported; +- } ++#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) + +- return bfd_reloc_ok; +-} +- +-static const bfd_byte shared_stub_entry[] = ++static const int shared_stub_entry[] = + { +- 0x48, 0x00, 0x00, 0x24, /* b .+36 */ +- 0x7c, 0x08, 0x02, 0xa6, /* mflr 0 */ +- 0x42, 0x9f, 0x00, 0x05, /* bcl 20, 31, .Lxxx */ +- 0x7d, 0x68, 0x02, 0xa6, /* mflr 11 */ +- 0x3d, 0x60, 0x00, 0x00, /* addis 11, 11, (xxx-.Lxxx)@ha */ +- 0x39, 0x6b, 0x00, 0x18, /* addi 11, 11, (xxx-.Lxxx)@l */ +- 0x7c, 0x08, 0x03, 0xa6, /* mtlr 0 */ +- 0x7d, 0x69, 0x03, 0xa6, /* mtctr 11 */ +- 0x4e, 0x80, 0x04, 0x20, /* bctr */ ++ 0x7c0802a6, /* mflr 0 */ ++ 0x429f0005, /* bcl 20, 31, .Lxxx */ ++ 0x7d6802a6, /* mflr 11 */ ++ 0x3d6b0000, /* addis 11, 11, (xxx-.Lxxx)@ha */ ++ 0x396b0018, /* addi 11, 11, (xxx-.Lxxx)@l */ ++ 0x7c0803a6, /* mtlr 0 */ ++ 0x7d6903a6, /* mtctr 11 */ ++ 0x4e800420, /* bctr */ + }; + +-static const bfd_byte stub_entry[] = ++static const int stub_entry[] = + { +- 0x48, 0x00, 0x00, 0x14, /* b .+20 */ +- 0x3d, 0x60, 0x00, 0x00, /* lis 11,xxx@ha */ +- 0x39, 0x6b, 0x00, 0x00, /* addi 11,11,xxx@l */ +- 0x7d, 0x69, 0x03, 0xa6, /* mtctr 11 */ +- 0x4e, 0x80, 0x04, 0x20, /* bctr */ ++ 0x3d600000, /* lis 11,xxx@ha */ ++ 0x396b0000, /* addi 11,11,xxx@l */ ++ 0x7d6903a6, /* mtctr 11 */ ++ 0x4e800420, /* bctr */ + }; + + +@@ -1721,9 +1671,9 @@ + Elf_Internal_Rela *internal_relocs = NULL; + Elf_Internal_Rela *irel, *irelend; + struct one_fixup *fixups = NULL; +- bfd_boolean changed_contents = FALSE; +- bfd_boolean changed_relocs = FALSE; ++ bfd_boolean changed; + struct ppc_elf_link_hash_table *ppc_info; ++ bfd_size_type trampoff; + + *again = FALSE; + +@@ -1738,6 +1688,10 @@ + if (isec->_cooked_size == 0) + isec->_cooked_size = isec->_raw_size; + ++ trampoff = (isec->_cooked_size + 3) & (bfd_vma) -4; ++ /* Space for a branch around any trampolines. */ ++ trampoff += 4; ++ + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + /* Get a copy of the native relocations. */ +@@ -1767,21 +1721,26 @@ + for (irel = internal_relocs; irel < irelend; irel++) + { + unsigned long r_type = ELF32_R_TYPE (irel->r_info); +- bfd_vma symaddr, reladdr, trampoff, toff, roff; ++ bfd_vma symaddr, reladdr, toff, roff; + asection *tsec; +- bfd_size_type amt; + struct one_fixup *f; + size_t insn_offset = 0; +- bfd_vma max_branch_offset; ++ bfd_vma max_branch_offset, val; ++ bfd_byte *hit_addr; ++ unsigned long t0; + + switch (r_type) + { + case R_PPC_REL24: + case R_PPC_LOCAL24PC: ++ case R_PPC_PLTREL24: ++ max_branch_offset = 1 << 25; ++ break; ++ + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: +- case R_PPC_PLTREL24: ++ max_branch_offset = 1 << 15; + break; + + default: +@@ -1819,7 +1778,7 @@ + } + else + { +- /* Need dynamic symbol handling. */ ++ /* Global symbol handling. */ + unsigned long indx; + struct elf_link_hash_entry *h; + +@@ -1830,62 +1789,34 @@ + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + +- if (r_type == R_PPC_PLTREL24) ++ if (r_type == R_PPC_PLTREL24 ++ && ppc_info->plt != NULL ++ && h->plt.offset != (bfd_vma) -1) + { +- Elf_Internal_Sym *isym; +- +- if (h->plt.offset == (bfd_vma) -1 +- || ppc_info->plt == NULL) +- { +- +- /* Read this BFD's local symbols. */ +- if (isymbuf == NULL) +- { +- isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; +- if (isymbuf == NULL) +- isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, +- symtab_hdr->sh_info, 0, +- NULL, NULL, NULL); +- if (isymbuf == 0) +- goto error_return; +- } +- isym = isymbuf + ELF32_R_SYM (irel->r_info); +- +- if (isym->st_shndx == SHN_UNDEF) +- /* We can't do anthing with undefined symbols. */ +- continue; +- else if (isym->st_shndx == SHN_ABS) +- tsec = bfd_abs_section_ptr; +- else if (isym->st_shndx == SHN_COMMON) +- tsec = bfd_com_section_ptr; +- else +- tsec = h->root.u.def.section; +- +- toff = h->root.u.def.value; +- } +- else +- { +- tsec = ppc_info->plt; +- toff = h->plt.offset; +- } ++ tsec = ppc_info->plt; ++ toff = h->plt.offset; + } +- else if (h->root.type == bfd_link_hash_undefined +- || h->root.type == bfd_link_hash_undefweak) +- continue; +- +- else ++ else if (h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) + { + tsec = h->root.u.def.section; + toff = h->root.u.def.value; + } ++ else ++ continue; + } + ++ /* If the branch and target are in the same section, you have ++ no hope of adding stubs. We'll error out later should the ++ branch overflow. */ ++ if (tsec == isec) ++ continue; ++ ++ toff += irel->r_addend; + if (tsec->sec_info_type == ELF_INFO_TYPE_MERGE) + toff = _bfd_merged_section_offset (abfd, &tsec, + elf_section_data (tsec)->sec_info, +- toff + irel->r_addend, 0); +- else +- toff += irel->r_addend; ++ toff, 0); + + symaddr = tsec->output_section->vma + tsec->output_offset + toff; + +@@ -1893,22 +1824,10 @@ + + reladdr = (isec->output_section->vma + + isec->output_offset +- + roff) & (bfd_vma) -4; ++ + roff); + + /* If the branch is in range, no need to do anything. */ +- max_branch_offset = 1 << 25; +- if (r_type != R_PPC_REL24 +- && r_type != R_PPC_LOCAL24PC +- && r_type != R_PPC_PLTREL24) +- max_branch_offset = 1 << 15; +- +- if ((bfd_vma) (symaddr - reladdr) + max_branch_offset +- <= 2 * max_branch_offset) +- continue; +- +- /* If the branch and target are in the same section, you have +- no hope. We'll error out later. */ +- if (tsec == isec) ++ if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset) + continue; + + /* Look for an existing fixup to this address. */ +@@ -1919,40 +1838,31 @@ + if (f == NULL) + { + size_t size; ++ unsigned long stub_rtype; + +- if (link_info->shared +- || tsec == ppc_info->plt +- || r_type == R_PPC_LOCAL24PC) ++ val = trampoff - roff; ++ if (val >= max_branch_offset) ++ /* Oh dear, we can't reach a trampoline. Don't try to add ++ one. We'll report an error later. */ ++ continue; ++ ++ if (link_info->shared) + { +- size = sizeof (shared_stub_entry); +- insn_offset = 16; ++ size = 4 * ARRAY_SIZE (shared_stub_entry); ++ insn_offset = 12; ++ stub_rtype = R_PPC_RELAX32PC; + } + else + { +- size = sizeof (stub_entry); +- insn_offset = 4; ++ size = 4 * ARRAY_SIZE (stub_entry); ++ insn_offset = 0; ++ stub_rtype = R_PPC_RELAX32; + } + +- /* Resize the current section to make room for the new branch. */ +- trampoff = (isec->_cooked_size + 3) & (bfd_vma) - 4; +- amt = trampoff + size; +- contents = bfd_realloc (contents, amt); +- if (contents == NULL) +- abort (); +- +- isec->_cooked_size = amt; +- +- if (link_info->shared +- || tsec == ppc_info->plt +- || r_type == R_PPC_LOCAL24PC) +- memcpy (contents + trampoff, shared_stub_entry, size); +- else +- memcpy (contents + trampoff, stub_entry, size); +- + /* Hijack the old relocation. Since we need two + relocations for this use a "composite" reloc. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), +- R_PPC_RELAX32); ++ stub_rtype); + irel->r_offset = trampoff + insn_offset; + + /* Record the fixup so we don't do it again this section. */ +@@ -1962,31 +1872,95 @@ + f->toff = toff; + f->trampoff = trampoff; + fixups = f; ++ ++ trampoff += size; + } + else + { ++ val = f->trampoff - roff; ++ if (val >= max_branch_offset) ++ continue; ++ + /* Nop out the reloc, since we're finalizing things here. */ + irel->r_info = ELF32_R_INFO (0, R_PPC_NONE); + } + +- /* Fix up the existing branch to hit the trampoline. Hope like +- hell this doesn't overflow too. */ +- if (ppc_elf_install_value (abfd, contents + roff, +- f->trampoff - (roff & (bfd_vma) -3) + 4, +- r_type) != bfd_reloc_ok) +- abort (); ++ /* Fix up the existing branch to hit the trampoline. */ ++ hit_addr = contents + roff; ++ switch (r_type) ++ { ++ case R_PPC_REL24: ++ case R_PPC_LOCAL24PC: ++ case R_PPC_PLTREL24: ++ t0 = bfd_get_32 (abfd, hit_addr); ++ t0 &= ~0x3fffffc; ++ t0 |= val & 0x3fffffc; ++ bfd_put_32 (abfd, t0, hit_addr); ++ break; + +- changed_contents = TRUE; +- changed_relocs = TRUE; ++ case R_PPC_REL14: ++ case R_PPC_REL14_BRTAKEN: ++ case R_PPC_REL14_BRNTAKEN: ++ t0 = bfd_get_32 (abfd, hit_addr); ++ t0 &= ~0xfffc; ++ t0 |= val & 0xfffc; ++ bfd_put_32 (abfd, t0, hit_addr); ++ break; ++ } + } + +- /* Clean up. */ +- while (fixups) ++ /* Write out the trampolines. */ ++ changed = fixups != NULL; ++ if (fixups != NULL) + { +- struct one_fixup *f = fixups; +- fixups = fixups->next; +- free (f); ++ const int *stub; ++ bfd_byte *dest; ++ bfd_vma val; ++ int i, size; ++ ++ do ++ { ++ struct one_fixup *f = fixups; ++ fixups = fixups->next; ++ free (f); ++ } ++ while (fixups); ++ ++ contents = bfd_realloc (contents, trampoff); ++ if (contents == NULL) ++ goto error_return; ++ ++ isec->_cooked_size = (isec->_cooked_size + 3) & (bfd_vma) -4; ++ /* Branch around the trampolines. */ ++ val = trampoff - isec->_cooked_size + 0x48000000; ++ dest = contents + isec->_cooked_size; ++ isec->_cooked_size = trampoff; ++ bfd_put_32 (abfd, val, dest); ++ dest += 4; ++ ++ if (link_info->shared) ++ { ++ stub = shared_stub_entry; ++ size = ARRAY_SIZE (shared_stub_entry); ++ } ++ else ++ { ++ stub = stub_entry; ++ size = ARRAY_SIZE (stub_entry); ++ } ++ ++ i = 0; ++ while (dest < contents + trampoff) ++ { ++ bfd_put_32 (abfd, stub[i], dest); ++ i++; ++ if (i == size) ++ i = 0; ++ dest += 4; ++ } ++ BFD_ASSERT (i == 0); + } ++ + if (isymbuf != NULL + && symtab_hdr->contents != (unsigned char *) isymbuf) + { +@@ -2002,7 +1976,7 @@ + if (contents != NULL + && elf_section_data (isec)->this_hdr.contents != contents) + { +- if (!changed_contents && !link_info->keep_memory) ++ if (!changed && !link_info->keep_memory) + free (contents); + else + { +@@ -2013,13 +1987,13 @@ + + if (elf_section_data (isec)->relocs != internal_relocs) + { +- if (!changed_relocs) ++ if (!changed) + free (internal_relocs); + else + elf_section_data (isec)->relocs = internal_relocs; + } + +- *again = changed_contents || changed_relocs; ++ *again = changed; + return TRUE; + + error_return: +@@ -4727,7 +4701,7 @@ + sec = local_sections[r_symndx]; + sym_name = bfd_elf_local_sym_name (input_bfd, sym); + +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +@@ -5454,45 +5428,33 @@ + } + break; + ++ case R_PPC_RELAX32PC: ++ relocation -= (input_section->output_section->vma ++ + input_section->output_offset ++ + rel->r_offset - 4); ++ /* Fall thru */ + case R_PPC_RELAX32: + { +- unsigned long r_symndx; +- Elf_Internal_Sym *sym; +- asection *sym_sec; +- bfd_byte *hit_addr = 0; +- bfd_vma value = 0; ++ unsigned long t0; ++ unsigned long t1; + +- r_symndx = ELF32_R_SYM (rel->r_info); +- +- if (r_symndx < symtab_hdr->sh_info) +- { +- sym = local_syms + r_symndx; +- sym_sec = local_sections[r_symndx]; +- +- value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel); +- } +- else +- { +- bfd_boolean warned; +- bfd_boolean unresolved_reloc; ++ t0 = bfd_get_32 (output_bfd, contents + rel->r_offset); ++ t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4); + +- RELOC_FOR_GLOBAL_SYMBOL (h, elf_sym_hashes (input_bfd), +- r_symndx, symtab_hdr, +- value, sym_sec, +- unresolved_reloc, info, +- warned); +- if (warned) +- continue; +- } +- hit_addr = contents + rel->r_offset; +- value += rel->r_addend; ++ /* We're clearing the bits for R_PPC_ADDR16_HA ++ and R_PPC_ADDR16_LO here. */ ++ t0 &= ~0xffff; ++ t1 &= ~0xffff; ++ ++ /* t0 is HA, t1 is LO */ ++ relocation += addend; ++ t0 |= ((relocation + 0x8000) >> 16) & 0xffff; ++ t1 |= relocation & 0xffff; + +- r = ppc_elf_install_value (output_bfd, hit_addr, value, r_type); +- if (r != bfd_reloc_ok) +- break; +- else +- continue; ++ bfd_put_32 (output_bfd, t0, contents + rel->r_offset); ++ bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4); + } ++ continue; + + /* Indirect .sdata relocation. */ + case R_PPC_EMB_SDAI16: +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-s390.c binutils-2.14.90.0.7/bfd/elf32-s390.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-s390.c 2003-11-07 00:11:15.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-s390.c 2003-11-07 00:21:16.000000000 +0100 +@@ -2325,7 +2325,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-sh.c binutils-2.14.90.0.7/bfd/elf32-sh.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-sh.c 2003-11-07 00:11:14.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-sh.c 2003-11-07 00:21:16.000000000 +0100 +@@ -4805,7 +4805,7 @@ + } + else if (! howto->partial_inplace) + { +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + addend = rel->r_addend; + } + else if ((sec->flags & SEC_MERGE) +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-sparc.c binutils-2.14.90.0.7/bfd/elf32-sparc.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-sparc.c 2003-11-07 00:11:25.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-sparc.c 2003-11-07 00:21:16.000000000 +0100 +@@ -2460,16 +2460,8 @@ + + if (is_plt) + sec = htab->splt; +- else 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)) ++ ++ if (bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-v850.c binutils-2.14.90.0.7/bfd/elf32-v850.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-v850.c 2003-11-07 00:11:24.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-v850.c 2003-11-07 00:21:16.000000000 +0100 +@@ -1681,7 +1681,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + #if 0 + { + char * name; +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-vax.c binutils-2.14.90.0.7/bfd/elf32-vax.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-vax.c 2003-11-07 00:11:13.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-vax.c 2003-11-07 00:21:16.000000000 +0100 +@@ -1483,7 +1483,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +@@ -1737,16 +1737,7 @@ + { + 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)) ++ if (bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-xstormy16.c binutils-2.14.90.0.7/bfd/elf32-xstormy16.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-xstormy16.c 2003-11-07 00:11:15.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-xstormy16.c 2003-11-07 00:21:16.000000000 +0100 +@@ -845,7 +845,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections [r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf32-xtensa.c binutils-2.14.90.0.7/bfd/elf32-xtensa.c +--- binutils-2.14.90.0.7.orig/bfd/elf32-xtensa.c 2003-11-07 00:11:17.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf32-xtensa.c 2003-11-07 00:21:16.000000000 +0100 +@@ -2004,7 +2004,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf64-alpha.c binutils-2.14.90.0.7/bfd/elf64-alpha.c +--- binutils-2.14.90.0.7.orig/bfd/elf64-alpha.c 2003-11-07 00:11:16.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf64-alpha.c 2003-11-07 00:21:16.000000000 +0100 +@@ -4394,9 +4394,11 @@ + + if (r_symndx < symtab_hdr->sh_info) + { ++ asection *msec; + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- value = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ msec = sec; ++ value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel); + + /* If this is a tp-relative relocation against sym 0, + this is hackery from relax_section. Force the value to +@@ -4424,7 +4426,6 @@ + && !gotent->reloc_xlated) + { + struct alpha_elf_got_entry *ent; +- asection *msec; + + for (ent = gotent; ent; ent = ent->next) + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf64-mmix.c binutils-2.14.90.0.7/bfd/elf64-mmix.c +--- binutils-2.14.90.0.7.orig/bfd/elf64-mmix.c 2003-11-07 00:11:14.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf64-mmix.c 2003-11-07 00:21:16.000000000 +0100 +@@ -1472,7 +1472,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections [r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf64-ppc.c binutils-2.14.90.0.7/bfd/elf64-ppc.c +--- binutils-2.14.90.0.7.orig/bfd/elf64-ppc.c 2003-11-07 00:11:18.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf64-ppc.c 2003-11-07 00:21:17.000000000 +0100 +@@ -7385,7 +7385,7 @@ + sec = local_sections[r_symndx]; + sym_name = bfd_elf_local_sym_name (input_bfd, sym); + sym_type = ELF64_ST_TYPE (sym->st_info); +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + if (elf_section_data (sec) != NULL) + { + long *opd_sym_adjust; +@@ -8178,7 +8178,9 @@ + relocation = TOCstart; + if (r_symndx == 0) + relocation += htab->stub_group[input_section->id].toc_off; +- else if (sec != NULL && !unresolved_reloc) ++ else if (unresolved_reloc) ++ ; ++ else if (sec != NULL && sec->id <= htab->top_id) + relocation += htab->stub_group[sec->id].toc_off; + else + unresolved_reloc = TRUE; +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf64-s390.c binutils-2.14.90.0.7/bfd/elf64-s390.c +--- binutils-2.14.90.0.7.orig/bfd/elf64-s390.c 2003-11-07 00:11:16.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf64-s390.c 2003-11-07 00:21:17.000000000 +0100 +@@ -2295,7 +2295,7 @@ + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf64-sh64.c binutils-2.14.90.0.7/bfd/elf64-sh64.c +--- binutils-2.14.90.0.7.orig/bfd/elf64-sh64.c 2003-11-07 00:11:21.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf64-sh64.c 2003-11-07 00:21:17.000000000 +0100 +@@ -1582,7 +1582,7 @@ + } + else if (! howto->partial_inplace) + { +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + relocation |= ((sym->st_other & STO_SH5_ISA32) != 0); + } + else if ((sec->flags & SEC_MERGE) +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf64-sparc.c binutils-2.14.90.0.7/bfd/elf64-sparc.c +--- binutils-2.14.90.0.7.orig/bfd/elf64-sparc.c 2003-11-07 00:11:24.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf64-sparc.c 2003-11-07 00:26:02.000000000 +0100 +@@ -2071,7 +2071,7 @@ + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + orig_addend = rel->r_addend; +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +@@ -2248,16 +2248,8 @@ + + if (is_plt) + sec = splt; +- else 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)) ++ ++ if (bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elf64-x86-64.c binutils-2.14.90.0.7/bfd/elf64-x86-64.c +--- binutils-2.14.90.0.7.orig/bfd/elf64-x86-64.c 2003-11-07 00:11:23.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elf64-x86-64.c 2003-11-07 00:21:17.000000000 +0100 +@@ -1823,7 +1823,7 @@ + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + +- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); ++ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + } + else + { +@@ -2048,16 +2048,7 @@ + { + long sindx; + +- 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)) ++ if (bfd_is_abs_section (sec)) + sindx = 0; + else if (sec == NULL || sec->owner == NULL) + { +diff -ruN binutils-2.14.90.0.7.orig/bfd/elfxx-ia64.c binutils-2.14.90.0.7/bfd/elfxx-ia64.c +--- binutils-2.14.90.0.7.orig/bfd/elfxx-ia64.c 2003-11-07 00:11:25.000000000 +0100 ++++ binutils-2.14.90.0.7/bfd/elfxx-ia64.c 2003-11-07 00:21:17.000000000 +0100 +@@ -3848,9 +3848,11 @@ + if (r_symndx < symtab_hdr->sh_info) + { + /* Reloc against local symbol. */ ++ asection *msec; + sym = local_syms + r_symndx; + sym_sec = local_sections[r_symndx]; +- value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel); ++ msec = sym_sec; ++ value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel); + if ((sym_sec->flags & SEC_MERGE) + && ELF_ST_TYPE (sym->st_info) == STT_SECTION + && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE) +@@ -3861,7 +3863,6 @@ + if (loc_h && ! loc_h->sec_merge_done) + { + struct elfNN_ia64_dyn_sym_info *dynent; +- asection *msec; + + for (dynent = loc_h->info; dynent; dynent = dynent->next) + { +diff -ruN binutils-2.14.90.0.7.orig/include/elf/ppc.h binutils-2.14.90.0.7/include/elf/ppc.h +--- binutils-2.14.90.0.7.orig/include/elf/ppc.h 2003-11-07 00:10:33.000000000 +0100 ++++ binutils-2.14.90.0.7/include/elf/ppc.h 2003-11-07 00:26:52.000000000 +0100 +@@ -120,9 +120,10 @@ + RELOC_NUMBER (R_PPC_EMB_BIT_FLD, 115) + RELOC_NUMBER (R_PPC_EMB_RELSDA, 116) + +-/* Fake relocation for branch stubs. This will keep them ++/* Fake relocations for branch stubs. This will keep them + together. */ + #define R_PPC_RELAX32 251 ++#define R_PPC_RELAX32PC 252 + + /* These are GNU extensions to enable C++ vtable garbage collection. */ + RELOC_NUMBER (R_PPC_GNU_VTINHERIT, 253) diff --git a/sys-devel/binutils/files/digest-binutils-2.14.90.0.7-r1 b/sys-devel/binutils/files/digest-binutils-2.14.90.0.7-r1 new file mode 100644 index 000000000000..07f652ab2119 --- /dev/null +++ b/sys-devel/binutils/files/digest-binutils-2.14.90.0.7-r1 @@ -0,0 +1 @@ +MD5 b5b1608f7308c487c0f3af8e4592a71a binutils-2.14.90.0.7.tar.bz2 10575077 |