summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Barbato <lu_zero@gentoo.org>2003-11-07 01:22:24 +0000
committerLuca Barbato <lu_zero@gentoo.org>2003-11-07 01:22:24 +0000
commit652ff9e206c4c71cc78af68d306742f271099de3 (patch)
tree88eb06a70325661fd463aca9f3a521c44fc8b9ad /sys-devel
parent~ppc, fix #32755 (diff)
downloadgentoo-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/ChangeLog11
-rw-r--r--sys-devel/binutils/Manifest4
-rw-r--r--sys-devel/binutils/binutils-2.14.90.0.7-r1.ebuild199
-rw-r--r--sys-devel/binutils/files/2.14/binutils-2.14.90.0.7-ppc-reloc.patch6673
-rw-r--r--sys-devel/binutils/files/digest-binutils-2.14.90.0.7-r11
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