Index: GNU/Makefile
===================================================================
--- GNU/Makefile (nonexistent)
+++ GNU/Makefile (revision 33)
@@ -0,0 +1,14 @@
+
+COMPONENT_TARGETS = $(TOOLCHAIN_NOARCH)
+
+SOURCE_REQUIRES += ALL_DIRS
+
+# ======= __END_OF_REQUIRES__ =======
+
+include ../../build-system/core.mk
+
+
+download_clean:
+ @true
+
+.PHONY: download_clean
Index: GNU/binutils/Makefile
===================================================================
--- GNU/binutils/Makefile (nonexistent)
+++ GNU/binutils/Makefile (revision 33)
@@ -0,0 +1,93 @@
+#
+# Download: http://www.gnu.org/prep/ftp.html
+#
+# You can use the generic url http://ftpmirror.gnu.org
+# to automatically choose a nearby and up-to-date mirror.
+#
+# original url: http://ftp.gnu.org/gnu/binutils
+#
+
+COMPONENT_TARGETS = $(TOOLCHAIN_NOARCH)
+
+
+include ../../../build-system/config.mk
+
+
+url = $(DOWNLOAD_SERVER)/sources/GNU/binutils
+
+versions = 2.40
+
+tarballs = $(addsuffix .tar.xz, $(addprefix binutils-, $(versions)))
+sha1s = $(addsuffix .sha1sum, $(tarballs))
+
+patches = $(CURDIR)/patches/binutils-2.40-aarch64-ifunc.patch
+patches += $(CURDIR)/patches/binutils-2.40-not-link-static-libstdc++.patch
+patches += $(CURDIR)/patches/binutils-2.40-fname-in-error-messages.patch
+patches += $(CURDIR)/patches/binutils-2.40-gold-i386-gnu-property-notes.patch
+patches += $(CURDIR)/patches/binutils-2.40-gold-mismatched-section-flags.patch
+patches += $(CURDIR)/patches/binutils-2.40-gold-warn-unsupported.patch
+patches += $(CURDIR)/patches/binutils-2.40-readelf-other-sym-info.patch
+patches += $(CURDIR)/patches/binutils-2.40-special-sections-in-groups.patch
+patches += $(CURDIR)/patches/binutils-2.40-testsuite-failures.patch
+
+patches += $(CURDIR)/patches/binutils-2.40-cleansweep.patch
+patches += $(CURDIR)/patches/binutils-2.40-copy-osabi.patch
+patches += $(CURDIR)/patches/binutils-2.40-export-demangle.patch
+patches += $(CURDIR)/patches/binutils-2.40-ldforcele.patch
+patches += $(CURDIR)/patches/binutils-2.40-libtool-lib64.patch
+patches += $(CURDIR)/patches/binutils-2.40-no-config-check.patch
+patches += $(CURDIR)/patches/binutils-2.40-sec-merge-emit.patch
+
+.NOTPARALLEL: $(patches)
+
+
+BUILD_TARGETS = $(tarballs) $(sha1s) $(patches)
+
+
+include ../../../build-system/core.mk
+
+
+.PHONY: download_clean
+
+
+$(tarballs):
+ @echo -e "\n======= Downloading source tarballs =======" ; \
+ for tarball in $(tarballs) ; do \
+ echo "$(url)/$$tarball" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & \
+ done ; wait
+
+$(sha1s): $(tarballs)
+ @for sha in $@ ; do \
+ echo -e "\n======= Downloading '$$sha' signature =======\n" ; \
+ echo "$(url)/$$sha" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & wait %1 ; \
+ touch $$sha ; \
+ echo -e "\n======= Check the '$$sha' sha1sum =======\n" ; \
+ sha1sum --check $$sha ; ret="$$?" ; \
+ if [ "$$ret" == "1" ]; then \
+ echo -e "\n======= ERROR: Bad '$$sha' sha1sum =======\n" ; \
+ exit 1 ; \
+ fi ; \
+ done
+
+$(patches): $(sha1s)
+ @echo -e "\n======= Create Patches =======\n" ; \
+ ( cd create-2.40-aarch64-ifunc-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-not-link-static-libstdc++-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-fname-in-error-messages-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-gold-i386-gnu-property-notes-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-gold-mismatched-section-flags-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-gold-warn-unsupported-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-readelf-other-sym-info-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-special-sections-in-groups-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-testsuite-failures-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-cleansweep-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-copy-osabi-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-export-demangle-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-ldforcele-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-libtool-lib64-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-no-config-check-patch ; ./create.patch.sh ) ; \
+ ( cd create-2.40-sec-merge-emit-patch ; ./create.patch.sh ) ; \
+ echo -e "\n"
+
+download_clean:
+ @rm -f $(tarballs) $(sha1s) $(patches)
Index: GNU/binutils/create-2.40-aarch64-ifunc-patch/binutils-2.40-new/bfd/elfnn-aarch64.c
===================================================================
--- GNU/binutils/create-2.40-aarch64-ifunc-patch/binutils-2.40-new/bfd/elfnn-aarch64.c (nonexistent)
+++ GNU/binutils/create-2.40-aarch64-ifunc-patch/binutils-2.40-new/bfd/elfnn-aarch64.c (revision 33)
@@ -0,0 +1,10242 @@
+/* AArch64-specific support for NN-bit ELF.
+ Copyright (C) 2009-2023 Free Software Foundation, Inc.
+ Contributed by ARM Ltd.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING3. If not,
+ see <http://www.gnu.org/licenses/>. */
+
+/* Notes on implementation:
+
+ Thread Local Store (TLS)
+
+ Overview:
+
+ The implementation currently supports both traditional TLS and TLS
+ descriptors, but only general dynamic (GD).
+
+ For traditional TLS the assembler will present us with code
+ fragments of the form:
+
+ adrp x0, :tlsgd:foo
+ R_AARCH64_TLSGD_ADR_PAGE21(foo)
+ add x0, :tlsgd_lo12:foo
+ R_AARCH64_TLSGD_ADD_LO12_NC(foo)
+ bl __tls_get_addr
+ nop
+
+ For TLS descriptors the assembler will present us with code
+ fragments of the form:
+
+ adrp x0, :tlsdesc:foo R_AARCH64_TLSDESC_ADR_PAGE21(foo)
+ ldr x1, [x0, #:tlsdesc_lo12:foo] R_AARCH64_TLSDESC_LD64_LO12(foo)
+ add x0, x0, #:tlsdesc_lo12:foo R_AARCH64_TLSDESC_ADD_LO12(foo)
+ .tlsdesccall foo
+ blr x1 R_AARCH64_TLSDESC_CALL(foo)
+
+ The relocations R_AARCH64_TLSGD_{ADR_PREL21,ADD_LO12_NC} against foo
+ indicate that foo is thread local and should be accessed via the
+ traditional TLS mechanims.
+
+ The relocations R_AARCH64_TLSDESC_{ADR_PAGE21,LD64_LO12_NC,ADD_LO12_NC}
+ against foo indicate that 'foo' is thread local and should be accessed
+ via a TLS descriptor mechanism.
+
+ The precise instruction sequence is only relevant from the
+ perspective of linker relaxation which is currently not implemented.
+
+ The static linker must detect that 'foo' is a TLS object and
+ allocate a double GOT entry. The GOT entry must be created for both
+ global and local TLS symbols. Note that this is different to none
+ TLS local objects which do not need a GOT entry.
+
+ In the traditional TLS mechanism, the double GOT entry is used to
+ provide the tls_index structure, containing module and offset
+ entries. The static linker places the relocation R_AARCH64_TLS_DTPMOD
+ on the module entry. The loader will subsequently fixup this
+ relocation with the module identity.
+
+ For global traditional TLS symbols the static linker places an
+ R_AARCH64_TLS_DTPREL relocation on the offset entry. The loader
+ will subsequently fixup the offset. For local TLS symbols the static
+ linker fixes up offset.
+
+ In the TLS descriptor mechanism the double GOT entry is used to
+ provide the descriptor. The static linker places the relocation
+ R_AARCH64_TLSDESC on the first GOT slot. The loader will
+ subsequently fix this up.
+
+ Implementation:
+
+ The handling of TLS symbols is implemented across a number of
+ different backend functions. The following is a top level view of
+ what processing is performed where.
+
+ The TLS implementation maintains state information for each TLS
+ symbol. The state information for local and global symbols is kept
+ in different places. Global symbols use generic BFD structures while
+ local symbols use backend specific structures that are allocated and
+ maintained entirely by the backend.
+
+ The flow:
+
+ elfNN_aarch64_check_relocs()
+
+ This function is invoked for each relocation.
+
+ The TLS relocations R_AARCH64_TLSGD_{ADR_PREL21,ADD_LO12_NC} and
+ R_AARCH64_TLSDESC_{ADR_PAGE21,LD64_LO12_NC,ADD_LO12_NC} are
+ spotted. One time creation of local symbol data structures are
+ created when the first local symbol is seen.
+
+ The reference count for a symbol is incremented. The GOT type for
+ each symbol is marked as general dynamic.
+
+ elfNN_aarch64_allocate_dynrelocs ()
+
+ For each global with positive reference count we allocate a double
+ GOT slot. For a traditional TLS symbol we allocate space for two
+ relocation entries on the GOT, for a TLS descriptor symbol we
+ allocate space for one relocation on the slot. Record the GOT offset
+ for this symbol.
+
+ elfNN_aarch64_size_dynamic_sections ()
+
+ Iterate all input BFDS, look for in the local symbol data structure
+ constructed earlier for local TLS symbols and allocate them double
+ GOT slots along with space for a single GOT relocation. Update the
+ local symbol structure to record the GOT offset allocated.
+
+ elfNN_aarch64_relocate_section ()
+
+ Calls elfNN_aarch64_final_link_relocate ()
+
+ Emit the relevant TLS relocations against the GOT for each TLS
+ symbol. For local TLS symbols emit the GOT offset directly. The GOT
+ relocations are emitted once the first time a TLS symbol is
+ encountered. The implementation uses the LSB of the GOT offset to
+ flag that the relevant GOT relocations for a symbol have been
+ emitted. All of the TLS code that uses the GOT offset needs to take
+ care to mask out this flag bit before using the offset.
+
+ elfNN_aarch64_final_link_relocate ()
+
+ Fixup the R_AARCH64_TLSGD_{ADR_PREL21, ADD_LO12_NC} relocations. */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libiberty.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "bfdlink.h"
+#include "objalloc.h"
+#include "elf/aarch64.h"
+#include "elfxx-aarch64.h"
+#include "cpu-aarch64.h"
+
+#define ARCH_SIZE NN
+
+#if ARCH_SIZE == 64
+#define AARCH64_R(NAME) R_AARCH64_ ## NAME
+#define AARCH64_R_STR(NAME) "R_AARCH64_" #NAME
+#define HOWTO64(...) HOWTO (__VA_ARGS__)
+#define HOWTO32(...) EMPTY_HOWTO (0)
+#define LOG_FILE_ALIGN 3
+#define BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC BFD_RELOC_AARCH64_TLSDESC_LD64_LO12
+#endif
+
+#if ARCH_SIZE == 32
+#define AARCH64_R(NAME) R_AARCH64_P32_ ## NAME
+#define AARCH64_R_STR(NAME) "R_AARCH64_P32_" #NAME
+#define HOWTO64(...) EMPTY_HOWTO (0)
+#define HOWTO32(...) HOWTO (__VA_ARGS__)
+#define LOG_FILE_ALIGN 2
+#define BFD_RELOC_AARCH64_TLSDESC_LD32_LO12 BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC
+#define R_AARCH64_P32_TLSDESC_ADD_LO12 R_AARCH64_P32_TLSDESC_ADD_LO12_NC
+#endif
+
+#define IS_AARCH64_TLS_RELOC(R_TYPE) \
+ ((R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PREL21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_MOVW_G1 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PREL21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLS_DTPMOD \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLS_DTPREL \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLS_TPREL \
+ || IS_AARCH64_TLSDESC_RELOC ((R_TYPE)))
+
+#define IS_AARCH64_TLS_RELAX_RELOC(R_TYPE) \
+ ((R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_CALL \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD_PREL19 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDNN_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDR \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G1 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDR \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PREL21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_MOVW_G1 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LDNN_GOTTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PREL21)
+
+#define IS_AARCH64_TLSDESC_RELOC(R_TYPE) \
+ ((R_TYPE) == BFD_RELOC_AARCH64_TLSDESC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_CALL \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD64_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDR \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD_PREL19 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G1)
+
+#define ELIMINATE_COPY_RELOCS 1
+
+/* Return size of a relocation entry. HTAB is the bfd's
+ elf_aarch64_link_hash_entry. */
+#define RELOC_SIZE(HTAB) (sizeof (ElfNN_External_Rela))
+
+/* GOT Entry size - 8 bytes in ELF64 and 4 bytes in ELF32. */
+#define GOT_ENTRY_SIZE (ARCH_SIZE / 8)
+#define PLT_ENTRY_SIZE (32)
+#define PLT_SMALL_ENTRY_SIZE (16)
+#define PLT_TLSDESC_ENTRY_SIZE (32)
+/* PLT sizes with BTI insn. */
+#define PLT_BTI_SMALL_ENTRY_SIZE (24)
+/* PLT sizes with PAC insn. */
+#define PLT_PAC_SMALL_ENTRY_SIZE (24)
+/* PLT sizes with BTI and PAC insn. */
+#define PLT_BTI_PAC_SMALL_ENTRY_SIZE (24)
+
+/* Encoding of the nop instruction. */
+#define INSN_NOP 0xd503201f
+
+#define aarch64_compute_jump_table_size(htab) \
+ (((htab)->root.srelplt == NULL) ? 0 \
+ : (htab)->root.srelplt->reloc_count * GOT_ENTRY_SIZE)
+
+/* The first entry in a procedure linkage table looks like this
+ if the distance between the PLTGOT and the PLT is < 4GB use
+ these PLT entries. Note that the dynamic linker gets &PLTGOT[2]
+ in x16 and needs to work out PLTGOT[1] by using an address of
+ [x16,#-GOT_ENTRY_SIZE]. */
+static const bfd_byte elfNN_aarch64_small_plt0_entry[PLT_ENTRY_SIZE] =
+{
+ 0xf0, 0x7b, 0xbf, 0xa9, /* stp x16, x30, [sp, #-16]! */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, (GOT+16) */
+#if ARCH_SIZE == 64
+ 0x11, 0x0A, 0x40, 0xf9, /* ldr x17, [x16, #PLT_GOT+0x10] */
+ 0x10, 0x42, 0x00, 0x91, /* add x16, x16,#PLT_GOT+0x10 */
+#else
+ 0x11, 0x0A, 0x40, 0xb9, /* ldr w17, [x16, #PLT_GOT+0x8] */
+ 0x10, 0x22, 0x00, 0x11, /* add w16, w16,#PLT_GOT+0x8 */
+#endif
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
+static const bfd_byte elfNN_aarch64_small_plt0_bti_entry[PLT_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0xf0, 0x7b, 0xbf, 0xa9, /* stp x16, x30, [sp, #-16]! */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, (GOT+16) */
+#if ARCH_SIZE == 64
+ 0x11, 0x0A, 0x40, 0xf9, /* ldr x17, [x16, #PLT_GOT+0x10] */
+ 0x10, 0x42, 0x00, 0x91, /* add x16, x16,#PLT_GOT+0x10 */
+#else
+ 0x11, 0x0A, 0x40, 0xb9, /* ldr w17, [x16, #PLT_GOT+0x8] */
+ 0x10, 0x22, 0x00, 0x11, /* add w16, w16,#PLT_GOT+0x8 */
+#endif
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
+/* Per function entry in a procedure linkage table looks like this
+ if the distance between the PLTGOT and the PLT is < 4GB use
+ these PLT entries. Use BTI versions of the PLTs when enabled. */
+static const bfd_byte elfNN_aarch64_small_plt_entry[PLT_SMALL_ENTRY_SIZE] =
+{
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
+#if ARCH_SIZE == 64
+ 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */
+ 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */
+#else
+ 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */
+ 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */
+#endif
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17. */
+};
+
+static const bfd_byte
+elfNN_aarch64_small_plt_bti_entry[PLT_BTI_SMALL_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
+#if ARCH_SIZE == 64
+ 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */
+ 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */
+#else
+ 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */
+ 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */
+#endif
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17. */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
+static const bfd_byte
+elfNN_aarch64_small_plt_pac_entry[PLT_PAC_SMALL_ENTRY_SIZE] =
+{
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
+#if ARCH_SIZE == 64
+ 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */
+ 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */
+#else
+ 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */
+ 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */
+#endif
+ 0x9f, 0x21, 0x03, 0xd5, /* autia1716 */
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17. */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
+static const bfd_byte
+elfNN_aarch64_small_plt_bti_pac_entry[PLT_BTI_PAC_SMALL_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
+#if ARCH_SIZE == 64
+ 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */
+ 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */
+#else
+ 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */
+ 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */
+#endif
+ 0x9f, 0x21, 0x03, 0xd5, /* autia1716 */
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17. */
+};
+
+static const bfd_byte
+elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] =
+{
+ 0xe2, 0x0f, 0xbf, 0xa9, /* stp x2, x3, [sp, #-16]! */
+ 0x02, 0x00, 0x00, 0x90, /* adrp x2, 0 */
+ 0x03, 0x00, 0x00, 0x90, /* adrp x3, 0 */
+#if ARCH_SIZE == 64
+ 0x42, 0x00, 0x40, 0xf9, /* ldr x2, [x2, #0] */
+ 0x63, 0x00, 0x00, 0x91, /* add x3, x3, 0 */
+#else
+ 0x42, 0x00, 0x40, 0xb9, /* ldr w2, [x2, #0] */
+ 0x63, 0x00, 0x00, 0x11, /* add w3, w3, 0 */
+#endif
+ 0x40, 0x00, 0x1f, 0xd6, /* br x2 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
+static const bfd_byte
+elfNN_aarch64_tlsdesc_small_plt_bti_entry[PLT_TLSDESC_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0xe2, 0x0f, 0xbf, 0xa9, /* stp x2, x3, [sp, #-16]! */
+ 0x02, 0x00, 0x00, 0x90, /* adrp x2, 0 */
+ 0x03, 0x00, 0x00, 0x90, /* adrp x3, 0 */
+#if ARCH_SIZE == 64
+ 0x42, 0x00, 0x40, 0xf9, /* ldr x2, [x2, #0] */
+ 0x63, 0x00, 0x00, 0x91, /* add x3, x3, 0 */
+#else
+ 0x42, 0x00, 0x40, 0xb9, /* ldr w2, [x2, #0] */
+ 0x63, 0x00, 0x00, 0x11, /* add w3, w3, 0 */
+#endif
+ 0x40, 0x00, 0x1f, 0xd6, /* br x2 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
+#define elf_info_to_howto elfNN_aarch64_info_to_howto
+#define elf_info_to_howto_rel elfNN_aarch64_info_to_howto
+
+#define AARCH64_ELF_ABI_VERSION 0
+
+/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */
+#define ALL_ONES (~ (bfd_vma) 0)
+
+/* Indexed by the bfd interal reloc enumerators.
+ Therefore, the table needs to be synced with BFD_RELOC_AARCH64_*
+ in reloc.c. */
+
+static reloc_howto_type elfNN_aarch64_howto_table[] =
+{
+ EMPTY_HOWTO (0),
+
+ /* Basic data relocations. */
+
+ /* Deprecated, but retained for backwards compatibility. */
+ HOWTO64 (R_AARCH64_NULL, /* 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_AARCH64_NULL", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false), /* pcrel_offset */
+ HOWTO (R_AARCH64_NONE, /* 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_AARCH64_NONE", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* .xword: (S+A) */
+ HOWTO64 (AARCH64_R (ABS64), /* type */
+ 0, /* rightshift */
+ 8, /* size */
+ 64, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (ABS64), /* name */
+ false, /* partial_inplace */
+ ALL_ONES, /* src_mask */
+ ALL_ONES, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* .word: (S+A) */
+ HOWTO (AARCH64_R (ABS32), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (ABS32), /* name */
+ false, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* .half: (S+A) */
+ HOWTO (AARCH64_R (ABS16), /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (ABS16), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* .xword: (S+A-P) */
+ HOWTO64 (AARCH64_R (PREL64), /* type */
+ 0, /* rightshift */
+ 8, /* size */
+ 64, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (PREL64), /* name */
+ false, /* partial_inplace */
+ ALL_ONES, /* src_mask */
+ ALL_ONES, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* .word: (S+A-P) */
+ HOWTO (AARCH64_R (PREL32), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 32, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (PREL32), /* name */
+ false, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* .half: (S+A-P) */
+ HOWTO (AARCH64_R (PREL16), /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 16, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (PREL16), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* Group relocations to create a 16, 32, 48 or 64 bit
+ unsigned data or abs address inline. */
+
+ /* MOVZ: ((S+A) >> 0) & 0xffff */
+ HOWTO (AARCH64_R (MOVW_UABS_G0), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_UABS_G0), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOVK: ((S+A) >> 0) & 0xffff [no overflow check] */
+ HOWTO (AARCH64_R (MOVW_UABS_G0_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_UABS_G0_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOVZ: ((S+A) >> 16) & 0xffff */
+ HOWTO (AARCH64_R (MOVW_UABS_G1), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_UABS_G1), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOVK: ((S+A) >> 16) & 0xffff [no overflow check] */
+ HOWTO64 (AARCH64_R (MOVW_UABS_G1_NC), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_UABS_G1_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOVZ: ((S+A) >> 32) & 0xffff */
+ HOWTO64 (AARCH64_R (MOVW_UABS_G2), /* type */
+ 32, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_UABS_G2), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOVK: ((S+A) >> 32) & 0xffff [no overflow check] */
+ HOWTO64 (AARCH64_R (MOVW_UABS_G2_NC), /* type */
+ 32, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_UABS_G2_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOVZ: ((S+A) >> 48) & 0xffff */
+ HOWTO64 (AARCH64_R (MOVW_UABS_G3), /* type */
+ 48, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_UABS_G3), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Group relocations to create high part of a 16, 32, 48 or 64 bit
+ signed data or abs address inline. Will change instruction
+ to MOVN or MOVZ depending on sign of calculated value. */
+
+ /* MOV[ZN]: ((S+A) >> 0) & 0xffff */
+ HOWTO (AARCH64_R (MOVW_SABS_G0), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 17, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_SABS_G0), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOV[ZN]: ((S+A) >> 16) & 0xffff */
+ HOWTO64 (AARCH64_R (MOVW_SABS_G1), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 17, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_SABS_G1), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOV[ZN]: ((S+A) >> 32) & 0xffff */
+ HOWTO64 (AARCH64_R (MOVW_SABS_G2), /* type */
+ 32, /* rightshift */
+ 4, /* size */
+ 17, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_SABS_G2), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Group relocations to create a 16, 32, 48 or 64 bit
+ PC relative address inline. */
+
+ /* MOV[NZ]: ((S+A-P) >> 0) & 0xffff */
+ HOWTO (AARCH64_R (MOVW_PREL_G0), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 17, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G0), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* MOVK: ((S+A-P) >> 0) & 0xffff [no overflow check] */
+ HOWTO (AARCH64_R (MOVW_PREL_G0_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G0_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* MOV[NZ]: ((S+A-P) >> 16) & 0xffff */
+ HOWTO (AARCH64_R (MOVW_PREL_G1), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 17, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G1), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* MOVK: ((S+A-P) >> 16) & 0xffff [no overflow check] */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G1_NC), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G1_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* MOV[NZ]: ((S+A-P) >> 32) & 0xffff */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G2), /* type */
+ 32, /* rightshift */
+ 4, /* size */
+ 17, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G2), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* MOVK: ((S+A-P) >> 32) & 0xffff [no overflow check] */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G2_NC), /* type */
+ 32, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G2_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* MOV[NZ]: ((S+A-P) >> 48) & 0xffff */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G3), /* type */
+ 48, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G3), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+/* Relocations to generate 19, 21 and 33 bit PC-relative load/store
+ addresses: PG(x) is (x & ~0xfff). */
+
+ /* LD-lit: ((S+A-P) >> 2) & 0x7ffff */
+ HOWTO (AARCH64_R (LD_PREL_LO19), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 19, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LD_PREL_LO19), /* name */
+ false, /* partial_inplace */
+ 0x7ffff, /* src_mask */
+ 0x7ffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* ADR: (S+A-P) & 0x1fffff */
+ HOWTO (AARCH64_R (ADR_PREL_LO21), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (ADR_PREL_LO21), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */
+ HOWTO (AARCH64_R (ADR_PREL_PG_HI21), /* type */
+ 12, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (ADR_PREL_PG_HI21), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff [no overflow check] */
+ HOWTO64 (AARCH64_R (ADR_PREL_PG_HI21_NC), /* type */
+ 12, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (ADR_PREL_PG_HI21_NC), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* ADD: (S+A) & 0xfff [no overflow check] */
+ HOWTO (AARCH64_R (ADD_ABS_LO12_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (ADD_ABS_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST8: (S+A) & 0xfff */
+ HOWTO (AARCH64_R (LDST8_ABS_LO12_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LDST8_ABS_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Relocations for control-flow instructions. */
+
+ /* TBZ/NZ: ((S+A-P) >> 2) & 0x3fff */
+ HOWTO (AARCH64_R (TSTBR14), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 14, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TSTBR14), /* name */
+ false, /* partial_inplace */
+ 0x3fff, /* src_mask */
+ 0x3fff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* B.cond: ((S+A-P) >> 2) & 0x7ffff */
+ HOWTO (AARCH64_R (CONDBR19), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 19, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (CONDBR19), /* name */
+ false, /* partial_inplace */
+ 0x7ffff, /* src_mask */
+ 0x7ffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* B: ((S+A-P) >> 2) & 0x3ffffff */
+ HOWTO (AARCH64_R (JUMP26), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 26, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (JUMP26), /* name */
+ false, /* partial_inplace */
+ 0x3ffffff, /* src_mask */
+ 0x3ffffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* BL: ((S+A-P) >> 2) & 0x3ffffff */
+ HOWTO (AARCH64_R (CALL26), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 26, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (CALL26), /* name */
+ false, /* partial_inplace */
+ 0x3ffffff, /* src_mask */
+ 0x3ffffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* LD/ST16: (S+A) & 0xffe */
+ HOWTO (AARCH64_R (LDST16_ABS_LO12_NC), /* type */
+ 1, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LDST16_ABS_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xffe, /* src_mask */
+ 0xffe, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST32: (S+A) & 0xffc */
+ HOWTO (AARCH64_R (LDST32_ABS_LO12_NC), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LDST32_ABS_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xffc, /* src_mask */
+ 0xffc, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST64: (S+A) & 0xff8 */
+ HOWTO (AARCH64_R (LDST64_ABS_LO12_NC), /* type */
+ 3, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LDST64_ABS_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xff8, /* src_mask */
+ 0xff8, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST128: (S+A) & 0xff0 */
+ HOWTO (AARCH64_R (LDST128_ABS_LO12_NC), /* type */
+ 4, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LDST128_ABS_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xff0, /* src_mask */
+ 0xff0, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Set a load-literal immediate field to bits
+ 0x1FFFFC of G(S)-P */
+ HOWTO (AARCH64_R (GOT_LD_PREL19), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 19, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (GOT_LD_PREL19), /* name */
+ false, /* partial_inplace */
+ 0xffffe0, /* src_mask */
+ 0xffffe0, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* Get to the page for the GOT entry for the symbol
+ (G(S) - P) using an ADRP instruction. */
+ HOWTO (AARCH64_R (ADR_GOT_PAGE), /* type */
+ 12, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (ADR_GOT_PAGE), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* LD64: GOT offset G(S) & 0xff8 */
+ HOWTO64 (AARCH64_R (LD64_GOT_LO12_NC), /* type */
+ 3, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LD64_GOT_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xff8, /* src_mask */
+ 0xff8, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD32: GOT offset G(S) & 0xffc */
+ HOWTO32 (AARCH64_R (LD32_GOT_LO12_NC), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LD32_GOT_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xffc, /* src_mask */
+ 0xffc, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Lower 16 bits of GOT offset for the symbol. */
+ HOWTO64 (AARCH64_R (MOVW_GOTOFF_G0_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_GOTOFF_G0_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Higher 16 bits of GOT offset for the symbol. */
+ HOWTO64 (AARCH64_R (MOVW_GOTOFF_G1), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_GOTOFF_G1), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD64: GOT offset for the symbol. */
+ HOWTO64 (AARCH64_R (LD64_GOTOFF_LO15), /* type */
+ 3, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LD64_GOTOFF_LO15), /* name */
+ false, /* partial_inplace */
+ 0x7ff8, /* src_mask */
+ 0x7ff8, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD32: GOT offset to the page address of GOT table.
+ (G(S) - PAGE (_GLOBAL_OFFSET_TABLE_)) & 0x5ffc. */
+ HOWTO32 (AARCH64_R (LD32_GOTPAGE_LO14), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LD32_GOTPAGE_LO14), /* name */
+ false, /* partial_inplace */
+ 0x5ffc, /* src_mask */
+ 0x5ffc, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD64: GOT offset to the page address of GOT table.
+ (G(S) - PAGE (_GLOBAL_OFFSET_TABLE_)) & 0x7ff8. */
+ HOWTO64 (AARCH64_R (LD64_GOTPAGE_LO15), /* type */
+ 3, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (LD64_GOTPAGE_LO15), /* name */
+ false, /* partial_inplace */
+ 0x7ff8, /* src_mask */
+ 0x7ff8, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Get to the page for the GOT entry for the symbol
+ (G(S) - P) using an ADRP instruction. */
+ HOWTO (AARCH64_R (TLSGD_ADR_PAGE21), /* type */
+ 12, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSGD_ADR_PAGE21), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSGD_ADR_PREL21), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSGD_ADR_PREL21), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* ADD: GOT offset G(S) & 0xff8 [no overflow check] */
+ HOWTO (AARCH64_R (TLSGD_ADD_LO12_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSGD_ADD_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Lower 16 bits of GOT offset to tls_index. */
+ HOWTO64 (AARCH64_R (TLSGD_MOVW_G0_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSGD_MOVW_G0_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Higher 16 bits of GOT offset to tls_index. */
+ HOWTO64 (AARCH64_R (TLSGD_MOVW_G1), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSGD_MOVW_G1), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSIE_ADR_GOTTPREL_PAGE21), /* type */
+ 12, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSIE_ADR_GOTTPREL_PAGE21), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO64 (AARCH64_R (TLSIE_LD64_GOTTPREL_LO12_NC), /* type */
+ 3, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSIE_LD64_GOTTPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xff8, /* src_mask */
+ 0xff8, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO32 (AARCH64_R (TLSIE_LD32_GOTTPREL_LO12_NC), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSIE_LD32_GOTTPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xffc, /* src_mask */
+ 0xffc, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSIE_LD_GOTTPREL_PREL19), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 19, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSIE_LD_GOTTPREL_PREL19), /* name */
+ false, /* partial_inplace */
+ 0x1ffffc, /* src_mask */
+ 0x1ffffc, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO64 (AARCH64_R (TLSIE_MOVW_GOTTPREL_G0_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSIE_MOVW_GOTTPREL_G0_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO64 (AARCH64_R (TLSIE_MOVW_GOTTPREL_G1), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSIE_MOVW_GOTTPREL_G1), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* ADD: bit[23:12] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLD_ADD_DTPREL_HI12), /* type */
+ 12, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_ADD_DTPREL_HI12), /* name */
+ false, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Unsigned 12 bit byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLD_ADD_DTPREL_LO12), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_ADD_DTPREL_LO12), /* name */
+ false, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12. */
+ HOWTO (AARCH64_R (TLSLD_ADD_DTPREL_LO12_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_ADD_DTPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* ADD: GOT offset G(S) & 0xff8 [no overflow check] */
+ HOWTO (AARCH64_R (TLSLD_ADD_LO12_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_ADD_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Get to the page for the GOT entry for the symbol
+ (G(S) - P) using an ADRP instruction. */
+ HOWTO (AARCH64_R (TLSLD_ADR_PAGE21), /* type */
+ 12, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_ADR_PAGE21), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSLD_ADR_PREL21), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_ADR_PREL21), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* LD/ST16: bit[11:1] of byte offset to module TLS base address. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST16_DTPREL_LO12), /* type */
+ 1, /* rightshift */
+ 4, /* size */
+ 11, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST16_DTPREL_LO12), /* name */
+ false, /* partial_inplace */
+ 0x1ffc00, /* src_mask */
+ 0x1ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12, but no overflow check. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST16_DTPREL_LO12_NC), /* type */
+ 1, /* rightshift */
+ 4, /* size */
+ 11, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST16_DTPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0x1ffc00, /* src_mask */
+ 0x1ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST32: bit[11:2] of byte offset to module TLS base address. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST32_DTPREL_LO12), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 10, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST32_DTPREL_LO12), /* name */
+ false, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12, but no overflow check. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST32_DTPREL_LO12_NC), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 10, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST32_DTPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xffc00, /* src_mask */
+ 0xffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST64: bit[11:3] of byte offset to module TLS base address. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST64_DTPREL_LO12), /* type */
+ 3, /* rightshift */
+ 4, /* size */
+ 9, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST64_DTPREL_LO12), /* name */
+ false, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12, but no overflow check. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST64_DTPREL_LO12_NC), /* type */
+ 3, /* rightshift */
+ 4, /* size */
+ 9, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST64_DTPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0x7fc00, /* src_mask */
+ 0x7fc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST8: bit[11:0] of byte offset to module TLS base address. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST8_DTPREL_LO12), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST8_DTPREL_LO12), /* name */
+ false, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12, but no overflow check. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST8_DTPREL_LO12_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST8_DTPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOVZ: bit[15:0] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLD_MOVW_DTPREL_G0), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_MOVW_DTPREL_G0), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0. */
+ HOWTO (AARCH64_R (TLSLD_MOVW_DTPREL_G0_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_MOVW_DTPREL_G0_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOVZ: bit[31:16] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLD_MOVW_DTPREL_G1), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_MOVW_DTPREL_G1), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1. */
+ HOWTO64 (AARCH64_R (TLSLD_MOVW_DTPREL_G1_NC), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_MOVW_DTPREL_G1_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* MOVZ: bit[47:32] of byte offset to module TLS base address. */
+ HOWTO64 (AARCH64_R (TLSLD_MOVW_DTPREL_G2), /* type */
+ 32, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_MOVW_DTPREL_G2), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO64 (AARCH64_R (TLSLE_MOVW_TPREL_G2), /* type */
+ 32, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_MOVW_TPREL_G2), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSLE_MOVW_TPREL_G1), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_MOVW_TPREL_G1), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO64 (AARCH64_R (TLSLE_MOVW_TPREL_G1_NC), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_MOVW_TPREL_G1_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSLE_MOVW_TPREL_G0), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_MOVW_TPREL_G0), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSLE_MOVW_TPREL_G0_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_MOVW_TPREL_G0_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSLE_ADD_TPREL_HI12), /* type */
+ 12, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_ADD_TPREL_HI12), /* name */
+ false, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSLE_ADD_TPREL_LO12), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_ADD_TPREL_LO12), /* name */
+ false, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSLE_ADD_TPREL_LO12_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_ADD_TPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST16: bit[11:1] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLE_LDST16_TPREL_LO12), /* type */
+ 1, /* rightshift */
+ 4, /* size */
+ 11, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST16_TPREL_LO12), /* name */
+ false, /* partial_inplace */
+ 0x1ffc00, /* src_mask */
+ 0x1ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12, but no overflow check. */
+ HOWTO (AARCH64_R (TLSLE_LDST16_TPREL_LO12_NC), /* type */
+ 1, /* rightshift */
+ 4, /* size */
+ 11, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST16_TPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0x1ffc00, /* src_mask */
+ 0x1ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST32: bit[11:2] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLE_LDST32_TPREL_LO12), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 10, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST32_TPREL_LO12), /* name */
+ false, /* partial_inplace */
+ 0xffc00, /* src_mask */
+ 0xffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12, but no overflow check. */
+ HOWTO (AARCH64_R (TLSLE_LDST32_TPREL_LO12_NC), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 10, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST32_TPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xffc00, /* src_mask */
+ 0xffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST64: bit[11:3] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLE_LDST64_TPREL_LO12), /* type */
+ 3, /* rightshift */
+ 4, /* size */
+ 9, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST64_TPREL_LO12), /* name */
+ false, /* partial_inplace */
+ 0x7fc00, /* src_mask */
+ 0x7fc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12, but no overflow check. */
+ HOWTO (AARCH64_R (TLSLE_LDST64_TPREL_LO12_NC), /* type */
+ 3, /* rightshift */
+ 4, /* size */
+ 9, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST64_TPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0x7fc00, /* src_mask */
+ 0x7fc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD/ST8: bit[11:0] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLE_LDST8_TPREL_LO12), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST8_TPREL_LO12), /* name */
+ false, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12, but no overflow check. */
+ HOWTO (AARCH64_R (TLSLE_LDST8_TPREL_LO12_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST8_TPREL_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSDESC_LD_PREL19), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 19, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_LD_PREL19), /* name */
+ false, /* partial_inplace */
+ 0x0ffffe0, /* src_mask */
+ 0x0ffffe0, /* dst_mask */
+ true), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSDESC_ADR_PREL21), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_ADR_PREL21), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* Get to the page for the GOT entry for the symbol
+ (G(S) - P) using an ADRP instruction. */
+ HOWTO (AARCH64_R (TLSDESC_ADR_PAGE21), /* type */
+ 12, /* rightshift */
+ 4, /* size */
+ 21, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_ADR_PAGE21), /* name */
+ false, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* LD64: GOT offset G(S) & 0xff8. */
+ HOWTO64 (AARCH64_R (TLSDESC_LD64_LO12), /* type */
+ 3, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_LD64_LO12), /* name */
+ false, /* partial_inplace */
+ 0xff8, /* src_mask */
+ 0xff8, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* LD32: GOT offset G(S) & 0xffc. */
+ HOWTO32 (AARCH64_R (TLSDESC_LD32_LO12_NC), /* type */
+ 2, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_LD32_LO12_NC), /* name */
+ false, /* partial_inplace */
+ 0xffc, /* src_mask */
+ 0xffc, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* ADD: GOT offset G(S) & 0xfff. */
+ HOWTO (AARCH64_R (TLSDESC_ADD_LO12), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_ADD_LO12), /* name */
+ false, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO64 (AARCH64_R (TLSDESC_OFF_G1), /* type */
+ 16, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_OFF_G1), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO64 (AARCH64_R (TLSDESC_OFF_G0_NC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_OFF_G0_NC), /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO64 (AARCH64_R (TLSDESC_LDR), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_LDR), /* name */
+ false, /* partial_inplace */
+ 0x0, /* src_mask */
+ 0x0, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO64 (AARCH64_R (TLSDESC_ADD), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 12, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_ADD), /* name */
+ false, /* partial_inplace */
+ 0x0, /* src_mask */
+ 0x0, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSDESC_CALL), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_CALL), /* name */
+ false, /* partial_inplace */
+ 0x0, /* src_mask */
+ 0x0, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (COPY), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 64, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (COPY), /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (GLOB_DAT), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 64, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (GLOB_DAT), /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (JUMP_SLOT), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 64, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (JUMP_SLOT), /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (RELATIVE), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 64, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (RELATIVE), /* name */
+ true, /* partial_inplace */
+ ALL_ONES, /* src_mask */
+ ALL_ONES, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLS_DTPMOD), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 64, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+#if ARCH_SIZE == 64
+ AARCH64_R_STR (TLS_DTPMOD64), /* name */
+#else
+ AARCH64_R_STR (TLS_DTPMOD), /* name */
+#endif
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ALL_ONES, /* dst_mask */
+ false), /* pc_reloffset */
+
+ HOWTO (AARCH64_R (TLS_DTPREL), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 64, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+#if ARCH_SIZE == 64
+ AARCH64_R_STR (TLS_DTPREL64), /* name */
+#else
+ AARCH64_R_STR (TLS_DTPREL), /* name */
+#endif
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ALL_ONES, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLS_TPREL), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 64, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+#if ARCH_SIZE == 64
+ AARCH64_R_STR (TLS_TPREL64), /* name */
+#else
+ AARCH64_R_STR (TLS_TPREL), /* name */
+#endif
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ALL_ONES, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSDESC), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 64, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC), /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ALL_ONES, /* dst_mask */
+ false), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (IRELATIVE), /* type */
+ 0, /* rightshift */
+ 4, /* size */
+ 64, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (IRELATIVE), /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ALL_ONES, /* dst_mask */
+ false), /* pcrel_offset */
+
+ EMPTY_HOWTO (0),
+};
+
+static reloc_howto_type elfNN_aarch64_howto_none =
+ HOWTO (R_AARCH64_NONE, /* 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_AARCH64_NONE", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false); /* pcrel_offset */
+
+/* Given HOWTO, return the bfd internal relocation enumerator. */
+
+static bfd_reloc_code_real_type
+elfNN_aarch64_bfd_reloc_from_howto (reloc_howto_type *howto)
+{
+ const int size
+ = (int) ARRAY_SIZE (elfNN_aarch64_howto_table);
+ const ptrdiff_t offset
+ = howto - elfNN_aarch64_howto_table;
+
+ if (offset > 0 && offset < size - 1)
+ return BFD_RELOC_AARCH64_RELOC_START + offset;
+
+ if (howto == &elfNN_aarch64_howto_none)
+ return BFD_RELOC_AARCH64_NONE;
+
+ return BFD_RELOC_AARCH64_RELOC_START;
+}
+
+/* Given R_TYPE, return the bfd internal relocation enumerator. */
+
+static bfd_reloc_code_real_type
+elfNN_aarch64_bfd_reloc_from_type (bfd *abfd, unsigned int r_type)
+{
+ static bool initialized_p = false;
+ /* Indexed by R_TYPE, values are offsets in the howto_table. */
+ static unsigned int offsets[R_AARCH64_end];
+
+ if (!initialized_p)
+ {
+ unsigned int i;
+
+ for (i = 1; i < ARRAY_SIZE (elfNN_aarch64_howto_table) - 1; ++i)
+ if (elfNN_aarch64_howto_table[i].type != 0)
+ offsets[elfNN_aarch64_howto_table[i].type] = i;
+
+ initialized_p = true;
+ }
+
+ if (r_type == R_AARCH64_NONE || r_type == R_AARCH64_NULL)
+ return BFD_RELOC_AARCH64_NONE;
+
+ /* PR 17512: file: b371e70a. */
+ if (r_type >= R_AARCH64_end)
+ {
+ _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+ abfd, r_type);
+ bfd_set_error (bfd_error_bad_value);
+ return BFD_RELOC_AARCH64_NONE;
+ }
+
+ return BFD_RELOC_AARCH64_RELOC_START + offsets[r_type];
+}
+
+struct elf_aarch64_reloc_map
+{
+ bfd_reloc_code_real_type from;
+ bfd_reloc_code_real_type to;
+};
+
+/* Map bfd generic reloc to AArch64-specific reloc. */
+static const struct elf_aarch64_reloc_map elf_aarch64_reloc_map[] =
+{
+ {BFD_RELOC_NONE, BFD_RELOC_AARCH64_NONE},
+
+ /* Basic data relocations. */
+ {BFD_RELOC_CTOR, BFD_RELOC_AARCH64_NN},
+ {BFD_RELOC_64, BFD_RELOC_AARCH64_64},
+ {BFD_RELOC_32, BFD_RELOC_AARCH64_32},
+ {BFD_RELOC_16, BFD_RELOC_AARCH64_16},
+ {BFD_RELOC_64_PCREL, BFD_RELOC_AARCH64_64_PCREL},
+ {BFD_RELOC_32_PCREL, BFD_RELOC_AARCH64_32_PCREL},
+ {BFD_RELOC_16_PCREL, BFD_RELOC_AARCH64_16_PCREL},
+};
+
+/* Given the bfd internal relocation enumerator in CODE, return the
+ corresponding howto entry. */
+
+static reloc_howto_type *
+elfNN_aarch64_howto_from_bfd_reloc (bfd_reloc_code_real_type code)
+{
+ unsigned int i;
+
+ /* Convert bfd generic reloc to AArch64-specific reloc. */
+ if (code < BFD_RELOC_AARCH64_RELOC_START
+ || code > BFD_RELOC_AARCH64_RELOC_END)
+ for (i = 0; i < ARRAY_SIZE (elf_aarch64_reloc_map); i++)
+ if (elf_aarch64_reloc_map[i].from == code)
+ {
+ code = elf_aarch64_reloc_map[i].to;
+ break;
+ }
+
+ if (code > BFD_RELOC_AARCH64_RELOC_START
+ && code < BFD_RELOC_AARCH64_RELOC_END)
+ if (elfNN_aarch64_howto_table[code - BFD_RELOC_AARCH64_RELOC_START].type)
+ return &elfNN_aarch64_howto_table[code - BFD_RELOC_AARCH64_RELOC_START];
+
+ if (code == BFD_RELOC_AARCH64_NONE)
+ return &elfNN_aarch64_howto_none;
+
+ return NULL;
+}
+
+static reloc_howto_type *
+elfNN_aarch64_howto_from_type (bfd *abfd, unsigned int r_type)
+{
+ bfd_reloc_code_real_type val;
+ reloc_howto_type *howto;
+
+#if ARCH_SIZE == 32
+ if (r_type > 256)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+ }
+#endif
+
+ if (r_type == R_AARCH64_NONE)
+ return &elfNN_aarch64_howto_none;
+
+ val = elfNN_aarch64_bfd_reloc_from_type (abfd, r_type);
+ howto = elfNN_aarch64_howto_from_bfd_reloc (val);
+
+ if (howto != NULL)
+ return howto;
+
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+}
+
+static bool
+elfNN_aarch64_info_to_howto (bfd *abfd, arelent *bfd_reloc,
+ Elf_Internal_Rela *elf_reloc)
+{
+ unsigned int r_type;
+
+ r_type = ELFNN_R_TYPE (elf_reloc->r_info);
+ bfd_reloc->howto = elfNN_aarch64_howto_from_type (abfd, r_type);
+
+ if (bfd_reloc->howto == NULL)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: unsupported relocation type %#x"), abfd, r_type);
+ return false;
+ }
+ return true;
+}
+
+static reloc_howto_type *
+elfNN_aarch64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ bfd_reloc_code_real_type code)
+{
+ reloc_howto_type *howto = elfNN_aarch64_howto_from_bfd_reloc (code);
+
+ if (howto != NULL)
+ return howto;
+
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+}
+
+static reloc_howto_type *
+elfNN_aarch64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 1; i < ARRAY_SIZE (elfNN_aarch64_howto_table) - 1; ++i)
+ if (elfNN_aarch64_howto_table[i].name != NULL
+ && strcasecmp (elfNN_aarch64_howto_table[i].name, r_name) == 0)
+ return &elfNN_aarch64_howto_table[i];
+
+ return NULL;
+}
+
+#define TARGET_LITTLE_SYM aarch64_elfNN_le_vec
+#define TARGET_LITTLE_NAME "elfNN-littleaarch64"
+#define TARGET_BIG_SYM aarch64_elfNN_be_vec
+#define TARGET_BIG_NAME "elfNN-bigaarch64"
+
+/* 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 STUB_ENTRY_NAME "__%s_veneer"
+
+/* The name of the dynamic interpreter. This is put in the .interp
+ section. */
+#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
+
+#define AARCH64_MAX_FWD_BRANCH_OFFSET \
+ (((1 << 25) - 1) << 2)
+#define AARCH64_MAX_BWD_BRANCH_OFFSET \
+ (-((1 << 25) << 2))
+
+#define AARCH64_MAX_ADRP_IMM ((1 << 20) - 1)
+#define AARCH64_MIN_ADRP_IMM (-(1 << 20))
+
+static int
+aarch64_valid_for_adrp_p (bfd_vma value, bfd_vma place)
+{
+ bfd_signed_vma offset = (bfd_signed_vma) (PG (value) - PG (place)) >> 12;
+ return offset <= AARCH64_MAX_ADRP_IMM && offset >= AARCH64_MIN_ADRP_IMM;
+}
+
+static int
+aarch64_valid_branch_p (bfd_vma value, bfd_vma place)
+{
+ bfd_signed_vma offset = (bfd_signed_vma) (value - place);
+ return (offset <= AARCH64_MAX_FWD_BRANCH_OFFSET
+ && offset >= AARCH64_MAX_BWD_BRANCH_OFFSET);
+}
+
+static const uint32_t aarch64_adrp_branch_stub [] =
+{
+ 0x90000010, /* adrp ip0, X */
+ /* R_AARCH64_ADR_HI21_PCREL(X) */
+ 0x91000210, /* add ip0, ip0, :lo12:X */
+ /* R_AARCH64_ADD_ABS_LO12_NC(X) */
+ 0xd61f0200, /* br ip0 */
+};
+
+static const uint32_t aarch64_long_branch_stub[] =
+{
+#if ARCH_SIZE == 64
+ 0x58000090, /* ldr ip0, 1f */
+#else
+ 0x18000090, /* ldr wip0, 1f */
+#endif
+ 0x10000011, /* adr ip1, #0 */
+ 0x8b110210, /* add ip0, ip0, ip1 */
+ 0xd61f0200, /* br ip0 */
+ 0x00000000, /* 1: .xword or .word
+ R_AARCH64_PRELNN(X) + 12
+ */
+ 0x00000000,
+};
+
+static const uint32_t aarch64_erratum_835769_stub[] =
+{
+ 0x00000000, /* Placeholder for multiply accumulate. */
+ 0x14000000, /* b <label> */
+};
+
+static const uint32_t aarch64_erratum_843419_stub[] =
+{
+ 0x00000000, /* Placeholder for LDR instruction. */
+ 0x14000000, /* b <label> */
+};
+
+/* Section name for stubs is the associated section name plus this
+ string. */
+#define STUB_SUFFIX ".stub"
+
+enum elf_aarch64_stub_type
+{
+ aarch64_stub_none,
+ aarch64_stub_adrp_branch,
+ aarch64_stub_long_branch,
+ aarch64_stub_erratum_835769_veneer,
+ aarch64_stub_erratum_843419_veneer,
+};
+
+struct elf_aarch64_stub_hash_entry
+{
+ /* Base hash table entry structure. */
+ struct bfd_hash_entry root;
+
+ /* The stub section. */
+ asection *stub_sec;
+
+ /* Offset within stub_sec of the beginning of this stub. */
+ bfd_vma stub_offset;
+
+ /* Given the symbol's value and its section we can determine its final
+ value when building the stubs (so the stub knows where to jump). */
+ bfd_vma target_value;
+ asection *target_section;
+
+ enum elf_aarch64_stub_type stub_type;
+
+ /* The symbol table entry, if any, that this was derived from. */
+ struct elf_aarch64_link_hash_entry *h;
+
+ /* Destination symbol type */
+ unsigned char st_type;
+
+ /* Where this stub is being called from, or, in the case of combined
+ stub sections, the first input section in the group. */
+ asection *id_sec;
+
+ /* The name for the local symbol at the start of this stub. The
+ stub name in the hash table has to be unique; this does not, so
+ it can be friendlier. */
+ char *output_name;
+
+ /* The instruction which caused this stub to be generated (only valid for
+ erratum 835769 workaround stubs at present). */
+ uint32_t veneered_insn;
+
+ /* In an erratum 843419 workaround stub, the ADRP instruction offset. */
+ bfd_vma adrp_offset;
+};
+
+/* Used to build a map of a section. This is required for mixed-endian
+ code/data. */
+
+typedef struct elf_elf_section_map
+{
+ bfd_vma vma;
+ char type;
+}
+elf_aarch64_section_map;
+
+
+typedef struct _aarch64_elf_section_data
+{
+ struct bfd_elf_section_data elf;
+ unsigned int mapcount;
+ unsigned int mapsize;
+ elf_aarch64_section_map *map;
+}
+_aarch64_elf_section_data;
+
+#define elf_aarch64_section_data(sec) \
+ ((_aarch64_elf_section_data *) elf_section_data (sec))
+
+/* The size of the thread control block which is defined to be two pointers. */
+#define TCB_SIZE (ARCH_SIZE/8)*2
+
+struct elf_aarch64_local_symbol
+{
+ unsigned int got_type;
+ bfd_signed_vma got_refcount;
+ bfd_vma got_offset;
+
+ /* Offset of the GOTPLT entry reserved for the TLS descriptor. The
+ offset is from the end of the jump table and reserved entries
+ within the PLTGOT.
+
+ The magic value (bfd_vma) -1 indicates that an offset has not be
+ allocated. */
+ bfd_vma tlsdesc_got_jump_table_offset;
+};
+
+struct elf_aarch64_obj_tdata
+{
+ struct elf_obj_tdata root;
+
+ /* local symbol descriptors */
+ struct elf_aarch64_local_symbol *locals;
+
+ /* Zero to warn when linking objects with incompatible enum sizes. */
+ int no_enum_size_warning;
+
+ /* Zero to warn when linking objects with incompatible wchar_t sizes. */
+ int no_wchar_size_warning;
+
+ /* All GNU_PROPERTY_AARCH64_FEATURE_1_AND properties. */
+ uint32_t gnu_and_prop;
+
+ /* Zero to warn when linking objects with incompatible
+ GNU_PROPERTY_AARCH64_FEATURE_1_BTI. */
+ int no_bti_warn;
+
+ /* PLT type based on security. */
+ aarch64_plt_type plt_type;
+};
+
+#define elf_aarch64_tdata(bfd) \
+ ((struct elf_aarch64_obj_tdata *) (bfd)->tdata.any)
+
+#define elf_aarch64_locals(bfd) (elf_aarch64_tdata (bfd)->locals)
+
+#define is_aarch64_elf(bfd) \
+ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+ && elf_tdata (bfd) != NULL \
+ && elf_object_id (bfd) == AARCH64_ELF_DATA)
+
+static bool
+elfNN_aarch64_mkobject (bfd *abfd)
+{
+ return bfd_elf_allocate_object (abfd, sizeof (struct elf_aarch64_obj_tdata),
+ AARCH64_ELF_DATA);
+}
+
+#define elf_aarch64_hash_entry(ent) \
+ ((struct elf_aarch64_link_hash_entry *)(ent))
+
+#define GOT_UNKNOWN 0
+#define GOT_NORMAL 1
+#define GOT_TLS_GD 2
+#define GOT_TLS_IE 4
+#define GOT_TLSDESC_GD 8
+
+#define GOT_TLS_GD_ANY_P(type) ((type & GOT_TLS_GD) || (type & GOT_TLSDESC_GD))
+
+/* AArch64 ELF linker hash entry. */
+struct elf_aarch64_link_hash_entry
+{
+ struct elf_link_hash_entry root;
+
+ /* Since PLT entries have variable size, we need to record the
+ index into .got.plt instead of recomputing it from the PLT
+ offset. */
+ bfd_signed_vma plt_got_offset;
+
+ /* Bit mask representing the type of GOT entry(s) if any required by
+ this symbol. */
+ unsigned int got_type;
+
+ /* TRUE if symbol is defined as a protected symbol. */
+ unsigned int def_protected : 1;
+
+ /* A pointer to the most recently used stub hash entry against this
+ symbol. */
+ struct elf_aarch64_stub_hash_entry *stub_cache;
+
+ /* Offset of the GOTPLT entry reserved for the TLS descriptor. The offset
+ is from the end of the jump table and reserved entries within the PLTGOT.
+
+ The magic value (bfd_vma) -1 indicates that an offset has not
+ be allocated. */
+ bfd_vma tlsdesc_got_jump_table_offset;
+};
+
+static unsigned int
+elfNN_aarch64_symbol_got_type (struct elf_link_hash_entry *h,
+ bfd *abfd,
+ unsigned long r_symndx)
+{
+ if (h)
+ return elf_aarch64_hash_entry (h)->got_type;
+
+ if (! elf_aarch64_locals (abfd))
+ return GOT_UNKNOWN;
+
+ return elf_aarch64_locals (abfd)[r_symndx].got_type;
+}
+
+/* Get the AArch64 elf linker hash table from a link_info structure. */
+#define elf_aarch64_hash_table(info) \
+ ((struct elf_aarch64_link_hash_table *) ((info)->hash))
+
+#define aarch64_stub_hash_lookup(table, string, create, copy) \
+ ((struct elf_aarch64_stub_hash_entry *) \
+ bfd_hash_lookup ((table), (string), (create), (copy)))
+
+/* AArch64 ELF linker hash table. */
+struct elf_aarch64_link_hash_table
+{
+ /* The main hash table. */
+ struct elf_link_hash_table root;
+
+ /* Nonzero to force PIC branch veneers. */
+ int pic_veneer;
+
+ /* Fix erratum 835769. */
+ int fix_erratum_835769;
+
+ /* Fix erratum 843419. */
+ erratum_84319_opts fix_erratum_843419;
+
+ /* Don't apply link-time values for dynamic relocations. */
+ int no_apply_dynamic_relocs;
+
+ /* The number of bytes in the initial entry in the PLT. */
+ bfd_size_type plt_header_size;
+
+ /* The bytes of the initial PLT entry. */
+ const bfd_byte *plt0_entry;
+
+ /* The number of bytes in the subsequent PLT entries. */
+ bfd_size_type plt_entry_size;
+
+ /* The bytes of the subsequent PLT entry. */
+ const bfd_byte *plt_entry;
+
+ /* For convenience in allocate_dynrelocs. */
+ bfd *obfd;
+
+ /* The amount of space used by the reserved portion of the sgotplt
+ section, plus whatever space is used by the jump slots. */
+ bfd_vma sgotplt_jump_table_size;
+
+ /* The stub hash table. */
+ struct bfd_hash_table stub_hash_table;
+
+ /* Linker stub bfd. */
+ bfd *stub_bfd;
+
+ /* Linker call-backs. */
+ asection *(*add_stub_section) (const char *, asection *);
+ void (*layout_sections_again) (void);
+
+ /* Array to keep track of which stub sections have been created, and
+ information on stub grouping. */
+ struct map_stub
+ {
+ /* This is the section to which stubs in the group will be
+ attached. */
+ asection *link_sec;
+ /* The stub section. */
+ asection *stub_sec;
+ } *stub_group;
+
+ /* Assorted information used by elfNN_aarch64_size_stubs. */
+ unsigned int bfd_count;
+ unsigned int top_index;
+ asection **input_list;
+
+ /* JUMP_SLOT relocs for variant PCS symbols may be present. */
+ int variant_pcs;
+
+ /* The number of bytes in the PLT enty for the TLS descriptor. */
+ bfd_size_type tlsdesc_plt_entry_size;
+
+ /* Used by local STT_GNU_IFUNC symbols. */
+ htab_t loc_hash_table;
+ void * loc_hash_memory;
+};
+
+/* Create an entry in an AArch64 ELF linker hash table. */
+
+static struct bfd_hash_entry *
+elfNN_aarch64_link_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
+{
+ struct elf_aarch64_link_hash_entry *ret =
+ (struct elf_aarch64_link_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == NULL)
+ ret = bfd_hash_allocate (table,
+ sizeof (struct elf_aarch64_link_hash_entry));
+ if (ret == NULL)
+ return (struct bfd_hash_entry *) ret;
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct elf_aarch64_link_hash_entry *)
+ _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
+ table, string));
+ if (ret != NULL)
+ {
+ ret->got_type = GOT_UNKNOWN;
+ ret->def_protected = 0;
+ ret->plt_got_offset = (bfd_vma) - 1;
+ ret->stub_cache = NULL;
+ ret->tlsdesc_got_jump_table_offset = (bfd_vma) - 1;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Initialize an entry in the stub hash table. */
+
+static struct bfd_hash_entry *
+stub_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table, const char *string)
+{
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (entry == NULL)
+ {
+ entry = bfd_hash_allocate (table,
+ sizeof (struct
+ elf_aarch64_stub_hash_entry));
+ if (entry == NULL)
+ return entry;
+ }
+
+ /* Call the allocation method of the superclass. */
+ entry = bfd_hash_newfunc (entry, table, string);
+ if (entry != NULL)
+ {
+ struct elf_aarch64_stub_hash_entry *eh;
+
+ /* Initialize the local fields. */
+ eh = (struct elf_aarch64_stub_hash_entry *) entry;
+ eh->adrp_offset = 0;
+ eh->stub_sec = NULL;
+ eh->stub_offset = 0;
+ eh->target_value = 0;
+ eh->target_section = NULL;
+ eh->stub_type = aarch64_stub_none;
+ eh->h = NULL;
+ eh->id_sec = NULL;
+ }
+
+ return entry;
+}
+
+/* Compute a hash of a local hash entry. We use elf_link_hash_entry
+ for local symbol so that we can handle local STT_GNU_IFUNC symbols
+ as global symbol. We reuse indx and dynstr_index for local symbol
+ hash since they aren't used by global symbols in this backend. */
+
+static hashval_t
+elfNN_aarch64_local_htab_hash (const void *ptr)
+{
+ struct elf_link_hash_entry *h
+ = (struct elf_link_hash_entry *) ptr;
+ return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index);
+}
+
+/* Compare local hash entries. */
+
+static int
+elfNN_aarch64_local_htab_eq (const void *ptr1, const void *ptr2)
+{
+ struct elf_link_hash_entry *h1
+ = (struct elf_link_hash_entry *) ptr1;
+ struct elf_link_hash_entry *h2
+ = (struct elf_link_hash_entry *) ptr2;
+
+ return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index;
+}
+
+/* Find and/or create a hash entry for local symbol. */
+
+static struct elf_link_hash_entry *
+elfNN_aarch64_get_local_sym_hash (struct elf_aarch64_link_hash_table *htab,
+ bfd *abfd, const Elf_Internal_Rela *rel,
+ bool create)
+{
+ struct elf_aarch64_link_hash_entry e, *ret;
+ asection *sec = abfd->sections;
+ hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id,
+ ELFNN_R_SYM (rel->r_info));
+ void **slot;
+
+ e.root.indx = sec->id;
+ e.root.dynstr_index = ELFNN_R_SYM (rel->r_info);
+ slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h,
+ create ? INSERT : NO_INSERT);
+
+ if (!slot)
+ return NULL;
+
+ if (*slot)
+ {
+ ret = (struct elf_aarch64_link_hash_entry *) *slot;
+ return &ret->root;
+ }
+
+ ret = (struct elf_aarch64_link_hash_entry *)
+ objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
+ sizeof (struct elf_aarch64_link_hash_entry));
+ if (ret)
+ {
+ memset (ret, 0, sizeof (*ret));
+ ret->root.indx = sec->id;
+ ret->root.dynstr_index = ELFNN_R_SYM (rel->r_info);
+ ret->root.dynindx = -1;
+ *slot = ret;
+ }
+ return &ret->root;
+}
+
+/* Copy the extra info we tack onto an elf_link_hash_entry. */
+
+static void
+elfNN_aarch64_copy_indirect_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *dir,
+ struct elf_link_hash_entry *ind)
+{
+ struct elf_aarch64_link_hash_entry *edir, *eind;
+
+ edir = (struct elf_aarch64_link_hash_entry *) dir;
+ eind = (struct elf_aarch64_link_hash_entry *) ind;
+
+ if (ind->root.type == bfd_link_hash_indirect)
+ {
+ /* Copy over PLT info. */
+ if (dir->got.refcount <= 0)
+ {
+ edir->got_type = eind->got_type;
+ eind->got_type = GOT_UNKNOWN;
+ }
+ }
+
+ _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+}
+
+/* Merge non-visibility st_other attributes. */
+
+static void
+elfNN_aarch64_merge_symbol_attribute (struct elf_link_hash_entry *h,
+ unsigned int st_other,
+ bool definition,
+ bool dynamic ATTRIBUTE_UNUSED)
+{
+ if (definition)
+ {
+ struct elf_aarch64_link_hash_entry *eh
+ = (struct elf_aarch64_link_hash_entry *)h;
+ eh->def_protected = ELF_ST_VISIBILITY (st_other) == STV_PROTECTED;
+ }
+
+ unsigned int isym_sto = st_other & ~ELF_ST_VISIBILITY (-1);
+ unsigned int h_sto = h->other & ~ELF_ST_VISIBILITY (-1);
+
+ if (isym_sto == h_sto)
+ return;
+
+ if (isym_sto & ~STO_AARCH64_VARIANT_PCS)
+ /* Not fatal, this callback cannot fail. */
+ _bfd_error_handler (_("unknown attribute for symbol `%s': 0x%02x"),
+ h->root.root.string, isym_sto);
+
+ /* Note: Ideally we would warn about any attribute mismatch, but
+ this api does not allow that without substantial changes. */
+ if (isym_sto & STO_AARCH64_VARIANT_PCS)
+ h->other |= STO_AARCH64_VARIANT_PCS;
+}
+
+/* Destroy an AArch64 elf linker hash table. */
+
+static void
+elfNN_aarch64_link_hash_table_free (bfd *obfd)
+{
+ struct elf_aarch64_link_hash_table *ret
+ = (struct elf_aarch64_link_hash_table *) obfd->link.hash;
+
+ if (ret->loc_hash_table)
+ htab_delete (ret->loc_hash_table);
+ if (ret->loc_hash_memory)
+ objalloc_free ((struct objalloc *) ret->loc_hash_memory);
+
+ bfd_hash_table_free (&ret->stub_hash_table);
+ _bfd_elf_link_hash_table_free (obfd);
+}
+
+/* Create an AArch64 elf linker hash table. */
+
+static struct bfd_link_hash_table *
+elfNN_aarch64_link_hash_table_create (bfd *abfd)
+{
+ struct elf_aarch64_link_hash_table *ret;
+ size_t amt = sizeof (struct elf_aarch64_link_hash_table);
+
+ ret = bfd_zmalloc (amt);
+ if (ret == NULL)
+ return NULL;
+
+ if (!_bfd_elf_link_hash_table_init
+ (&ret->root, abfd, elfNN_aarch64_link_hash_newfunc,
+ sizeof (struct elf_aarch64_link_hash_entry), AARCH64_ELF_DATA))
+ {
+ free (ret);
+ return NULL;
+ }
+
+ ret->plt_header_size = PLT_ENTRY_SIZE;
+ ret->plt0_entry = elfNN_aarch64_small_plt0_entry;
+ ret->plt_entry_size = PLT_SMALL_ENTRY_SIZE;
+ ret->plt_entry = elfNN_aarch64_small_plt_entry;
+ ret->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
+ ret->obfd = abfd;
+ ret->root.tlsdesc_got = (bfd_vma) - 1;
+
+ if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc,
+ sizeof (struct elf_aarch64_stub_hash_entry)))
+ {
+ _bfd_elf_link_hash_table_free (abfd);
+ return NULL;
+ }
+
+ ret->loc_hash_table = htab_try_create (1024,
+ elfNN_aarch64_local_htab_hash,
+ elfNN_aarch64_local_htab_eq,
+ NULL);
+ ret->loc_hash_memory = objalloc_create ();
+ if (!ret->loc_hash_table || !ret->loc_hash_memory)
+ {
+ elfNN_aarch64_link_hash_table_free (abfd);
+ return NULL;
+ }
+ ret->root.root.hash_table_free = elfNN_aarch64_link_hash_table_free;
+
+ return &ret->root.root;
+}
+
+/* Perform relocation R_TYPE. Returns TRUE upon success, FALSE otherwise. */
+
+static bool
+aarch64_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section,
+ bfd_vma offset, bfd_vma value)
+{
+ reloc_howto_type *howto;
+ bfd_vma place;
+
+ howto = elfNN_aarch64_howto_from_type (input_bfd, r_type);
+ place = (input_section->output_section->vma + input_section->output_offset
+ + offset);
+
+ r_type = elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type);
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, r_type, place,
+ value, 0, false);
+ return _bfd_aarch64_elf_put_addend (input_bfd,
+ input_section->contents + offset, r_type,
+ howto, value) == bfd_reloc_ok;
+}
+
+static enum elf_aarch64_stub_type
+aarch64_select_branch_stub (bfd_vma value, bfd_vma place)
+{
+ if (aarch64_valid_for_adrp_p (value, place))
+ return aarch64_stub_adrp_branch;
+ return aarch64_stub_long_branch;
+}
+
+/* Determine the type of stub needed, if any, for a call. */
+
+static enum elf_aarch64_stub_type
+aarch64_type_of_stub (asection *input_sec,
+ const Elf_Internal_Rela *rel,
+ asection *sym_sec,
+ unsigned char st_type,
+ bfd_vma destination)
+{
+ bfd_vma location;
+ bfd_signed_vma branch_offset;
+ unsigned int r_type;
+ enum elf_aarch64_stub_type stub_type = aarch64_stub_none;
+
+ if (st_type != STT_FUNC
+ && (sym_sec == input_sec))
+ return stub_type;
+
+ /* Determine where the call point is. */
+ location = (input_sec->output_offset
+ + input_sec->output_section->vma + rel->r_offset);
+
+ branch_offset = (bfd_signed_vma) (destination - location);
+
+ r_type = ELFNN_R_TYPE (rel->r_info);
+
+ /* We don't want to redirect any old unconditional jump in this way,
+ only one which is being used for a sibcall, where it is
+ acceptable for the IP0 and IP1 registers to be clobbered. */
+ if ((r_type == AARCH64_R (CALL26) || r_type == AARCH64_R (JUMP26))
+ && (branch_offset > AARCH64_MAX_FWD_BRANCH_OFFSET
+ || branch_offset < AARCH64_MAX_BWD_BRANCH_OFFSET))
+ {
+ stub_type = aarch64_stub_long_branch;
+ }
+
+ return stub_type;
+}
+
+/* Build a name for an entry in the stub hash table. */
+
+static char *
+elfNN_aarch64_stub_name (const asection *input_section,
+ const asection *sym_sec,
+ const struct elf_aarch64_link_hash_entry *hash,
+ const Elf_Internal_Rela *rel)
+{
+ char *stub_name;
+ bfd_size_type len;
+
+ if (hash)
+ {
+ len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 16 + 1;
+ stub_name = bfd_malloc (len);
+ if (stub_name != NULL)
+ snprintf (stub_name, len, "%08x_%s+%" PRIx64,
+ (unsigned int) input_section->id,
+ hash->root.root.root.string,
+ (uint64_t) rel->r_addend);
+ }
+ else
+ {
+ len = 8 + 1 + 8 + 1 + 8 + 1 + 16 + 1;
+ stub_name = bfd_malloc (len);
+ if (stub_name != NULL)
+ snprintf (stub_name, len, "%08x_%x:%x+%" PRIx64,
+ (unsigned int) input_section->id,
+ (unsigned int) sym_sec->id,
+ (unsigned int) ELFNN_R_SYM (rel->r_info),
+ (uint64_t) rel->r_addend);
+ }
+
+ return stub_name;
+}
+
+/* Return TRUE if symbol H should be hashed in the `.gnu.hash' section. For
+ executable PLT slots where the executable never takes the address of those
+ functions, the function symbols are not added to the hash table. */
+
+static bool
+elf_aarch64_hash_symbol (struct elf_link_hash_entry *h)
+{
+ if (h->plt.offset != (bfd_vma) -1
+ && !h->def_regular
+ && !h->pointer_equality_needed)
+ return false;
+
+ return _bfd_elf_hash_symbol (h);
+}
+
+
+/* Look up an entry in the stub hash. Stub entries are cached because
+ creating the stub name takes a bit of time. */
+
+static struct elf_aarch64_stub_hash_entry *
+elfNN_aarch64_get_stub_entry (const asection *input_section,
+ const asection *sym_sec,
+ struct elf_link_hash_entry *hash,
+ const Elf_Internal_Rela *rel,
+ struct elf_aarch64_link_hash_table *htab)
+{
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+ struct elf_aarch64_link_hash_entry *h =
+ (struct elf_aarch64_link_hash_entry *) hash;
+ const asection *id_sec;
+
+ if ((input_section->flags & SEC_CODE) == 0)
+ return NULL;
+
+ /* If this input section is part of a group of sections sharing one
+ stub section, then use the id of the first section in the group.
+ Stub names need to include a section id, as there may well be
+ more than one stub used to reach say, printf, and we need to
+ distinguish between them. */
+ id_sec = htab->stub_group[input_section->id].link_sec;
+
+ if (h != NULL && h->stub_cache != NULL
+ && h->stub_cache->h == h && h->stub_cache->id_sec == id_sec)
+ {
+ stub_entry = h->stub_cache;
+ }
+ else
+ {
+ char *stub_name;
+
+ stub_name = elfNN_aarch64_stub_name (id_sec, sym_sec, h, rel);
+ if (stub_name == NULL)
+ return NULL;
+
+ stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table,
+ stub_name, false, false);
+ if (h != NULL)
+ h->stub_cache = stub_entry;
+
+ free (stub_name);
+ }
+
+ return stub_entry;
+}
+
+
+/* Create a stub section. */
+
+static asection *
+_bfd_aarch64_create_stub_section (asection *section,
+ struct elf_aarch64_link_hash_table *htab)
+{
+ size_t namelen;
+ bfd_size_type len;
+ char *s_name;
+
+ namelen = strlen (section->name);
+ len = namelen + sizeof (STUB_SUFFIX);
+ s_name = bfd_alloc (htab->stub_bfd, len);
+ if (s_name == NULL)
+ return NULL;
+
+ memcpy (s_name, section->name, namelen);
+ memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
+ return (*htab->add_stub_section) (s_name, section);
+}
+
+
+/* Find or create a stub section for a link section.
+
+ Fix or create the stub section used to collect stubs attached to
+ the specified link section. */
+
+static asection *
+_bfd_aarch64_get_stub_for_link_section (asection *link_section,
+ struct elf_aarch64_link_hash_table *htab)
+{
+ if (htab->stub_group[link_section->id].stub_sec == NULL)
+ htab->stub_group[link_section->id].stub_sec
+ = _bfd_aarch64_create_stub_section (link_section, htab);
+ return htab->stub_group[link_section->id].stub_sec;
+}
+
+
+/* Find or create a stub section in the stub group for an input
+ section. */
+
+static asection *
+_bfd_aarch64_create_or_find_stub_sec (asection *section,
+ struct elf_aarch64_link_hash_table *htab)
+{
+ asection *link_sec = htab->stub_group[section->id].link_sec;
+ return _bfd_aarch64_get_stub_for_link_section (link_sec, htab);
+}
+
+
+/* Add a new stub entry in the stub group associated with an input
+ section to the stub hash. Not all fields of the new stub entry are
+ initialised. */
+
+static struct elf_aarch64_stub_hash_entry *
+_bfd_aarch64_add_stub_entry_in_group (const char *stub_name,
+ asection *section,
+ struct elf_aarch64_link_hash_table *htab)
+{
+ asection *link_sec;
+ asection *stub_sec;
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+
+ link_sec = htab->stub_group[section->id].link_sec;
+ stub_sec = _bfd_aarch64_create_or_find_stub_sec (section, htab);
+
+ /* Enter this entry into the linker stub hash table. */
+ stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+ true, false);
+ if (stub_entry == NULL)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: cannot create stub entry %s"),
+ section->owner, stub_name);
+ return NULL;
+ }
+
+ stub_entry->stub_sec = stub_sec;
+ stub_entry->stub_offset = 0;
+ stub_entry->id_sec = link_sec;
+
+ return stub_entry;
+}
+
+/* Add a new stub entry in the final stub section to the stub hash.
+ Not all fields of the new stub entry are initialised. */
+
+static struct elf_aarch64_stub_hash_entry *
+_bfd_aarch64_add_stub_entry_after (const char *stub_name,
+ asection *link_section,
+ struct elf_aarch64_link_hash_table *htab)
+{
+ asection *stub_sec;
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+
+ stub_sec = NULL;
+ /* Only create the actual stub if we will end up needing it. */
+ if (htab->fix_erratum_843419 & ERRAT_ADRP)
+ stub_sec = _bfd_aarch64_get_stub_for_link_section (link_section, htab);
+ stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+ true, false);
+ if (stub_entry == NULL)
+ {
+ _bfd_error_handler (_("cannot create stub entry %s"), stub_name);
+ return NULL;
+ }
+
+ stub_entry->stub_sec = stub_sec;
+ stub_entry->stub_offset = 0;
+ stub_entry->id_sec = link_section;
+
+ return stub_entry;
+}
+
+
+static bool
+aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
+ void *in_arg)
+{
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+ asection *stub_sec;
+ bfd *stub_bfd;
+ bfd_byte *loc;
+ bfd_vma sym_value;
+ bfd_vma veneered_insn_loc;
+ bfd_vma veneer_entry_loc;
+ bfd_signed_vma branch_offset = 0;
+ unsigned int template_size;
+ const uint32_t *template;
+ unsigned int i;
+ struct bfd_link_info *info;
+
+ /* Massage our args to the form they really have. */
+ stub_entry = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+
+ info = (struct bfd_link_info *) in_arg;
+
+ /* Fail if the target section could not be assigned to an output
+ section. The user should fix his linker script. */
+ if (stub_entry->target_section->output_section == NULL
+ && info->non_contiguous_regions)
+ info->callbacks->einfo (_("%F%P: Could not assign `%pA' to an output section. "
+ "Retry without "
+ "--enable-non-contiguous-regions.\n"),
+ stub_entry->target_section);
+
+ stub_sec = stub_entry->stub_sec;
+
+ /* Make a note of the offset within the stubs for this entry. */
+ stub_entry->stub_offset = stub_sec->size;
+ loc = stub_sec->contents + stub_entry->stub_offset;
+
+ stub_bfd = stub_sec->owner;
+
+ /* This is the address of the stub destination. */
+ sym_value = (stub_entry->target_value
+ + stub_entry->target_section->output_offset
+ + stub_entry->target_section->output_section->vma);
+
+ if (stub_entry->stub_type == aarch64_stub_long_branch)
+ {
+ bfd_vma place = (stub_entry->stub_offset + stub_sec->output_section->vma
+ + stub_sec->output_offset);
+
+ /* See if we can relax the stub. */
+ if (aarch64_valid_for_adrp_p (sym_value, place))
+ stub_entry->stub_type = aarch64_select_branch_stub (sym_value, place);
+ }
+
+ switch (stub_entry->stub_type)
+ {
+ case aarch64_stub_adrp_branch:
+ template = aarch64_adrp_branch_stub;
+ template_size = sizeof (aarch64_adrp_branch_stub);
+ break;
+ case aarch64_stub_long_branch:
+ template = aarch64_long_branch_stub;
+ template_size = sizeof (aarch64_long_branch_stub);
+ break;
+ case aarch64_stub_erratum_835769_veneer:
+ template = aarch64_erratum_835769_stub;
+ template_size = sizeof (aarch64_erratum_835769_stub);
+ break;
+ case aarch64_stub_erratum_843419_veneer:
+ template = aarch64_erratum_843419_stub;
+ template_size = sizeof (aarch64_erratum_843419_stub);
+ break;
+ default:
+ abort ();
+ }
+
+ for (i = 0; i < (template_size / sizeof template[0]); i++)
+ {
+ bfd_putl32 (template[i], loc);
+ loc += 4;
+ }
+
+ template_size = (template_size + 7) & ~7;
+ stub_sec->size += template_size;
+
+ switch (stub_entry->stub_type)
+ {
+ case aarch64_stub_adrp_branch:
+ if (!aarch64_relocate (AARCH64_R (ADR_PREL_PG_HI21), stub_bfd, stub_sec,
+ stub_entry->stub_offset, sym_value))
+ /* The stub would not have been relaxed if the offset was out
+ of range. */
+ BFD_FAIL ();
+
+ if (!aarch64_relocate (AARCH64_R (ADD_ABS_LO12_NC), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 4, sym_value))
+ BFD_FAIL ();
+ break;
+
+ case aarch64_stub_long_branch:
+ /* We want the value relative to the address 12 bytes back from the
+ value itself. */
+ if (!aarch64_relocate (AARCH64_R (PRELNN), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 16, sym_value + 12))
+ BFD_FAIL ();
+ break;
+
+ case aarch64_stub_erratum_835769_veneer:
+ veneered_insn_loc = stub_entry->target_section->output_section->vma
+ + stub_entry->target_section->output_offset
+ + stub_entry->target_value;
+ veneer_entry_loc = stub_entry->stub_sec->output_section->vma
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_offset;
+ branch_offset = veneered_insn_loc - veneer_entry_loc;
+ branch_offset >>= 2;
+ branch_offset &= 0x3ffffff;
+ bfd_putl32 (stub_entry->veneered_insn,
+ stub_sec->contents + stub_entry->stub_offset);
+ bfd_putl32 (template[1] | branch_offset,
+ stub_sec->contents + stub_entry->stub_offset + 4);
+ break;
+
+ case aarch64_stub_erratum_843419_veneer:
+ if (!aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 4, sym_value + 4))
+ BFD_FAIL ();
+ break;
+
+ default:
+ abort ();
+ }
+
+ return true;
+}
+
+/* As above, but don't actually build the stub. Just bump offset so
+ we know stub section sizes. */
+
+static bool
+aarch64_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
+{
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+ struct elf_aarch64_link_hash_table *htab;
+ int size;
+
+ /* Massage our args to the form they really have. */
+ stub_entry = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+ htab = (struct elf_aarch64_link_hash_table *) in_arg;
+
+ switch (stub_entry->stub_type)
+ {
+ case aarch64_stub_adrp_branch:
+ size = sizeof (aarch64_adrp_branch_stub);
+ break;
+ case aarch64_stub_long_branch:
+ size = sizeof (aarch64_long_branch_stub);
+ break;
+ case aarch64_stub_erratum_835769_veneer:
+ size = sizeof (aarch64_erratum_835769_stub);
+ break;
+ case aarch64_stub_erratum_843419_veneer:
+ {
+ if (htab->fix_erratum_843419 == ERRAT_ADR)
+ return true;
+ size = sizeof (aarch64_erratum_843419_stub);
+ }
+ break;
+ default:
+ abort ();
+ }
+
+ size = (size + 7) & ~7;
+ stub_entry->stub_sec->size += size;
+ return true;
+}
+
+/* External entry points for sizing and building linker stubs. */
+
+/* Set up various things so that we can make a list of input sections
+ for each output section included in the link. Returns -1 on error,
+ 0 when no stubs will be needed, and 1 on success. */
+
+int
+elfNN_aarch64_setup_section_lists (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ bfd *input_bfd;
+ unsigned int bfd_count;
+ unsigned int top_id, top_index;
+ asection *section;
+ asection **input_list, **list;
+ size_t amt;
+ struct elf_aarch64_link_hash_table *htab =
+ elf_aarch64_hash_table (info);
+
+ if (!is_elf_hash_table (&htab->root.root))
+ return 0;
+
+ /* Count the number of input BFDs and find the top input section id. */
+ for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
+ input_bfd != NULL; input_bfd = input_bfd->link.next)
+ {
+ bfd_count += 1;
+ for (section = input_bfd->sections;
+ section != NULL; section = section->next)
+ {
+ if (top_id < section->id)
+ top_id = section->id;
+ }
+ }
+ htab->bfd_count = bfd_count;
+
+ amt = sizeof (struct map_stub) * (top_id + 1);
+ htab->stub_group = bfd_zmalloc (amt);
+ if (htab->stub_group == NULL)
+ return -1;
+
+ /* We can't use output_bfd->section_count here to find the top output
+ section index as some sections may have been removed, and
+ _bfd_strip_section_from_output doesn't renumber the indices. */
+ for (section = output_bfd->sections, top_index = 0;
+ section != NULL; section = section->next)
+ {
+ if (top_index < section->index)
+ top_index = section->index;
+ }
+
+ htab->top_index = top_index;
+ amt = sizeof (asection *) * (top_index + 1);
+ input_list = bfd_malloc (amt);
+ htab->input_list = input_list;
+ if (input_list == NULL)
+ return -1;
+
+ /* For sections we aren't interested in, mark their entries with a
+ value we can check later. */
+ list = input_list + top_index;
+ do
+ *list = bfd_abs_section_ptr;
+ while (list-- != input_list);
+
+ for (section = output_bfd->sections;
+ section != NULL; section = section->next)
+ {
+ if ((section->flags & SEC_CODE) != 0)
+ input_list[section->index] = NULL;
+ }
+
+ return 1;
+}
+
+/* Used by elfNN_aarch64_next_input_section and group_sections. */
+#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec)
+
+/* The linker repeatedly calls this function for each input section,
+ in the order that input sections are linked into output sections.
+ Build lists of input sections to determine groupings between which
+ we may insert linker stubs. */
+
+void
+elfNN_aarch64_next_input_section (struct bfd_link_info *info, asection *isec)
+{
+ struct elf_aarch64_link_hash_table *htab =
+ elf_aarch64_hash_table (info);
+
+ if (isec->output_section->index <= htab->top_index)
+ {
+ asection **list = htab->input_list + isec->output_section->index;
+
+ if (*list != bfd_abs_section_ptr && (isec->flags & SEC_CODE) != 0)
+ {
+ /* Steal the link_sec pointer for our list. */
+ /* This happens to make the list in reverse order,
+ which is what we want. */
+ PREV_SEC (isec) = *list;
+ *list = isec;
+ }
+ }
+}
+
+/* See whether we can group stub sections together. Grouping stub
+ sections may result in fewer stubs. More importantly, we need to
+ put all .init* and .fini* stubs at the beginning of the .init or
+ .fini output sections respectively, because glibc splits the
+ _init and _fini functions into multiple parts. Putting a stub in
+ the middle of a function is not a good idea. */
+
+static void
+group_sections (struct elf_aarch64_link_hash_table *htab,
+ bfd_size_type stub_group_size,
+ bool stubs_always_after_branch)
+{
+ asection **list = htab->input_list;
+
+ do
+ {
+ asection *tail = *list;
+ asection *head;
+
+ if (tail == bfd_abs_section_ptr)
+ continue;
+
+ /* Reverse the list: we must avoid placing stubs at the
+ beginning of the section because the beginning of the text
+ section may be required for an interrupt vector in bare metal
+ code. */
+#define NEXT_SEC PREV_SEC
+ head = NULL;
+ while (tail != NULL)
+ {
+ /* Pop from tail. */
+ asection *item = tail;
+ tail = PREV_SEC (item);
+
+ /* Push on head. */
+ NEXT_SEC (item) = head;
+ head = item;
+ }
+
+ while (head != NULL)
+ {
+ asection *curr;
+ asection *next;
+ bfd_vma stub_group_start = head->output_offset;
+ bfd_vma end_of_next;
+
+ curr = head;
+ while (NEXT_SEC (curr) != NULL)
+ {
+ next = NEXT_SEC (curr);
+ end_of_next = next->output_offset + next->size;
+ if (end_of_next - stub_group_start >= stub_group_size)
+ /* End of NEXT is too far from start, so stop. */
+ break;
+ /* Add NEXT to the group. */
+ curr = next;
+ }
+
+ /* OK, the size from the start to the start of CURR is less
+ than stub_group_size and thus can be handled by one stub
+ section. (Or the head section is itself larger than
+ stub_group_size, in which case we may be toast.)
+ We should really be keeping track of the total size of
+ stubs added here, as stubs contribute to the final output
+ section size. */
+ do
+ {
+ next = NEXT_SEC (head);
+ /* Set up this stub group. */
+ htab->stub_group[head->id].link_sec = curr;
+ }
+ while (head != curr && (head = next) != NULL);
+
+ /* But wait, there's more! Input sections up to stub_group_size
+ bytes after the stub section can be handled by it too. */
+ if (!stubs_always_after_branch)
+ {
+ stub_group_start = curr->output_offset + curr->size;
+
+ while (next != NULL)
+ {
+ end_of_next = next->output_offset + next->size;
+ if (end_of_next - stub_group_start >= stub_group_size)
+ /* End of NEXT is too far from stubs, so stop. */
+ break;
+ /* Add NEXT to the stub group. */
+ head = next;
+ next = NEXT_SEC (head);
+ htab->stub_group[head->id].link_sec = curr;
+ }
+ }
+ head = next;
+ }
+ }
+ while (list++ != htab->input_list + htab->top_index);
+
+ free (htab->input_list);
+}
+
+#undef PREV_SEC
+#undef PREV_SEC
+
+#define AARCH64_BITS(x, pos, n) (((x) >> (pos)) & ((1 << (n)) - 1))
+
+#define AARCH64_RT(insn) AARCH64_BITS (insn, 0, 5)
+#define AARCH64_RT2(insn) AARCH64_BITS (insn, 10, 5)
+#define AARCH64_RA(insn) AARCH64_BITS (insn, 10, 5)
+#define AARCH64_RD(insn) AARCH64_BITS (insn, 0, 5)
+#define AARCH64_RN(insn) AARCH64_BITS (insn, 5, 5)
+#define AARCH64_RM(insn) AARCH64_BITS (insn, 16, 5)
+
+#define AARCH64_MAC(insn) (((insn) & 0xff000000) == 0x9b000000)
+#define AARCH64_BIT(insn, n) AARCH64_BITS (insn, n, 1)
+#define AARCH64_OP31(insn) AARCH64_BITS (insn, 21, 3)
+#define AARCH64_ZR 0x1f
+
+/* All ld/st ops. See C4-182 of the ARM ARM. The encoding space for
+ LD_PCREL, LDST_RO, LDST_UI and LDST_UIMM cover prefetch ops. */
+
+#define AARCH64_LD(insn) (AARCH64_BIT (insn, 22) == 1)
+#define AARCH64_LDST(insn) (((insn) & 0x0a000000) == 0x08000000)
+#define AARCH64_LDST_EX(insn) (((insn) & 0x3f000000) == 0x08000000)
+#define AARCH64_LDST_PCREL(insn) (((insn) & 0x3b000000) == 0x18000000)
+#define AARCH64_LDST_NAP(insn) (((insn) & 0x3b800000) == 0x28000000)
+#define AARCH64_LDSTP_PI(insn) (((insn) & 0x3b800000) == 0x28800000)
+#define AARCH64_LDSTP_O(insn) (((insn) & 0x3b800000) == 0x29000000)
+#define AARCH64_LDSTP_PRE(insn) (((insn) & 0x3b800000) == 0x29800000)
+#define AARCH64_LDST_UI(insn) (((insn) & 0x3b200c00) == 0x38000000)
+#define AARCH64_LDST_PIIMM(insn) (((insn) & 0x3b200c00) == 0x38000400)
+#define AARCH64_LDST_U(insn) (((insn) & 0x3b200c00) == 0x38000800)
+#define AARCH64_LDST_PREIMM(insn) (((insn) & 0x3b200c00) == 0x38000c00)
+#define AARCH64_LDST_RO(insn) (((insn) & 0x3b200c00) == 0x38200800)
+#define AARCH64_LDST_UIMM(insn) (((insn) & 0x3b000000) == 0x39000000)
+#define AARCH64_LDST_SIMD_M(insn) (((insn) & 0xbfbf0000) == 0x0c000000)
+#define AARCH64_LDST_SIMD_M_PI(insn) (((insn) & 0xbfa00000) == 0x0c800000)
+#define AARCH64_LDST_SIMD_S(insn) (((insn) & 0xbf9f0000) == 0x0d000000)
+#define AARCH64_LDST_SIMD_S_PI(insn) (((insn) & 0xbf800000) == 0x0d800000)
+
+/* Classify an INSN if it is indeed a load/store.
+
+ Return TRUE if INSN is a LD/ST instruction otherwise return FALSE.
+
+ For scalar LD/ST instructions PAIR is FALSE, RT is returned and RT2
+ is set equal to RT.
+
+ For LD/ST pair instructions PAIR is TRUE, RT and RT2 are returned. */
+
+static bool
+aarch64_mem_op_p (uint32_t insn, unsigned int *rt, unsigned int *rt2,
+ bool *pair, bool *load)
+{
+ uint32_t opcode;
+ unsigned int r;
+ uint32_t opc = 0;
+ uint32_t v = 0;
+ uint32_t opc_v = 0;
+
+ /* Bail out quickly if INSN doesn't fall into the load-store
+ encoding space. */
+ if (!AARCH64_LDST (insn))
+ return false;
+
+ *pair = false;
+ *load = false;
+ if (AARCH64_LDST_EX (insn))
+ {
+ *rt = AARCH64_RT (insn);
+ *rt2 = *rt;
+ if (AARCH64_BIT (insn, 21) == 1)
+ {
+ *pair = true;
+ *rt2 = AARCH64_RT2 (insn);
+ }
+ *load = AARCH64_LD (insn);
+ return true;
+ }
+ else if (AARCH64_LDST_NAP (insn)
+ || AARCH64_LDSTP_PI (insn)
+ || AARCH64_LDSTP_O (insn)
+ || AARCH64_LDSTP_PRE (insn))
+ {
+ *pair = true;
+ *rt = AARCH64_RT (insn);
+ *rt2 = AARCH64_RT2 (insn);
+ *load = AARCH64_LD (insn);
+ return true;
+ }
+ else if (AARCH64_LDST_PCREL (insn)
+ || AARCH64_LDST_UI (insn)
+ || AARCH64_LDST_PIIMM (insn)
+ || AARCH64_LDST_U (insn)
+ || AARCH64_LDST_PREIMM (insn)
+ || AARCH64_LDST_RO (insn)
+ || AARCH64_LDST_UIMM (insn))
+ {
+ *rt = AARCH64_RT (insn);
+ *rt2 = *rt;
+ if (AARCH64_LDST_PCREL (insn))
+ *load = true;
+ opc = AARCH64_BITS (insn, 22, 2);
+ v = AARCH64_BIT (insn, 26);
+ opc_v = opc | (v << 2);
+ *load = (opc_v == 1 || opc_v == 2 || opc_v == 3
+ || opc_v == 5 || opc_v == 7);
+ return true;
+ }
+ else if (AARCH64_LDST_SIMD_M (insn)
+ || AARCH64_LDST_SIMD_M_PI (insn))
+ {
+ *rt = AARCH64_RT (insn);
+ *load = AARCH64_BIT (insn, 22);
+ opcode = (insn >> 12) & 0xf;
+ switch (opcode)
+ {
+ case 0:
+ case 2:
+ *rt2 = *rt + 3;
+ break;
+
+ case 4:
+ case 6:
+ *rt2 = *rt + 2;
+ break;
+
+ case 7:
+ *rt2 = *rt;
+ break;
+
+ case 8:
+ case 10:
+ *rt2 = *rt + 1;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+ }
+ else if (AARCH64_LDST_SIMD_S (insn)
+ || AARCH64_LDST_SIMD_S_PI (insn))
+ {
+ *rt = AARCH64_RT (insn);
+ r = (insn >> 21) & 1;
+ *load = AARCH64_BIT (insn, 22);
+ opcode = (insn >> 13) & 0x7;
+ switch (opcode)
+ {
+ case 0:
+ case 2:
+ case 4:
+ *rt2 = *rt + r;
+ break;
+
+ case 1:
+ case 3:
+ case 5:
+ *rt2 = *rt + (r == 0 ? 2 : 3);
+ break;
+
+ case 6:
+ *rt2 = *rt + r;
+ break;
+
+ case 7:
+ *rt2 = *rt + (r == 0 ? 2 : 3);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/* Return TRUE if INSN is multiply-accumulate. */
+
+static bool
+aarch64_mlxl_p (uint32_t insn)
+{
+ uint32_t op31 = AARCH64_OP31 (insn);
+
+ if (AARCH64_MAC (insn)
+ && (op31 == 0 || op31 == 1 || op31 == 5)
+ /* Exclude MUL instructions which are encoded as a multiple accumulate
+ with RA = XZR. */
+ && AARCH64_RA (insn) != AARCH64_ZR)
+ return true;
+
+ return false;
+}
+
+/* Some early revisions of the Cortex-A53 have an erratum (835769) whereby
+ it is possible for a 64-bit multiply-accumulate instruction to generate an
+ incorrect result. The details are quite complex and hard to
+ determine statically, since branches in the code may exist in some
+ circumstances, but all cases end with a memory (load, store, or
+ prefetch) instruction followed immediately by the multiply-accumulate
+ operation. We employ a linker patching technique, by moving the potentially
+ affected multiply-accumulate instruction into a patch region and replacing
+ the original instruction with a branch to the patch. This function checks
+ if INSN_1 is the memory operation followed by a multiply-accumulate
+ operation (INSN_2). Return TRUE if an erratum sequence is found, FALSE
+ if INSN_1 and INSN_2 are safe. */
+
+static bool
+aarch64_erratum_sequence (uint32_t insn_1, uint32_t insn_2)
+{
+ uint32_t rt;
+ uint32_t rt2;
+ uint32_t rn;
+ uint32_t rm;
+ uint32_t ra;
+ bool pair;
+ bool load;
+
+ if (aarch64_mlxl_p (insn_2)
+ && aarch64_mem_op_p (insn_1, &rt, &rt2, &pair, &load))
+ {
+ /* Any SIMD memory op is independent of the subsequent MLA
+ by definition of the erratum. */
+ if (AARCH64_BIT (insn_1, 26))
+ return true;
+
+ /* If not SIMD, check for integer memory ops and MLA relationship. */
+ rn = AARCH64_RN (insn_2);
+ ra = AARCH64_RA (insn_2);
+ rm = AARCH64_RM (insn_2);
+
+ /* If this is a load and there's a true(RAW) dependency, we are safe
+ and this is not an erratum sequence. */
+ if (load &&
+ (rt == rn || rt == rm || rt == ra
+ || (pair && (rt2 == rn || rt2 == rm || rt2 == ra))))
+ return false;
+
+ /* We conservatively put out stubs for all other cases (including
+ writebacks). */
+ return true;
+ }
+
+ return false;
+}
+
+/* Used to order a list of mapping symbols by address. */
+
+static int
+elf_aarch64_compare_mapping (const void *a, const void *b)
+{
+ const elf_aarch64_section_map *amap = (const elf_aarch64_section_map *) a;
+ const elf_aarch64_section_map *bmap = (const elf_aarch64_section_map *) b;
+
+ if (amap->vma > bmap->vma)
+ return 1;
+ else if (amap->vma < bmap->vma)
+ return -1;
+ else if (amap->type > bmap->type)
+ /* Ensure results do not depend on the host qsort for objects with
+ multiple mapping symbols at the same address by sorting on type
+ after vma. */
+ return 1;
+ else if (amap->type < bmap->type)
+ return -1;
+ else
+ return 0;
+}
+
+
+static char *
+_bfd_aarch64_erratum_835769_stub_name (unsigned num_fixes)
+{
+ char *stub_name = (char *) bfd_malloc
+ (strlen ("__erratum_835769_veneer_") + 16);
+ if (stub_name != NULL)
+ sprintf (stub_name,"__erratum_835769_veneer_%d", num_fixes);
+ return stub_name;
+}
+
+/* Scan for Cortex-A53 erratum 835769 sequence.
+
+ Return TRUE else FALSE on abnormal termination. */
+
+static bool
+_bfd_aarch64_erratum_835769_scan (bfd *input_bfd,
+ struct bfd_link_info *info,
+ unsigned int *num_fixes_p)
+{
+ asection *section;
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+ unsigned int num_fixes = *num_fixes_p;
+
+ if (htab == NULL)
+ return true;
+
+ for (section = input_bfd->sections;
+ section != NULL;
+ section = section->next)
+ {
+ bfd_byte *contents = NULL;
+ struct _aarch64_elf_section_data *sec_data;
+ unsigned int span;
+
+ if (elf_section_type (section) != SHT_PROGBITS
+ || (elf_section_flags (section) & SHF_EXECINSTR) == 0
+ || (section->flags & SEC_EXCLUDE) != 0
+ || (section->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
+ || (section->output_section == bfd_abs_section_ptr))
+ continue;
+
+ if (elf_section_data (section)->this_hdr.contents != NULL)
+ contents = elf_section_data (section)->this_hdr.contents;
+ else if (! bfd_malloc_and_get_section (input_bfd, section, &contents))
+ return false;
+
+ sec_data = elf_aarch64_section_data (section);
+
+ if (sec_data->mapcount)
+ qsort (sec_data->map, sec_data->mapcount,
+ sizeof (elf_aarch64_section_map), elf_aarch64_compare_mapping);
+
+ for (span = 0; span < sec_data->mapcount; span++)
+ {
+ unsigned int span_start = sec_data->map[span].vma;
+ unsigned int span_end = ((span == sec_data->mapcount - 1)
+ ? sec_data->map[0].vma + section->size
+ : sec_data->map[span + 1].vma);
+ unsigned int i;
+ char span_type = sec_data->map[span].type;
+
+ if (span_type == 'd')
+ continue;
+
+ for (i = span_start; i + 4 < span_end; i += 4)
+ {
+ uint32_t insn_1 = bfd_getl32 (contents + i);
+ uint32_t insn_2 = bfd_getl32 (contents + i + 4);
+
+ if (aarch64_erratum_sequence (insn_1, insn_2))
+ {
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+ char *stub_name = _bfd_aarch64_erratum_835769_stub_name (num_fixes);
+ if (! stub_name)
+ return false;
+
+ stub_entry = _bfd_aarch64_add_stub_entry_in_group (stub_name,
+ section,
+ htab);
+ if (! stub_entry)
+ return false;
+
+ stub_entry->stub_type = aarch64_stub_erratum_835769_veneer;
+ stub_entry->target_section = section;
+ stub_entry->target_value = i + 4;
+ stub_entry->veneered_insn = insn_2;
+ stub_entry->output_name = stub_name;
+ num_fixes++;
+ }
+ }
+ }
+ if (elf_section_data (section)->this_hdr.contents == NULL)
+ free (contents);
+ }
+
+ *num_fixes_p = num_fixes;
+
+ return true;
+}
+
+
+/* Test if instruction INSN is ADRP. */
+
+static bool
+_bfd_aarch64_adrp_p (uint32_t insn)
+{
+ return ((insn & AARCH64_ADRP_OP_MASK) == AARCH64_ADRP_OP);
+}
+
+
+/* Helper predicate to look for cortex-a53 erratum 843419 sequence 1. */
+
+static bool
+_bfd_aarch64_erratum_843419_sequence_p (uint32_t insn_1, uint32_t insn_2,
+ uint32_t insn_3)
+{
+ uint32_t rt;
+ uint32_t rt2;
+ bool pair;
+ bool load;
+
+ return (aarch64_mem_op_p (insn_2, &rt, &rt2, &pair, &load)
+ && (!pair
+ || (pair && !load))
+ && AARCH64_LDST_UIMM (insn_3)
+ && AARCH64_RN (insn_3) == AARCH64_RD (insn_1));
+}
+
+
+/* Test for the presence of Cortex-A53 erratum 843419 instruction sequence.
+
+ Return TRUE if section CONTENTS at offset I contains one of the
+ erratum 843419 sequences, otherwise return FALSE. If a sequence is
+ seen set P_VENEER_I to the offset of the final LOAD/STORE
+ instruction in the sequence.
+ */
+
+static bool
+_bfd_aarch64_erratum_843419_p (bfd_byte *contents, bfd_vma vma,
+ bfd_vma i, bfd_vma span_end,
+ bfd_vma *p_veneer_i)
+{
+ uint32_t insn_1 = bfd_getl32 (contents + i);
+
+ if (!_bfd_aarch64_adrp_p (insn_1))
+ return false;
+
+ if (span_end < i + 12)
+ return false;
+
+ uint32_t insn_2 = bfd_getl32 (contents + i + 4);
+ uint32_t insn_3 = bfd_getl32 (contents + i + 8);
+
+ if ((vma & 0xfff) != 0xff8 && (vma & 0xfff) != 0xffc)
+ return false;
+
+ if (_bfd_aarch64_erratum_843419_sequence_p (insn_1, insn_2, insn_3))
+ {
+ *p_veneer_i = i + 8;
+ return true;
+ }
+
+ if (span_end < i + 16)
+ return false;
+
+ uint32_t insn_4 = bfd_getl32 (contents + i + 12);
+
+ if (_bfd_aarch64_erratum_843419_sequence_p (insn_1, insn_2, insn_4))
+ {
+ *p_veneer_i = i + 12;
+ return true;
+ }
+
+ return false;
+}
+
+
+/* Resize all stub sections. */
+
+static void
+_bfd_aarch64_resize_stubs (struct elf_aarch64_link_hash_table *htab)
+{
+ asection *section;
+
+ /* OK, we've added some stubs. Find out the new size of the
+ stub sections. */
+ for (section = htab->stub_bfd->sections;
+ section != NULL; section = section->next)
+ {
+ /* Ignore non-stub sections. */
+ if (!strstr (section->name, STUB_SUFFIX))
+ continue;
+ section->size = 0;
+ }
+
+ bfd_hash_traverse (&htab->stub_hash_table, aarch64_size_one_stub, htab);
+
+ for (section = htab->stub_bfd->sections;
+ section != NULL; section = section->next)
+ {
+ if (!strstr (section->name, STUB_SUFFIX))
+ continue;
+
+ /* Add space for a branch. Add 8 bytes to keep section 8 byte aligned,
+ as long branch stubs contain a 64-bit address. */
+ if (section->size)
+ section->size += 8;
+
+ /* Ensure all stub sections have a size which is a multiple of
+ 4096. This is important in order to ensure that the insertion
+ of stub sections does not in itself move existing code around
+ in such a way that new errata sequences are created. We only do this
+ when the ADRP workaround is enabled. If only the ADR workaround is
+ enabled then the stubs workaround won't ever be used. */
+ if (htab->fix_erratum_843419 & ERRAT_ADRP)
+ if (section->size)
+ section->size = BFD_ALIGN (section->size, 0x1000);
+ }
+}
+
+/* Construct an erratum 843419 workaround stub name. */
+
+static char *
+_bfd_aarch64_erratum_843419_stub_name (asection *input_section,
+ bfd_vma offset)
+{
+ const bfd_size_type len = 8 + 4 + 1 + 8 + 1 + 16 + 1;
+ char *stub_name = bfd_malloc (len);
+
+ if (stub_name != NULL)
+ snprintf (stub_name, len, "e843419@%04x_%08x_%" PRIx64,
+ input_section->owner->id,
+ input_section->id,
+ (uint64_t) offset);
+ return stub_name;
+}
+
+/* Build a stub_entry structure describing an 843419 fixup.
+
+ The stub_entry constructed is populated with the bit pattern INSN
+ of the instruction located at OFFSET within input SECTION.
+
+ Returns TRUE on success. */
+
+static bool
+_bfd_aarch64_erratum_843419_fixup (uint32_t insn,
+ bfd_vma adrp_offset,
+ bfd_vma ldst_offset,
+ asection *section,
+ struct bfd_link_info *info)
+{
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+ char *stub_name;
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+
+ stub_name = _bfd_aarch64_erratum_843419_stub_name (section, ldst_offset);
+ if (stub_name == NULL)
+ return false;
+ stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+ false, false);
+ if (stub_entry)
+ {
+ free (stub_name);
+ return true;
+ }
+
+ /* We always place an 843419 workaround veneer in the stub section
+ attached to the input section in which an erratum sequence has
+ been found. This ensures that later in the link process (in
+ elfNN_aarch64_write_section) when we copy the veneered
+ instruction from the input section into the stub section the
+ copied instruction will have had any relocations applied to it.
+ If we placed workaround veneers in any other stub section then we
+ could not assume that all relocations have been processed on the
+ corresponding input section at the point we output the stub
+ section. */
+
+ stub_entry = _bfd_aarch64_add_stub_entry_after (stub_name, section, htab);
+ if (stub_entry == NULL)
+ {
+ free (stub_name);
+ return false;
+ }
+
+ stub_entry->adrp_offset = adrp_offset;
+ stub_entry->target_value = ldst_offset;
+ stub_entry->target_section = section;
+ stub_entry->stub_type = aarch64_stub_erratum_843419_veneer;
+ stub_entry->veneered_insn = insn;
+ stub_entry->output_name = stub_name;
+
+ return true;
+}
+
+
+/* Scan an input section looking for the signature of erratum 843419.
+
+ Scans input SECTION in INPUT_BFD looking for erratum 843419
+ signatures, for each signature found a stub_entry is created
+ describing the location of the erratum for subsequent fixup.
+
+ Return TRUE on successful scan, FALSE on failure to scan.
+ */
+
+static bool
+_bfd_aarch64_erratum_843419_scan (bfd *input_bfd, asection *section,
+ struct bfd_link_info *info)
+{
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+
+ if (htab == NULL)
+ return true;
+
+ if (elf_section_type (section) != SHT_PROGBITS
+ || (elf_section_flags (section) & SHF_EXECINSTR) == 0
+ || (section->flags & SEC_EXCLUDE) != 0
+ || (section->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
+ || (section->output_section == bfd_abs_section_ptr))
+ return true;
+
+ do
+ {
+ bfd_byte *contents = NULL;
+ struct _aarch64_elf_section_data *sec_data;
+ unsigned int span;
+
+ if (elf_section_data (section)->this_hdr.contents != NULL)
+ contents = elf_section_data (section)->this_hdr.contents;
+ else if (! bfd_malloc_and_get_section (input_bfd, section, &contents))
+ return false;
+
+ sec_data = elf_aarch64_section_data (section);
+
+ if (sec_data->mapcount)
+ qsort (sec_data->map, sec_data->mapcount,
+ sizeof (elf_aarch64_section_map), elf_aarch64_compare_mapping);
+
+ for (span = 0; span < sec_data->mapcount; span++)
+ {
+ unsigned int span_start = sec_data->map[span].vma;
+ unsigned int span_end = ((span == sec_data->mapcount - 1)
+ ? sec_data->map[0].vma + section->size
+ : sec_data->map[span + 1].vma);
+ unsigned int i;
+ char span_type = sec_data->map[span].type;
+
+ if (span_type == 'd')
+ continue;
+
+ for (i = span_start; i + 8 < span_end; i += 4)
+ {
+ bfd_vma vma = (section->output_section->vma
+ + section->output_offset
+ + i);
+ bfd_vma veneer_i;
+
+ if (_bfd_aarch64_erratum_843419_p
+ (contents, vma, i, span_end, &veneer_i))
+ {
+ uint32_t insn = bfd_getl32 (contents + veneer_i);
+
+ if (!_bfd_aarch64_erratum_843419_fixup (insn, i, veneer_i,
+ section, info))
+ return false;
+ }
+ }
+ }
+
+ if (elf_section_data (section)->this_hdr.contents == NULL)
+ free (contents);
+ }
+ while (0);
+
+ return true;
+}
+
+
+/* Determine and set the size of the stub section for a final link.
+
+ The basic idea here is to examine all the relocations looking for
+ PC-relative calls to a target that is unreachable with a "bl"
+ instruction. */
+
+bool
+elfNN_aarch64_size_stubs (bfd *output_bfd,
+ bfd *stub_bfd,
+ struct bfd_link_info *info,
+ bfd_signed_vma group_size,
+ asection * (*add_stub_section) (const char *,
+ asection *),
+ void (*layout_sections_again) (void))
+{
+ bfd_size_type stub_group_size;
+ bool stubs_always_before_branch;
+ bool stub_changed = false;
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+ unsigned int num_erratum_835769_fixes = 0;
+
+ /* Propagate mach to stub bfd, because it may not have been
+ finalized when we created stub_bfd. */
+ bfd_set_arch_mach (stub_bfd, bfd_get_arch (output_bfd),
+ bfd_get_mach (output_bfd));
+
+ /* Stash our params away. */
+ htab->stub_bfd = stub_bfd;
+ htab->add_stub_section = add_stub_section;
+ htab->layout_sections_again = layout_sections_again;
+ stubs_always_before_branch = group_size < 0;
+ if (group_size < 0)
+ stub_group_size = -group_size;
+ else
+ stub_group_size = group_size;
+
+ if (stub_group_size == 1)
+ {
+ /* Default values. */
+ /* AArch64 branch range is +-128MB. The value used is 1MB less. */
+ stub_group_size = 127 * 1024 * 1024;
+ }
+
+ group_sections (htab, stub_group_size, stubs_always_before_branch);
+
+ (*htab->layout_sections_again) ();
+
+ if (htab->fix_erratum_835769)
+ {
+ bfd *input_bfd;
+
+ for (input_bfd = info->input_bfds;
+ input_bfd != NULL; input_bfd = input_bfd->link.next)
+ {
+ if (!is_aarch64_elf (input_bfd)
+ || (input_bfd->flags & BFD_LINKER_CREATED) != 0)
+ continue;
+
+ if (!_bfd_aarch64_erratum_835769_scan (input_bfd, info,
+ &num_erratum_835769_fixes))
+ return false;
+ }
+
+ _bfd_aarch64_resize_stubs (htab);
+ (*htab->layout_sections_again) ();
+ }
+
+ if (htab->fix_erratum_843419 != ERRAT_NONE)
+ {
+ bfd *input_bfd;
+
+ for (input_bfd = info->input_bfds;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link.next)
+ {
+ asection *section;
+
+ if (!is_aarch64_elf (input_bfd)
+ || (input_bfd->flags & BFD_LINKER_CREATED) != 0)
+ continue;
+
+ for (section = input_bfd->sections;
+ section != NULL;
+ section = section->next)
+ if (!_bfd_aarch64_erratum_843419_scan (input_bfd, section, info))
+ return false;
+ }
+
+ _bfd_aarch64_resize_stubs (htab);
+ (*htab->layout_sections_again) ();
+ }
+
+ while (1)
+ {
+ bfd *input_bfd;
+
+ for (input_bfd = info->input_bfds;
+ input_bfd != NULL; input_bfd = input_bfd->link.next)
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+ asection *section;
+ Elf_Internal_Sym *local_syms = NULL;
+
+ if (!is_aarch64_elf (input_bfd)
+ || (input_bfd->flags & BFD_LINKER_CREATED) != 0)
+ continue;
+
+ /* We'll need the symbol table in a second. */
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ if (symtab_hdr->sh_info == 0)
+ continue;
+
+ /* Walk over each section attached to the input bfd. */
+ for (section = input_bfd->sections;
+ section != NULL; section = section->next)
+ {
+ Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
+
+ /* If there aren't any relocs, then there's nothing more
+ to do. */
+ if ((section->flags & SEC_RELOC) == 0
+ || section->reloc_count == 0
+ || (section->flags & SEC_CODE) == 0)
+ continue;
+
+ /* If this section is a link-once section that will be
+ discarded, then don't create any stubs. */
+ if (section->output_section == NULL
+ || section->output_section->owner != output_bfd)
+ continue;
+
+ /* Get the relocs. */
+ internal_relocs
+ = _bfd_elf_link_read_relocs (input_bfd, section, NULL,
+ NULL, info->keep_memory);
+ if (internal_relocs == NULL)
+ goto error_ret_free_local;
+
+ /* Now examine each relocation. */
+ irela = internal_relocs;
+ irelaend = irela + section->reloc_count;
+ for (; irela < irelaend; irela++)
+ {
+ unsigned int r_type, r_indx;
+ enum elf_aarch64_stub_type stub_type;
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+ asection *sym_sec;
+ bfd_vma sym_value;
+ bfd_vma destination;
+ struct elf_aarch64_link_hash_entry *hash;
+ const char *sym_name;
+ char *stub_name;
+ const asection *id_sec;
+ unsigned char st_type;
+ bfd_size_type len;
+
+ r_type = ELFNN_R_TYPE (irela->r_info);
+ r_indx = ELFNN_R_SYM (irela->r_info);
+
+ if (r_type >= (unsigned int) R_AARCH64_end)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ error_ret_free_internal:
+ if (elf_section_data (section)->relocs == NULL)
+ free (internal_relocs);
+ goto error_ret_free_local;
+ }
+
+ /* Only look for stubs on unconditional branch and
+ branch and link instructions. */
+ if (r_type != (unsigned int) AARCH64_R (CALL26)
+ && r_type != (unsigned int) AARCH64_R (JUMP26))
+ continue;
+
+ /* Now determine the call target, its name, value,
+ section. */
+ sym_sec = NULL;
+ sym_value = 0;
+ destination = 0;
+ hash = NULL;
+ sym_name = NULL;
+ if (r_indx < symtab_hdr->sh_info)
+ {
+ /* It's a local symbol. */
+ Elf_Internal_Sym *sym;
+ Elf_Internal_Shdr *hdr;
+
+ if (local_syms == NULL)
+ {
+ local_syms
+ = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (local_syms == NULL)
+ local_syms
+ = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (local_syms == NULL)
+ goto error_ret_free_internal;
+ }
+
+ sym = local_syms + r_indx;
+ hdr = elf_elfsections (input_bfd)[sym->st_shndx];
+ sym_sec = hdr->bfd_section;
+ if (!sym_sec)
+ /* This is an undefined symbol. It can never
+ be resolved. */
+ continue;
+
+ if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+ sym_value = sym->st_value;
+ destination = (sym_value + irela->r_addend
+ + sym_sec->output_offset
+ + sym_sec->output_section->vma);
+ st_type = ELF_ST_TYPE (sym->st_info);
+ sym_name
+ = bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ sym->st_name);
+ }
+ else
+ {
+ int e_indx;
+
+ e_indx = r_indx - symtab_hdr->sh_info;
+ hash = ((struct elf_aarch64_link_hash_entry *)
+ elf_sym_hashes (input_bfd)[e_indx]);
+
+ while (hash->root.root.type == bfd_link_hash_indirect
+ || hash->root.root.type == bfd_link_hash_warning)
+ hash = ((struct elf_aarch64_link_hash_entry *)
+ hash->root.root.u.i.link);
+
+ if (hash->root.root.type == bfd_link_hash_defined
+ || hash->root.root.type == bfd_link_hash_defweak)
+ {
+ struct elf_aarch64_link_hash_table *globals =
+ elf_aarch64_hash_table (info);
+ sym_sec = hash->root.root.u.def.section;
+ sym_value = hash->root.root.u.def.value;
+ /* For a destination in a shared library,
+ use the PLT stub as target address to
+ decide whether a branch stub is
+ needed. */
+ if (globals->root.splt != NULL && hash != NULL
+ && hash->root.plt.offset != (bfd_vma) - 1)
+ {
+ sym_sec = globals->root.splt;
+ sym_value = hash->root.plt.offset;
+ if (sym_sec->output_section != NULL)
+ destination = (sym_value
+ + sym_sec->output_offset
+ +
+ sym_sec->output_section->vma);
+ }
+ else if (sym_sec->output_section != NULL)
+ destination = (sym_value + irela->r_addend
+ + sym_sec->output_offset
+ + sym_sec->output_section->vma);
+ }
+ else if (hash->root.root.type == bfd_link_hash_undefined
+ || (hash->root.root.type
+ == bfd_link_hash_undefweak))
+ {
+ /* For a shared library, use the PLT stub as
+ target address to decide whether a long
+ branch stub is needed.
+ For absolute code, they cannot be handled. */
+ struct elf_aarch64_link_hash_table *globals =
+ elf_aarch64_hash_table (info);
+
+ if (globals->root.splt != NULL && hash != NULL
+ && hash->root.plt.offset != (bfd_vma) - 1)
+ {
+ sym_sec = globals->root.splt;
+ sym_value = hash->root.plt.offset;
+ if (sym_sec->output_section != NULL)
+ destination = (sym_value
+ + sym_sec->output_offset
+ +
+ sym_sec->output_section->vma);
+ }
+ else
+ continue;
+ }
+ else
+ {
+ bfd_set_error (bfd_error_bad_value);
+ goto error_ret_free_internal;
+ }
+ st_type = ELF_ST_TYPE (hash->root.type);
+ sym_name = hash->root.root.root.string;
+ }
+
+ /* Determine what (if any) linker stub is needed. */
+ stub_type = aarch64_type_of_stub (section, irela, sym_sec,
+ st_type, destination);
+ if (stub_type == aarch64_stub_none)
+ continue;
+
+ /* Support for grouping stub sections. */
+ id_sec = htab->stub_group[section->id].link_sec;
+
+ /* Get the name of this stub. */
+ stub_name = elfNN_aarch64_stub_name (id_sec, sym_sec, hash,
+ irela);
+ if (!stub_name)
+ goto error_ret_free_internal;
+
+ stub_entry =
+ aarch64_stub_hash_lookup (&htab->stub_hash_table,
+ stub_name, false, false);
+ if (stub_entry != NULL)
+ {
+ /* The proper stub has already been created. */
+ free (stub_name);
+ /* Always update this stub's target since it may have
+ changed after layout. */
+ stub_entry->target_value = sym_value + irela->r_addend;
+ continue;
+ }
+
+ stub_entry = _bfd_aarch64_add_stub_entry_in_group
+ (stub_name, section, htab);
+ if (stub_entry == NULL)
+ {
+ free (stub_name);
+ goto error_ret_free_internal;
+ }
+
+ stub_entry->target_value = sym_value + irela->r_addend;
+ stub_entry->target_section = sym_sec;
+ stub_entry->stub_type = stub_type;
+ stub_entry->h = hash;
+ stub_entry->st_type = st_type;
+
+ if (sym_name == NULL)
+ sym_name = "unnamed";
+ len = sizeof (STUB_ENTRY_NAME) + strlen (sym_name);
+ stub_entry->output_name = bfd_alloc (htab->stub_bfd, len);
+ if (stub_entry->output_name == NULL)
+ {
+ free (stub_name);
+ goto error_ret_free_internal;
+ }
+
+ snprintf (stub_entry->output_name, len, STUB_ENTRY_NAME,
+ sym_name);
+
+ stub_changed = true;
+ }
+
+ /* We're done with the internal relocs, free them. */
+ if (elf_section_data (section)->relocs == NULL)
+ free (internal_relocs);
+ }
+ }
+
+ if (!stub_changed)
+ break;
+
+ _bfd_aarch64_resize_stubs (htab);
+
+ /* Ask the linker to do its stuff. */
+ (*htab->layout_sections_again) ();
+ stub_changed = false;
+ }
+
+ return true;
+
+ error_ret_free_local:
+ return false;
+}
+
+/* Build all the stubs associated with the current output file. The
+ stubs are kept in a hash table attached to the main linker hash
+ table. We also set up the .plt entries for statically linked PIC
+ functions here. This function is called via aarch64_elf_finish in the
+ linker. */
+
+bool
+elfNN_aarch64_build_stubs (struct bfd_link_info *info)
+{
+ asection *stub_sec;
+ struct bfd_hash_table *table;
+ struct elf_aarch64_link_hash_table *htab;
+
+ htab = elf_aarch64_hash_table (info);
+
+ for (stub_sec = htab->stub_bfd->sections;
+ stub_sec != NULL; stub_sec = stub_sec->next)
+ {
+ bfd_size_type size;
+
+ /* Ignore non-stub sections. */
+ if (!strstr (stub_sec->name, STUB_SUFFIX))
+ continue;
+
+ /* Allocate memory to hold the linker stubs. */
+ size = stub_sec->size;
+ stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
+ if (stub_sec->contents == NULL && size != 0)
+ return false;
+ stub_sec->size = 0;
+
+ /* Add a branch around the stub section, and a nop, to keep it 8 byte
+ aligned, as long branch stubs contain a 64-bit address. */
+ bfd_putl32 (0x14000000 | (size >> 2), stub_sec->contents);
+ bfd_putl32 (INSN_NOP, stub_sec->contents + 4);
+ stub_sec->size += 8;
+ }
+
+ /* Build the stubs as directed by the stub hash table. */
+ table = &htab->stub_hash_table;
+ bfd_hash_traverse (table, aarch64_build_one_stub, info);
+
+ return true;
+}
+
+
+/* Add an entry to the code/data map for section SEC. */
+
+static void
+elfNN_aarch64_section_map_add (asection *sec, char type, bfd_vma vma)
+{
+ struct _aarch64_elf_section_data *sec_data =
+ elf_aarch64_section_data (sec);
+ unsigned int newidx;
+
+ if (sec_data->map == NULL)
+ {
+ sec_data->map = bfd_malloc (sizeof (elf_aarch64_section_map));
+ sec_data->mapcount = 0;
+ sec_data->mapsize = 1;
+ }
+
+ newidx = sec_data->mapcount++;
+
+ if (sec_data->mapcount > sec_data->mapsize)
+ {
+ sec_data->mapsize *= 2;
+ sec_data->map = bfd_realloc_or_free
+ (sec_data->map, sec_data->mapsize * sizeof (elf_aarch64_section_map));
+ }
+
+ if (sec_data->map)
+ {
+ sec_data->map[newidx].vma = vma;
+ sec_data->map[newidx].type = type;
+ }
+}
+
+
+/* Initialise maps of insn/data for input BFDs. */
+void
+bfd_elfNN_aarch64_init_maps (bfd *abfd)
+{
+ Elf_Internal_Sym *isymbuf;
+ Elf_Internal_Shdr *hdr;
+ unsigned int i, localsyms;
+
+ /* Make sure that we are dealing with an AArch64 elf binary. */
+ if (!is_aarch64_elf (abfd))
+ return;
+
+ if ((abfd->flags & DYNAMIC) != 0)
+ return;
+
+ hdr = &elf_symtab_hdr (abfd);
+ localsyms = hdr->sh_info;
+
+ /* Obtain a buffer full of symbols for this BFD. The hdr->sh_info field
+ should contain the number of local symbols, which should come before any
+ global symbols. Mapping symbols are always local. */
+ isymbuf = bfd_elf_get_elf_syms (abfd, hdr, localsyms, 0, NULL, NULL, NULL);
+
+ /* No internal symbols read? Skip this BFD. */
+ if (isymbuf == NULL)
+ return;
+
+ for (i = 0; i < localsyms; i++)
+ {
+ Elf_Internal_Sym *isym = &isymbuf[i];
+ asection *sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+ const char *name;
+
+ if (sec != NULL && ELF_ST_BIND (isym->st_info) == STB_LOCAL)
+ {
+ name = bfd_elf_string_from_elf_section (abfd,
+ hdr->sh_link,
+ isym->st_name);
+
+ if (bfd_is_aarch64_special_symbol_name
+ (name, BFD_AARCH64_SPECIAL_SYM_TYPE_MAP))
+ elfNN_aarch64_section_map_add (sec, name[1], isym->st_value);
+ }
+ }
+}
+
+static void
+setup_plt_values (struct bfd_link_info *link_info,
+ aarch64_plt_type plt_type)
+{
+ struct elf_aarch64_link_hash_table *globals;
+ globals = elf_aarch64_hash_table (link_info);
+
+ if (plt_type == PLT_BTI_PAC)
+ {
+ globals->plt0_entry = elfNN_aarch64_small_plt0_bti_entry;
+
+ /* Only in ET_EXEC we need PLTn with BTI. */
+ if (bfd_link_pde (link_info))
+ {
+ globals->plt_entry_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE;
+ globals->plt_entry = elfNN_aarch64_small_plt_bti_pac_entry;
+ }
+ else
+ {
+ globals->plt_entry_size = PLT_PAC_SMALL_ENTRY_SIZE;
+ globals->plt_entry = elfNN_aarch64_small_plt_pac_entry;
+ }
+ }
+ else if (plt_type == PLT_BTI)
+ {
+ globals->plt0_entry = elfNN_aarch64_small_plt0_bti_entry;
+
+ /* Only in ET_EXEC we need PLTn with BTI. */
+ if (bfd_link_pde (link_info))
+ {
+ globals->plt_entry_size = PLT_BTI_SMALL_ENTRY_SIZE;
+ globals->plt_entry = elfNN_aarch64_small_plt_bti_entry;
+ }
+ }
+ else if (plt_type == PLT_PAC)
+ {
+ globals->plt_entry_size = PLT_PAC_SMALL_ENTRY_SIZE;
+ globals->plt_entry = elfNN_aarch64_small_plt_pac_entry;
+ }
+}
+
+/* Set option values needed during linking. */
+void
+bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
+ struct bfd_link_info *link_info,
+ int no_enum_warn,
+ int no_wchar_warn, int pic_veneer,
+ int fix_erratum_835769,
+ erratum_84319_opts fix_erratum_843419,
+ int no_apply_dynamic_relocs,
+ aarch64_bti_pac_info bp_info)
+{
+ struct elf_aarch64_link_hash_table *globals;
+
+ globals = elf_aarch64_hash_table (link_info);
+ globals->pic_veneer = pic_veneer;
+ globals->fix_erratum_835769 = fix_erratum_835769;
+ /* If the default options are used, then ERRAT_ADR will be set by default
+ which will enable the ADRP->ADR workaround for the erratum 843419
+ workaround. */
+ globals->fix_erratum_843419 = fix_erratum_843419;
+ globals->no_apply_dynamic_relocs = no_apply_dynamic_relocs;
+
+ BFD_ASSERT (is_aarch64_elf (output_bfd));
+ elf_aarch64_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
+ elf_aarch64_tdata (output_bfd)->no_wchar_size_warning = no_wchar_warn;
+
+ switch (bp_info.bti_type)
+ {
+ case BTI_WARN:
+ elf_aarch64_tdata (output_bfd)->no_bti_warn = 0;
+ elf_aarch64_tdata (output_bfd)->gnu_and_prop
+ |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+ break;
+
+ default:
+ break;
+ }
+ elf_aarch64_tdata (output_bfd)->plt_type = bp_info.plt_type;
+ setup_plt_values (link_info, bp_info.plt_type);
+}
+
+static bfd_vma
+aarch64_calculate_got_entry_vma (struct elf_link_hash_entry *h,
+ struct elf_aarch64_link_hash_table
+ *globals, struct bfd_link_info *info,
+ bfd_vma value, bfd *output_bfd,
+ bool *unresolved_reloc_p)
+{
+ bfd_vma off = (bfd_vma) - 1;
+ asection *basegot = globals->root.sgot;
+ bool dyn = globals->root.dynamic_sections_created;
+
+ if (h != NULL)
+ {
+ BFD_ASSERT (basegot != NULL);
+ off = h->got.offset;
+ BFD_ASSERT (off != (bfd_vma) - 1);
+ if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+ || (bfd_link_pic (info)
+ && SYMBOL_REFERENCES_LOCAL (info, h))
+ || (ELF_ST_VISIBILITY (h->other)
+ && h->root.type == bfd_link_hash_undefweak))
+ {
+ /* 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 8 (4 in the case of ILP32), we use
+ the least significant bit to record whether we have
+ initialized it already.
+ When doing a dynamic link, we create a .rel(a).got relocation
+ entry to initialize the value. This is done in the
+ finish_dynamic_symbol routine. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_NN (output_bfd, value, basegot->contents + off);
+ h->got.offset |= 1;
+ }
+ }
+ else
+ *unresolved_reloc_p = false;
+
+ off = off + basegot->output_section->vma + basegot->output_offset;
+ }
+
+ return off;
+}
+
+/* Change R_TYPE to a more efficient access model where possible,
+ return the new reloc type. */
+
+static bfd_reloc_code_real_type
+aarch64_tls_transition_without_check (bfd_reloc_code_real_type r_type,
+ struct elf_link_hash_entry *h,
+ struct bfd_link_info *info)
+{
+ bool local_exec = bfd_link_executable (info)
+ && SYMBOL_REFERENCES_LOCAL (info, h);
+
+ switch (r_type)
+ {
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
+ return (local_exec
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1
+ : BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21);
+
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
+ return (local_exec
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC
+ : r_type);
+
+ case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
+ return (local_exec
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1
+ : BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19);
+
+ case BFD_RELOC_AARCH64_TLSDESC_LDR:
+ return (local_exec
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC
+ : BFD_RELOC_AARCH64_NONE);
+
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ return (local_exec
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC
+ : BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC);
+
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+ return (local_exec
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2
+ : BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1);
+
+ case BFD_RELOC_AARCH64_TLSDESC_LDNN_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
+ return (local_exec
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC
+ : BFD_RELOC_AARCH64_TLSIE_LDNN_GOTTPREL_LO12_NC);
+
+ case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ return local_exec ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1 : r_type;
+
+ case BFD_RELOC_AARCH64_TLSIE_LDNN_GOTTPREL_LO12_NC:
+ return local_exec ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC : r_type;
+
+ case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
+ return r_type;
+
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
+ return (local_exec
+ ? BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12
+ : BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19);
+
+ case BFD_RELOC_AARCH64_TLSDESC_ADD:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
+ case BFD_RELOC_AARCH64_TLSDESC_CALL:
+ /* Instructions with these relocations will become NOPs. */
+ return BFD_RELOC_AARCH64_NONE;
+
+ case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
+ return local_exec ? BFD_RELOC_AARCH64_NONE : r_type;
+
+#if ARCH_SIZE == 64
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+ return local_exec
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC
+ : BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC;
+
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
+ return local_exec
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2
+ : BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1;
+#endif
+
+ default:
+ break;
+ }
+
+ return r_type;
+}
+
+static unsigned int
+aarch64_reloc_got_type (bfd_reloc_code_real_type r_type)
+{
+ switch (r_type)
+ {
+ case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
+ case BFD_RELOC_AARCH64_GOT_LD_PREL19:
+ case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
+ case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+ case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+ case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
+ case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+ return GOT_NORMAL;
+
+ case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
+ case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
+ return GOT_TLS_GD;
+
+ case BFD_RELOC_AARCH64_TLSDESC_ADD:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
+ case BFD_RELOC_AARCH64_TLSDESC_CALL:
+ case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12:
+ case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
+ case BFD_RELOC_AARCH64_TLSDESC_LDR:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+ return GOT_TLSDESC_GD;
+
+ case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
+ case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
+ case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
+ return GOT_TLS_IE;
+
+ default:
+ break;
+ }
+ return GOT_UNKNOWN;
+}
+
+static bool
+aarch64_can_relax_tls (bfd *input_bfd,
+ struct bfd_link_info *info,
+ bfd_reloc_code_real_type r_type,
+ struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
+{
+ unsigned int symbol_got_type;
+ unsigned int reloc_got_type;
+
+ if (! IS_AARCH64_TLS_RELAX_RELOC (r_type))
+ return false;
+
+ symbol_got_type = elfNN_aarch64_symbol_got_type (h, input_bfd, r_symndx);
+ reloc_got_type = aarch64_reloc_got_type (r_type);
+
+ if (symbol_got_type == GOT_TLS_IE && GOT_TLS_GD_ANY_P (reloc_got_type))
+ return true;
+
+ if (!bfd_link_executable (info))
+ return false;
+
+ if (h && h->root.type == bfd_link_hash_undefweak)
+ return false;
+
+ return true;
+}
+
+/* Given the relocation code R_TYPE, return the relaxed bfd reloc
+ enumerator. */
+
+static bfd_reloc_code_real_type
+aarch64_tls_transition (bfd *input_bfd,
+ struct bfd_link_info *info,
+ unsigned int r_type,
+ struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
+{
+ bfd_reloc_code_real_type bfd_r_type
+ = elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type);
+
+ if (! aarch64_can_relax_tls (input_bfd, info, bfd_r_type, h, r_symndx))
+ return bfd_r_type;
+
+ return aarch64_tls_transition_without_check (bfd_r_type, h, info);
+}
+
+/* Return the base VMA address which should be subtracted from real addresses
+ when resolving R_AARCH64_TLS_DTPREL relocation. */
+
+static bfd_vma
+dtpoff_base (struct bfd_link_info *info)
+{
+ /* If tls_sec is NULL, we should have signalled an error already. */
+ BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
+ return elf_hash_table (info)->tls_sec->vma;
+}
+
+/* Return the base VMA address which should be subtracted from real addresses
+ when resolving R_AARCH64_TLS_GOTTPREL64 relocations. */
+
+static bfd_vma
+tpoff_base (struct bfd_link_info *info)
+{
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+
+ /* If tls_sec is NULL, we should have signalled an error already. */
+ BFD_ASSERT (htab->tls_sec != NULL);
+
+ bfd_vma base = align_power ((bfd_vma) TCB_SIZE,
+ htab->tls_sec->alignment_power);
+ return htab->tls_sec->vma - base;
+}
+
+static bfd_vma *
+symbol_got_offset_ref (bfd *input_bfd, struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
+{
+ /* Calculate the address of the GOT entry for symbol
+ referred to in h. */
+ if (h != NULL)
+ return &h->got.offset;
+ else
+ {
+ /* local symbol */
+ struct elf_aarch64_local_symbol *l;
+
+ l = elf_aarch64_locals (input_bfd);
+ return &l[r_symndx].got_offset;
+ }
+}
+
+static void
+symbol_got_offset_mark (bfd *input_bfd, struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
+{
+ bfd_vma *p;
+ p = symbol_got_offset_ref (input_bfd, h, r_symndx);
+ *p |= 1;
+}
+
+static int
+symbol_got_offset_mark_p (bfd *input_bfd, struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
+{
+ bfd_vma value;
+ value = * symbol_got_offset_ref (input_bfd, h, r_symndx);
+ return value & 1;
+}
+
+static bfd_vma
+symbol_got_offset (bfd *input_bfd, struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
+{
+ bfd_vma value;
+ value = * symbol_got_offset_ref (input_bfd, h, r_symndx);
+ value &= ~1;
+ return value;
+}
+
+static bfd_vma *
+symbol_tlsdesc_got_offset_ref (bfd *input_bfd, struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
+{
+ /* Calculate the address of the GOT entry for symbol
+ referred to in h. */
+ if (h != NULL)
+ {
+ struct elf_aarch64_link_hash_entry *eh;
+ eh = (struct elf_aarch64_link_hash_entry *) h;
+ return &eh->tlsdesc_got_jump_table_offset;
+ }
+ else
+ {
+ /* local symbol */
+ struct elf_aarch64_local_symbol *l;
+
+ l = elf_aarch64_locals (input_bfd);
+ return &l[r_symndx].tlsdesc_got_jump_table_offset;
+ }
+}
+
+static void
+symbol_tlsdesc_got_offset_mark (bfd *input_bfd, struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
+{
+ bfd_vma *p;
+ p = symbol_tlsdesc_got_offset_ref (input_bfd, h, r_symndx);
+ *p |= 1;
+}
+
+static int
+symbol_tlsdesc_got_offset_mark_p (bfd *input_bfd,
+ struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
+{
+ bfd_vma value;
+ value = * symbol_tlsdesc_got_offset_ref (input_bfd, h, r_symndx);
+ return value & 1;
+}
+
+static bfd_vma
+symbol_tlsdesc_got_offset (bfd *input_bfd, struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
+{
+ bfd_vma value;
+ value = * symbol_tlsdesc_got_offset_ref (input_bfd, h, r_symndx);
+ value &= ~1;
+ return value;
+}
+
+/* Data for make_branch_to_erratum_835769_stub(). */
+
+struct erratum_835769_branch_to_stub_data
+{
+ struct bfd_link_info *info;
+ asection *output_section;
+ bfd_byte *contents;
+};
+
+/* Helper to insert branches to erratum 835769 stubs in the right
+ places for a particular section. */
+
+static bool
+make_branch_to_erratum_835769_stub (struct bfd_hash_entry *gen_entry,
+ void *in_arg)
+{
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+ struct erratum_835769_branch_to_stub_data *data;
+ bfd_byte *contents;
+ unsigned long branch_insn = 0;
+ bfd_vma veneered_insn_loc, veneer_entry_loc;
+ bfd_signed_vma branch_offset;
+ unsigned int target;
+ bfd *abfd;
+
+ stub_entry = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+ data = (struct erratum_835769_branch_to_stub_data *) in_arg;
+
+ if (stub_entry->target_section != data->output_section
+ || stub_entry->stub_type != aarch64_stub_erratum_835769_veneer)
+ return true;
+
+ contents = data->contents;
+ veneered_insn_loc = stub_entry->target_section->output_section->vma
+ + stub_entry->target_section->output_offset
+ + stub_entry->target_value;
+ veneer_entry_loc = stub_entry->stub_sec->output_section->vma
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_offset;
+ branch_offset = veneer_entry_loc - veneered_insn_loc;
+
+ abfd = stub_entry->target_section->owner;
+ if (!aarch64_valid_branch_p (veneer_entry_loc, veneered_insn_loc))
+ _bfd_error_handler
+ (_("%pB: error: erratum 835769 stub out "
+ "of range (input file too large)"), abfd);
+
+ target = stub_entry->target_value;
+ branch_insn = 0x14000000;
+ branch_offset >>= 2;
+ branch_offset &= 0x3ffffff;
+ branch_insn |= branch_offset;
+ bfd_putl32 (branch_insn, &contents[target]);
+
+ return true;
+}
+
+
+static bool
+_bfd_aarch64_erratum_843419_branch_to_stub (struct bfd_hash_entry *gen_entry,
+ void *in_arg)
+{
+ struct elf_aarch64_stub_hash_entry *stub_entry
+ = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+ struct erratum_835769_branch_to_stub_data *data
+ = (struct erratum_835769_branch_to_stub_data *) in_arg;
+ struct bfd_link_info *info;
+ struct elf_aarch64_link_hash_table *htab;
+ bfd_byte *contents;
+ asection *section;
+ bfd *abfd;
+ bfd_vma place;
+ uint32_t insn;
+
+ info = data->info;
+ contents = data->contents;
+ section = data->output_section;
+
+ htab = elf_aarch64_hash_table (info);
+
+ if (stub_entry->target_section != section
+ || stub_entry->stub_type != aarch64_stub_erratum_843419_veneer)
+ return true;
+
+ BFD_ASSERT (((htab->fix_erratum_843419 & ERRAT_ADRP) && stub_entry->stub_sec)
+ || (htab->fix_erratum_843419 & ERRAT_ADR));
+
+ /* Only update the stub section if we have one. We should always have one if
+ we're allowed to use the ADRP errata workaround, otherwise it is not
+ required. */
+ if (stub_entry->stub_sec)
+ {
+ insn = bfd_getl32 (contents + stub_entry->target_value);
+ bfd_putl32 (insn,
+ stub_entry->stub_sec->contents + stub_entry->stub_offset);
+ }
+
+ place = (section->output_section->vma + section->output_offset
+ + stub_entry->adrp_offset);
+ insn = bfd_getl32 (contents + stub_entry->adrp_offset);
+
+ if (!_bfd_aarch64_adrp_p (insn))
+ abort ();
+
+ bfd_signed_vma imm =
+ (_bfd_aarch64_sign_extend
+ ((bfd_vma) _bfd_aarch64_decode_adrp_imm (insn) << 12, 33)
+ - (place & 0xfff));
+
+ if ((htab->fix_erratum_843419 & ERRAT_ADR)
+ && (imm >= AARCH64_MIN_ADRP_IMM && imm <= AARCH64_MAX_ADRP_IMM))
+ {
+ insn = (_bfd_aarch64_reencode_adr_imm (AARCH64_ADR_OP, imm)
+ | AARCH64_RT (insn));
+ bfd_putl32 (insn, contents + stub_entry->adrp_offset);
+ /* Stub is not needed, don't map it out. */
+ stub_entry->stub_type = aarch64_stub_none;
+ }
+ else if (htab->fix_erratum_843419 & ERRAT_ADRP)
+ {
+ bfd_vma veneered_insn_loc;
+ bfd_vma veneer_entry_loc;
+ bfd_signed_vma branch_offset;
+ uint32_t branch_insn;
+
+ veneered_insn_loc = stub_entry->target_section->output_section->vma
+ + stub_entry->target_section->output_offset
+ + stub_entry->target_value;
+ veneer_entry_loc = stub_entry->stub_sec->output_section->vma
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_offset;
+ branch_offset = veneer_entry_loc - veneered_insn_loc;
+
+ abfd = stub_entry->target_section->owner;
+ if (!aarch64_valid_branch_p (veneer_entry_loc, veneered_insn_loc))
+ _bfd_error_handler
+ (_("%pB: error: erratum 843419 stub out "
+ "of range (input file too large)"), abfd);
+
+ branch_insn = 0x14000000;
+ branch_offset >>= 2;
+ branch_offset &= 0x3ffffff;
+ branch_insn |= branch_offset;
+ bfd_putl32 (branch_insn, contents + stub_entry->target_value);
+ }
+ else
+ {
+ abfd = stub_entry->target_section->owner;
+ _bfd_error_handler
+ (_("%pB: error: erratum 843419 immediate 0x%" PRIx64
+ " out of range for ADR (input file too large) and "
+ "--fix-cortex-a53-843419=adr used. Run the linker with "
+ "--fix-cortex-a53-843419=full instead"),
+ abfd, (uint64_t) (bfd_vma) imm);
+ bfd_set_error (bfd_error_bad_value);
+ /* This function is called inside a hashtable traversal and the error
+ handlers called above turn into non-fatal errors. Which means this
+ case ld returns an exit code 0 and also produces a broken object file.
+ To prevent this, issue a hard abort. */
+ BFD_FAIL ();
+ }
+ return true;
+}
+
+
+static bool
+elfNN_aarch64_write_section (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *link_info,
+ asection *sec,
+ bfd_byte *contents)
+
+{
+ struct elf_aarch64_link_hash_table *globals =
+ elf_aarch64_hash_table (link_info);
+
+ if (globals == NULL)
+ return false;
+
+ /* Fix code to point to erratum 835769 stubs. */
+ if (globals->fix_erratum_835769)
+ {
+ struct erratum_835769_branch_to_stub_data data;
+
+ data.info = link_info;
+ data.output_section = sec;
+ data.contents = contents;
+ bfd_hash_traverse (&globals->stub_hash_table,
+ make_branch_to_erratum_835769_stub, &data);
+ }
+
+ if (globals->fix_erratum_843419)
+ {
+ struct erratum_835769_branch_to_stub_data data;
+
+ data.info = link_info;
+ data.output_section = sec;
+ data.contents = contents;
+ bfd_hash_traverse (&globals->stub_hash_table,
+ _bfd_aarch64_erratum_843419_branch_to_stub, &data);
+ }
+
+ return false;
+}
+
+/* Return TRUE if RELOC is a relocation against the base of GOT table. */
+
+static bool
+aarch64_relocation_aginst_gp_p (bfd_reloc_code_real_type reloc)
+{
+ return (reloc == BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14
+ || reloc == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15
+ || reloc == BFD_RELOC_AARCH64_LD64_GOTOFF_LO15
+ || reloc == BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC
+ || reloc == BFD_RELOC_AARCH64_MOVW_GOTOFF_G1);
+}
+
+/* Perform a relocation as part of a final link. The input relocation type
+ should be TLS relaxed. */
+
+static bfd_reloc_status_type
+elfNN_aarch64_final_link_relocate (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,
+ struct elf_link_hash_entry *h,
+ bool *unresolved_reloc_p,
+ bool save_addend,
+ bfd_vma *saved_addend,
+ Elf_Internal_Sym *sym)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ unsigned int r_type = howto->type;
+ bfd_reloc_code_real_type bfd_r_type
+ = elfNN_aarch64_bfd_reloc_from_howto (howto);
+ unsigned long r_symndx;
+ bfd_byte *hit_data = contents + rel->r_offset;
+ bfd_vma place, off, got_entry_addr = 0;
+ bfd_signed_vma signed_addend;
+ struct elf_aarch64_link_hash_table *globals;
+ bool weak_undef_p;
+ bool relative_reloc;
+ asection *base_got;
+ bfd_vma orig_value = value;
+ bool resolved_to_zero;
+ bool abs_symbol_p;
+
+ globals = elf_aarch64_hash_table (info);
+
+ symtab_hdr = &elf_symtab_hdr (input_bfd);
+
+ BFD_ASSERT (is_aarch64_elf (input_bfd));
+
+ r_symndx = ELFNN_R_SYM (rel->r_info);
+
+ place = input_section->output_section->vma
+ + input_section->output_offset + rel->r_offset;
+
+ /* Get addend, accumulating the addend for consecutive relocs
+ which refer to the same offset. */
+ signed_addend = saved_addend ? *saved_addend : 0;
+ signed_addend += rel->r_addend;
+
+ weak_undef_p = (h ? h->root.type == bfd_link_hash_undefweak
+ : bfd_is_und_section (sym_sec));
+ abs_symbol_p = h != NULL && bfd_is_abs_symbol (&h->root);
+
+
+ /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
+ it here if it is defined in a non-shared object. */
+ if (h != NULL
+ && h->type == STT_GNU_IFUNC
+ && (input_section->flags & SEC_ALLOC)
+ && h->def_regular)
+ {
+ asection *plt;
+ const char *name;
+ bfd_vma addend = 0;
+
+ if ((input_section->flags & SEC_ALLOC) == 0)
+ {
+ /* If this is a SHT_NOTE section without SHF_ALLOC, treat
+ STT_GNU_IFUNC symbol as STT_FUNC. */
+ if (elf_section_type (input_section) == SHT_NOTE)
+ goto skip_ifunc;
+
+ /* Dynamic relocs are not propagated for SEC_DEBUGGING
+ sections because such sections are not SEC_ALLOC and
+ thus ld.so will not process them. */
+ if ((input_section->flags & SEC_DEBUGGING) != 0)
+ return bfd_reloc_ok;
+
+ if (h->root.root.string)
+ name = h->root.root.string;
+ else
+ name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, NULL);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA+%#" PRIx64 "): "
+ "unresolvable %s relocation against symbol `%s'"),
+ input_bfd, input_section, (uint64_t) rel->r_offset,
+ howto->name, name);
+ bfd_set_error (bfd_error_bad_value);
+ return bfd_reloc_notsupported;
+ }
+ else if (h->plt.offset == (bfd_vma) -1)
+ goto bad_ifunc_reloc;
+
+ /* STT_GNU_IFUNC symbol must go through PLT. */
+ plt = globals->root.splt ? globals->root.splt : globals->root.iplt;
+ value = (plt->output_section->vma + plt->output_offset + h->plt.offset);
+
+ switch (bfd_r_type)
+ {
+ default:
+ bad_ifunc_reloc:
+ if (h->root.root.string)
+ name = h->root.root.string;
+ else
+ name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
+ NULL);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against STT_GNU_IFUNC "
+ "symbol `%s' isn't handled by %s"), input_bfd,
+ howto->name, name, __FUNCTION__);
+ bfd_set_error (bfd_error_bad_value);
+ return bfd_reloc_notsupported;
+
+ case BFD_RELOC_AARCH64_NN:
+ if (rel->r_addend != 0)
+ {
+ if (h->root.root.string)
+ name = h->root.root.string;
+ else
+ name = bfd_elf_sym_name (input_bfd, symtab_hdr,
+ sym, NULL);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against STT_GNU_IFUNC "
+ "symbol `%s' has non-zero addend: %" PRId64),
+ input_bfd, howto->name, name, (int64_t) rel->r_addend);
+ bfd_set_error (bfd_error_bad_value);
+ return bfd_reloc_notsupported;
+ }
+
+ /* Generate dynamic relocation only when there is a
+ non-GOT reference in a shared object. */
+ if (bfd_link_pic (info) && h->non_got_ref)
+ {
+ Elf_Internal_Rela outrel;
+ asection *sreloc;
+
+ /* Need a dynamic relocation to get the real function
+ address. */
+ outrel.r_offset = _bfd_elf_section_offset (output_bfd,
+ info,
+ input_section,
+ rel->r_offset);
+ if (outrel.r_offset == (bfd_vma) -1
+ || outrel.r_offset == (bfd_vma) -2)
+ abort ();
+
+ outrel.r_offset += (input_section->output_section->vma
+ + input_section->output_offset);
+
+ if (h->dynindx == -1
+ || h->forced_local
+ || bfd_link_executable (info))
+ {
+ /* This symbol is resolved locally. */
+ outrel.r_info = ELFNN_R_INFO (0, AARCH64_R (IRELATIVE));
+ outrel.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
+ else
+ {
+ outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
+ outrel.r_addend = 0;
+ }
+
+ sreloc = globals->root.irelifunc;
+ elf_append_rela (output_bfd, sreloc, &outrel);
+
+ /* 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. For an
+ internal symbol, we have updated addend. */
+ return bfd_reloc_ok;
+ }
+ /* FALLTHROUGH */
+ case BFD_RELOC_AARCH64_CALL26:
+ case BFD_RELOC_AARCH64_JUMP26:
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ signed_addend,
+ weak_undef_p);
+ return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type,
+ howto, value);
+ case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
+ case BFD_RELOC_AARCH64_GOT_LD_PREL19:
+ case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
+ case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+ case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+ case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+ case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+ base_got = globals->root.sgot;
+ off = h->got.offset;
+
+ if (base_got == NULL)
+ abort ();
+
+ if (off == (bfd_vma) -1)
+ {
+ bfd_vma plt_index;
+
+ /* We can't use h->got.offset here to save state, or
+ even just remember the offset, as finish_dynamic_symbol
+ would use that as offset into .got. */
+
+ if (globals->root.splt != NULL)
+ {
+ plt_index = ((h->plt.offset - globals->plt_header_size) /
+ globals->plt_entry_size);
+ off = (plt_index + 3) * GOT_ENTRY_SIZE;
+ base_got = globals->root.sgotplt;
+ }
+ else
+ {
+ plt_index = h->plt.offset / globals->plt_entry_size;
+ off = plt_index * GOT_ENTRY_SIZE;
+ base_got = globals->root.igotplt;
+ }
+
+ if (h->dynindx == -1
+ || h->forced_local
+ || info->symbolic)
+ {
+ /* This references the local definition. We must
+ initialize this entry in the global offset table.
+ Since the offset must always be a multiple of 8,
+ we use the least significant bit to record
+ whether we have initialized it already.
+
+ When doing a dynamic link, we create a .rela.got
+ relocation entry to initialize the value. This
+ is done in the finish_dynamic_symbol routine. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_NN (output_bfd, value,
+ base_got->contents + off);
+ /* Note that this is harmless as -1 | 1 still is -1. */
+ h->got.offset |= 1;
+ }
+ }
+ value = (base_got->output_section->vma
+ + base_got->output_offset + off);
+ }
+ else
+ value = aarch64_calculate_got_entry_vma (h, globals, info,
+ value, output_bfd,
+ unresolved_reloc_p);
+
+ if (aarch64_relocation_aginst_gp_p (bfd_r_type))
+ addend = (globals->root.sgot->output_section->vma
+ + globals->root.sgot->output_offset);
+
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ addend, weak_undef_p);
+ return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type, howto, value);
+ case BFD_RELOC_AARCH64_ADD_LO12:
+ case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+ break;
+ }
+ }
+
+ skip_ifunc:
+ resolved_to_zero = (h != NULL
+ && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+
+ switch (bfd_r_type)
+ {
+ case BFD_RELOC_AARCH64_NONE:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD:
+ case BFD_RELOC_AARCH64_TLSDESC_CALL:
+ case BFD_RELOC_AARCH64_TLSDESC_LDR:
+ *unresolved_reloc_p = false;
+ return bfd_reloc_ok;
+
+ case BFD_RELOC_AARCH64_NN:
+
+ /* When generating a shared object or relocatable executable, these
+ relocations are copied into the output file to be resolved at
+ run time. */
+ if (((bfd_link_pic (info)
+ || globals->root.is_relocatable_executable)
+ && (input_section->flags & SEC_ALLOC)
+ && (h == NULL
+ || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && !resolved_to_zero)
+ || h->root.type != bfd_link_hash_undefweak))
+ /* Or we are creating an executable, we may need to keep relocations
+ for symbols satisfied by a dynamic library if we manage to avoid
+ copy relocs for the symbol. */
+ || (ELIMINATE_COPY_RELOCS
+ && !bfd_link_pic (info)
+ && h != NULL
+ && (input_section->flags & SEC_ALLOC)
+ && h->dynindx != -1
+ && !h->non_got_ref
+ && ((h->def_dynamic
+ && !h->def_regular)
+ || h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_undefined)))
+ {
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+ bool skip, relocate;
+ asection *sreloc;
+
+ *unresolved_reloc_p = false;
+
+ skip = false;
+ relocate = false;
+
+ outrel.r_addend = signed_addend;
+ 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;
+ }
+ else if (abs_symbol_p)
+ {
+ /* Local absolute symbol. */
+ skip = (h->forced_local || (h->dynindx == -1));
+ relocate = skip;
+ }
+
+ outrel.r_offset += (input_section->output_section->vma
+ + input_section->output_offset);
+
+ if (skip)
+ memset (&outrel, 0, sizeof outrel);
+ else if (h != NULL
+ && h->dynindx != -1
+ && (!bfd_link_pic (info)
+ || !(bfd_link_pie (info) || SYMBOLIC_BIND (info, h))
+ || !h->def_regular))
+ outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
+ else
+ {
+ int symbol;
+
+ /* On SVR4-ish systems, the dynamic loader cannot
+ relocate the text and data segments independently,
+ so the symbol does not matter. */
+ symbol = 0;
+ relocate = !globals->no_apply_dynamic_relocs;
+ outrel.r_info = ELFNN_R_INFO (symbol, AARCH64_R (RELATIVE));
+ outrel.r_addend += value;
+ }
+
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (sreloc == NULL || sreloc->contents == NULL)
+ return bfd_reloc_notsupported;
+
+ loc = sreloc->contents + sreloc->reloc_count++ * RELOC_SIZE (globals);
+ bfd_elfNN_swap_reloca_out (output_bfd, &outrel, loc);
+
+ if (sreloc->reloc_count * RELOC_SIZE (globals) > sreloc->size)
+ {
+ /* Sanity to check that we have previously allocated
+ sufficient space in the relocation section for the
+ number of relocations we actually want to emit. */
+ abort ();
+ }
+
+ /* 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,
+ signed_addend);
+ }
+ else
+ value += signed_addend;
+ break;
+
+ case BFD_RELOC_AARCH64_CALL26:
+ case BFD_RELOC_AARCH64_JUMP26:
+ {
+ asection *splt = globals->root.splt;
+ bool via_plt_p =
+ splt != NULL && h != NULL && h->plt.offset != (bfd_vma) - 1;
+
+ /* A call to an undefined weak symbol is converted to a jump to
+ the next instruction unless a PLT entry will be created.
+ The jump to the next instruction is optimized as a NOP.
+ Do the same for local undefined symbols. */
+ if (weak_undef_p && ! via_plt_p)
+ {
+ bfd_putl32 (INSN_NOP, hit_data);
+ return bfd_reloc_ok;
+ }
+
+ /* If the call goes through a PLT entry, make sure to
+ check distance to the right destination address. */
+ if (via_plt_p)
+ value = (splt->output_section->vma
+ + splt->output_offset + h->plt.offset);
+
+ /* Check if a stub has to be inserted because the destination
+ is too far away. */
+ struct elf_aarch64_stub_hash_entry *stub_entry = NULL;
+
+ /* If the branch destination is directed to plt stub, "value" will be
+ the final destination, otherwise we should plus signed_addend, it may
+ contain non-zero value, for example call to local function symbol
+ which are turned into "sec_sym + sec_off", and sec_off is kept in
+ signed_addend. */
+ if (! aarch64_valid_branch_p (via_plt_p ? value : value + signed_addend,
+ place))
+ /* The target is out of reach, so redirect the branch to
+ the local stub for this function. */
+ stub_entry = elfNN_aarch64_get_stub_entry (input_section, sym_sec, h,
+ rel, globals);
+ if (stub_entry != NULL)
+ {
+ value = (stub_entry->stub_offset
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_sec->output_section->vma);
+
+ /* We have redirected the destination to stub entry address,
+ so ignore any addend record in the original rela entry. */
+ signed_addend = 0;
+ }
+ }
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ signed_addend, weak_undef_p);
+ *unresolved_reloc_p = false;
+ break;
+
+ case BFD_RELOC_AARCH64_16_PCREL:
+ case BFD_RELOC_AARCH64_32_PCREL:
+ case BFD_RELOC_AARCH64_64_PCREL:
+ case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
+ case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+ case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
+ case BFD_RELOC_AARCH64_LD_LO19_PCREL:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G0:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G1:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G2:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G3:
+ if (bfd_link_pic (info)
+ && (input_section->flags & SEC_ALLOC) != 0
+ && (input_section->flags & SEC_READONLY) != 0
+ && !_bfd_elf_symbol_refs_local_p (h, info, 1))
+ {
+ int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against symbol `%s' which may bind "
+ "externally can not be used when making a shared object; "
+ "recompile with -fPIC"),
+ input_bfd, elfNN_aarch64_howto_table[howto_index].name,
+ h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return bfd_reloc_notsupported;
+ }
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ signed_addend,
+ weak_undef_p);
+ break;
+
+ case BFD_RELOC_AARCH64_BRANCH19:
+ case BFD_RELOC_AARCH64_TSTBR14:
+ if (h && h->root.type == bfd_link_hash_undefined)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: conditional branch to undefined symbol `%s' "
+ "not allowed"), input_bfd, h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return bfd_reloc_notsupported;
+ }
+ /* Fall through. */
+
+ case BFD_RELOC_AARCH64_16:
+#if ARCH_SIZE == 64
+ case BFD_RELOC_AARCH64_32:
+#endif
+ case BFD_RELOC_AARCH64_ADD_LO12:
+ case BFD_RELOC_AARCH64_LDST128_LO12:
+ case BFD_RELOC_AARCH64_LDST16_LO12:
+ case BFD_RELOC_AARCH64_LDST32_LO12:
+ case BFD_RELOC_AARCH64_LDST64_LO12:
+ case BFD_RELOC_AARCH64_LDST8_LO12:
+ case BFD_RELOC_AARCH64_MOVW_G0:
+ case BFD_RELOC_AARCH64_MOVW_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_G0_S:
+ case BFD_RELOC_AARCH64_MOVW_G1:
+ case BFD_RELOC_AARCH64_MOVW_G1_NC:
+ case BFD_RELOC_AARCH64_MOVW_G1_S:
+ case BFD_RELOC_AARCH64_MOVW_G2:
+ case BFD_RELOC_AARCH64_MOVW_G2_NC:
+ case BFD_RELOC_AARCH64_MOVW_G2_S:
+ case BFD_RELOC_AARCH64_MOVW_G3:
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ signed_addend, weak_undef_p);
+ break;
+
+ case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
+ case BFD_RELOC_AARCH64_GOT_LD_PREL19:
+ case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
+ case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+ case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
+ case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+ case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+ if (globals->root.sgot == NULL)
+ BFD_ASSERT (h != NULL);
+
+ relative_reloc = false;
+ if (h != NULL)
+ {
+ bfd_vma addend = 0;
+
+ /* If a symbol is not dynamic and is not undefined weak, bind it
+ locally and generate a RELATIVE relocation under PIC mode.
+
+ NOTE: one symbol may be referenced by several relocations, we
+ should only generate one RELATIVE relocation for that symbol.
+ Therefore, check GOT offset mark first. */
+ if (h->dynindx == -1
+ && !h->forced_local
+ && h->root.type != bfd_link_hash_undefweak
+ && bfd_link_pic (info)
+ && !symbol_got_offset_mark_p (input_bfd, h, r_symndx))
+ relative_reloc = true;
+
+ value = aarch64_calculate_got_entry_vma (h, globals, info, value,
+ output_bfd,
+ unresolved_reloc_p);
+ /* Record the GOT entry address which will be used when generating
+ RELATIVE relocation. */
+ if (relative_reloc)
+ got_entry_addr = value;
+
+ if (aarch64_relocation_aginst_gp_p (bfd_r_type))
+ addend = (globals->root.sgot->output_section->vma
+ + globals->root.sgot->output_offset);
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ addend, weak_undef_p);
+ }
+ else
+ {
+ bfd_vma addend = 0;
+ struct elf_aarch64_local_symbol *locals
+ = elf_aarch64_locals (input_bfd);
+
+ if (locals == NULL)
+ {
+ int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: local symbol descriptor table be NULL when applying "
+ "relocation %s against local symbol"),
+ input_bfd, elfNN_aarch64_howto_table[howto_index].name);
+ abort ();
+ }
+
+ off = symbol_got_offset (input_bfd, h, r_symndx);
+ base_got = globals->root.sgot;
+ got_entry_addr = (base_got->output_section->vma
+ + base_got->output_offset + off);
+
+ if (!symbol_got_offset_mark_p (input_bfd, h, r_symndx))
+ {
+ bfd_put_64 (output_bfd, value, base_got->contents + off);
+
+ /* For local symbol, we have done absolute relocation in static
+ linking stage. While for shared library, we need to update the
+ content of GOT entry according to the shared object's runtime
+ base address. So, we need to generate a R_AARCH64_RELATIVE reloc
+ for dynamic linker. */
+ if (bfd_link_pic (info))
+ relative_reloc = true;
+
+ symbol_got_offset_mark (input_bfd, h, r_symndx);
+ }
+
+ /* Update the relocation value to GOT entry addr as we have transformed
+ the direct data access into indirect data access through GOT. */
+ value = got_entry_addr;
+
+ if (aarch64_relocation_aginst_gp_p (bfd_r_type))
+ addend = base_got->output_section->vma + base_got->output_offset;
+
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ addend, weak_undef_p);
+ }
+
+ if (relative_reloc)
+ {
+ asection *s;
+ Elf_Internal_Rela outrel;
+
+ s = globals->root.srelgot;
+ if (s == NULL)
+ abort ();
+
+ outrel.r_offset = got_entry_addr;
+ outrel.r_info = ELFNN_R_INFO (0, AARCH64_R (RELATIVE));
+ outrel.r_addend = orig_value;
+ elf_append_rela (output_bfd, s, &outrel);
+ }
+ break;
+
+ case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
+ case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
+ case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
+ if (globals->root.sgot == NULL)
+ return bfd_reloc_notsupported;
+
+ value = (symbol_got_offset (input_bfd, h, r_symndx)
+ + globals->root.sgot->output_section->vma
+ + globals->root.sgot->output_offset);
+
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ 0, weak_undef_p);
+ *unresolved_reloc_p = false;
+ break;
+
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
+ case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
+ case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
+ if (globals->root.sgot == NULL)
+ return bfd_reloc_notsupported;
+
+ value = symbol_got_offset (input_bfd, h, r_symndx);
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ 0, weak_undef_p);
+ *unresolved_reloc_p = false;
+ break;
+
+ case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12:
+ case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0:
+ case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
+ case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1:
+ case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC:
+ case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
+ {
+ if (!(weak_undef_p || elf_hash_table (info)->tls_sec))
+ {
+ int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: TLS relocation %s against undefined symbol `%s'"),
+ input_bfd, elfNN_aarch64_howto_table[howto_index].name,
+ h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return bfd_reloc_notsupported;
+ }
+
+ bfd_vma def_value
+ = weak_undef_p ? 0 : signed_addend - dtpoff_base (info);
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ def_value, weak_undef_p);
+ break;
+ }
+
+ case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
+ case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+ case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
+ case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
+ case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
+ {
+ if (!(weak_undef_p || elf_hash_table (info)->tls_sec))
+ {
+ int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: TLS relocation %s against undefined symbol `%s'"),
+ input_bfd, elfNN_aarch64_howto_table[howto_index].name,
+ h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return bfd_reloc_notsupported;
+ }
+
+ bfd_vma def_value
+ = weak_undef_p ? 0 : signed_addend - tpoff_base (info);
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ def_value, weak_undef_p);
+ *unresolved_reloc_p = false;
+ break;
+ }
+
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
+ case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12:
+ case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
+ if (globals->root.sgot == NULL)
+ return bfd_reloc_notsupported;
+ value = (symbol_tlsdesc_got_offset (input_bfd, h, r_symndx)
+ + globals->root.sgotplt->output_section->vma
+ + globals->root.sgotplt->output_offset
+ + globals->sgotplt_jump_table_size);
+
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ 0, weak_undef_p);
+ *unresolved_reloc_p = false;
+ break;
+
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+ if (globals->root.sgot == NULL)
+ return bfd_reloc_notsupported;
+
+ value = (symbol_tlsdesc_got_offset (input_bfd, h, r_symndx)
+ + globals->root.sgotplt->output_section->vma
+ + globals->root.sgotplt->output_offset
+ + globals->sgotplt_jump_table_size);
+
+ value -= (globals->root.sgot->output_section->vma
+ + globals->root.sgot->output_offset);
+
+ value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
+ place, value,
+ 0, weak_undef_p);
+ *unresolved_reloc_p = false;
+ break;
+
+ default:
+ return bfd_reloc_notsupported;
+ }
+
+ if (saved_addend)
+ *saved_addend = value;
+
+ /* Only apply the final relocation in a sequence. */
+ if (save_addend)
+ return bfd_reloc_continue;
+
+ return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type,
+ howto, value);
+}
+
+/* LP64 and ILP32 operates on x- and w-registers respectively.
+ Next definitions take into account the difference between
+ corresponding machine codes. R means x-register if the target
+ arch is LP64, and w-register if the target is ILP32. */
+
+#if ARCH_SIZE == 64
+# define add_R0_R0 (0x91000000)
+# define add_R0_R0_R1 (0x8b000020)
+# define add_R0_R1 (0x91400020)
+# define ldr_R0 (0x58000000)
+# define ldr_R0_mask(i) (i & 0xffffffe0)
+# define ldr_R0_x0 (0xf9400000)
+# define ldr_hw_R0 (0xf2a00000)
+# define movk_R0 (0xf2800000)
+# define movz_R0 (0xd2a00000)
+# define movz_hw_R0 (0xd2c00000)
+#else /*ARCH_SIZE == 32 */
+# define add_R0_R0 (0x11000000)
+# define add_R0_R0_R1 (0x0b000020)
+# define add_R0_R1 (0x11400020)
+# define ldr_R0 (0x18000000)
+# define ldr_R0_mask(i) (i & 0xbfffffe0)
+# define ldr_R0_x0 (0xb9400000)
+# define ldr_hw_R0 (0x72a00000)
+# define movk_R0 (0x72800000)
+# define movz_R0 (0x52a00000)
+# define movz_hw_R0 (0x52c00000)
+#endif
+
+/* Structure to hold payload for _bfd_aarch64_erratum_843419_clear_stub,
+ it is used to identify the stub information to reset. */
+
+struct erratum_843419_branch_to_stub_clear_data
+{
+ bfd_vma adrp_offset;
+ asection *output_section;
+};
+
+/* Clear the erratum information for GEN_ENTRY if the ADRP_OFFSET and
+ section inside IN_ARG matches. The clearing is done by setting the
+ stub_type to none. */
+
+static bool
+_bfd_aarch64_erratum_843419_clear_stub (struct bfd_hash_entry *gen_entry,
+ void *in_arg)
+{
+ struct elf_aarch64_stub_hash_entry *stub_entry
+ = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+ struct erratum_843419_branch_to_stub_clear_data *data
+ = (struct erratum_843419_branch_to_stub_clear_data *) in_arg;
+
+ if (stub_entry->target_section != data->output_section
+ || stub_entry->stub_type != aarch64_stub_erratum_843419_veneer
+ || stub_entry->adrp_offset != data->adrp_offset)
+ return true;
+
+ /* Change the stub type instead of removing the entry, removing from the hash
+ table would be slower and we have already reserved the memory for the entry
+ so there wouldn't be much gain. Changing the stub also keeps around a
+ record of what was there before. */
+ stub_entry->stub_type = aarch64_stub_none;
+
+ /* We're done and there could have been only one matching stub at that
+ particular offset, so abort further traversal. */
+ return false;
+}
+
+/* TLS Relaxations may relax an adrp sequence that matches the erratum 843419
+ sequence. In this case the erratum no longer applies and we need to remove
+ the entry from the pending stub generation. This clears matching adrp insn
+ at ADRP_OFFSET in INPUT_SECTION in the stub table defined in GLOBALS. */
+
+static void
+clear_erratum_843419_entry (struct elf_aarch64_link_hash_table *globals,
+ bfd_vma adrp_offset, asection *input_section)
+{
+ if (globals->fix_erratum_843419 & ERRAT_ADRP)
+ {
+ struct erratum_843419_branch_to_stub_clear_data data;
+ data.adrp_offset = adrp_offset;
+ data.output_section = input_section;
+
+ bfd_hash_traverse (&globals->stub_hash_table,
+ _bfd_aarch64_erratum_843419_clear_stub, &data);
+ }
+}
+
+/* Handle TLS relaxations. Relaxing is possible for symbols that use
+ R_AARCH64_TLSDESC_ADR_{PAGE, LD64_LO12_NC, ADD_LO12_NC} during a static
+ link.
+
+ Return bfd_reloc_ok if we're done, bfd_reloc_continue if the caller
+ is to then call final_link_relocate. Return other values in the
+ case of error. */
+
+static bfd_reloc_status_type
+elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals,
+ bfd *input_bfd, asection *input_section,
+ bfd_byte *contents, Elf_Internal_Rela *rel,
+ struct elf_link_hash_entry *h,
+ struct bfd_link_info *info)
+{
+ bool local_exec = bfd_link_executable (info)
+ && SYMBOL_REFERENCES_LOCAL (info, h);
+ unsigned int r_type = ELFNN_R_TYPE (rel->r_info);
+ unsigned long insn;
+
+ BFD_ASSERT (globals && input_bfd && contents && rel);
+
+ switch (elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type))
+ {
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
+ if (local_exec)
+ {
+ /* GD->LE relaxation:
+ adrp x0, :tlsgd:var => movz R0, :tprel_g1:var
+ or
+ adrp x0, :tlsdesc:var => movz R0, :tprel_g1:var
+
+ Where R is x for LP64, and w for ILP32. */
+ bfd_putl32 (movz_R0, contents + rel->r_offset);
+ /* We have relaxed the adrp into a mov, we may have to clear any
+ pending erratum fixes. */
+ clear_erratum_843419_entry (globals, rel->r_offset, input_section);
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* GD->IE relaxation:
+ adrp x0, :tlsgd:var => adrp x0, :gottprel:var
+ or
+ adrp x0, :tlsdesc:var => adrp x0, :gottprel:var
+ */
+ return bfd_reloc_continue;
+ }
+
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
+ BFD_ASSERT (0);
+ break;
+
+ case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
+ if (local_exec)
+ {
+ /* Tiny TLSDESC->LE relaxation:
+ ldr x1, :tlsdesc:var => movz R0, #:tprel_g1:var
+ adr x0, :tlsdesc:var => movk R0, #:tprel_g0_nc:var
+ .tlsdesccall var
+ blr x1 => nop
+
+ Where R is x for LP64, and w for ILP32. */
+ BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (TLSDESC_ADR_PREL21));
+ BFD_ASSERT (ELFNN_R_TYPE (rel[2].r_info) == AARCH64_R (TLSDESC_CALL));
+
+ rel[1].r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info),
+ AARCH64_R (TLSLE_MOVW_TPREL_G0_NC));
+ rel[2].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
+
+ bfd_putl32 (movz_R0, contents + rel->r_offset);
+ bfd_putl32 (movk_R0, contents + rel->r_offset + 4);
+ bfd_putl32 (INSN_NOP, contents + rel->r_offset + 8);
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* Tiny TLSDESC->IE relaxation:
+ ldr x1, :tlsdesc:var => ldr x0, :gottprel:var
+ adr x0, :tlsdesc:var => nop
+ .tlsdesccall var
+ blr x1 => nop
+ */
+ BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (TLSDESC_ADR_PREL21));
+ BFD_ASSERT (ELFNN_R_TYPE (rel[2].r_info) == AARCH64_R (TLSDESC_CALL));
+
+ rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
+ rel[2].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
+
+ bfd_putl32 (ldr_R0, contents + rel->r_offset);
+ bfd_putl32 (INSN_NOP, contents + rel->r_offset + 4);
+ bfd_putl32 (INSN_NOP, contents + rel->r_offset + 8);
+ return bfd_reloc_continue;
+ }
+
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
+ if (local_exec)
+ {
+ /* Tiny GD->LE relaxation:
+ adr x0, :tlsgd:var => mrs x1, tpidr_el0
+ bl __tls_get_addr => add R0, R1, #:tprel_hi12:x, lsl #12
+ nop => add R0, R0, #:tprel_lo12_nc:x
+
+ Where R is x for LP64, and x for Ilp32. */
+
+ /* First kill the tls_get_addr reloc on the bl instruction. */
+ BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset);
+
+ bfd_putl32 (0xd53bd041, contents + rel->r_offset + 0);
+ bfd_putl32 (add_R0_R1, contents + rel->r_offset + 4);
+ bfd_putl32 (add_R0_R0, contents + rel->r_offset + 8);
+
+ rel[1].r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info),
+ AARCH64_R (TLSLE_ADD_TPREL_LO12_NC));
+ rel[1].r_offset = rel->r_offset + 8;
+
+ /* Move the current relocation to the second instruction in
+ the sequence. */
+ rel->r_offset += 4;
+ rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info),
+ AARCH64_R (TLSLE_ADD_TPREL_HI12));
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* Tiny GD->IE relaxation:
+ adr x0, :tlsgd:var => ldr R0, :gottprel:var
+ bl __tls_get_addr => mrs x1, tpidr_el0
+ nop => add R0, R0, R1
+
+ Where R is x for LP64, and w for Ilp32. */
+
+ /* First kill the tls_get_addr reloc on the bl instruction. */
+ BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset);
+ rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
+
+ bfd_putl32 (ldr_R0, contents + rel->r_offset);
+ bfd_putl32 (0xd53bd041, contents + rel->r_offset + 4);
+ bfd_putl32 (add_R0_R0_R1, contents + rel->r_offset + 8);
+ return bfd_reloc_continue;
+ }
+
+#if ARCH_SIZE == 64
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
+ BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (TLSGD_MOVW_G0_NC));
+ BFD_ASSERT (rel->r_offset + 12 == rel[2].r_offset);
+ BFD_ASSERT (ELFNN_R_TYPE (rel[2].r_info) == AARCH64_R (CALL26));
+
+ if (local_exec)
+ {
+ /* Large GD->LE relaxation:
+ movz x0, #:tlsgd_g1:var => movz x0, #:tprel_g2:var, lsl #32
+ movk x0, #:tlsgd_g0_nc:var => movk x0, #:tprel_g1_nc:var, lsl #16
+ add x0, gp, x0 => movk x0, #:tprel_g0_nc:var
+ bl __tls_get_addr => mrs x1, tpidr_el0
+ nop => add x0, x0, x1
+ */
+ rel[2].r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info),
+ AARCH64_R (TLSLE_MOVW_TPREL_G0_NC));
+ rel[2].r_offset = rel->r_offset + 8;
+
+ bfd_putl32 (movz_hw_R0, contents + rel->r_offset + 0);
+ bfd_putl32 (ldr_hw_R0, contents + rel->r_offset + 4);
+ bfd_putl32 (movk_R0, contents + rel->r_offset + 8);
+ bfd_putl32 (0xd53bd041, contents + rel->r_offset + 12);
+ bfd_putl32 (add_R0_R0_R1, contents + rel->r_offset + 16);
+ }
+ else
+ {
+ /* Large GD->IE relaxation:
+ movz x0, #:tlsgd_g1:var => movz x0, #:gottprel_g1:var, lsl #16
+ movk x0, #:tlsgd_g0_nc:var => movk x0, #:gottprel_g0_nc:var
+ add x0, gp, x0 => ldr x0, [gp, x0]
+ bl __tls_get_addr => mrs x1, tpidr_el0
+ nop => add x0, x0, x1
+ */
+ rel[2].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
+ bfd_putl32 (0xd2a80000, contents + rel->r_offset + 0);
+ bfd_putl32 (ldr_R0, contents + rel->r_offset + 8);
+ bfd_putl32 (0xd53bd041, contents + rel->r_offset + 12);
+ bfd_putl32 (add_R0_R0_R1, contents + rel->r_offset + 16);
+ }
+ return bfd_reloc_continue;
+
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+ return bfd_reloc_continue;
+#endif
+
+ case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
+ return bfd_reloc_continue;
+
+ case BFD_RELOC_AARCH64_TLSDESC_LDNN_LO12_NC:
+ if (local_exec)
+ {
+ /* GD->LE relaxation:
+ ldr xd, [x0, #:tlsdesc_lo12:var] => movk x0, :tprel_g0_nc:var
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ bfd_putl32 (movk_R0, contents + rel->r_offset);
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* GD->IE relaxation:
+ ldr xd, [x0, #:tlsdesc_lo12:var] => ldr R0, [x0, #:gottprel_lo12:var]
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ insn = bfd_getl32 (contents + rel->r_offset);
+ bfd_putl32 (ldr_R0_mask (insn), contents + rel->r_offset);
+ return bfd_reloc_continue;
+ }
+
+ case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
+ if (local_exec)
+ {
+ /* GD->LE relaxation
+ add x0, #:tlsgd_lo12:var => movk R0, :tprel_g0_nc:var
+ bl __tls_get_addr => mrs x1, tpidr_el0
+ nop => add R0, R1, R0
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+
+ /* First kill the tls_get_addr reloc on the bl instruction. */
+ BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset);
+ rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
+
+ bfd_putl32 (movk_R0, contents + rel->r_offset);
+ bfd_putl32 (0xd53bd041, contents + rel->r_offset + 4);
+ bfd_putl32 (add_R0_R0_R1, contents + rel->r_offset + 8);
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* GD->IE relaxation
+ ADD x0, #:tlsgd_lo12:var => ldr R0, [x0, #:gottprel_lo12:var]
+ BL __tls_get_addr => mrs x1, tpidr_el0
+ R_AARCH64_CALL26
+ NOP => add R0, R1, R0
+
+ Where R is x for lp64 mode, and w for ilp32 mode. */
+
+ BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (CALL26));
+
+ /* Remove the relocation on the BL instruction. */
+ rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
+
+ /* We choose to fixup the BL and NOP instructions using the
+ offset from the second relocation to allow flexibility in
+ scheduling instructions between the ADD and BL. */
+ bfd_putl32 (ldr_R0_x0, contents + rel->r_offset);
+ bfd_putl32 (0xd53bd041, contents + rel[1].r_offset);
+ bfd_putl32 (add_R0_R0_R1, contents + rel[1].r_offset + 4);
+ return bfd_reloc_continue;
+ }
+
+ case BFD_RELOC_AARCH64_TLSDESC_ADD:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
+ case BFD_RELOC_AARCH64_TLSDESC_CALL:
+ /* GD->IE/LE relaxation:
+ add x0, x0, #:tlsdesc_lo12:var => nop
+ blr xd => nop
+ */
+ bfd_putl32 (INSN_NOP, contents + rel->r_offset);
+ return bfd_reloc_ok;
+
+ case BFD_RELOC_AARCH64_TLSDESC_LDR:
+ if (local_exec)
+ {
+ /* GD->LE relaxation:
+ ldr xd, [gp, xn] => movk R0, #:tprel_g0_nc:var
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ bfd_putl32 (movk_R0, contents + rel->r_offset);
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* GD->IE relaxation:
+ ldr xd, [gp, xn] => ldr R0, [gp, xn]
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ insn = bfd_getl32 (contents + rel->r_offset);
+ bfd_putl32 (ldr_R0_mask (insn), contents + rel->r_offset);
+ return bfd_reloc_ok;
+ }
+
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ /* GD->LE relaxation:
+ movk xd, #:tlsdesc_off_g0_nc:var => movk R0, #:tprel_g1_nc:var, lsl #16
+ GD->IE relaxation:
+ movk xd, #:tlsdesc_off_g0_nc:var => movk Rd, #:gottprel_g0_nc:var
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ if (local_exec)
+ bfd_putl32 (ldr_hw_R0, contents + rel->r_offset);
+ return bfd_reloc_continue;
+
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+ if (local_exec)
+ {
+ /* GD->LE relaxation:
+ movz xd, #:tlsdesc_off_g1:var => movz R0, #:tprel_g2:var, lsl #32
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ bfd_putl32 (movz_hw_R0, contents + rel->r_offset);
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* GD->IE relaxation:
+ movz xd, #:tlsdesc_off_g1:var => movz Rd, #:gottprel_g1:var, lsl #16
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ insn = bfd_getl32 (contents + rel->r_offset);
+ bfd_putl32 (movz_R0 | (insn & 0x1f), contents + rel->r_offset);
+ return bfd_reloc_continue;
+ }
+
+ case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ /* IE->LE relaxation:
+ adrp xd, :gottprel:var => movz Rd, :tprel_g1:var
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ if (local_exec)
+ {
+ insn = bfd_getl32 (contents + rel->r_offset);
+ bfd_putl32 (movz_R0 | (insn & 0x1f), contents + rel->r_offset);
+ /* We have relaxed the adrp into a mov, we may have to clear any
+ pending erratum fixes. */
+ clear_erratum_843419_entry (globals, rel->r_offset, input_section);
+ }
+ return bfd_reloc_continue;
+
+ case BFD_RELOC_AARCH64_TLSIE_LDNN_GOTTPREL_LO12_NC:
+ /* IE->LE relaxation:
+ ldr xd, [xm, #:gottprel_lo12:var] => movk Rd, :tprel_g0_nc:var
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ if (local_exec)
+ {
+ insn = bfd_getl32 (contents + rel->r_offset);
+ bfd_putl32 (movk_R0 | (insn & 0x1f), contents + rel->r_offset);
+ }
+ return bfd_reloc_continue;
+
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
+ /* LD->LE relaxation (tiny):
+ adr x0, :tlsldm:x => mrs x0, tpidr_el0
+ bl __tls_get_addr => add R0, R0, TCB_SIZE
+
+ Where R is x for lp64 mode, and w for ilp32 mode. */
+ if (local_exec)
+ {
+ BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset);
+ BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (CALL26));
+ /* No need of CALL26 relocation for tls_get_addr. */
+ rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
+ bfd_putl32 (0xd53bd040, contents + rel->r_offset + 0);
+ bfd_putl32 (add_R0_R0 | (TCB_SIZE << 10),
+ contents + rel->r_offset + 4);
+ return bfd_reloc_ok;
+ }
+ return bfd_reloc_continue;
+
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+ /* LD->LE relaxation (small):
+ adrp x0, :tlsldm:x => mrs x0, tpidr_el0
+ */
+ if (local_exec)
+ {
+ bfd_putl32 (0xd53bd040, contents + rel->r_offset);
+ return bfd_reloc_ok;
+ }
+ return bfd_reloc_continue;
+
+ case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+ /* LD->LE relaxation (small):
+ add x0, #:tlsldm_lo12:x => add R0, R0, TCB_SIZE
+ bl __tls_get_addr => nop
+
+ Where R is x for lp64 mode, and w for ilp32 mode. */
+ if (local_exec)
+ {
+ BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset);
+ BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (CALL26));
+ /* No need of CALL26 relocation for tls_get_addr. */
+ rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
+ bfd_putl32 (add_R0_R0 | (TCB_SIZE << 10),
+ contents + rel->r_offset + 0);
+ bfd_putl32 (INSN_NOP, contents + rel->r_offset + 4);
+ return bfd_reloc_ok;
+ }
+ return bfd_reloc_continue;
+
+ default:
+ return bfd_reloc_continue;
+ }
+
+ return bfd_reloc_ok;
+}
+
+/* Relocate an AArch64 ELF section. */
+
+static int
+elfNN_aarch64_relocate_section (bfd *output_bfd,
+ struct bfd_link_info *info,
+ bfd *input_bfd,
+ asection *input_section,
+ bfd_byte *contents,
+ Elf_Internal_Rela *relocs,
+ Elf_Internal_Sym *local_syms,
+ asection **local_sections)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend;
+ const char *name;
+ struct elf_aarch64_link_hash_table *globals;
+ bool save_addend = false;
+ bfd_vma addend = 0;
+
+ globals = elf_aarch64_hash_table (info);
+
+ symtab_hdr = &elf_symtab_hdr (input_bfd);
+ sym_hashes = elf_sym_hashes (input_bfd);
+
+ rel = relocs;
+ relend = relocs + input_section->reloc_count;
+ for (; rel < relend; rel++)
+ {
+ unsigned int r_type;
+ bfd_reloc_code_real_type bfd_r_type;
+ bfd_reloc_code_real_type relaxed_bfd_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;
+ char sym_type;
+ bool unresolved_reloc = false;
+ char *error_message = NULL;
+
+ r_symndx = ELFNN_R_SYM (rel->r_info);
+ r_type = ELFNN_R_TYPE (rel->r_info);
+
+ bfd_reloc.howto = elfNN_aarch64_howto_from_type (input_bfd, r_type);
+ howto = bfd_reloc.howto;
+
+ if (howto == NULL)
+ return _bfd_unrecognized_reloc (input_bfd, input_section, r_type);
+
+ bfd_r_type = elfNN_aarch64_bfd_reloc_from_howto (howto);
+
+ h = NULL;
+ sym = NULL;
+ sec = NULL;
+
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ sym = local_syms + r_symndx;
+ sym_type = ELFNN_ST_TYPE (sym->st_info);
+ sec = local_sections[r_symndx];
+
+ /* An object file might have a reference to a local
+ undefined symbol. This is a daft object file, but we
+ should at least do something about it. */
+ if (r_type != R_AARCH64_NONE && r_type != R_AARCH64_NULL
+ && bfd_is_und_section (sec)
+ && ELF_ST_BIND (sym->st_info) != STB_WEAK)
+ (*info->callbacks->undefined_symbol)
+ (info, bfd_elf_string_from_elf_section
+ (input_bfd, symtab_hdr->sh_link, sym->st_name),
+ input_bfd, input_section, rel->r_offset, true);
+
+ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+
+ /* Relocate against local STT_GNU_IFUNC symbol. */
+ if (!bfd_link_relocatable (info)
+ && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+ {
+ h = elfNN_aarch64_get_local_sym_hash (globals, input_bfd,
+ rel, false);
+ if (h == NULL)
+ abort ();
+
+ /* Set STT_GNU_IFUNC symbol value. */
+ h->root.u.def.value = sym->st_value;
+ h->root.u.def.section = sec;
+ }
+ }
+ else
+ {
+ bool warned, ignored;
+
+ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+ r_symndx, symtab_hdr, sym_hashes,
+ h, sec, relocation,
+ unresolved_reloc, warned, ignored);
+
+ sym_type = h->type;
+ }
+
+ if (sec != NULL && discarded_section (sec))
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, 1, relend, howto, 0, contents);
+
+ if (bfd_link_relocatable (info))
+ continue;
+
+ 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 (sec);
+ }
+
+ if (r_symndx != 0
+ && r_type != R_AARCH64_NONE
+ && r_type != R_AARCH64_NULL
+ && (h == NULL
+ || h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && IS_AARCH64_TLS_RELOC (bfd_r_type) != (sym_type == STT_TLS))
+ {
+ _bfd_error_handler
+ ((sym_type == STT_TLS
+ /* xgettext:c-format */
+ ? _("%pB(%pA+%#" PRIx64 "): %s used with TLS symbol %s")
+ /* xgettext:c-format */
+ : _("%pB(%pA+%#" PRIx64 "): %s used with non-TLS symbol %s")),
+ input_bfd,
+ input_section, (uint64_t) rel->r_offset, howto->name, name);
+ }
+
+ /* We relax only if we can see that there can be a valid transition
+ from a reloc type to another.
+ We call elfNN_aarch64_final_link_relocate unless we're completely
+ done, i.e., the relaxation produced the final output we want. */
+
+ relaxed_bfd_r_type = aarch64_tls_transition (input_bfd, info, r_type,
+ h, r_symndx);
+ if (relaxed_bfd_r_type != bfd_r_type)
+ {
+ bfd_r_type = relaxed_bfd_r_type;
+ howto = elfNN_aarch64_howto_from_bfd_reloc (bfd_r_type);
+ BFD_ASSERT (howto != NULL);
+ r_type = howto->type;
+ r = elfNN_aarch64_tls_relax (globals, input_bfd, input_section,
+ contents, rel, h, info);
+ unresolved_reloc = 0;
+ }
+ else
+ r = bfd_reloc_continue;
+
+ /* There may be multiple consecutive relocations for the
+ same offset. In that case we are supposed to treat the
+ output of each relocation as the addend for the next. */
+ if (rel + 1 < relend
+ && rel->r_offset == rel[1].r_offset
+ && ELFNN_R_TYPE (rel[1].r_info) != R_AARCH64_NONE
+ && ELFNN_R_TYPE (rel[1].r_info) != R_AARCH64_NULL)
+ save_addend = true;
+ else
+ save_addend = false;
+
+ if (r == bfd_reloc_continue)
+ r = elfNN_aarch64_final_link_relocate (howto, input_bfd, output_bfd,
+ input_section, contents, rel,
+ relocation, info, sec,
+ h, &unresolved_reloc,
+ save_addend, &addend, sym);
+
+ switch (elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type))
+ {
+ case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
+ case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
+ if (! symbol_got_offset_mark_p (input_bfd, h, r_symndx))
+ {
+ bool need_relocs = false;
+ bfd_byte *loc;
+ int indx;
+ bfd_vma off;
+
+ off = symbol_got_offset (input_bfd, h, r_symndx);
+ indx = h && h->dynindx != -1 ? h->dynindx : 0;
+
+ need_relocs =
+ (!bfd_link_executable (info) || indx != 0) &&
+ (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak);
+
+ BFD_ASSERT (globals->root.srelgot != NULL);
+
+ if (need_relocs)
+ {
+ Elf_Internal_Rela rela;
+ rela.r_info = ELFNN_R_INFO (indx, AARCH64_R (TLS_DTPMOD));
+ rela.r_addend = 0;
+ rela.r_offset = globals->root.sgot->output_section->vma +
+ globals->root.sgot->output_offset + off;
+
+
+ loc = globals->root.srelgot->contents;
+ loc += globals->root.srelgot->reloc_count++
+ * RELOC_SIZE (htab);
+ bfd_elfNN_swap_reloca_out (output_bfd, &rela, loc);
+
+ bfd_reloc_code_real_type real_type =
+ elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type);
+
+ if (real_type == BFD_RELOC_AARCH64_TLSLD_ADR_PREL21
+ || real_type == BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21
+ || real_type == BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC)
+ {
+ /* For local dynamic, don't generate DTPREL in any case.
+ Initialize the DTPREL slot into zero, so we get module
+ base address when invoke runtime TLS resolver. */
+ bfd_put_NN (output_bfd, 0,
+ globals->root.sgot->contents + off
+ + GOT_ENTRY_SIZE);
+ }
+ else if (indx == 0)
+ {
+ bfd_put_NN (output_bfd,
+ relocation - dtpoff_base (info),
+ globals->root.sgot->contents + off
+ + GOT_ENTRY_SIZE);
+ }
+ else
+ {
+ /* This TLS symbol is global. We emit a
+ relocation to fixup the tls offset at load
+ time. */
+ rela.r_info =
+ ELFNN_R_INFO (indx, AARCH64_R (TLS_DTPREL));
+ rela.r_addend = 0;
+ rela.r_offset =
+ (globals->root.sgot->output_section->vma
+ + globals->root.sgot->output_offset + off
+ + GOT_ENTRY_SIZE);
+
+ loc = globals->root.srelgot->contents;
+ loc += globals->root.srelgot->reloc_count++
+ * RELOC_SIZE (globals);
+ bfd_elfNN_swap_reloca_out (output_bfd, &rela, loc);
+ bfd_put_NN (output_bfd, (bfd_vma) 0,
+ globals->root.sgot->contents + off
+ + GOT_ENTRY_SIZE);
+ }
+ }
+ else
+ {
+ bfd_put_NN (output_bfd, (bfd_vma) 1,
+ globals->root.sgot->contents + off);
+ bfd_put_NN (output_bfd,
+ relocation - dtpoff_base (info),
+ globals->root.sgot->contents + off
+ + GOT_ENTRY_SIZE);
+ }
+
+ symbol_got_offset_mark (input_bfd, h, r_symndx);
+ }
+ break;
+
+ case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case BFD_RELOC_AARCH64_TLSIE_LDNN_GOTTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
+ case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
+ case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
+ if (! symbol_got_offset_mark_p (input_bfd, h, r_symndx))
+ {
+ bool need_relocs = false;
+ bfd_byte *loc;
+ int indx;
+ bfd_vma off;
+
+ off = symbol_got_offset (input_bfd, h, r_symndx);
+
+ indx = h && h->dynindx != -1 ? h->dynindx : 0;
+
+ need_relocs =
+ (!bfd_link_executable (info) || indx != 0) &&
+ (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak);
+
+ BFD_ASSERT (globals->root.srelgot != NULL);
+
+ if (need_relocs)
+ {
+ Elf_Internal_Rela rela;
+
+ if (indx == 0)
+ rela.r_addend = relocation - dtpoff_base (info);
+ else
+ rela.r_addend = 0;
+
+ rela.r_info = ELFNN_R_INFO (indx, AARCH64_R (TLS_TPREL));
+ rela.r_offset = globals->root.sgot->output_section->vma +
+ globals->root.sgot->output_offset + off;
+
+ loc = globals->root.srelgot->contents;
+ loc += globals->root.srelgot->reloc_count++
+ * RELOC_SIZE (htab);
+
+ bfd_elfNN_swap_reloca_out (output_bfd, &rela, loc);
+
+ bfd_put_NN (output_bfd, rela.r_addend,
+ globals->root.sgot->contents + off);
+ }
+ else
+ bfd_put_NN (output_bfd, relocation - tpoff_base (info),
+ globals->root.sgot->contents + off);
+
+ symbol_got_offset_mark (input_bfd, h, r_symndx);
+ }
+ break;
+
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
+ case BFD_RELOC_AARCH64_TLSDESC_LDNN_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+ if (! symbol_tlsdesc_got_offset_mark_p (input_bfd, h, r_symndx))
+ {
+ bool need_relocs = false;
+ int indx = h && h->dynindx != -1 ? h->dynindx : 0;
+ bfd_vma off = symbol_tlsdesc_got_offset (input_bfd, h, r_symndx);
+
+ need_relocs = (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak);
+
+ BFD_ASSERT (globals->root.srelgot != NULL);
+ BFD_ASSERT (globals->root.sgot != NULL);
+
+ if (need_relocs)
+ {
+ bfd_byte *loc;
+ Elf_Internal_Rela rela;
+ rela.r_info = ELFNN_R_INFO (indx, AARCH64_R (TLSDESC));
+
+ rela.r_addend = 0;
+ rela.r_offset = (globals->root.sgotplt->output_section->vma
+ + globals->root.sgotplt->output_offset
+ + off + globals->sgotplt_jump_table_size);
+
+ if (indx == 0)
+ rela.r_addend = relocation - dtpoff_base (info);
+
+ /* Allocate the next available slot in the PLT reloc
+ section to hold our R_AARCH64_TLSDESC, the next
+ available slot is determined from reloc_count,
+ which we step. But note, reloc_count was
+ artifically moved down while allocating slots for
+ real PLT relocs such that all of the PLT relocs
+ will fit above the initial reloc_count and the
+ extra stuff will fit below. */
+ loc = globals->root.srelplt->contents;
+ loc += globals->root.srelplt->reloc_count++
+ * RELOC_SIZE (globals);
+
+ bfd_elfNN_swap_reloca_out (output_bfd, &rela, loc);
+
+ bfd_put_NN (output_bfd, (bfd_vma) 0,
+ globals->root.sgotplt->contents + off +
+ globals->sgotplt_jump_table_size);
+ bfd_put_NN (output_bfd, (bfd_vma) 0,
+ globals->root.sgotplt->contents + off +
+ globals->sgotplt_jump_table_size +
+ GOT_ENTRY_SIZE);
+ }
+
+ symbol_tlsdesc_got_offset_mark (input_bfd, h, r_symndx);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
+ because such sections are not SEC_ALLOC and thus ld.so will
+ not process them. */
+ if (unresolved_reloc
+ && !((input_section->flags & SEC_DEBUGGING) != 0
+ && h->def_dynamic)
+ && _bfd_elf_section_offset (output_bfd, info, input_section,
+ +rel->r_offset) != (bfd_vma) - 1)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA+%#" PRIx64 "): "
+ "unresolvable %s relocation against symbol `%s'"),
+ input_bfd, input_section, (uint64_t) rel->r_offset, howto->name,
+ h->root.root.string);
+ return false;
+ }
+
+ if (r != bfd_reloc_ok && r != bfd_reloc_continue)
+ {
+ bfd_reloc_code_real_type real_r_type
+ = elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type);
+
+ switch (r)
+ {
+ case bfd_reloc_overflow:
+ (*info->callbacks->reloc_overflow)
+ (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0,
+ input_bfd, input_section, rel->r_offset);
+ if (real_r_type == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15
+ || real_r_type == BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14)
+ {
+ (*info->callbacks->warning)
+ (info,
+ _("too many GOT entries for -fpic, "
+ "please recompile with -fPIC"),
+ name, input_bfd, input_section, rel->r_offset);
+ return false;
+ }
+ /* Overflow can occur when a variable is referenced with a type
+ that has a larger alignment than the type with which it was
+ declared. eg:
+ file1.c: extern int foo; int a (void) { return foo; }
+ file2.c: char bar, foo, baz;
+ If the variable is placed into a data section at an offset
+ that is incompatible with the larger alignment requirement
+ overflow will occur. (Strictly speaking this is not overflow
+ but rather an alignment problem, but the bfd_reloc_ error
+ enum does not have a value to cover that situation).
+
+ Try to catch this situation here and provide a more helpful
+ error message to the user. */
+ if (addend & (((bfd_vma) 1 << howto->rightshift) - 1)
+ /* FIXME: Are we testing all of the appropriate reloc
+ types here ? */
+ && (real_r_type == BFD_RELOC_AARCH64_LD_LO19_PCREL
+ || real_r_type == BFD_RELOC_AARCH64_LDST16_LO12
+ || real_r_type == BFD_RELOC_AARCH64_LDST32_LO12
+ || real_r_type == BFD_RELOC_AARCH64_LDST64_LO12
+ || real_r_type == BFD_RELOC_AARCH64_LDST128_LO12))
+ {
+ info->callbacks->warning
+ (info, _("one possible cause of this error is that the \
+symbol is being referenced in the indicated code as if it had a larger \
+alignment than was declared where it was defined"),
+ name, input_bfd, input_section, rel->r_offset);
+ }
+ break;
+
+ case bfd_reloc_undefined:
+ (*info->callbacks->undefined_symbol)
+ (info, name, input_bfd, input_section, rel->r_offset, true);
+ break;
+
+ case bfd_reloc_outofrange:
+ error_message = _("out of range");
+ goto common_error;
+
+ case bfd_reloc_notsupported:
+ error_message = _("unsupported relocation");
+ goto common_error;
+
+ case bfd_reloc_dangerous:
+ /* error_message should already be set. */
+ goto common_error;
+
+ default:
+ error_message = _("unknown error");
+ /* Fall through. */
+
+ common_error:
+ BFD_ASSERT (error_message != NULL);
+ (*info->callbacks->reloc_dangerous)
+ (info, error_message, input_bfd, input_section, rel->r_offset);
+ break;
+ }
+ }
+
+ if (!save_addend)
+ addend = 0;
+ }
+
+ return true;
+}
+
+/* Set the right machine number. */
+
+static bool
+elfNN_aarch64_object_p (bfd *abfd)
+{
+#if ARCH_SIZE == 32
+ bfd_default_set_arch_mach (abfd, bfd_arch_aarch64, bfd_mach_aarch64_ilp32);
+#else
+ bfd_default_set_arch_mach (abfd, bfd_arch_aarch64, bfd_mach_aarch64);
+#endif
+ return true;
+}
+
+/* Function to keep AArch64 specific flags in the ELF header. */
+
+static bool
+elfNN_aarch64_set_private_flags (bfd *abfd, flagword flags)
+{
+ if (elf_flags_init (abfd) && elf_elfheader (abfd)->e_flags != flags)
+ {
+ }
+ else
+ {
+ elf_elfheader (abfd)->e_flags = flags;
+ elf_flags_init (abfd) = true;
+ }
+
+ return true;
+}
+
+/* Merge backend specific data from an object file to the output
+ object file when linking. */
+
+static bool
+elfNN_aarch64_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
+{
+ bfd *obfd = info->output_bfd;
+ flagword out_flags;
+ flagword in_flags;
+ bool flags_compatible = true;
+ asection *sec;
+
+ /* Check if we have the same endianess. */
+ if (!_bfd_generic_verify_endian_match (ibfd, info))
+ return false;
+
+ if (!is_aarch64_elf (ibfd) || !is_aarch64_elf (obfd))
+ 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;
+ }
+
+ /* 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 incompatiblity. Do not short-circuit
+ dynamic objects; their section list may be emptied by
+ elf_link_add_object_symbols.
+
+ Also check to see if there are no code sections in the input.
+ In this case there is no need to check for code specific flags.
+ XXX - do we need to worry about floating-point format compatability
+ in data sections ? */
+ if (!(ibfd->flags & DYNAMIC))
+ {
+ bool null_input_bfd = true;
+ bool only_data_sections = true;
+
+ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+ {
+ if ((bfd_section_flags (sec)
+ & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
+ == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
+ only_data_sections = false;
+
+ null_input_bfd = false;
+ break;
+ }
+
+ if (null_input_bfd || only_data_sections)
+ return true;
+ }
+
+ return flags_compatible;
+}
+
+/* Display the flags field. */
+
+static bool
+elfNN_aarch64_print_private_bfd_data (bfd *abfd, void *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 = 0x%lx:"), elf_elfheader (abfd)->e_flags);
+
+ if (flags)
+ fprintf (file, _(" <Unrecognised flag bits set>"));
+
+ fputc ('\n', file);
+
+ return true;
+}
+
+/* Return true if we need copy relocation against EH. */
+
+static bool
+need_copy_relocation_p (struct elf_aarch64_link_hash_entry *eh)
+{
+ struct elf_dyn_relocs *p;
+ asection *s;
+
+ for (p = eh->root.dyn_relocs; p != NULL; p = p->next)
+ {
+ /* If there is any pc-relative reference, we need to keep copy relocation
+ to avoid propagating the relocation into runtime that current glibc
+ does not support. */
+ if (p->pc_count)
+ return true;
+
+ s = p->sec->output_section;
+ /* Need copy relocation if it's against read-only section. */
+ if (s != NULL && (s->flags & SEC_READONLY) != 0)
+ return true;
+ }
+
+ return false;
+}
+
+/* Adjust a symbol defined by a dynamic object and referenced by a
+ regular object. The current definition is in some section of the
+ dynamic object, but we're not including those sections. We have to
+ change the definition to something the rest of the link can
+ understand. */
+
+static bool
+elfNN_aarch64_adjust_dynamic_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ struct elf_aarch64_link_hash_table *htab;
+ asection *s, *srel;
+
+ /* 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->type == STT_GNU_IFUNC || h->needs_plt)
+ {
+ if (h->plt.refcount <= 0
+ || (h->type != STT_GNU_IFUNC
+ && (SYMBOL_CALLS_LOCAL (info, h)
+ || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ && h->root.type == bfd_link_hash_undefweak))))
+ {
+ /* This case can occur if we saw a CALL26 reloc in
+ an input file, but the symbol wasn't referred to
+ by a dynamic object or all references were
+ garbage collected. In which case we can end up
+ resolving. */
+ h->plt.offset = (bfd_vma) - 1;
+ h->needs_plt = 0;
+ }
+
+ return true;
+ }
+ else
+ /* Otherwise, reset to -1. */
+ h->plt.offset = (bfd_vma) - 1;
+
+
+ /* If this is a weak symbol, and there is a real definition, the
+ processor independent code will have arranged for us to see the
+ real definition first, and we can just use the same value. */
+ if (h->is_weakalias)
+ {
+ struct elf_link_hash_entry *def = weakdef (h);
+ BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+ h->root.u.def.section = def->root.u.def.section;
+ h->root.u.def.value = def->root.u.def.value;
+ if (ELIMINATE_COPY_RELOCS || info->nocopyreloc)
+ h->non_got_ref = def->non_got_ref;
+ return true;
+ }
+
+ /* 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 (bfd_link_pic (info))
+ return true;
+
+ /* If there are no references to this symbol that do not use the
+ GOT, we don't need to generate a copy reloc. */
+ if (!h->non_got_ref)
+ return true;
+
+ /* If -z nocopyreloc was given, we won't generate them either. */
+ if (info->nocopyreloc)
+ {
+ h->non_got_ref = 0;
+ return true;
+ }
+
+ if (ELIMINATE_COPY_RELOCS)
+ {
+ struct elf_aarch64_link_hash_entry *eh;
+ /* If we don't find any dynamic relocs in read-only sections, then
+ we'll be keeping the dynamic relocs and avoiding the copy reloc. */
+ eh = (struct elf_aarch64_link_hash_entry *) h;
+ if (!need_copy_relocation_p (eh))
+ {
+ h->non_got_ref = 0;
+ return true;
+ }
+ }
+
+ /* We must allocate the symbol in our .dynbss section, which will
+ become part of the .bss section of the executable. There will be
+ an entry for this symbol in the .dynsym section. The dynamic
+ object will contain position independent code, so all references
+ from the dynamic object to this symbol will go through the global
+ offset table. The dynamic linker will use the .dynsym entry to
+ determine the address it must put in the global offset table, so
+ both the dynamic object and the regular object will refer to the
+ same memory location for the variable. */
+
+ htab = elf_aarch64_hash_table (info);
+
+ /* We must generate a R_AARCH64_COPY reloc to tell the dynamic linker
+ to copy the initial value out of the dynamic object and into the
+ runtime process image. */
+ if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+ {
+ s = htab->root.sdynrelro;
+ srel = htab->root.sreldynrelro;
+ }
+ else
+ {
+ s = htab->root.sdynbss;
+ srel = htab->root.srelbss;
+ }
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
+ {
+ srel->size += RELOC_SIZE (htab);
+ h->needs_copy = 1;
+ }
+
+ return _bfd_elf_adjust_dynamic_copy (info, h, s);
+
+}
+
+static bool
+elfNN_aarch64_allocate_local_symbols (bfd *abfd, unsigned number)
+{
+ struct elf_aarch64_local_symbol *locals;
+ locals = elf_aarch64_locals (abfd);
+ if (locals == NULL)
+ {
+ locals = (struct elf_aarch64_local_symbol *)
+ bfd_zalloc (abfd, number * sizeof (struct elf_aarch64_local_symbol));
+ if (locals == NULL)
+ return false;
+ elf_aarch64_locals (abfd) = locals;
+ }
+ return true;
+}
+
+/* Create the .got section to hold the global offset table. */
+
+static bool
+aarch64_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ flagword flags;
+ asection *s;
+ struct elf_link_hash_entry *h;
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+
+ /* This function may be called more than once. */
+ if (htab->sgot != NULL)
+ return true;
+
+ flags = bed->dynamic_sec_flags;
+
+ s = bfd_make_section_anyway_with_flags (abfd,
+ (bed->rela_plts_and_copies_p
+ ? ".rela.got" : ".rel.got"),
+ (bed->dynamic_sec_flags
+ | SEC_READONLY));
+ if (s == NULL
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
+ return false;
+ htab->srelgot = s;
+
+ s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
+ if (s == NULL
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
+ return false;
+ htab->sgot = s;
+ htab->sgot->size += GOT_ENTRY_SIZE;
+
+ if (bed->want_got_sym)
+ {
+ /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
+ (or .got.plt) section. We don't do this in the linker script
+ because we don't want to define the symbol if we are not creating
+ a global offset table. */
+ h = _bfd_elf_define_linkage_sym (abfd, info, s,
+ "_GLOBAL_OFFSET_TABLE_");
+ elf_hash_table (info)->hgot = h;
+ if (h == NULL)
+ return false;
+ }
+
+ if (bed->want_got_plt)
+ {
+ s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags);
+ if (s == NULL
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
+ return false;
+ htab->sgotplt = s;
+ }
+
+ /* The first bit of the global offset table is the header. */
+ s->size += bed->got_header_size;
+
+ return true;
+}
+
+/* Look through the relocs for a section during the first phase. */
+
+static bool
+elfNN_aarch64_check_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;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ asection *sreloc;
+
+ struct elf_aarch64_link_hash_table *htab;
+
+ if (bfd_link_relocatable (info))
+ return true;
+
+ BFD_ASSERT (is_aarch64_elf (abfd));
+
+ htab = elf_aarch64_hash_table (info);
+ sreloc = NULL;
+
+ symtab_hdr = &elf_symtab_hdr (abfd);
+ sym_hashes = elf_sym_hashes (abfd);
+
+ rel_end = relocs + sec->reloc_count;
+ for (rel = relocs; rel < rel_end; rel++)
+ {
+ struct elf_link_hash_entry *h;
+ unsigned int r_symndx;
+ unsigned int r_type;
+ bfd_reloc_code_real_type bfd_r_type;
+ Elf_Internal_Sym *isym;
+
+ r_symndx = ELFNN_R_SYM (rel->r_info);
+ r_type = ELFNN_R_TYPE (rel->r_info);
+
+ if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: bad symbol index: %d"), abfd, r_symndx);
+ return false;
+ }
+
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ /* A local symbol. */
+ isym = bfd_sym_from_r_symndx (&htab->root.sym_cache,
+ abfd, r_symndx);
+ if (isym == NULL)
+ return false;
+
+ /* Check relocation against local STT_GNU_IFUNC symbol. */
+ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+ {
+ h = elfNN_aarch64_get_local_sym_hash (htab, abfd, rel,
+ true);
+ if (h == NULL)
+ return false;
+
+ /* Fake a STT_GNU_IFUNC symbol. */
+ h->type = STT_GNU_IFUNC;
+ h->def_regular = 1;
+ h->ref_regular = 1;
+ h->forced_local = 1;
+ h->root.type = bfd_link_hash_defined;
+ }
+ else
+ h = NULL;
+ }
+ else
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+
+ /* Could be done earlier, if h were already available. */
+ bfd_r_type = aarch64_tls_transition (abfd, info, r_type, h, r_symndx);
+
+ if (h != NULL)
+ {
+ /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
+ This shows up in particular in an R_AARCH64_PREL64 in large model
+ when calculating the pc-relative address to .got section which is
+ used to initialize the gp register. */
+ if (h->root.root.string
+ && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ {
+ if (htab->root.dynobj == NULL)
+ htab->root.dynobj = abfd;
+
+ if (! aarch64_elf_create_got_section (htab->root.dynobj, info))
+ return false;
+
+ BFD_ASSERT (h == htab->root.hgot);
+ }
+
+ /* Create the ifunc sections for static executables. If we
+ never see an indirect function symbol nor we are building
+ a static executable, those sections will be empty and
+ won't appear in output. */
+ switch (bfd_r_type)
+ {
+ default:
+ break;
+
+ case BFD_RELOC_AARCH64_ADD_LO12:
+ case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
+ case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+ case BFD_RELOC_AARCH64_CALL26:
+ case BFD_RELOC_AARCH64_GOT_LD_PREL19:
+ case BFD_RELOC_AARCH64_JUMP26:
+ case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
+ case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+ case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+ case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
+ case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+ case BFD_RELOC_AARCH64_NN:
+ if (htab->root.dynobj == NULL)
+ htab->root.dynobj = abfd;
+ if (!_bfd_elf_create_ifunc_sections (htab->root.dynobj, info))
+ return false;
+ break;
+ }
+
+ /* It is referenced by a non-shared object. */
+ h->ref_regular = 1;
+ }
+
+ switch (bfd_r_type)
+ {
+ case BFD_RELOC_AARCH64_16:
+#if ARCH_SIZE == 64
+ case BFD_RELOC_AARCH64_32:
+#endif
+ if (bfd_link_pic (info) && (sec->flags & SEC_ALLOC) != 0)
+ {
+ if (h != NULL
+ /* This is an absolute symbol. It represents a value instead
+ of an address. */
+ && (bfd_is_abs_symbol (&h->root)
+ /* This is an undefined symbol. */
+ || h->root.type == bfd_link_hash_undefined))
+ break;
+
+ /* For local symbols, defined global symbols in a non-ABS section,
+ it is assumed that the value is an address. */
+ int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against `%s' can not be used when making "
+ "a shared object"),
+ abfd, elfNN_aarch64_howto_table[howto_index].name,
+ (h) ? h->root.root.string : "a local symbol");
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ else
+ break;
+
+ case BFD_RELOC_AARCH64_MOVW_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_G1_NC:
+ case BFD_RELOC_AARCH64_MOVW_G2_NC:
+ case BFD_RELOC_AARCH64_MOVW_G3:
+ if (bfd_link_pic (info))
+ {
+ int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against `%s' can not be used when making "
+ "a shared object; recompile with -fPIC"),
+ abfd, elfNN_aarch64_howto_table[howto_index].name,
+ (h) ? h->root.root.string : "a local symbol");
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ /* Fall through. */
+
+ case BFD_RELOC_AARCH64_16_PCREL:
+ case BFD_RELOC_AARCH64_32_PCREL:
+ case BFD_RELOC_AARCH64_64_PCREL:
+ case BFD_RELOC_AARCH64_ADD_LO12:
+ case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
+ case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+ case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
+ case BFD_RELOC_AARCH64_LDST128_LO12:
+ case BFD_RELOC_AARCH64_LDST16_LO12:
+ case BFD_RELOC_AARCH64_LDST32_LO12:
+ case BFD_RELOC_AARCH64_LDST64_LO12:
+ case BFD_RELOC_AARCH64_LDST8_LO12:
+ case BFD_RELOC_AARCH64_LD_LO19_PCREL:
+ if (h == NULL || bfd_link_pic (info))
+ break;
+ /* Fall through. */
+
+ case BFD_RELOC_AARCH64_NN:
+
+ /* We don't need to handle relocs into sections not going into
+ the "real" output. */
+ if ((sec->flags & SEC_ALLOC) == 0)
+ break;
+
+ if (h != NULL)
+ {
+ if (!bfd_link_pic (info))
+ h->non_got_ref = 1;
+
+ h->plt.refcount += 1;
+ h->pointer_equality_needed = 1;
+ }
+
+ /* No need to do anything if we're not creating a shared
+ object. */
+ if (!(bfd_link_pic (info)
+ /* If on the other hand, we are creating an executable, we
+ may need to keep relocations for symbols satisfied by a
+ dynamic library if we manage to avoid copy relocs for the
+ symbol.
+
+ NOTE: Currently, there is no support of copy relocs
+ elimination on pc-relative relocation types, because there is
+ no dynamic relocation support for them in glibc. We still
+ record the dynamic symbol reference for them. This is
+ because one symbol may be referenced by both absolute
+ relocation (for example, BFD_RELOC_AARCH64_NN) and
+ pc-relative relocation. We need full symbol reference
+ information to make correct decision later in
+ elfNN_aarch64_adjust_dynamic_symbol. */
+ || (ELIMINATE_COPY_RELOCS
+ && !bfd_link_pic (info)
+ && h != NULL
+ && (h->root.type == bfd_link_hash_defweak
+ || !h->def_regular))))
+ break;
+
+ {
+ struct elf_dyn_relocs *p;
+ struct elf_dyn_relocs **head;
+ int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+
+ /* We must copy these reloc types into the output file.
+ Create a reloc section in dynobj and make room for
+ this reloc. */
+ if (sreloc == NULL)
+ {
+ if (htab->root.dynobj == NULL)
+ htab->root.dynobj = abfd;
+
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, htab->root.dynobj, LOG_FILE_ALIGN, abfd, /*rela? */ true);
+
+ if (sreloc == NULL)
+ return false;
+ }
+
+ /* If this is a global symbol, we count the number of
+ relocations we need for this symbol. */
+ if (h != NULL)
+ {
+ head = &h->dyn_relocs;
+ }
+ else
+ {
+ /* Track dynamic relocs needed for local syms too.
+ We really need local syms available to do this
+ easily. Oh well. */
+
+ asection *s;
+ void **vpp;
+
+ isym = bfd_sym_from_r_symndx (&htab->root.sym_cache,
+ abfd, r_symndx);
+ if (isym == NULL)
+ return false;
+
+ s = bfd_section_from_elf_index (abfd, isym->st_shndx);
+ if (s == NULL)
+ s = sec;
+
+ /* Beware of type punned pointers vs strict aliasing
+ rules. */
+ vpp = &(elf_section_data (s)->local_dynrel);
+ head = (struct elf_dyn_relocs **) vpp;
+ }
+
+ p = *head;
+ if (p == NULL || p->sec != sec)
+ {
+ size_t amt = sizeof *p;
+ p = ((struct elf_dyn_relocs *)
+ bfd_zalloc (htab->root.dynobj, amt));
+ if (p == NULL)
+ return false;
+ p->next = *head;
+ *head = p;
+ p->sec = sec;
+ }
+
+ p->count += 1;
+
+ if (elfNN_aarch64_howto_table[howto_index].pc_relative)
+ p->pc_count += 1;
+ }
+ break;
+
+ /* RR: We probably want to keep a consistency check that
+ there are no dangling GOT_PAGE relocs. */
+ case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
+ case BFD_RELOC_AARCH64_GOT_LD_PREL19:
+ case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
+ case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
+ case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+ case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
+ case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
+ case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12:
+ case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+ case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
+ case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
+ case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
+ case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
+ case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
+ {
+ unsigned got_type;
+ unsigned old_got_type;
+
+ got_type = aarch64_reloc_got_type (bfd_r_type);
+
+ if (h)
+ {
+ h->got.refcount += 1;
+ old_got_type = elf_aarch64_hash_entry (h)->got_type;
+ }
+ else
+ {
+ struct elf_aarch64_local_symbol *locals;
+
+ if (!elfNN_aarch64_allocate_local_symbols
+ (abfd, symtab_hdr->sh_info))
+ return false;
+
+ locals = elf_aarch64_locals (abfd);
+ BFD_ASSERT (r_symndx < symtab_hdr->sh_info);
+ locals[r_symndx].got_refcount += 1;
+ old_got_type = locals[r_symndx].got_type;
+ }
+
+ /* If a variable is accessed with both general dynamic TLS
+ methods, two slots may be created. */
+ if (GOT_TLS_GD_ANY_P (old_got_type) && GOT_TLS_GD_ANY_P (got_type))
+ got_type |= old_got_type;
+
+ /* We will already have issued an error message if there
+ is a TLS/non-TLS mismatch, based on the symbol type.
+ So just combine any TLS types needed. */
+ if (old_got_type != GOT_UNKNOWN && old_got_type != GOT_NORMAL
+ && got_type != GOT_NORMAL)
+ got_type |= old_got_type;
+
+ /* If the symbol is accessed by both IE and GD methods, we
+ are able to relax. Turn off the GD flag, without
+ messing up with any other kind of TLS types that may be
+ involved. */
+ if ((got_type & GOT_TLS_IE) && GOT_TLS_GD_ANY_P (got_type))
+ got_type &= ~ (GOT_TLSDESC_GD | GOT_TLS_GD);
+
+ if (old_got_type != got_type)
+ {
+ if (h != NULL)
+ elf_aarch64_hash_entry (h)->got_type = got_type;
+ else
+ {
+ struct elf_aarch64_local_symbol *locals;
+ locals = elf_aarch64_locals (abfd);
+ BFD_ASSERT (r_symndx < symtab_hdr->sh_info);
+ locals[r_symndx].got_type = got_type;
+ }
+ }
+
+ if (htab->root.dynobj == NULL)
+ htab->root.dynobj = abfd;
+ if (! aarch64_elf_create_got_section (htab->root.dynobj, info))
+ return false;
+ break;
+ }
+
+ case BFD_RELOC_AARCH64_CALL26:
+ case BFD_RELOC_AARCH64_JUMP26:
+ /* If this is a local symbol then we resolve it
+ directly without creating a PLT entry. */
+ if (h == NULL)
+ continue;
+
+ h->needs_plt = 1;
+ if (h->plt.refcount <= 0)
+ h->plt.refcount = 1;
+ else
+ h->plt.refcount += 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
+/* Treat mapping symbols as special target symbols. */
+
+static bool
+elfNN_aarch64_is_target_special_symbol (bfd *abfd ATTRIBUTE_UNUSED,
+ asymbol *sym)
+{
+ return bfd_is_aarch64_special_symbol_name (sym->name,
+ BFD_AARCH64_SPECIAL_SYM_TYPE_ANY);
+}
+
+/* If the ELF symbol SYM might be a function in SEC, return the
+ function size and set *CODE_OFF to the function's entry point,
+ otherwise return zero. */
+
+static bfd_size_type
+elfNN_aarch64_maybe_function_sym (const asymbol *sym, asection *sec,
+ bfd_vma *code_off)
+{
+ bfd_size_type size;
+ elf_symbol_type * elf_sym = (elf_symbol_type *) sym;
+
+ if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
+ | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
+ || sym->section != sec)
+ return 0;
+
+ size = (sym->flags & BSF_SYNTHETIC) ? 0 : elf_sym->internal_elf_sym.st_size;
+
+ if (!(sym->flags & BSF_SYNTHETIC))
+ switch (ELF_ST_TYPE (elf_sym->internal_elf_sym.st_info))
+ {
+ case STT_NOTYPE:
+ /* Ignore symbols created by the annobin plugin for gcc and clang.
+ These symbols are hidden, local, notype and have a size of 0. */
+ if (size == 0
+ && sym->flags & BSF_LOCAL
+ && ELF_ST_VISIBILITY (elf_sym->internal_elf_sym.st_other) == STV_HIDDEN)
+ return 0;
+ /* Fall through. */
+ case STT_FUNC:
+ /* FIXME: Allow STT_GNU_IFUNC as well ? */
+ break;
+ default:
+ return 0;
+ }
+
+ if ((sym->flags & BSF_LOCAL)
+ && bfd_is_aarch64_special_symbol_name (sym->name,
+ BFD_AARCH64_SPECIAL_SYM_TYPE_ANY))
+ return 0;
+
+ *code_off = sym->value;
+
+ /* Do not return 0 for the function's size. */
+ return size ? size : 1;
+}
+
+static bool
+elfNN_aarch64_find_inliner_info (bfd *abfd,
+ const char **filename_ptr,
+ const char **functionname_ptr,
+ unsigned int *line_ptr)
+{
+ bool found;
+ found = _bfd_dwarf2_find_inliner_info
+ (abfd, filename_ptr,
+ functionname_ptr, line_ptr, &elf_tdata (abfd)->dwarf2_find_line_info);
+ return found;
+}
+
+
+static bool
+elfNN_aarch64_init_file_header (bfd *abfd, struct bfd_link_info *link_info)
+{
+ Elf_Internal_Ehdr *i_ehdrp; /* ELF file header, internal form. */
+
+ if (!_bfd_elf_init_file_header (abfd, link_info))
+ return false;
+
+ i_ehdrp = elf_elfheader (abfd);
+ i_ehdrp->e_ident[EI_ABIVERSION] = AARCH64_ELF_ABI_VERSION;
+ return true;
+}
+
+static enum elf_reloc_type_class
+elfNN_aarch64_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ const asection *rel_sec ATTRIBUTE_UNUSED,
+ const Elf_Internal_Rela *rela)
+{
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+
+ if (htab->root.dynsym != NULL
+ && htab->root.dynsym->contents != NULL)
+ {
+ /* Check relocation against STT_GNU_IFUNC symbol if there are
+ dynamic symbols. */
+ bfd *abfd = info->output_bfd;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ unsigned long r_symndx = ELFNN_R_SYM (rela->r_info);
+ if (r_symndx != STN_UNDEF)
+ {
+ Elf_Internal_Sym sym;
+ if (!bed->s->swap_symbol_in (abfd,
+ (htab->root.dynsym->contents
+ + r_symndx * bed->s->sizeof_sym),
+ 0, &sym))
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB symbol number %lu references"
+ " nonexistent SHT_SYMTAB_SHNDX section"),
+ abfd, r_symndx);
+ /* Ideally an error class should be returned here. */
+ }
+ else if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+ return reloc_class_ifunc;
+ }
+ }
+
+ switch ((int) ELFNN_R_TYPE (rela->r_info))
+ {
+ case AARCH64_R (IRELATIVE):
+ return reloc_class_ifunc;
+ case AARCH64_R (RELATIVE):
+ return reloc_class_relative;
+ case AARCH64_R (JUMP_SLOT):
+ return reloc_class_plt;
+ case AARCH64_R (COPY):
+ return reloc_class_copy;
+ default:
+ return reloc_class_normal;
+ }
+}
+
+/* Handle an AArch64 specific section when reading an object file. This is
+ called when bfd_section_from_shdr finds a section with an unknown
+ type. */
+
+static bool
+elfNN_aarch64_section_from_shdr (bfd *abfd,
+ Elf_Internal_Shdr *hdr,
+ const char *name, int shindex)
+{
+ /* There ought to be a place to keep ELF backend specific flags, but
+ at the moment there isn't one. We just keep track of the
+ sections by their name, instead. Fortunately, the ABI gives
+ names for all the AArch64 specific sections, so we will probably get
+ away with this. */
+ switch (hdr->sh_type)
+ {
+ case SHT_AARCH64_ATTRIBUTES:
+ break;
+
+ default:
+ return false;
+ }
+
+ if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+ return false;
+
+ return true;
+}
+
+/* Process any AArch64-specific program segment types. */
+
+static bool
+elfNN_aarch64_section_from_phdr (bfd *abfd ATTRIBUTE_UNUSED,
+ Elf_Internal_Phdr *hdr,
+ int hdr_index ATTRIBUTE_UNUSED,
+ const char *name ATTRIBUTE_UNUSED)
+{
+ /* Right now we only handle the PT_AARCH64_MEMTAG_MTE segment type. */
+ if (hdr == NULL || hdr->p_type != PT_AARCH64_MEMTAG_MTE)
+ return false;
+
+ if (hdr->p_filesz > 0)
+ {
+ /* Sections created from memory tag p_type's are always named
+ "memtag". This makes it easier for tools (for example, GDB)
+ to find them. */
+ asection *newsect = bfd_make_section_anyway (abfd, "memtag");
+
+ if (newsect == NULL)
+ return false;
+
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
+
+ /* p_vaddr holds the original start address of the tagged memory
+ range. */
+ newsect->vma = hdr->p_vaddr / opb;
+
+ /* p_filesz holds the storage size of the packed tags. */
+ newsect->size = hdr->p_filesz;
+ newsect->filepos = hdr->p_offset;
+
+ /* p_memsz holds the size of the memory range that contains tags. The
+ section's rawsize field is reused for this purpose. */
+ newsect->rawsize = hdr->p_memsz;
+
+ /* Make sure the section's flags has SEC_HAS_CONTENTS set, otherwise
+ BFD will return all zeroes when attempting to get contents from this
+ section. */
+ newsect->flags |= SEC_HAS_CONTENTS;
+ }
+
+ return true;
+}
+
+/* Implements the bfd_elf_modify_headers hook for aarch64. */
+
+static bool
+elfNN_aarch64_modify_headers (bfd *abfd,
+ struct bfd_link_info *info)
+{
+ struct elf_segment_map *m;
+ unsigned int segment_count = 0;
+ Elf_Internal_Phdr *p;
+
+ for (m = elf_seg_map (abfd); m != NULL; m = m->next, segment_count++)
+ {
+ /* We are only interested in the memory tag segment that will be dumped
+ to a core file. If we have no memory tags or this isn't a core file we
+ are dealing with, just skip this segment. */
+ if (m->p_type != PT_AARCH64_MEMTAG_MTE
+ || bfd_get_format (abfd) != bfd_core)
+ continue;
+
+ /* For memory tag segments in core files, the size of the file contents
+ is smaller than the size of the memory range. Adjust the memory size
+ accordingly. The real memory size is held in the section's rawsize
+ field. */
+ if (m->count > 0)
+ {
+ p = elf_tdata (abfd)->phdr;
+ p += m->idx;
+ p->p_memsz = m->sections[0]->rawsize;
+ p->p_flags = 0;
+ p->p_paddr = 0;
+ p->p_align = 0;
+ }
+ }
+
+ /* Give the generic code a chance to handle the headers. */
+ return _bfd_elf_modify_headers (abfd, info);
+}
+
+/* A structure used to record a list of sections, independently
+ of the next and prev fields in the asection structure. */
+typedef struct section_list
+{
+ asection *sec;
+ struct section_list *next;
+ struct section_list *prev;
+}
+section_list;
+
+/* Unfortunately we need to keep a list of sections for which
+ an _aarch64_elf_section_data structure has been allocated. This
+ is because it is possible for functions like elfNN_aarch64_write_section
+ to be called on a section which has had an elf_data_structure
+ allocated for it (and so the used_by_bfd field is valid) but
+ for which the AArch64 extended version of this structure - the
+ _aarch64_elf_section_data structure - has not been allocated. */
+static section_list *sections_with_aarch64_elf_section_data = NULL;
+
+static void
+record_section_with_aarch64_elf_section_data (asection *sec)
+{
+ struct section_list *entry;
+
+ entry = bfd_malloc (sizeof (*entry));
+ if (entry == NULL)
+ return;
+ entry->sec = sec;
+ entry->next = sections_with_aarch64_elf_section_data;
+ entry->prev = NULL;
+ if (entry->next != NULL)
+ entry->next->prev = entry;
+ sections_with_aarch64_elf_section_data = entry;
+}
+
+static struct section_list *
+find_aarch64_elf_section_entry (asection *sec)
+{
+ struct section_list *entry;
+ static struct section_list *last_entry = NULL;
+
+ /* This is a short cut for the typical case where the sections are added
+ to the sections_with_aarch64_elf_section_data list in forward order and
+ then looked up here in backwards order. This makes a real difference
+ to the ld-srec/sec64k.exp linker test. */
+ entry = sections_with_aarch64_elf_section_data;
+ if (last_entry != NULL)
+ {
+ if (last_entry->sec == sec)
+ entry = last_entry;
+ else if (last_entry->next != NULL && last_entry->next->sec == sec)
+ entry = last_entry->next;
+ }
+
+ for (; entry; entry = entry->next)
+ if (entry->sec == sec)
+ break;
+
+ if (entry)
+ /* Record the entry prior to this one - it is the entry we are
+ most likely to want to locate next time. Also this way if we
+ have been called from
+ unrecord_section_with_aarch64_elf_section_data () we will not
+ be caching a pointer that is about to be freed. */
+ last_entry = entry->prev;
+
+ return entry;
+}
+
+static void
+unrecord_section_with_aarch64_elf_section_data (asection *sec)
+{
+ struct section_list *entry;
+
+ entry = find_aarch64_elf_section_entry (sec);
+
+ if (entry)
+ {
+ if (entry->prev != NULL)
+ entry->prev->next = entry->next;
+ if (entry->next != NULL)
+ entry->next->prev = entry->prev;
+ if (entry == sections_with_aarch64_elf_section_data)
+ sections_with_aarch64_elf_section_data = entry->next;
+ free (entry);
+ }
+}
+
+
+typedef struct
+{
+ void *finfo;
+ struct bfd_link_info *info;
+ asection *sec;
+ int sec_shndx;
+ int (*func) (void *, const char *, Elf_Internal_Sym *,
+ asection *, struct elf_link_hash_entry *);
+} output_arch_syminfo;
+
+enum map_symbol_type
+{
+ AARCH64_MAP_INSN,
+ AARCH64_MAP_DATA
+};
+
+
+/* Output a single mapping symbol. */
+
+static bool
+elfNN_aarch64_output_map_sym (output_arch_syminfo *osi,
+ enum map_symbol_type type, bfd_vma offset)
+{
+ static const char *names[2] = { "$x", "$d" };
+ Elf_Internal_Sym sym;
+
+ sym.st_value = (osi->sec->output_section->vma
+ + osi->sec->output_offset + offset);
+ sym.st_size = 0;
+ sym.st_other = 0;
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
+ sym.st_shndx = osi->sec_shndx;
+ return osi->func (osi->finfo, names[type], &sym, osi->sec, NULL) == 1;
+}
+
+/* Output a single local symbol for a generated stub. */
+
+static bool
+elfNN_aarch64_output_stub_sym (output_arch_syminfo *osi, const char *name,
+ bfd_vma offset, bfd_vma size)
+{
+ Elf_Internal_Sym sym;
+
+ sym.st_value = (osi->sec->output_section->vma
+ + osi->sec->output_offset + offset);
+ sym.st_size = size;
+ sym.st_other = 0;
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
+ sym.st_shndx = osi->sec_shndx;
+ return osi->func (osi->finfo, name, &sym, osi->sec, NULL) == 1;
+}
+
+static bool
+aarch64_map_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
+{
+ struct elf_aarch64_stub_hash_entry *stub_entry;
+ asection *stub_sec;
+ bfd_vma addr;
+ char *stub_name;
+ output_arch_syminfo *osi;
+
+ /* Massage our args to the form they really have. */
+ stub_entry = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+ osi = (output_arch_syminfo *) in_arg;
+
+ stub_sec = stub_entry->stub_sec;
+
+ /* Ensure this stub is attached to the current section being
+ processed. */
+ if (stub_sec != osi->sec)
+ return true;
+
+ addr = (bfd_vma) stub_entry->stub_offset;
+
+ stub_name = stub_entry->output_name;
+
+ switch (stub_entry->stub_type)
+ {
+ case aarch64_stub_adrp_branch:
+ if (!elfNN_aarch64_output_stub_sym (osi, stub_name, addr,
+ sizeof (aarch64_adrp_branch_stub)))
+ return false;
+ if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
+ return false;
+ break;
+ case aarch64_stub_long_branch:
+ if (!elfNN_aarch64_output_stub_sym
+ (osi, stub_name, addr, sizeof (aarch64_long_branch_stub)))
+ return false;
+ if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
+ return false;
+ if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_DATA, addr + 16))
+ return false;
+ break;
+ case aarch64_stub_erratum_835769_veneer:
+ if (!elfNN_aarch64_output_stub_sym (osi, stub_name, addr,
+ sizeof (aarch64_erratum_835769_stub)))
+ return false;
+ if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
+ return false;
+ break;
+ case aarch64_stub_erratum_843419_veneer:
+ if (!elfNN_aarch64_output_stub_sym (osi, stub_name, addr,
+ sizeof (aarch64_erratum_843419_stub)))
+ return false;
+ if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
+ return false;
+ break;
+ case aarch64_stub_none:
+ break;
+
+ default:
+ abort ();
+ }
+
+ return true;
+}
+
+/* Output mapping symbols for linker generated sections. */
+
+static bool
+elfNN_aarch64_output_arch_local_syms (bfd *output_bfd,
+ struct bfd_link_info *info,
+ void *finfo,
+ int (*func) (void *, const char *,
+ Elf_Internal_Sym *,
+ asection *,
+ struct elf_link_hash_entry
+ *))
+{
+ output_arch_syminfo osi;
+ struct elf_aarch64_link_hash_table *htab;
+
+ if (info->strip == strip_all
+ && !info->emitrelocations
+ && !bfd_link_relocatable (info))
+ return true;
+
+ htab = elf_aarch64_hash_table (info);
+
+ osi.finfo = finfo;
+ osi.info = info;
+ osi.func = func;
+
+ /* Long calls stubs. */
+ if (htab->stub_bfd && htab->stub_bfd->sections)
+ {
+ asection *stub_sec;
+
+ for (stub_sec = htab->stub_bfd->sections;
+ stub_sec != NULL; stub_sec = stub_sec->next)
+ {
+ /* Ignore non-stub sections. */
+ if (!strstr (stub_sec->name, STUB_SUFFIX))
+ continue;
+
+ osi.sec = stub_sec;
+
+ osi.sec_shndx = _bfd_elf_section_from_bfd_section
+ (output_bfd, osi.sec->output_section);
+
+ /* The first instruction in a stub is always a branch. */
+ if (!elfNN_aarch64_output_map_sym (&osi, AARCH64_MAP_INSN, 0))
+ return false;
+
+ bfd_hash_traverse (&htab->stub_hash_table, aarch64_map_one_stub,
+ &osi);
+ }
+ }
+
+ /* Finally, output mapping symbols for the PLT. */
+ if (!htab->root.splt || htab->root.splt->size == 0)
+ return true;
+
+ osi.sec_shndx = _bfd_elf_section_from_bfd_section
+ (output_bfd, htab->root.splt->output_section);
+ osi.sec = htab->root.splt;
+
+ elfNN_aarch64_output_map_sym (&osi, AARCH64_MAP_INSN, 0);
+
+ return true;
+
+}
+
+/* Allocate target specific section data. */
+
+static bool
+elfNN_aarch64_new_section_hook (bfd *abfd, asection *sec)
+{
+ if (!sec->used_by_bfd)
+ {
+ _aarch64_elf_section_data *sdata;
+ size_t amt = sizeof (*sdata);
+
+ sdata = bfd_zalloc (abfd, amt);
+ if (sdata == NULL)
+ return false;
+ sec->used_by_bfd = sdata;
+ }
+
+ record_section_with_aarch64_elf_section_data (sec);
+
+ return _bfd_elf_new_section_hook (abfd, sec);
+}
+
+
+static void
+unrecord_section_via_map_over_sections (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sec,
+ void *ignore ATTRIBUTE_UNUSED)
+{
+ unrecord_section_with_aarch64_elf_section_data (sec);
+}
+
+static bool
+elfNN_aarch64_close_and_cleanup (bfd *abfd)
+{
+ if (abfd->sections)
+ bfd_map_over_sections (abfd,
+ unrecord_section_via_map_over_sections, NULL);
+
+ return _bfd_elf_close_and_cleanup (abfd);
+}
+
+static bool
+elfNN_aarch64_bfd_free_cached_info (bfd *abfd)
+{
+ if (abfd->sections)
+ bfd_map_over_sections (abfd,
+ unrecord_section_via_map_over_sections, NULL);
+
+ return _bfd_free_cached_info (abfd);
+}
+
+/* Create dynamic sections. This is different from the ARM backend in that
+ the got, plt, gotplt and their relocation sections are all created in the
+ standard part of the bfd elf backend. */
+
+static bool
+elfNN_aarch64_create_dynamic_sections (bfd *dynobj,
+ struct bfd_link_info *info)
+{
+ /* We need to create .got section. */
+ if (!aarch64_elf_create_got_section (dynobj, info))
+ return false;
+
+ return _bfd_elf_create_dynamic_sections (dynobj, info);
+}
+
+
+/* Allocate space in .plt, .got and associated reloc sections for
+ dynamic relocs. */
+
+static bool
+elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
+{
+ struct bfd_link_info *info;
+ struct elf_aarch64_link_hash_table *htab;
+ struct elf_aarch64_link_hash_entry *eh;
+ struct elf_dyn_relocs *p;
+
+ /* An example of a bfd_link_hash_indirect symbol is versioned
+ symbol. For example: __gxx_personality_v0(bfd_link_hash_indirect)
+ -> __gxx_personality_v0(bfd_link_hash_defined)
+
+ There is no need to process bfd_link_hash_indirect symbols here
+ because we will also be presented with the concrete instance of
+ the symbol and elfNN_aarch64_copy_indirect_symbol () will have been
+ called to copy all relevant data from the generic to the concrete
+ symbol instance. */
+ if (h->root.type == bfd_link_hash_indirect)
+ return true;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ info = (struct bfd_link_info *) inf;
+ htab = elf_aarch64_hash_table (info);
+
+ /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
+ here if it is defined and referenced in a non-shared object. */
+ if (h->type == STT_GNU_IFUNC
+ && h->def_regular)
+ return true;
+ else if (htab->root.dynamic_sections_created && h->plt.refcount > 0)
+ {
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1 && !h->forced_local
+ && h->root.type == bfd_link_hash_undefweak)
+ {
+ if (!bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ if (bfd_link_pic (info) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
+ {
+ asection *s = htab->root.splt;
+
+ /* If this is the first .plt entry, make room for the special
+ first entry. */
+ if (s->size == 0)
+ s->size += htab->plt_header_size;
+
+ h->plt.offset = s->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 (!bfd_link_pic (info) && !h->def_regular)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = h->plt.offset;
+ }
+
+ /* Make room for this entry. For now we only create the
+ small model PLT entries. We later need to find a way
+ of relaxing into these from the large model PLT entries. */
+ s->size += htab->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. */
+ htab->root.sgotplt->size += GOT_ENTRY_SIZE;
+
+ /* We also need to make an entry in the .rela.plt section. */
+ htab->root.srelplt->size += RELOC_SIZE (htab);
+
+ /* We need to ensure that all GOT entries that serve the PLT
+ are consecutive with the special GOT slots [0] [1] and
+ [2]. Any addtional relocations, such as
+ R_AARCH64_TLSDESC, must be placed after the PLT related
+ entries. We abuse the reloc_count such that during
+ sizing we adjust reloc_count to indicate the number of
+ PLT related reserved entries. In subsequent phases when
+ filling in the contents of the reloc entries, PLT related
+ entries are placed by computing their PLT index (0
+ .. reloc_count). While other none PLT relocs are placed
+ at the slot indicated by reloc_count and reloc_count is
+ updated. */
+
+ htab->root.srelplt->reloc_count++;
+
+ /* Mark the DSO in case R_<CLS>_JUMP_SLOT relocs against
+ variant PCS symbols are present. */
+ if (h->other & STO_AARCH64_VARIANT_PCS)
+ htab->variant_pcs = 1;
+
+ }
+ else
+ {
+ h->plt.offset = (bfd_vma) - 1;
+ h->needs_plt = 0;
+ }
+ }
+ else
+ {
+ h->plt.offset = (bfd_vma) - 1;
+ h->needs_plt = 0;
+ }
+
+ eh = (struct elf_aarch64_link_hash_entry *) h;
+ eh->tlsdesc_got_jump_table_offset = (bfd_vma) - 1;
+
+ if (h->got.refcount > 0)
+ {
+ bool dyn;
+ unsigned got_type = elf_aarch64_hash_entry (h)->got_type;
+
+ h->got.offset = (bfd_vma) - 1;
+
+ dyn = htab->root.dynamic_sections_created;
+
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (dyn && h->dynindx == -1 && !h->forced_local
+ && h->root.type == bfd_link_hash_undefweak)
+ {
+ if (!bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ if (got_type == GOT_UNKNOWN)
+ {
+ }
+ else if (got_type == GOT_NORMAL)
+ {
+ h->got.offset = htab->root.sgot->size;
+ htab->root.sgot->size += GOT_ENTRY_SIZE;
+ if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
+ && (bfd_link_pic (info)
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+ /* Undefined weak symbol in static PIE resolves to 0 without
+ any dynamic relocations. */
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ {
+ htab->root.srelgot->size += RELOC_SIZE (htab);
+ }
+ }
+ else
+ {
+ int indx;
+ if (got_type & GOT_TLSDESC_GD)
+ {
+ eh->tlsdesc_got_jump_table_offset =
+ (htab->root.sgotplt->size
+ - aarch64_compute_jump_table_size (htab));
+ htab->root.sgotplt->size += GOT_ENTRY_SIZE * 2;
+ h->got.offset = (bfd_vma) - 2;
+ }
+
+ if (got_type & GOT_TLS_GD)
+ {
+ h->got.offset = htab->root.sgot->size;
+ htab->root.sgot->size += GOT_ENTRY_SIZE * 2;
+ }
+
+ if (got_type & GOT_TLS_IE)
+ {
+ h->got.offset = htab->root.sgot->size;
+ htab->root.sgot->size += GOT_ENTRY_SIZE;
+ }
+
+ indx = h && h->dynindx != -1 ? h->dynindx : 0;
+ if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
+ && (!bfd_link_executable (info)
+ || indx != 0
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
+ {
+ if (got_type & GOT_TLSDESC_GD)
+ {
+ htab->root.srelplt->size += RELOC_SIZE (htab);
+ /* Note reloc_count not incremented here! We have
+ already adjusted reloc_count for this relocation
+ type. */
+
+ /* TLSDESC PLT is now needed, but not yet determined. */
+ htab->root.tlsdesc_plt = (bfd_vma) - 1;
+ }
+
+ if (got_type & GOT_TLS_GD)
+ htab->root.srelgot->size += RELOC_SIZE (htab) * 2;
+
+ if (got_type & GOT_TLS_IE)
+ htab->root.srelgot->size += RELOC_SIZE (htab);
+ }
+ }
+ }
+ else
+ {
+ h->got.offset = (bfd_vma) - 1;
+ }
+
+ if (h->dyn_relocs == NULL)
+ return true;
+
+ for (p = h->dyn_relocs; p != NULL; p = p->next)
+ if (eh->def_protected)
+ {
+ /* Disallow copy relocations against protected symbol. */
+ asection *s = p->sec->output_section;
+ if (s != NULL && (s->flags & SEC_READONLY) != 0)
+ {
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_ ("%F%P: %pB: copy relocation against non-copyable "
+ "protected symbol `%s'\n"),
+ p->sec->owner, h->root.root.string);
+ return false;
+ }
+ }
+
+ /* In the shared -Bsymbolic case, discard space allocated for
+ dynamic pc-relative relocs against symbols which turn out to be
+ defined in regular objects. For the normal shared case, discard
+ space for pc-relative relocs that have become local due to symbol
+ visibility changes. */
+
+ if (bfd_link_pic (info))
+ {
+ /* Relocs that use pc_count are those that appear on a call
+ insn, or certain REL relocs that can generated via assembly.
+ We want calls to protected symbols to resolve directly to the
+ function rather than going via the plt. If people want
+ function pointer comparisons to work as expected then they
+ should avoid writing weird assembly. */
+ if (SYMBOL_CALLS_LOCAL (info, h))
+ {
+ struct elf_dyn_relocs **pp;
+
+ for (pp = &h->dyn_relocs; (p = *pp) != NULL;)
+ {
+ p->count -= p->pc_count;
+ p->pc_count = 0;
+ if (p->count == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
+ }
+
+ /* Also discard relocs on undefined weak syms with non-default
+ visibility. */
+ if (h->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak)
+ {
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ h->dyn_relocs = NULL;
+
+ /* Make sure undefined weak symbols are output as a dynamic
+ symbol in PIEs. */
+ else if (h->dynindx == -1
+ && !h->forced_local
+ && h->root.type == bfd_link_hash_undefweak
+ && !bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ }
+ else if (ELIMINATE_COPY_RELOCS)
+ {
+ /* For the non-shared case, discard space for relocs against
+ symbols which turn out to need copy relocs or are not
+ dynamic. */
+
+ if (!h->non_got_ref
+ && ((h->def_dynamic
+ && !h->def_regular)
+ || (htab->root.dynamic_sections_created
+ && (h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_undefined))))
+ {
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1
+ && !h->forced_local
+ && h->root.type == bfd_link_hash_undefweak
+ && !bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+
+ /* If that succeeded, we know we'll be keeping all the
+ relocs. */
+ if (h->dynindx != -1)
+ goto keep;
+ }
+
+ h->dyn_relocs = NULL;
+
+ keep:;
+ }
+
+ /* Finally, allocate space. */
+ for (p = h->dyn_relocs; p != NULL; p = p->next)
+ {
+ asection *sreloc;
+
+ sreloc = elf_section_data (p->sec)->sreloc;
+
+ BFD_ASSERT (sreloc != NULL);
+
+ sreloc->size += p->count * RELOC_SIZE (htab);
+ }
+
+ return true;
+}
+
+/* Allocate space in .plt, .got and associated reloc sections for
+ ifunc dynamic relocs. */
+
+static bool
+elfNN_aarch64_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
+ void *inf)
+{
+ struct bfd_link_info *info;
+ struct elf_aarch64_link_hash_table *htab;
+
+ /* An example of a bfd_link_hash_indirect symbol is versioned
+ symbol. For example: __gxx_personality_v0(bfd_link_hash_indirect)
+ -> __gxx_personality_v0(bfd_link_hash_defined)
+
+ There is no need to process bfd_link_hash_indirect symbols here
+ because we will also be presented with the concrete instance of
+ the symbol and elfNN_aarch64_copy_indirect_symbol () will have been
+ called to copy all relevant data from the generic to the concrete
+ symbol instance. */
+ if (h->root.type == bfd_link_hash_indirect)
+ return true;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ info = (struct bfd_link_info *) inf;
+ htab = elf_aarch64_hash_table (info);
+
+ /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
+ here if it is defined and referenced in a non-shared object. */
+ if (h->type == STT_GNU_IFUNC
+ && h->def_regular)
+ return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
+ &h->dyn_relocs,
+ htab->plt_entry_size,
+ htab->plt_header_size,
+ GOT_ENTRY_SIZE,
+ false);
+ return true;
+}
+
+/* Allocate space in .plt, .got and associated reloc sections for
+ local ifunc dynamic relocs. */
+
+static int
+elfNN_aarch64_allocate_local_ifunc_dynrelocs (void **slot, void *inf)
+{
+ struct elf_link_hash_entry *h
+ = (struct elf_link_hash_entry *) *slot;
+
+ if (h->type != STT_GNU_IFUNC
+ || !h->def_regular
+ || !h->ref_regular
+ || !h->forced_local
+ || h->root.type != bfd_link_hash_defined)
+ abort ();
+
+ return elfNN_aarch64_allocate_ifunc_dynrelocs (h, inf);
+}
+
+/* This is the most important function of all . Innocuosly named
+ though ! */
+
+static bool
+elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info)
+{
+ struct elf_aarch64_link_hash_table *htab;
+ bfd *dynobj;
+ asection *s;
+ bool relocs;
+ bfd *ibfd;
+
+ htab = elf_aarch64_hash_table ((info));
+ dynobj = htab->root.dynobj;
+
+ BFD_ASSERT (dynobj != NULL);
+
+ if (htab->root.dynamic_sections_created)
+ {
+ if (bfd_link_executable (info) && !info->nointerp)
+ {
+ s = bfd_get_linker_section (dynobj, ".interp");
+ if (s == NULL)
+ abort ();
+ s->size = sizeof ELF_DYNAMIC_INTERPRETER;
+ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+ }
+ }
+
+ /* Set up .got offsets for local syms, and space for local dynamic
+ relocs. */
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+ {
+ struct elf_aarch64_local_symbol *locals = NULL;
+ Elf_Internal_Shdr *symtab_hdr;
+ asection *srel;
+ unsigned int i;
+
+ if (!is_aarch64_elf (ibfd))
+ continue;
+
+ for (s = ibfd->sections; s != NULL; s = s->next)
+ {
+ struct elf_dyn_relocs *p;
+
+ for (p = (struct elf_dyn_relocs *)
+ (elf_section_data (s)->local_dynrel); p != NULL; p = p->next)
+ {
+ if (!bfd_is_abs_section (p->sec)
+ && bfd_is_abs_section (p->sec->output_section))
+ {
+ /* Input section has been discarded, either because
+ it is a copy of a linkonce section or due to
+ linker script /DISCARD/, so we'll be discarding
+ the relocs too. */
+ }
+ else if (p->count != 0)
+ {
+ srel = elf_section_data (p->sec)->sreloc;
+ srel->size += p->count * RELOC_SIZE (htab);
+ if ((p->sec->output_section->flags & SEC_READONLY) != 0)
+ info->flags |= DF_TEXTREL;
+ }
+ }
+ }
+
+ locals = elf_aarch64_locals (ibfd);
+ if (!locals)
+ continue;
+
+ symtab_hdr = &elf_symtab_hdr (ibfd);
+ srel = htab->root.srelgot;
+ for (i = 0; i < symtab_hdr->sh_info; i++)
+ {
+ locals[i].got_offset = (bfd_vma) - 1;
+ locals[i].tlsdesc_got_jump_table_offset = (bfd_vma) - 1;
+ if (locals[i].got_refcount > 0)
+ {
+ unsigned got_type = locals[i].got_type;
+ if (got_type & GOT_TLSDESC_GD)
+ {
+ locals[i].tlsdesc_got_jump_table_offset =
+ (htab->root.sgotplt->size
+ - aarch64_compute_jump_table_size (htab));
+ htab->root.sgotplt->size += GOT_ENTRY_SIZE * 2;
+ locals[i].got_offset = (bfd_vma) - 2;
+ }
+
+ if (got_type & GOT_TLS_GD)
+ {
+ locals[i].got_offset = htab->root.sgot->size;
+ htab->root.sgot->size += GOT_ENTRY_SIZE * 2;
+ }
+
+ if (got_type & GOT_TLS_IE
+ || got_type & GOT_NORMAL)
+ {
+ locals[i].got_offset = htab->root.sgot->size;
+ htab->root.sgot->size += GOT_ENTRY_SIZE;
+ }
+
+ if (got_type == GOT_UNKNOWN)
+ {
+ }
+
+ if (bfd_link_pic (info))
+ {
+ if (got_type & GOT_TLSDESC_GD)
+ {
+ htab->root.srelplt->size += RELOC_SIZE (htab);
+ /* Note RELOC_COUNT not incremented here! */
+ htab->root.tlsdesc_plt = (bfd_vma) - 1;
+ }
+
+ if (got_type & GOT_TLS_GD)
+ htab->root.srelgot->size += RELOC_SIZE (htab) * 2;
+
+ if (got_type & GOT_TLS_IE
+ || got_type & GOT_NORMAL)
+ htab->root.srelgot->size += RELOC_SIZE (htab);
+ }
+ }
+ else
+ {
+ locals[i].got_refcount = (bfd_vma) - 1;
+ }
+ }
+ }
+
+
+ /* Allocate global sym .plt and .got entries, and space for global
+ sym dynamic relocs. */
+ elf_link_hash_traverse (&htab->root, elfNN_aarch64_allocate_dynrelocs,
+ info);
+
+ /* Allocate global ifunc sym .plt and .got entries, and space for global
+ ifunc sym dynamic relocs. */
+ elf_link_hash_traverse (&htab->root, elfNN_aarch64_allocate_ifunc_dynrelocs,
+ info);
+
+ /* Allocate .plt and .got entries, and space for local ifunc symbols. */
+ htab_traverse (htab->loc_hash_table,
+ elfNN_aarch64_allocate_local_ifunc_dynrelocs,
+ info);
+
+ /* For every jump slot reserved in the sgotplt, reloc_count is
+ incremented. However, when we reserve space for TLS descriptors,
+ it's not incremented, so in order to compute the space reserved
+ for them, it suffices to multiply the reloc count by the jump
+ slot size. */
+
+ if (htab->root.srelplt)
+ htab->sgotplt_jump_table_size = aarch64_compute_jump_table_size (htab);
+
+ if (htab->root.tlsdesc_plt)
+ {
+ if (htab->root.splt->size == 0)
+ htab->root.splt->size += htab->plt_header_size;
+
+ /* If we're not using lazy TLS relocations, don't generate the
+ GOT and PLT entry required. */
+ if ((info->flags & DF_BIND_NOW))
+ htab->root.tlsdesc_plt = 0;
+ else
+ {
+ htab->root.tlsdesc_plt = htab->root.splt->size;
+ htab->root.splt->size += htab->tlsdesc_plt_entry_size;
+
+ htab->root.tlsdesc_got = htab->root.sgot->size;
+ htab->root.sgot->size += GOT_ENTRY_SIZE;
+ }
+ }
+
+ /* Init mapping symbols information to use later to distingush between
+ code and data while scanning for errata. */
+ if (htab->fix_erratum_835769 || htab->fix_erratum_843419)
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+ {
+ if (!is_aarch64_elf (ibfd))
+ continue;
+ bfd_elfNN_aarch64_init_maps (ibfd);
+ }
+
+ /* We now have determined the sizes of the various dynamic sections.
+ Allocate memory for them. */
+ relocs = false;
+ for (s = dynobj->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_LINKER_CREATED) == 0)
+ continue;
+
+ if (s == htab->root.splt
+ || s == htab->root.sgot
+ || s == htab->root.sgotplt
+ || s == htab->root.iplt
+ || s == htab->root.igotplt
+ || s == htab->root.sdynbss
+ || s == htab->root.sdynrelro)
+ {
+ /* Strip this section if we don't need it; see the
+ comment below. */
+ }
+ else if (startswith (bfd_section_name (s), ".rela"))
+ {
+ if (s->size != 0 && s != htab->root.srelplt)
+ relocs = true;
+
+ /* We use the reloc_count field as a counter if we need
+ to copy relocs into the output file. */
+ if (s != htab->root.srelplt)
+ s->reloc_count = 0;
+ }
+ else
+ {
+ /* It's not one of our sections, so don't allocate space. */
+ continue;
+ }
+
+ if (s->size == 0)
+ {
+ /* If we don't need this section, strip it from the
+ output file. This is mostly to handle .rela.bss and
+ .rela.plt. We must create both sections in
+ create_dynamic_sections, because they must be created
+ before the linker maps input sections to output
+ sections. The linker does that before
+ adjust_dynamic_symbol is called, and it is that
+ function which decides whether anything needs to go
+ into these sections. */
+ s->flags |= SEC_EXCLUDE;
+ continue;
+ }
+
+ if ((s->flags & SEC_HAS_CONTENTS) == 0)
+ continue;
+
+ /* Allocate memory for the section contents. We use bfd_zalloc
+ here in case unused entries are not reclaimed before the
+ section's contents are written out. This should not happen,
+ but this way if it does, we get a R_AARCH64_NONE reloc instead
+ of garbage. */
+ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
+ if (s->contents == NULL)
+ return false;
+ }
+
+ if (htab->root.dynamic_sections_created)
+ {
+ /* Add some entries to the .dynamic section. We fill in the
+ values later, in elfNN_aarch64_finish_dynamic_sections, but we
+ must add the entries now so that we get the correct size for
+ the .dynamic section. The DT_DEBUG entry is filled in by the
+ dynamic linker and used by the debugger. */
+#define add_dynamic_entry(TAG, VAL) \
+ _bfd_elf_add_dynamic_entry (info, TAG, VAL)
+
+ if (!_bfd_elf_add_dynamic_tags (output_bfd, info, relocs))
+ return false;
+
+ if (htab->root.splt->size != 0)
+ {
+ if (htab->variant_pcs
+ && !add_dynamic_entry (DT_AARCH64_VARIANT_PCS, 0))
+ return false;
+
+ if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI_PAC)
+ && (!add_dynamic_entry (DT_AARCH64_BTI_PLT, 0)
+ || !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0)))
+ return false;
+
+ else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI)
+ && !add_dynamic_entry (DT_AARCH64_BTI_PLT, 0))
+ return false;
+
+ else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_PAC)
+ && !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0))
+ return false;
+ }
+ }
+#undef add_dynamic_entry
+
+ return true;
+}
+
+static inline void
+elf_aarch64_update_plt_entry (bfd *output_bfd,
+ bfd_reloc_code_real_type r_type,
+ bfd_byte *plt_entry, bfd_vma value)
+{
+ reloc_howto_type *howto = elfNN_aarch64_howto_from_bfd_reloc (r_type);
+
+ /* FIXME: We should check the return value from this function call. */
+ (void) _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type, howto, value);
+}
+
+static void
+elfNN_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
+ struct elf_aarch64_link_hash_table
+ *htab, bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ bfd_byte *plt_entry;
+ bfd_vma plt_index;
+ bfd_vma got_offset;
+ bfd_vma gotplt_entry_address;
+ bfd_vma plt_entry_address;
+ Elf_Internal_Rela rela;
+ bfd_byte *loc;
+ asection *plt, *gotplt, *relplt;
+
+ /* When building a static executable, use .iplt, .igot.plt and
+ .rela.iplt sections for STT_GNU_IFUNC symbols. */
+ if (htab->root.splt != NULL)
+ {
+ plt = htab->root.splt;
+ gotplt = htab->root.sgotplt;
+ relplt = htab->root.srelplt;
+ }
+ else
+ {
+ plt = htab->root.iplt;
+ gotplt = htab->root.igotplt;
+ relplt = htab->root.irelplt;
+ }
+
+ /* 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.
+
+ Get the offset into the .got table of the entry that
+ corresponds to this function. Each .got entry is GOT_ENTRY_SIZE
+ bytes. The first three are reserved for the dynamic linker.
+
+ For static executables, we don't reserve anything. */
+
+ if (plt == htab->root.splt)
+ {
+ plt_index = (h->plt.offset - htab->plt_header_size) / htab->plt_entry_size;
+ got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
+ }
+ else
+ {
+ plt_index = h->plt.offset / htab->plt_entry_size;
+ got_offset = plt_index * GOT_ENTRY_SIZE;
+ }
+
+ plt_entry = plt->contents + h->plt.offset;
+ plt_entry_address = plt->output_section->vma
+ + plt->output_offset + h->plt.offset;
+ gotplt_entry_address = gotplt->output_section->vma +
+ gotplt->output_offset + got_offset;
+
+ /* Copy in the boiler-plate for the PLTn entry. */
+ memcpy (plt_entry, htab->plt_entry, htab->plt_entry_size);
+
+ /* First instruction in BTI enabled PLT stub is a BTI
+ instruction so skip it. */
+ if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI
+ && elf_elfheader (output_bfd)->e_type == ET_EXEC)
+ plt_entry = plt_entry + 4;
+
+ /* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8.
+ ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */
+ elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADR_HI21_PCREL,
+ plt_entry,
+ PG (gotplt_entry_address) -
+ PG (plt_entry_address));
+
+ /* Fill in the lo12 bits for the load from the pltgot. */
+ elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_LDSTNN_LO12,
+ plt_entry + 4,
+ PG_OFFSET (gotplt_entry_address));
+
+ /* Fill in the lo12 bits for the add from the pltgot entry. */
+ elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADD_LO12,
+ plt_entry + 8,
+ PG_OFFSET (gotplt_entry_address));
+
+ /* All the GOTPLT Entries are essentially initialized to PLT0. */
+ bfd_put_NN (output_bfd,
+ plt->output_section->vma + plt->output_offset,
+ gotplt->contents + got_offset);
+
+ rela.r_offset = gotplt_entry_address;
+
+ if (h->dynindx == -1
+ || ((bfd_link_executable (info)
+ || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ && h->def_regular
+ && h->type == STT_GNU_IFUNC))
+ {
+ /* If an STT_GNU_IFUNC symbol is locally defined, generate
+ R_AARCH64_IRELATIVE instead of R_AARCH64_JUMP_SLOT. */
+ rela.r_info = ELFNN_R_INFO (0, AARCH64_R (IRELATIVE));
+ rela.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
+ else
+ {
+ /* Fill in the entry in the .rela.plt section. */
+ rela.r_info = ELFNN_R_INFO (h->dynindx, AARCH64_R (JUMP_SLOT));
+ rela.r_addend = 0;
+ }
+
+ /* Compute the relocation entry to used based on PLT index and do
+ not adjust reloc_count. The reloc_count has already been adjusted
+ to account for this entry. */
+ loc = relplt->contents + plt_index * RELOC_SIZE (htab);
+ bfd_elfNN_swap_reloca_out (output_bfd, &rela, loc);
+}
+
+/* Size sections even though they're not dynamic. We use it to setup
+ _TLS_MODULE_BASE_, if needed. */
+
+static bool
+elfNN_aarch64_always_size_sections (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ asection *tls_sec;
+
+ if (bfd_link_relocatable (info))
+ return true;
+
+ tls_sec = elf_hash_table (info)->tls_sec;
+
+ if (tls_sec)
+ {
+ struct elf_link_hash_entry *tlsbase;
+
+ tlsbase = elf_link_hash_lookup (elf_hash_table (info),
+ "_TLS_MODULE_BASE_", true, true, false);
+
+ if (tlsbase)
+ {
+ struct bfd_link_hash_entry *h = NULL;
+ const struct elf_backend_data *bed =
+ get_elf_backend_data (output_bfd);
+
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL,
+ tls_sec, 0, NULL, false, bed->collect, &h)))
+ return false;
+
+ tlsbase->type = STT_TLS;
+ tlsbase = (struct elf_link_hash_entry *) h;
+ tlsbase->def_regular = 1;
+ tlsbase->other = STV_HIDDEN;
+ (*bed->elf_backend_hide_symbol) (info, tlsbase, true);
+ }
+ }
+
+ return true;
+}
+
+/* Finish up dynamic symbol handling. We set the contents of various
+ dynamic sections here. */
+
+static bool
+elfNN_aarch64_finish_dynamic_symbol (bfd *output_bfd,
+ struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
+{
+ struct elf_aarch64_link_hash_table *htab;
+ htab = elf_aarch64_hash_table (info);
+
+ if (h->plt.offset != (bfd_vma) - 1)
+ {
+ asection *plt, *gotplt, *relplt;
+
+ /* This symbol has an entry in the procedure linkage table. Set
+ it up. */
+
+ /* When building a static executable, use .iplt, .igot.plt and
+ .rela.iplt sections for STT_GNU_IFUNC symbols. */
+ if (htab->root.splt != NULL)
+ {
+ plt = htab->root.splt;
+ gotplt = htab->root.sgotplt;
+ relplt = htab->root.srelplt;
+ }
+ else
+ {
+ plt = htab->root.iplt;
+ gotplt = htab->root.igotplt;
+ relplt = htab->root.irelplt;
+ }
+
+ /* This symbol has an entry in the procedure linkage table. Set
+ it up. */
+ if ((h->dynindx == -1
+ && !((h->forced_local || bfd_link_executable (info))
+ && h->def_regular
+ && h->type == STT_GNU_IFUNC))
+ || plt == NULL
+ || gotplt == NULL
+ || relplt == NULL)
+ return false;
+
+ elfNN_aarch64_create_small_pltn_entry (h, htab, output_bfd, info);
+ if (!h->def_regular)
+ {
+ /* Mark the symbol as undefined, rather than as defined in
+ the .plt section. */
+ sym->st_shndx = SHN_UNDEF;
+ /* If the symbol is weak we 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. Leave the value if
+ there were any relocations where pointer equality matters
+ (this is a clue for the dynamic linker, to make function
+ pointer comparisons work between an application and shared
+ library). */
+ if (!h->ref_regular_nonweak || !h->pointer_equality_needed)
+ sym->st_value = 0;
+ }
+ }
+
+ if (h->got.offset != (bfd_vma) - 1
+ && elf_aarch64_hash_entry (h)->got_type == GOT_NORMAL
+ /* Undefined weak symbol in static PIE resolves to 0 without
+ any dynamic relocations. */
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ {
+ Elf_Internal_Rela rela;
+ bfd_byte *loc;
+
+ /* This symbol has an entry in the global offset table. Set it
+ up. */
+ if (htab->root.sgot == NULL || htab->root.srelgot == NULL)
+ abort ();
+
+ rela.r_offset = (htab->root.sgot->output_section->vma
+ + htab->root.sgot->output_offset
+ + (h->got.offset & ~(bfd_vma) 1));
+
+ if (h->def_regular
+ && h->type == STT_GNU_IFUNC)
+ {
+ if (bfd_link_pic (info))
+ {
+ /* Generate R_AARCH64_GLOB_DAT. */
+ goto do_glob_dat;
+ }
+ else
+ {
+ asection *plt;
+
+ if (!h->pointer_equality_needed)
+ abort ();
+
+ /* For non-shared object, we can't use .got.plt, which
+ contains the real function address if we need pointer
+ equality. We load the GOT entry with the PLT entry. */
+ plt = htab->root.splt ? htab->root.splt : htab->root.iplt;
+ bfd_put_NN (output_bfd, (plt->output_section->vma
+ + plt->output_offset
+ + h->plt.offset),
+ htab->root.sgot->contents
+ + (h->got.offset & ~(bfd_vma) 1));
+ return true;
+ }
+ }
+ else if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))
+ {
+ if (!(h->def_regular || ELF_COMMON_DEF_P (h)))
+ return false;
+
+ BFD_ASSERT ((h->got.offset & 1) != 0);
+ rela.r_info = ELFNN_R_INFO (0, AARCH64_R (RELATIVE));
+ rela.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
+ else
+ {
+ do_glob_dat:
+ BFD_ASSERT ((h->got.offset & 1) == 0);
+ bfd_put_NN (output_bfd, (bfd_vma) 0,
+ htab->root.sgot->contents + h->got.offset);
+ rela.r_info = ELFNN_R_INFO (h->dynindx, AARCH64_R (GLOB_DAT));
+ rela.r_addend = 0;
+ }
+
+ loc = htab->root.srelgot->contents;
+ loc += htab->root.srelgot->reloc_count++ * RELOC_SIZE (htab);
+ bfd_elfNN_swap_reloca_out (output_bfd, &rela, loc);
+ }
+
+ if (h->needs_copy)
+ {
+ Elf_Internal_Rela rela;
+ asection *s;
+ bfd_byte *loc;
+
+ /* This symbol needs a copy reloc. Set it up. */
+ if (h->dynindx == -1
+ || (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ || htab->root.srelbss == NULL)
+ abort ();
+
+ rela.r_offset = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ rela.r_info = ELFNN_R_INFO (h->dynindx, AARCH64_R (COPY));
+ rela.r_addend = 0;
+ if (h->root.u.def.section == htab->root.sdynrelro)
+ s = htab->root.sreldynrelro;
+ else
+ s = htab->root.srelbss;
+ loc = s->contents + s->reloc_count++ * RELOC_SIZE (htab);
+ bfd_elfNN_swap_reloca_out (output_bfd, &rela, loc);
+ }
+
+ /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. SYM may
+ be NULL for local symbols. */
+ if (sym != NULL
+ && (h == elf_hash_table (info)->hdynamic
+ || h == elf_hash_table (info)->hgot))
+ sym->st_shndx = SHN_ABS;
+
+ return true;
+}
+
+/* Finish up local dynamic symbol handling. We set the contents of
+ various dynamic sections here. */
+
+static int
+elfNN_aarch64_finish_local_dynamic_symbol (void **slot, void *inf)
+{
+ struct elf_link_hash_entry *h
+ = (struct elf_link_hash_entry *) *slot;
+ struct bfd_link_info *info
+ = (struct bfd_link_info *) inf;
+
+ return elfNN_aarch64_finish_dynamic_symbol (info->output_bfd,
+ info, h, NULL);
+}
+
+static void
+elfNN_aarch64_init_small_plt0_entry (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct elf_aarch64_link_hash_table
+ *htab)
+{
+ /* Fill in PLT0. Fixme:RR Note this doesn't distinguish between
+ small and large plts and at the minute just generates
+ the small PLT. */
+
+ /* PLT0 of the small PLT looks like this in ELF64 -
+ stp x16, x30, [sp, #-16]! // Save the reloc and lr on stack.
+ adrp x16, PLT_GOT + 16 // Get the page base of the GOTPLT
+ ldr x17, [x16, #:lo12:PLT_GOT+16] // Load the address of the
+ // symbol resolver
+ add x16, x16, #:lo12:PLT_GOT+16 // Load the lo12 bits of the
+ // GOTPLT entry for this.
+ br x17
+ PLT0 will be slightly different in ELF32 due to different got entry
+ size. */
+ bfd_vma plt_got_2nd_ent; /* Address of GOT[2]. */
+ bfd_vma plt_base;
+
+
+ memcpy (htab->root.splt->contents, htab->plt0_entry,
+ htab->plt_header_size);
+
+ /* PR 26312: Explicitly set the sh_entsize to 0 so that
+ consumers do not think that the section contains fixed
+ sized objects. */
+ elf_section_data (htab->root.splt->output_section)->this_hdr.sh_entsize = 0;
+
+ plt_got_2nd_ent = (htab->root.sgotplt->output_section->vma
+ + htab->root.sgotplt->output_offset
+ + GOT_ENTRY_SIZE * 2);
+
+ plt_base = htab->root.splt->output_section->vma +
+ htab->root.splt->output_offset;
+
+ /* First instruction in BTI enabled PLT stub is a BTI
+ instruction so skip it. */
+ bfd_byte *plt0_entry = htab->root.splt->contents;
+ if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI)
+ plt0_entry = plt0_entry + 4;
+
+ /* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8.
+ ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */
+ elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADR_HI21_PCREL,
+ plt0_entry + 4,
+ PG (plt_got_2nd_ent) - PG (plt_base + 4));
+
+ elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_LDSTNN_LO12,
+ plt0_entry + 8,
+ PG_OFFSET (plt_got_2nd_ent));
+
+ elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADD_LO12,
+ plt0_entry + 12,
+ PG_OFFSET (plt_got_2nd_ent));
+}
+
+static bool
+elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ struct elf_aarch64_link_hash_table *htab;
+ bfd *dynobj;
+ asection *sdyn;
+
+ htab = elf_aarch64_hash_table (info);
+ dynobj = htab->root.dynobj;
+ sdyn = bfd_get_linker_section (dynobj, ".dynamic");
+
+ if (htab->root.dynamic_sections_created)
+ {
+ ElfNN_External_Dyn *dyncon, *dynconend;
+
+ if (sdyn == NULL || htab->root.sgot == NULL)
+ abort ();
+
+ dyncon = (ElfNN_External_Dyn *) sdyn->contents;
+ dynconend = (ElfNN_External_Dyn *) (sdyn->contents + sdyn->size);
+ for (; dyncon < dynconend; dyncon++)
+ {
+ Elf_Internal_Dyn dyn;
+ asection *s;
+
+ bfd_elfNN_swap_dyn_in (dynobj, dyncon, &dyn);
+
+ switch (dyn.d_tag)
+ {
+ default:
+ continue;
+
+ case DT_PLTGOT:
+ s = htab->root.sgotplt;
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
+ break;
+
+ case DT_JMPREL:
+ s = htab->root.srelplt;
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
+ break;
+
+ case DT_PLTRELSZ:
+ s = htab->root.srelplt;
+ dyn.d_un.d_val = s->size;
+ break;
+
+ case DT_TLSDESC_PLT:
+ s = htab->root.splt;
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
+ + htab->root.tlsdesc_plt;
+ break;
+
+ case DT_TLSDESC_GOT:
+ s = htab->root.sgot;
+ BFD_ASSERT (htab->root.tlsdesc_got != (bfd_vma)-1);
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
+ + htab->root.tlsdesc_got;
+ break;
+ }
+
+ bfd_elfNN_swap_dyn_out (output_bfd, &dyn, dyncon);
+ }
+
+ }
+
+ /* Fill in the special first entry in the procedure linkage table. */
+ if (htab->root.splt && htab->root.splt->size > 0)
+ {
+ elfNN_aarch64_init_small_plt0_entry (output_bfd, htab);
+
+ if (htab->root.tlsdesc_plt && !(info->flags & DF_BIND_NOW))
+ {
+ BFD_ASSERT (htab->root.tlsdesc_got != (bfd_vma)-1);
+ bfd_put_NN (output_bfd, (bfd_vma) 0,
+ htab->root.sgot->contents + htab->root.tlsdesc_got);
+
+ const bfd_byte *entry = elfNN_aarch64_tlsdesc_small_plt_entry;
+ htab->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
+
+ aarch64_plt_type type = elf_aarch64_tdata (output_bfd)->plt_type;
+ if (type == PLT_BTI || type == PLT_BTI_PAC)
+ {
+ entry = elfNN_aarch64_tlsdesc_small_plt_bti_entry;
+ }
+
+ memcpy (htab->root.splt->contents + htab->root.tlsdesc_plt,
+ entry, htab->tlsdesc_plt_entry_size);
+
+ {
+ bfd_vma adrp1_addr =
+ htab->root.splt->output_section->vma
+ + htab->root.splt->output_offset
+ + htab->root.tlsdesc_plt + 4;
+
+ bfd_vma adrp2_addr = adrp1_addr + 4;
+
+ bfd_vma got_addr =
+ htab->root.sgot->output_section->vma
+ + htab->root.sgot->output_offset;
+
+ bfd_vma pltgot_addr =
+ htab->root.sgotplt->output_section->vma
+ + htab->root.sgotplt->output_offset;
+
+ bfd_vma dt_tlsdesc_got = got_addr + htab->root.tlsdesc_got;
+
+ bfd_byte *plt_entry =
+ htab->root.splt->contents + htab->root.tlsdesc_plt;
+
+ /* First instruction in BTI enabled PLT stub is a BTI
+ instruction so skip it. */
+ if (type & PLT_BTI)
+ {
+ plt_entry = plt_entry + 4;
+ adrp1_addr = adrp1_addr + 4;
+ adrp2_addr = adrp2_addr + 4;
+ }
+
+ /* adrp x2, DT_TLSDESC_GOT */
+ elf_aarch64_update_plt_entry (output_bfd,
+ BFD_RELOC_AARCH64_ADR_HI21_PCREL,
+ plt_entry + 4,
+ (PG (dt_tlsdesc_got)
+ - PG (adrp1_addr)));
+
+ /* adrp x3, 0 */
+ elf_aarch64_update_plt_entry (output_bfd,
+ BFD_RELOC_AARCH64_ADR_HI21_PCREL,
+ plt_entry + 8,
+ (PG (pltgot_addr)
+ - PG (adrp2_addr)));
+
+ /* ldr x2, [x2, #0] */
+ elf_aarch64_update_plt_entry (output_bfd,
+ BFD_RELOC_AARCH64_LDSTNN_LO12,
+ plt_entry + 12,
+ PG_OFFSET (dt_tlsdesc_got));
+
+ /* add x3, x3, 0 */
+ elf_aarch64_update_plt_entry (output_bfd,
+ BFD_RELOC_AARCH64_ADD_LO12,
+ plt_entry + 16,
+ PG_OFFSET (pltgot_addr));
+ }
+ }
+ }
+
+ if (htab->root.sgotplt)
+ {
+ if (bfd_is_abs_section (htab->root.sgotplt->output_section))
+ {
+ _bfd_error_handler
+ (_("discarded output section: `%pA'"), htab->root.sgotplt);
+ return false;
+ }
+
+ /* Fill in the first three entries in the global offset table. */
+ if (htab->root.sgotplt->size > 0)
+ {
+ bfd_put_NN (output_bfd, (bfd_vma) 0, htab->root.sgotplt->contents);
+
+ /* Write GOT[1] and GOT[2], needed for the dynamic linker. */
+ bfd_put_NN (output_bfd,
+ (bfd_vma) 0,
+ htab->root.sgotplt->contents + GOT_ENTRY_SIZE);
+ bfd_put_NN (output_bfd,
+ (bfd_vma) 0,
+ htab->root.sgotplt->contents + GOT_ENTRY_SIZE * 2);
+ }
+
+ if (htab->root.sgot)
+ {
+ if (htab->root.sgot->size > 0)
+ {
+ bfd_vma addr =
+ sdyn ? sdyn->output_section->vma + sdyn->output_offset : 0;
+ bfd_put_NN (output_bfd, addr, htab->root.sgot->contents);
+ }
+ }
+
+ elf_section_data (htab->root.sgotplt->output_section)->
+ this_hdr.sh_entsize = GOT_ENTRY_SIZE;
+ }
+
+ if (htab->root.sgot && htab->root.sgot->size > 0)
+ elf_section_data (htab->root.sgot->output_section)->this_hdr.sh_entsize
+ = GOT_ENTRY_SIZE;
+
+ /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */
+ htab_traverse (htab->loc_hash_table,
+ elfNN_aarch64_finish_local_dynamic_symbol,
+ info);
+
+ return true;
+}
+
+/* Check if BTI enabled PLTs are needed. Returns the type needed. */
+static aarch64_plt_type
+get_plt_type (bfd *abfd)
+{
+ aarch64_plt_type ret = PLT_NORMAL;
+ bfd_byte *contents, *extdyn, *extdynend;
+ asection *sec = bfd_get_section_by_name (abfd, ".dynamic");
+ if (!sec
+ || sec->size < sizeof (ElfNN_External_Dyn)
+ || !bfd_malloc_and_get_section (abfd, sec, &contents))
+ return ret;
+ extdyn = contents;
+ extdynend = contents + sec->size - sizeof (ElfNN_External_Dyn);
+ for (; extdyn <= extdynend; extdyn += sizeof (ElfNN_External_Dyn))
+ {
+ Elf_Internal_Dyn dyn;
+ bfd_elfNN_swap_dyn_in (abfd, extdyn, &dyn);
+
+ /* Let's check the processor specific dynamic array tags. */
+ bfd_vma tag = dyn.d_tag;
+ if (tag < DT_LOPROC || tag > DT_HIPROC)
+ continue;
+
+ switch (tag)
+ {
+ case DT_AARCH64_BTI_PLT:
+ ret |= PLT_BTI;
+ break;
+
+ case DT_AARCH64_PAC_PLT:
+ ret |= PLT_PAC;
+ break;
+
+ default: break;
+ }
+ }
+ free (contents);
+ return ret;
+}
+
+static long
+elfNN_aarch64_get_synthetic_symtab (bfd *abfd,
+ long symcount,
+ asymbol **syms,
+ long dynsymcount,
+ asymbol **dynsyms,
+ asymbol **ret)
+{
+ elf_aarch64_tdata (abfd)->plt_type = get_plt_type (abfd);
+ return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
+ dynsymcount, dynsyms, ret);
+}
+
+/* Return address for Ith PLT stub in section PLT, for relocation REL
+ or (bfd_vma) -1 if it should not be included. */
+
+static bfd_vma
+elfNN_aarch64_plt_sym_val (bfd_vma i, const asection *plt,
+ const arelent *rel ATTRIBUTE_UNUSED)
+{
+ size_t plt0_size = PLT_ENTRY_SIZE;
+ size_t pltn_size = PLT_SMALL_ENTRY_SIZE;
+
+ if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI_PAC)
+ {
+ if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
+ pltn_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE;
+ else
+ pltn_size = PLT_PAC_SMALL_ENTRY_SIZE;
+ }
+ else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI)
+ {
+ if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
+ pltn_size = PLT_BTI_SMALL_ENTRY_SIZE;
+ }
+ else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_PAC)
+ {
+ pltn_size = PLT_PAC_SMALL_ENTRY_SIZE;
+ }
+
+ return plt->vma + plt0_size + i * pltn_size;
+}
+
+/* Returns TRUE if NAME is an AArch64 mapping symbol.
+ The ARM ELF standard defines $x (for A64 code) and $d (for data).
+ It also allows a period initiated suffix to be added to the symbol, ie:
+ "$[adtx]\.[:sym_char]+". */
+
+static bool
+is_aarch64_mapping_symbol (const char * name)
+{
+ return name != NULL /* Paranoia. */
+ && name[0] == '$' /* Note: if objcopy --prefix-symbols has been used then
+ the mapping symbols could have acquired a prefix.
+ We do not support this here, since such symbols no
+ longer conform to the ARM ELF ABI. */
+ && (name[1] == 'd' || name[1] == 'x')
+ && (name[2] == 0 || name[2] == '.');
+ /* FIXME: Strictly speaking the symbol is only a valid mapping symbol if
+ any characters that follow the period are legal characters for the body
+ of a symbol's name. For now we just assume that this is the case. */
+}
+
+/* Make sure that mapping symbols in object files are not removed via the
+ "strip --strip-unneeded" tool. These symbols might needed in order to
+ correctly generate linked files. Once an object file has been linked,
+ it should be safe to remove them. */
+
+static void
+elfNN_aarch64_backend_symbol_processing (bfd *abfd, asymbol *sym)
+{
+ if (((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ && sym->section != bfd_abs_section_ptr
+ && is_aarch64_mapping_symbol (sym->name))
+ sym->flags |= BSF_KEEP;
+}
+
+/* Implement elf_backend_setup_gnu_properties for AArch64. It serves as a
+ wrapper function for _bfd_aarch64_elf_link_setup_gnu_properties to account
+ for the effect of GNU properties of the output_bfd. */
+static bfd *
+elfNN_aarch64_link_setup_gnu_properties (struct bfd_link_info *info)
+{
+ uint32_t prop = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
+ bfd *pbfd = _bfd_aarch64_elf_link_setup_gnu_properties (info, &prop);
+ elf_aarch64_tdata (info->output_bfd)->gnu_and_prop = prop;
+ elf_aarch64_tdata (info->output_bfd)->plt_type
+ |= (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) ? PLT_BTI : 0;
+ setup_plt_values (info, elf_aarch64_tdata (info->output_bfd)->plt_type);
+ return pbfd;
+}
+
+/* Implement elf_backend_merge_gnu_properties for AArch64. It serves as a
+ wrapper function for _bfd_aarch64_elf_merge_gnu_properties to account
+ for the effect of GNU properties of the output_bfd. */
+static bool
+elfNN_aarch64_merge_gnu_properties (struct bfd_link_info *info,
+ bfd *abfd, bfd *bbfd,
+ elf_property *aprop,
+ elf_property *bprop)
+{
+ uint32_t prop
+ = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
+
+ /* If output has been marked with BTI using command line argument, give out
+ warning if necessary. */
+ /* Properties are merged per type, hence only check for warnings when merging
+ GNU_PROPERTY_AARCH64_FEATURE_1_AND. */
+ if (((aprop && aprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+ || (bprop && bprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND))
+ && (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
+ && (!elf_aarch64_tdata (info->output_bfd)->no_bti_warn))
+ {
+ if ((aprop && !(aprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+ || !aprop)
+ {
+ _bfd_error_handler (_("%pB: warning: BTI turned on by -z force-bti when "
+ "all inputs do not have BTI in NOTE section."),
+ abfd);
+ }
+ if ((bprop && !(bprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+ || !bprop)
+ {
+ _bfd_error_handler (_("%pB: warning: BTI turned on by -z force-bti when "
+ "all inputs do not have BTI in NOTE section."),
+ bbfd);
+ }
+ }
+
+ return _bfd_aarch64_elf_merge_gnu_properties (info, abfd, aprop,
+ bprop, prop);
+}
+
+/* We use this so we can override certain functions
+ (though currently we don't). */
+
+const struct elf_size_info elfNN_aarch64_size_info =
+{
+ sizeof (ElfNN_External_Ehdr),
+ sizeof (ElfNN_External_Phdr),
+ sizeof (ElfNN_External_Shdr),
+ sizeof (ElfNN_External_Rel),
+ sizeof (ElfNN_External_Rela),
+ sizeof (ElfNN_External_Sym),
+ sizeof (ElfNN_External_Dyn),
+ sizeof (Elf_External_Note),
+ 4, /* Hash table entry size. */
+ 1, /* Internal relocs per external relocs. */
+ ARCH_SIZE, /* Arch size. */
+ LOG_FILE_ALIGN, /* Log_file_align. */
+ ELFCLASSNN, EV_CURRENT,
+ bfd_elfNN_write_out_phdrs,
+ bfd_elfNN_write_shdrs_and_ehdr,
+ bfd_elfNN_checksum_contents,
+ bfd_elfNN_write_relocs,
+ bfd_elfNN_swap_symbol_in,
+ bfd_elfNN_swap_symbol_out,
+ bfd_elfNN_slurp_reloc_table,
+ bfd_elfNN_slurp_symbol_table,
+ bfd_elfNN_swap_dyn_in,
+ bfd_elfNN_swap_dyn_out,
+ bfd_elfNN_swap_reloc_in,
+ bfd_elfNN_swap_reloc_out,
+ bfd_elfNN_swap_reloca_in,
+ bfd_elfNN_swap_reloca_out
+};
+
+#define ELF_ARCH bfd_arch_aarch64
+#define ELF_MACHINE_CODE EM_AARCH64
+#define ELF_MAXPAGESIZE 0x10000
+#define ELF_COMMONPAGESIZE 0x1000
+
+#define bfd_elfNN_close_and_cleanup \
+ elfNN_aarch64_close_and_cleanup
+
+#define bfd_elfNN_bfd_free_cached_info \
+ elfNN_aarch64_bfd_free_cached_info
+
+#define bfd_elfNN_bfd_is_target_special_symbol \
+ elfNN_aarch64_is_target_special_symbol
+
+#define bfd_elfNN_bfd_link_hash_table_create \
+ elfNN_aarch64_link_hash_table_create
+
+#define bfd_elfNN_bfd_merge_private_bfd_data \
+ elfNN_aarch64_merge_private_bfd_data
+
+#define bfd_elfNN_bfd_print_private_bfd_data \
+ elfNN_aarch64_print_private_bfd_data
+
+#define bfd_elfNN_bfd_reloc_type_lookup \
+ elfNN_aarch64_reloc_type_lookup
+
+#define bfd_elfNN_bfd_reloc_name_lookup \
+ elfNN_aarch64_reloc_name_lookup
+
+#define bfd_elfNN_bfd_set_private_flags \
+ elfNN_aarch64_set_private_flags
+
+#define bfd_elfNN_find_inliner_info \
+ elfNN_aarch64_find_inliner_info
+
+#define bfd_elfNN_get_synthetic_symtab \
+ elfNN_aarch64_get_synthetic_symtab
+
+#define bfd_elfNN_mkobject \
+ elfNN_aarch64_mkobject
+
+#define bfd_elfNN_new_section_hook \
+ elfNN_aarch64_new_section_hook
+
+#define elf_backend_adjust_dynamic_symbol \
+ elfNN_aarch64_adjust_dynamic_symbol
+
+#define elf_backend_always_size_sections \
+ elfNN_aarch64_always_size_sections
+
+#define elf_backend_check_relocs \
+ elfNN_aarch64_check_relocs
+
+#define elf_backend_copy_indirect_symbol \
+ elfNN_aarch64_copy_indirect_symbol
+
+#define elf_backend_merge_symbol_attribute \
+ elfNN_aarch64_merge_symbol_attribute
+
+/* Create .dynbss, and .rela.bss sections in DYNOBJ, and set up shortcuts
+ to them in our hash. */
+#define elf_backend_create_dynamic_sections \
+ elfNN_aarch64_create_dynamic_sections
+
+#define elf_backend_init_index_section \
+ _bfd_elf_init_2_index_sections
+
+#define elf_backend_finish_dynamic_sections \
+ elfNN_aarch64_finish_dynamic_sections
+
+#define elf_backend_finish_dynamic_symbol \
+ elfNN_aarch64_finish_dynamic_symbol
+
+#define elf_backend_object_p \
+ elfNN_aarch64_object_p
+
+#define elf_backend_output_arch_local_syms \
+ elfNN_aarch64_output_arch_local_syms
+
+#define elf_backend_maybe_function_sym \
+ elfNN_aarch64_maybe_function_sym
+
+#define elf_backend_plt_sym_val \
+ elfNN_aarch64_plt_sym_val
+
+#define elf_backend_init_file_header \
+ elfNN_aarch64_init_file_header
+
+#define elf_backend_relocate_section \
+ elfNN_aarch64_relocate_section
+
+#define elf_backend_reloc_type_class \
+ elfNN_aarch64_reloc_type_class
+
+#define elf_backend_section_from_shdr \
+ elfNN_aarch64_section_from_shdr
+
+#define elf_backend_section_from_phdr \
+ elfNN_aarch64_section_from_phdr
+
+#define elf_backend_modify_headers \
+ elfNN_aarch64_modify_headers
+
+#define elf_backend_size_dynamic_sections \
+ elfNN_aarch64_size_dynamic_sections
+
+#define elf_backend_size_info \
+ elfNN_aarch64_size_info
+
+#define elf_backend_write_section \
+ elfNN_aarch64_write_section
+
+#define elf_backend_symbol_processing \
+ elfNN_aarch64_backend_symbol_processing
+
+#define elf_backend_setup_gnu_properties \
+ elfNN_aarch64_link_setup_gnu_properties
+
+#define elf_backend_merge_gnu_properties \
+ elfNN_aarch64_merge_gnu_properties
+
+#define elf_backend_can_refcount 1
+#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
+#define elf_backend_want_dynrelro 1
+#define elf_backend_may_use_rel_p 0
+#define elf_backend_may_use_rela_p 1
+#define elf_backend_default_use_rela_p 1
+#define elf_backend_rela_normal 1
+#define elf_backend_dtrel_excludes_plt 1
+#define elf_backend_got_header_size (GOT_ENTRY_SIZE * 3)
+#define elf_backend_default_execstack 0
+#define elf_backend_extern_protected_data 0
+#define elf_backend_hash_symbol elf_aarch64_hash_symbol
+
+#undef elf_backend_obj_attrs_section
+#define elf_backend_obj_attrs_section ".ARM.attributes"
+
+#include "elfNN-target.h"
+
+/* CloudABI support. */
+
+#undef TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM aarch64_elfNN_le_cloudabi_vec
+#undef TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME "elfNN-littleaarch64-cloudabi"
+#undef TARGET_BIG_SYM
+#define TARGET_BIG_SYM aarch64_elfNN_be_cloudabi_vec
+#undef TARGET_BIG_NAME
+#define TARGET_BIG_NAME "elfNN-bigaarch64-cloudabi"
+
+#undef ELF_OSABI
+#define ELF_OSABI ELFOSABI_CLOUDABI
+
+#undef elfNN_bed
+#define elfNN_bed elfNN_aarch64_cloudabi_bed
+
+#include "elfNN-target.h"
Index: GNU/binutils/create-2.40-aarch64-ifunc-patch/create.patch.sh
===================================================================
--- GNU/binutils/create-2.40-aarch64-ifunc-patch/create.patch.sh (nonexistent)
+++ GNU/binutils/create-2.40-aarch64-ifunc-patch/create.patch.sh (revision 33)
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+VERSION=2.40
+
+tar --files-from=file.list -xJvf ../binutils-$VERSION.tar.xz
+mv binutils-$VERSION binutils-$VERSION-orig
+
+cp -rf ./binutils-$VERSION-new ./binutils-$VERSION
+
+diff --unified -Nr binutils-$VERSION-orig binutils-$VERSION > binutils-$VERSION-aarch64-ifunc.patch
+
+mv binutils-$VERSION-aarch64-ifunc.patch ../patches
+
+rm -rf ./binutils-$VERSION
+rm -rf ./binutils-$VERSION-orig
Property changes on: GNU/binutils/create-2.40-aarch64-ifunc-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: GNU/binutils/create-2.40-aarch64-ifunc-patch/file.list
===================================================================
--- GNU/binutils/create-2.40-aarch64-ifunc-patch/file.list (nonexistent)
+++ GNU/binutils/create-2.40-aarch64-ifunc-patch/file.list (revision 33)
@@ -0,0 +1 @@
+binutils-2.40/bfd/elfnn-aarch64.c
Index: GNU/binutils/create-2.40-cleansweep-patch/binutils-2.40-new/ld/testsuite/ld-plugin/lto.exp
===================================================================
--- GNU/binutils/create-2.40-cleansweep-patch/binutils-2.40-new/ld/testsuite/ld-plugin/lto.exp (nonexistent)
+++ GNU/binutils/create-2.40-cleansweep-patch/binutils-2.40-new/ld/testsuite/ld-plugin/lto.exp (revision 33)
@@ -0,0 +1,1041 @@
+# Expect script for ld-plugin LTO tests
+# Copyright (C) 2011-2023 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# Check to see if the C and C++ compilers work
+if { ![check_compiler_available] || [which $CXX_FOR_TARGET] == 0 } {
+ return
+}
+
+# These tests require plugin and LTO.
+if { ![check_plugin_api_available]
+ || ![check_lto_available] } {
+ return
+}
+
+set saved_CFLAGS "$CFLAGS_FOR_TARGET"
+set saved_CXXFLAGS "$CXXFLAGS_FOR_TARGET"
+regsub -all "(\\-Wp,)?-D_FORTIFY_SOURCE=\[0-9\]+" $CFLAGS_FOR_TARGET "" CFLAGS_FOR_TARGET
+regsub -all "(\\-Wp,)?-D_FORTIFY_SOURCE=\[0-9\]+" $CXXFLAGS_FOR_TARGET "" CXXFLAGS_FOR_TARGET
+
+proc restore_notify { } {
+ global saved_CFLAGS
+ global saved_CXXFLAGS
+ global CFLAGS_FOR_TARGET
+ global CXXFLAGS_FOR_TARGET
+ set CFLAGS_FOR_TARGET "$saved_CFLAGS"
+ set CXXFLAGS_FOR_TARGET "$saved_CXXFLAGS"
+}
+
+set lto_fat ""
+set lto_no_fat ""
+if { [check_lto_fat_available] } {
+ set lto_fat "-ffat-lto-objects"
+ set lto_no_fat "-fno-fat-lto-objects"
+ set no_lto "-fno-lto"
+}
+
+# Simple LTO tests and generate input files for complex LTO tests.
+set lto_link_tests [list \
+ [list "LTO 1" \
+ "-O2 -flto -fuse-linker-plugin" "-flto -fuse-linker-plugin" \
+ {lto-1a.c lto-1b.c} {} "lto-1.exe"] \
+ [list "Compile 2" \
+ "" "-O2 -flto -fuse-linker-plugin $NOSANITIZE_CFLAGS" \
+ {lto-2.c} {} ""] \
+ [list "LTO 2" \
+ "-static -O2 -flto -fuse-linker-plugin tmpdir/lto-2.o -lm" \
+ "$NOSANITIZE_CFLAGS" \
+ {dummy.c} {} "lto-2.exe"] \
+ [list "Compile 3a" \
+ "" "-flto" \
+ {lto-3a.c} {} ""] \
+ [list "Compile 3c" \
+ "" "-O2" \
+ {lto-3c.c} {} ""] \
+ [list "Build liblto-3.a" \
+ "" "-flto $lto_fat" \
+ {lto-3b.c} {} "liblto-3.a"] \
+ [list "Compile 5a" \
+ "" "-flto $lto_fat" \
+ {lto-5a.c} {} ""] \
+ [list "Compile 5b" \
+ "" "-flto $lto_fat" \
+ {lto-5b.c} {} ""] \
+ [list "Compile PR ld/12365" \
+ "" "-flto -O2 $lto_fat" \
+ {pr12365a.c pr12365b.c pr12365c.c} {} ""] \
+ [list "Compile 9" \
+ "" "-O2 -finline -flto" \
+ {lto-9.cc} {} "" "c++"] \
+ [list "Compile 11a" \
+ "" "-O -flto" \
+ {lto-11a.c} {} ""] \
+ [list "Compile 11b" \
+ "" "-O -flto" \
+ {lto-11b.c} {} ""] \
+ [list "Compile 11c" \
+ "" "-O" \
+ {lto-11c.c} {} ""] \
+ [list "Build liblto-12.a" \
+ "$plug_opt" "-O2 -flto" \
+ {lto-12c.c} {} "liblto-12.a"] \
+ [list "Compile 12" \
+ "" "-O2 -flto" \
+ {lto-12a.c lto-12b.c} {} ""] \
+ [list "Compile 13" \
+ "" "-O2 -flto" \
+ {lto-13a.c lto-13b.c} {} ""] \
+ [list "Build liblto-13.a" \
+ "" "-O2" \
+ {lto-13c.c} {} "liblto-13.a"] \
+ [list "Compile 14a" \
+ "" "-flto" \
+ {lto-14a.c lto-14b.c} {} ""] \
+ [list "Build liblto-14.a" \
+ "$plug_opt" "-flto" \
+ {lto-14c.c} {} "liblto-14.a"] \
+ [list "Compile 15a" \
+ "" "-flto" \
+ {lto-15a.c} {} ""] \
+ [list "Build liblto-15.a" \
+ "$plug_opt" "-flto" \
+ {lto-15b.c} {} "liblto-15.a"] \
+ [list "PR ld/12696" \
+ "-O2 -flto -fuse-linker-plugin -r -nostdlib" "-O2 -flto" \
+ {pr12696-1.cc} {} "pr12696-1r.o" "c++"] \
+ [list "Compile PR ld/12758" \
+ "" "" \
+ {pr12758a.s} {} ""] \
+ [list "Build libpr12758.a" \
+ "" "-flto -O2 $lto_fat $NOSANITIZE_CFLAGS" \
+ {pr12758b.c} {} "libpr12758.a"] \
+ [list "PR ld/12758" \
+ "$NOPIE_LDFLAGS $NOSANITIZE_CFLAGS -O2 -Wl,-e,foo -nostdlib -flto -fuse-linker-plugin tmpdir/pr12758a.o -Wl,--start-group tmpdir/libpr12758.a -Wl,--end-group" \
+ "$NOSANITIZE_CFLAGS" \
+ {dummy.c} {} "pr12758.exe"] \
+ [list "Build libpr13183.a" \
+ "-T" "-flto -O2 $lto_fat" \
+ {pr13183a.c} {} "libpr13183.a"] \
+ [list "Compile PR ld/13183" \
+ "" "-flto -O2" \
+ {pr13183b.c} {} ""] \
+ [list "Compile PR ld/13201" \
+ "" "-flto -O2" \
+ {pr13201.c} {} ""] \
+ [list "PR ld/13287" \
+ "-flto -fuse-linker-plugin -Wl,--as-needed" "-flto" \
+ {pr13287.cc} {} "pr13287.exe" "c++"] \
+ [list "PR ld/15323 (1)" \
+ "" "-O2" \
+ {pr15323a.c} {} "" "c"] \
+ [list "PR ld/15323 (2)" \
+ "-O2 -flto -r -nostdlib" "-O2 -flto" \
+ {pr15323a.c} {} "pr15323a-r.o" "c"] \
+ [list "Compile(1) PR ld/pr16846" \
+ "" "-flto" \
+ {pr16846a.c pr16846b.c} {} ""] \
+ [list "Compile(2) PR ld/pr16846" \
+ "" "" \
+ {pr16846c.c} {} ""] \
+ [list "PR ld/pr16846(1)" \
+ "-flto -fuse-linker-plugin tmpdir/pr16846a.o tmpdir/pr16846b.o tmpdir/pr16846c.o" "" \
+ {dummy.c} {} "pr16846a.exe"] \
+ [list "PR ld/pr16846(2)" \
+ "-flto -fuse-linker-plugin tmpdir/pr16846a.o tmpdir/pr16846c.o tmpdir/pr16846b.o" "" \
+ {dummy.c} {} "pr16846b.exe"] \
+ [list "PR ld/19317 (1)" \
+ "$plug_opt" "-flto $lto_no_fat" \
+ {pr19317.c} {} "libpr19317.a"] \
+ [list "Build pr20276a.o" \
+ "" "-fno-lto -fcommon" \
+ {pr20276a.c}] \
+ [list "Build pr20276b.o" \
+ "$plug_opt" "-flto $lto_no_fat -fcommon" \
+ {pr20276b.c}] \
+ [list "Build pr20267a.o" \
+ "" "-fcommon" \
+ {pr20267a.c}] \
+ [list "Build libpr20267a.a" \
+ "$plug_opt" "-flto $lto_fat -fcommon" \
+ {pr20267b.c} {} "libpr20267a.a"] \
+ [list "Build libpr20267b.a" \
+ "$plug_opt" "-flto $lto_no_fat -fcommon" \
+ {pr20267b.c} {} "libpr20267b.a"] \
+ [list "Build pr20321" \
+ "-flto -Wl,-plugin,$plug_so" "-flto" \
+ {pr20321.c} {{warning ".*: duplicated plugin"}} \
+ "pr20321" "c"] \
+ [list "Build pr22502a.o" \
+ "" "" \
+ {pr22502a.c}] \
+ [list "Build pr22502b.o" \
+ "$plug_opt" "-flto $lto_no_fat" \
+ {pr22502b.c}] \
+ [list "Build pr22751.a" \
+ "$plug_opt" "-flto $lto_no_fat $INT128_CFLAGS" \
+ {pr22751.c} {} "pr22751.a"] \
+ [list "Build pr24406-2b.o" \
+ "" "-O2 -fno-lto" \
+ {pr24406-2b.c}] \
+ [list "Build pr26163a.o" \
+ "" "-O2 -fno-lto" \
+ {pr26163a.c}] \
+ [list "Build pr26262b.o" \
+ "" "-O2" \
+ {pr26262b.c} {} "" "c"] \
+ [list "Build pr26262c.o" \
+ "" "-O2" \
+ {pr26262c.c} {} "" "c"] \
+ [list "Build pr26267a.o" \
+ "" "-O2 -flto $lto_no_fat" \
+ {pr26267a.c} {} "" "c"] \
+ [list "Build pr26267b.o" \
+ "" "-O2" \
+ {pr26267b.c} {} "" "c"] \
+ [list "Build pr26267c.o" \
+ "" "-O2" \
+ {pr26267c.c} {} "" "c"] \
+ [list "Build pr26267a" \
+ "" "-O2" \
+ {pr26267a.c} {} "" "c"] \
+ [list "Build pr26267a" \
+ "-flto tmpdir/pr26267a.o tmpdir/pr26267b.o tmpdir/pr26267c.o" \
+ "-flto $lto_no_fat" \
+ {dummy.c} \
+ {{error_output "pr26267.err"}} \
+ "pr26267a"] \
+ [list "Build pr26267b" \
+ "-flto tmpdir/pr26267b.o tmpdir/pr26267c.o tmpdir/pr26267a.o" \
+ "-flto $lto_no_fat" \
+ {dummy.c} \
+ {{error_output "pr26267.err"}} \
+ "pr26267b"] \
+ [list "Build pr26389.o" \
+ "$plug_opt" "-flto $lto_no_fat -fcommon" \
+ {pr26389.c} \
+ [list [list "nm" "$plug_opt" "pr26389.d"]]] \
+]
+
+if { [at_least_gcc_version 10 0] && [check_lto_shared_available] } {
+ set lto_link_tests [concat $lto_link_tests [list \
+ [list "pr25355.o" \
+ "" \
+ "-flto -fno-common $lto_no_fat" \
+ {pr25355.c} \
+ [list [list "nm" "$plug_opt" "pr25355.d"]]] \
+ [list "pr28264.so" \
+ "-shared -Wl,--version-script=pr28264.ver" \
+ "-flto $lto_no_fat -fPIC" \
+ {pr28264.c} \
+ {{readelf {--dyn-syms --wide} pr28264-1.d} \
+ {readelf {--dyn-syms --wide} pr28264-2.d} \
+ {readelf {--dyn-syms --wide} pr28264-3.d} \
+ {readelf {--dyn-syms --wide} pr28264-4.d}} \
+ {pr28264.so}] \
+ ]]
+}
+
+if { [at_least_gcc_version 4 7] } {
+ set lto_link_tests [concat $lto_link_tests [list \
+ [list "Compile PR ld/12942 (1)" \
+ "" "-flto -O2" \
+ {pr12942a.cc pr12942c.cc} {} "" "c++"] \
+ [list "Compile PR ld/12942 (2)" \
+ "" "-O0" \
+ {pr12942b.cc} {} "" "c++"] \
+ ]]
+}
+
+set lto_compile_elf_tests [list \
+ [list "Compile 7" \
+ "" "-flto -O2" \
+ {lto-7a.c lto-7b.c lto-7c.c} {} ""] \
+ [list "Compile 8a" \
+ "" "-O2" \
+ {lto-8a.c} {} ""] \
+ [list "Compile 8b" \
+ "" "-flto -O2" \
+ {lto-8b.c} {} ""] \
+ [list "PR ld/23309" \
+ "-O2 -flto -fuse-linker-plugin -fvisibility=hidden -ffunction-sections -Wl,--gc-sections,-u,KeepMe" \
+ "-O2 -flto -fuse-linker-plugin -fvisibility=hidden -ffunction-sections" \
+ {pr23309.c} {{"nm" {} "pr23309.d"}} "pr23309.exe" "c"] \
+]
+
+# Generate input files for complex LTO tests for ELF.
+set lto_link_elf_tests [list \
+ [list "LTO 6" \
+ "-O2 -flto -fuse-linker-plugin" "" \
+ {lto-6.c} {} "lto-6.exe" "c"] \
+ [list "Build liblto-7.so" \
+ "-shared" "-O2 -fpic" \
+ {lto-7d.c} {} "liblto-7.so" "c"] \
+ [list "Build liblto-17a.so" \
+ "-shared -O2 -fpic -flto -fuse-linker-plugin" "-O2 -fpic -flto" \
+ {lto-17a.c} {{"nm" {} "lto-17a.d"}} "liblto-17a.so" "c"] \
+ [list "Build liblto-17b.so 1" \
+ "-shared -O2 -fpic -flto -fuse-linker-plugin tmpdir/lto-17a.o" "-O2 -fpic -flto" \
+ {lto-17b.c} {{"nm" {} "lto-17b-1.d"}} "liblto-17b.so"] \
+ [list "Build liblto-17b.so 2" \
+ "-shared -O2 -fpic -flto -fuse-linker-plugin tmpdir/lto-17a.o" "-O2 -fpic -flto" \
+ {lto-17b.c} {{"nm" {} "lto-17b-2.d"}} "liblto-17b.so"] \
+ [list "Compile PR ld/12760" \
+ "" "-g -O0" \
+ {pr12760a.c} {} ""] \
+ [list "Build libpr12760.a" \
+ "" "-flto -O2 $lto_fat" \
+ {pr12760b.c} {} "libpr12760.a"] \
+ [list "PR ld/12760" \
+ "-O2 -Wl,-e,foo -nostdlib -flto -fuse-linker-plugin tmpdir/pr12760a.o -Wl,--start-group tmpdir/libpr12760.a -Wl,--end-group" "" \
+ {dummy.c} {{warning "pr12760a.c:6: warning: Bad \\.?bar"}} \
+ "pr12760.exe" "c"] \
+ [list "PR ld/12975" \
+ "-shared -O2 -fPIC -flto -fuse-linker-plugin -nostdlib -Wl,-version-script,pr12975.t" "-O2 -flto" \
+ {pr12975.c} {{"readelf" {-s --wide} "pr12975.d"}} "pr12975.so" "c"] \
+ [list "PR ld/13229" \
+ "-shared -O2 -fPIC -flto -fuse-linker-plugin -nostdlib" "-O2 -finline -fno-early-inlining -flto" \
+ {pr13229.cc} {{"readelf" {-s --wide} "pr13229.d"}} "pr13229.so" "c++"] \
+ [list "PR ld/13244" \
+ "-shared -O2 -fPIC -flto -fuse-linker-plugin -nostdlib" "-O2 -fno-early-inlining -flto" \
+ {pr13244.c} {{"readelf" {-s --wide} "pr13244.d"}} "pr13244.so" "c"] \
+ [list "Build libpr15146a.a" \
+ "$plug_opt" "-flto -O2" \
+ {pr15146a.c} {} "lib15146a.a"] \
+ [list "Build pr15146b.so" \
+ "-shared" "-O2 -fpic" \
+ {pr15146b.c} {} "pr15146b.so" "c"] \
+ [list "Build pr15146c.so" \
+ "-shared -Wl,--no-as-needed tmpdir/pr15146b.so" "-O2 -fpic $no_lto" \
+ {pr15146c.c} {} "pr15146c.so" "c"] \
+ [list "PR ld/15146 (1)" \
+ "-O2 -flto -fuse-linker-plugin -Wl,-rpath-link,. -Wl,--no-copy-dt-needed-entries -Wl,--no-as-needed tmpdir/pr15146a.o tmpdir/pr15146c.so" "" \
+ {dummy.c} {{"readelf" {-d} "pr15146.d"}} "pr15146a.exe"] \
+ [list "Build libpr15146d.a" \
+ "$plug_opt" "-flto -O2" \
+ {pr15146d.c} {} "lib15146d.a"] \
+ [list "Build libpr16746a.a" \
+ "" "" \
+ {pr16746a.c pr16746b.c} {} "lib15146a.a"] \
+ [list "Build libpr16746b.a" \
+ "$plug_opt" "-O2 -flto" \
+ {pr16746c.c pr16746d.c} {} "lib15146b.a"] \
+ [list "PR ld/16746 (1)" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/pr16746a.o tmpdir/pr16746c.o" "-O2 -flto" \
+ {dummy.c} {} "pr16746a.exe"] \
+ [list "PR ld/16746 (2)" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/pr16746c.o tmpdir/pr16746a.o" "-O2 -flto" \
+ {dummy.c} {} "pr16746b.exe"] \
+ [list "Build pr21382a.o" \
+ "" "-O2 -flto" \
+ {pr21382a.c} {} "" "c"] \
+ [list "Build pr21382.so" \
+ "-shared" "-O2 -fpic" \
+ {pr21382b.c} {} "pr21382.so" "c"] \
+ [list {Build pr22220lib.so} \
+ {-shared -Wl,--version-script=pr22220lib.ver} {-fPIC} \
+ {pr22220lib.cc} {} {pr22220lib.so} {c++}] \
+ [list {Build pr22220main.o} \
+ {} {-flto} \
+ {pr22220main.cc} {} {} {c++}] \
+ [list "Build libpr23818.so" \
+ "-shared -flto -g -Wl,-version-script,pr23818.t" \
+ "-g -flto $lto_fat" \
+ {pr23818a.c pr23818b.c} \
+ {{"readelf" {-s --wide} "pr23818.d"}} \
+ "libpr23818.so"] \
+ [list "Build libpr23958.so" \
+ "-shared -flto -Wl,-version-script,pr23958.t" \
+ "-g -flto $lto_fat" \
+ {pr23958.c} \
+ "" \
+ "libpr23958.so"] \
+ [list "Build pr24486a.o" \
+ "$plug_opt" "-flto -O2" \
+ {pr24486a.c} {} "" "c"] \
+ [list "Build pr24486b.so" \
+ "-shared" "-O2 -fpic" \
+ {pr24486b.c} {} "pr24486b.so" "c"] \
+ [list "Build pr24486c.so" \
+ "-shared -Wl,--no-as-needed tmpdir/pr24486b.so" "-O2 -fpic" \
+ {pr24486c.c} {} "pr24486c.so" "c"] \
+ [list "PR ld/24486" \
+ "-O2 -flto tmpdir/pr24486a.o tmpdir/pr24486c.so -Wl,--as-needed tmpdir/pr24486b.so" "" \
+ {dummy.c} {} "pr24486.exe"] \
+ [list "Build pr25593a-1.o" \
+ "$plug_opt" "-flto -O2" \
+ {pr25593a-1.c} {} "" "c"] \
+ [list "Build pr25593a-2.o" \
+ "" "-O2" \
+ {pr25593a-2.c} {} "" "c"] \
+ [list "Build pr25593b.o" \
+ "" "-O2" \
+ {pr25593b.c} {} "" "c"] \
+ [list "Build pr25593c.so" \
+ "-shared" "-O2 -fpic" \
+ {pr25593c.c} {} "pr25593c.so" "c"] \
+ [list "Build pr25593d.so" \
+ "-shared" "-O2 -fpic" \
+ {pr25593d.c} {} "pr25593d.so" "c"] \
+ [list "Build pr25593e.so" \
+ "-shared" "-O2 -fpic" \
+ {pr25593e.c} {} "pr25593e.so" "c"] \
+ [list "PR ld/r25593 (LTO)" \
+ "-O2 -flto -Wl,--as-needed tmpdir/pr25593a-1.o tmpdir/pr25593b.o \
+ tmpdir/pr25593c.so tmpdir/pr25593d.so tmpdir/pr25593e.so" "" \
+ {dummy.c} {{readelf {-d --wide} pr25593.d}} "pr25593a.exe"] \
+ [list "PR ld/r25593" \
+ "-O2 -flto -Wl,--as-needed tmpdir/pr25593a-2.o tmpdir/pr25593b.o \
+ tmpdir/pr25593c.so tmpdir/pr25593d.so tmpdir/pr25593e.so" "" \
+ {dummy.c} {{readelf {-d --wide} pr25593.d}} "pr25593b.exe"] \
+ [list "Build pr25618a.o" \
+ "$plug_opt" "-O2 -flto -fpic" \
+ {pr25618a.cc} {} "" "c++"] \
+ [list "Build pr25618.a" \
+ "$plug_opt" "-O2 -flto -fpic" \
+ {pr25618b.cc} {} "pr25618.a" "c++"] \
+ [list "Build pr25618.so" \
+ "-shared -Wl,--exclude-libs,ALL tmpdir/pr25618a.o tmpdir/pr25618.a" \
+ "-fpic" \
+ {dummy.c} {{readelf {--dyn-syms --wide} pr25618.d}} "pr25618.so" "c++"] \
+ [list {liblto-18b.so} \
+ {-shared} {-O2 -fpic} \
+ {lto-18b.c} {} {liblto-18b.so}] \
+ [list {liblto-18b.a} \
+ "$plug_opt" {-flto -O2} \
+ {lto-18b.c} {} {liblto-18b.a}] \
+ [list {liblto-18c.so} \
+ {-shared} {-O2 -fpic} \
+ {lto-18c.c} {} {liblto-18c.so}] \
+ [list {liblto-18c.a} \
+ "$plug_opt" {-flto -O2} \
+ {lto-18c.c} {} {liblto-18c.a}] \
+ [list {lto-18d.o} \
+ {} {-flto -O2} \
+ {lto-18d.c} {} {}] \
+ [list {liblto-19.a} \
+ "$plug_opt" {-flto -O2 -fPIC} \
+ {lto-19a.c} {} {liblto-19.a}] \
+ [list {compile lto-19b.c} \
+ "$plug_opt" {-flto -O2 -fPIC} \
+ {lto-19b.c} {} {} {c}] \
+ [list {liblto-19.so} \
+ {-shared tmpdir/lto-19b.o tmpdir/liblto-19.a} {-O2 -fPIC} \
+ {dummy.c} {} {liblto-19.so}] \
+ [list {pr26806.so} \
+ {-shared} {-fpic -O2 -flto} \
+ {pr26806.c} {{nm {-D} pr26806.d}} {pr26806.so}] \
+ [list {pr27311a.so} \
+ {-shared -Wl,--version-script=pr27311.ver} {-fPIC} \
+ {pr27311a.c} {} {pr27311a.so}] \
+ [list {pr27311b.so} \
+ {-shared -Wl,--no-as-needed tmpdir/pr27311a.so} {-fPIC} \
+ {pr27311b.c} {} {pr27311b.so}] \
+ [list {pr27311c.o} \
+ {} {-flto} \
+ {pr27311c.c} {} {} {c}] \
+ [list {pr27311d.o} \
+ {} {-flto} \
+ {pr27311d.c} {} {} {c}] \
+ [list {pr27311-1} \
+ {tmpdir/pr27311c.o -Wl,--no-as-needed,--rpath-link=. tmpdir/pr27311b.so} {} \
+ {dummy.c} {{readelf {--dyn-syms --wide} pr27311.d}} {pr27311-1}] \
+ [list {pr27311-2} \
+ {tmpdir/pr27311d.o -Wl,--no-as-needed,--rpath-link=. tmpdir/pr27311b.so} {} \
+ {dummy.c} {{readelf {--dyn-syms --wide} pr27311.d}} {pr27311-2}] \
+ [list {pr27441a.so} \
+ {-shared} {-fPIC} \
+ {pr27441a.c} {} {pr27441a.so}] \
+ [list {pr27441b.so} \
+ {-shared} {-fPIC} \
+ {pr27441b.c} {} {pr27441b.so}] \
+ [list {pr27441c.o} \
+ {} {-fPIC -flto} \
+ {pr27441c.c} {} {}] \
+ [list {pr27441c.so} \
+ {-shared -fPIC -Wl,--as-needed tmpdir/pr27441c.o tmpdir/pr27441b.so tmpdir/pr27441a.so} {-fPIC} \
+ {dummy.c} {{readelf {-dW} pr27441c.d}} {pr27441c.so}] \
+ [list \
+ "Build libpr28879a.so" \
+ "-shared" \
+ "-O0 -fpic" \
+ {pr28879a.cc} \
+ {} \
+ "libpr28879a.so" \
+ "c++" \
+ ] \
+ [list \
+ "Build libpr28879b.so" \
+ "-shared -Wl,--no-as-needed tmpdir/libpr28879a.so" \
+ "-O2 -fpic" \
+ {dummy.c} \
+ {} \
+ "libpr28879b.so" \
+ ] \
+ [list \
+ "Build pr28879" \
+ "-Wl,--no-as-needed tmpdir/libpr28879b.so -Wl,-rpath-link,." \
+ "-O0 -flto -D_GLIBCXX_ASSERTIONS" \
+ {pr28879b.cc} \
+ {} \
+ "pr28879" \
+ "c++" \
+ ] \
+ [list \
+ "Build libpr28849a.so" \
+ "-shared" \
+ "-fPIC" \
+ {pr28849a.c} \
+ "" \
+ "libpr28849a.so" \
+ ] \
+ [list \
+ "Build libpr28849b.so" \
+ "-shared -Wl,--no-as-needed,tmpdir/libpr28849a.so" \
+ "" \
+ {dummy.c} \
+ "" \
+ "libpr28849b.so" \
+ ] \
+ [list \
+ "Build pr28849" \
+ "-Wl,--no-as-needed,--copy-dt-needed-entries,-rpath-link,. \
+ tmpdir/libpr28849b.so" \
+ "-O2 -flto" \
+ {pr28849b.c} \
+ {{"nm" {-D} "pr28849.d"}} \
+ "pr28849" \
+ ] \
+ [list \
+ "PR ld/pr29086" \
+ "-Wl,--wrap=foo" \
+ "-O0 -flto" \
+ {pr29086.c} \
+ {} \
+ "pr29086" \
+ ] \
+]
+
+# PR 14918 checks that libgcc is not spuriously included in a shared link of
+# an empty program. The ARM crt1.o startup code however calls __libc_csu_init
+# in /usr/lib/libc_nonshared.a(elf-init.oS). This in turn needs
+# __aeabi_unwind_cpp_pr0@@GCC_3.5 which is provided by libgcc_s.so.1, so the
+# test fails. Hence this code to skip the test.
+if { ! [istarget "arm*-*-*"] } {
+ lappend lto_link_elf_tests \
+ [list "PR ld/14918" \
+ "-flto" "-flto" \
+ {pr14918.c} {{"readelf" {-d --wide} "pr14918.d"}} "pr14918.exe" "c"]
+}
+
+# PR 12982 checks that an executable stack is not created by default
+# when using the LTO plugin. The HPPA target however requires an
+# executable stack for syscall restarts and signal returns, so we
+# skip this test for that target.
+if { ! [istarget "hppa*-*-*"] } {
+ lappend lto_link_elf_tests \
+ [list "PR ld/12982" \
+ "-O2 -flto -fuse-linker-plugin" "-O2 -flto" \
+ {pr12982.c} {{"readelf" {-l --wide} "pr12982.d"}} "pr12982.exe"]
+}
+
+# Check final symbols in executables.
+set lto_link_symbol_tests [list \
+ [list "LTO 3 symbol" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-3a.o tmpdir/lto-3c.o tmpdir/liblto-3.a" "" \
+ {dummy.c} {{"nm" {} "lto-3.d"}} "lto-3.exe" "c"] \
+ [list "LTO 5 symbol" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-5.o" "" \
+ {dummy.c} {{"nm" {} "lto-5.d"}} "lto-5.exe" "c"] \
+ [list "LTO 9 symbol" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-9.o" "" \
+ {dummy.c} {{"nm" {-C} "lto-9.d"}} "lto-9.exe" "c++"] \
+ [list "LTO 16a symbol" \
+ "-O2 $NOSANITIZE_CFLAGS -Wl,-e,foo -nostdlib -flto -fuse-linker-plugin" \
+ "-flto $NOSANITIZE_CFLAGS" \
+ {lto-16a.c} {{"nm" {} "lto-16a.d"}} "lto-16.exe" "c"] \
+ [list "LTO 16b symbol" \
+ "-O2 $NOSANITIZE_CFLAGS -Wl,-e,foo -u bar -nostdlib -flto -fuse-linker-plugin" \
+ "-flto $NOSANITIZE_CFLAGS" \
+ {lto-16a.c lto-16b.c} {{"nm" {} "lto-16b.d"}} "lto-16b.exe" "c"] \
+ [list "PR ld/13183" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/pr13183b.o tmpdir/libpr13183.a" "" \
+ {dummy.c} {{"nm" {} "pr13183.d"}} "pr13183.exe" "c"] \
+]
+
+# LTO run-time tests.
+set lto_run_tests [list \
+ [list "LTO 3a" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-3a.o tmpdir/lto-3c.o tmpdir/liblto-3.a" "" \
+ {dummy.c} "lto-3b.exe" "lto-3.out" "" "c"] \
+ [list "LTO 3b" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-3a.o tmpdir/lto-3c.o tmpdir/lto-3.o" "" \
+ {dummy.c} "lto-3c.exe" "lto-3.out" "" "c"] \
+ [list "LTO 3c" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-3a.o tmpdir/lto-3c.o -Wl,--whole-archive tmpdir/liblto-3.a -Wl,--no-whole-archive tmpdir/liblto-3.a" "" \
+ {dummy.c} "lto-3d.exe" "lto-3.out" "" "c"] \
+ [list "LTO 5" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-5.o" "" \
+ {dummy.c} "lto-5.exe" "lto-5.out" "" "c"] \
+ [list "LTO 11" \
+ "-O -flto -fuse-linker-plugin tmpdir/liblto-11.a" "" \
+ {dummy.c} "lto-11.exe" "lto-11.out" "" "c"] \
+ [list "LTO 12a" \
+ "-O -flto -fuse-linker-plugin tmpdir/lto-12a.o tmpdir/liblto-12.a tmpdir/lto-12b.o" "" \
+ {dummy.c} "lto-12a.exe" "lto-12.out" "" "c"] \
+ [list "LTO 12b" \
+ "-O -flto -fuse-linker-plugin tmpdir/lto-12a.o tmpdir/lto-12b.o tmpdir/liblto-12.a" "" \
+ {dummy.c} "lto-12b.exe" "lto-12.out" "" "c"] \
+ [list "LTO 13" \
+ "-O -flto -fuse-linker-plugin tmpdir/lto-13a.o tmpdir/liblto-13.a tmpdir/lto-13b.o" "" \
+ {dummy.c} "lto-13.exe" "lto-13.out" "" "c"] \
+ [list "LTO 14" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-14a.o -Wl,--whole-archive tmpdir/liblto-14.a -Wl,--no-whole-archive tmpdir/lto-14b.o" "" \
+ {dummy.c} "lto-14.exe" "lto-14.out" "" "c"] \
+ [list "LTO 15" \
+ "-O2 -flto -fuse-linker-plugin -Wl,--start-group tmpdir/liblto-15.a tmpdir/lto-15a.o -Wl,--end-group" "" \
+ {dummy.c} "lto-15.exe" "lto-15.out" "" "c"] \
+ [list "PR ld/13066" \
+ "-O2 -flto -fuse-linker-plugin" "" \
+ {pr13066.cc} "pr13066.exe" "pr13066.out" "" "c++"] \
+ [list "PR ld/13201" \
+ "-O2 -flto -fuse-linker-plugin -Wl,--as-needed tmpdir/pr13201.o -lm" "" \
+ {dummy.c} "pr13201.exe" "pr13201.out" "" "c"] \
+ [list "PR ld/15323 (3)" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/pr15323a.o" "" \
+ {pr15323b.c} "pr15323.exe" "pr15323.out" "-flto -O2" "c"] \
+ [list "PR ld/15323 (4)" \
+ "-O2 -flto tmpdir/pr15323a-r.o" "" \
+ {dummy.c} "pr15323a.exe" "pr15323.out" "-flto -O2" "c"] \
+ [list "PR ld/19317 (3)" \
+ "-O2 -flto tmpdir/pr19317-r.o" "" \
+ {dummy.c} "pr19317.exe" "pr19317.out" "-flto -O2" "c"] \
+ [list "Run pr20276" \
+ "-O2 -flto tmpdir/pr20276a.o tmpdir/pr20276b.o" "" \
+ {dummy.c} "pr20276" "pass.out" "-flto -O2" "c"] \
+ [list "Run pr20267a" \
+ "-O2 -flto -fcommon tmpdir/pr20267a.o tmpdir/libpr20267a.a" "" \
+ {dummy.c} "pr20267a" "pass.out" "-flto -O2 -fcommon" "c"] \
+ [list "Run pr20267b" \
+ "-O2 -flto -fcommon tmpdir/pr20267a.o tmpdir/libpr20267b.a" "" \
+ {dummy.c} "pr20267b" "pass.out" "-flto -O2 -fcommon" "c"] \
+ [list "Run pr22502" \
+ "-O2 -flto tmpdir/pr22502a.o tmpdir/pr22502b.o" "" \
+ {dummy.c} "pr20267" "pass.out" "-flto -O2 -fcommon" "c"] \
+ [list "Run pr22751" \
+ "-O2 -flto" "" \
+ {dummy.c} "pr22751" "pass.out" "-flto -O2" "c" "" \
+ "-Wl,--whole-archive tmpdir/pr22751.a -Wl,--no-whole-archive"] \
+ [list "Run pr24406-1" \
+ "-O2 -flto" "" \
+ {pr24406-1.c} "pr24406-1" "pass.out" "-flto -O2" "c" "" \
+ "-Wl,--wrap=read"] \
+ [list "Run pr24406-2" \
+ "-O2 -flto" "" \
+ {pr24406-2a.c} "pr24406-2" "pass.out" \
+ "-flto -O2" "c" "" \
+ "tmpdir/pr24406-2b.o -Wl,--wrap=cook"] \
+ [list "Run pr26163" \
+ "-O2 -flto" "" \
+ {pr26163b.c} "pr24406-2" "pass.out" \
+ "-flto -O2" "c" "" \
+ "tmpdir/pr26163a.o -Wl,--defsym,g=real_g"] \
+ [list "Run pr26262a" \
+ "-O2 -flto" "" \
+ {pr26262a.c} "pr26262a" "pass.out" \
+ "-flto -O2" "c" "" \
+ "tmpdir/pr26262b.o tmpdir/pr26262c.o"] \
+ [list "Run pr26262b" \
+ "-flto -O2 tmpdir/pr26262b.o tmpdir/pr26262c.o" "" \
+ {pr26262a.c} "pr26262b" "pass.out" \
+ "-flto -O2" "c" "" \
+ ""] \
+]
+
+if { [at_least_gcc_version 4 7] } {
+ set lto_run_tests [concat $lto_run_tests [list \
+ [list "PR ld/12942 (1)" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/pr12942a.o tmpdir/pr12942b.o" "" \
+ {dummy.c} "pr12942a.exe" "pr12942.out" "" "c++"] \
+ [list "PR ld/12942 (2)" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/pr12942a.o tmpdir/pr12942c.o" "" \
+ {dummy.c} "pr12942c.exe" "pr12942.out" "" "c++"] \
+ ]]
+}
+
+# LTO run-time tests for ELF which require shared library support.
+set lto_run_elf_shared_tests [list \
+ [list "LTO 7" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-7b.o tmpdir/lto-7c.o tmpdir/lto-7a.o -Wl,--no-as-needed tmpdir/liblto-7.so" "" \
+ {dummy.c} "lto-7.exe" "lto-7.out" "" "c"] \
+ [list "Run pr21382" \
+ "-O2 -flto -fuse-linker-plugin -Wl,--as-needed tmpdir/pr21382a.o tmpdir/pr21382.so" "" \
+ {dummy.c} "pr21382.exe" "pass.out" "" "c"] \
+ [list {pr22220a} \
+ {-flto -fuse-linker-plugin tmpdir/pr22220main.o tmpdir/pr22220lib.so} {} \
+ {dummy.c} {pr22220a.exe} {pass.out} {} {c++}] \
+ [list {pr22220b} \
+ {-flto -fuse-linker-plugin -Wl,--no-as-needed tmpdir/pr22220lib.so tmpdir/pr22220main.o} {} \
+ {dummy.c} {pr22220b.exe} {pass.out} {} {c++}] \
+ [list {lto-18 (1)} \
+ {-flto -fuse-linker-plugin} {} \
+ {lto-18a.c} {lto-18-1.exe} {lto-18.out} {-flto -O2} {c} {} \
+ {tmpdir/lto-18d.o -Wl,--as-needed,-R,tmpdir -Ltmpdir -llto-18b -llto-18c}] \
+ [list {lto-18 (2)} \
+ {-flto -fuse-linker-plugin} {} \
+ {lto-18a.c} {lto-18-2.exe} {lto-18.out} {-flto -O2} {c} {} \
+ {-Wl,--as-needed,-R,tmpdir -Ltmpdir -llto-18b -llto-18c tmpdir/lto-18d.o}] \
+ [list {lto-18 (3)} \
+ {-static -flto -fuse-linker-plugin} {} \
+ {lto-18a.c} {lto-18-3.exe} {lto-18.out} {-flto -O2} {c} {} \
+ {tmpdir/lto-18d.o -Ltmpdir -llto-18b -llto-18c}] \
+ [list {lto-18 (4)} \
+ {-static -flto -fuse-linker-plugin} {} \
+ {lto-18a.c} {lto-18-4.exe} {lto-18.out} {-flto -O2} {c} {} \
+ { -Ltmpdir -llto-18b -llto-18c tmpdir/lto-18d.o}] \
+ [list {lto-19} \
+ {-Wl,--as-needed,-R,tmpdir} {} \
+ {lto-19c.c} {lto-19.exe} {pass.out} {-flto -O2} {c} {} \
+ {tmpdir/liblto-19.so tmpdir/liblto-19.a}] \
+]
+
+# LTO run-time tests for ELF
+set lto_run_elf_tests [list \
+ [list "LTO 8" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-8b.o tmpdir/lto-8a.o" "" \
+ {dummy.c} "lto-8.exe" "lto-8.out" "" "c"] \
+ [list "LTO TLS IE" \
+ "-O2 -flto -fuse-linker-plugin" "" \
+ {run-ie.c} "run-ie.exe" "run-ie.out" "" "c"] \
+]
+
+run_cc_link_tests $lto_link_tests
+
+# These compilation tests generate intermediate object files which will be used
+# by some elf tests besides shared libs tests. So, always compile them.
+run_cc_link_tests $lto_compile_elf_tests
+
+# Restrict these to ELF targets that support shared libs and PIC.
+if { [is_elf_format] && [check_lto_shared_available] } {
+ run_cc_link_tests $lto_link_elf_tests
+ set testname "PR ld/15146 (2)"
+ set exec_output [run_host_cmd "$CC_FOR_TARGET" "-O2 -flto -fuse-linker-plugin -Wl,-rpath-link,. -Wl,--no-copy-dt-needed-entries -Wl,--no-as-needed tmpdir/pr15146d.o tmpdir/pr15146c.so"]
+ if { [ regexp "undefined reference to symbol '\\.?xxx'" $exec_output ] } {
+ pass $testname
+ } {
+ fail $testname
+ }
+ set testname "PR ld/16746 (3)"
+ set exec_output [run_host_cmd "$CC_FOR_TARGET" "-O2 -flto -fuse-linker-plugin tmpdir/pr16746b.o tmpdir/pr16746d.o"]
+ if { [ regexp "warning: \\.?foobar" $exec_output ] && ![ regexp "symbol from plugin" $exec_output ] } {
+ pass $testname
+ } {
+ fail $testname
+ }
+ set testname "PR ld/16746 (4)"
+ set exec_output [run_host_cmd "$CC_FOR_TARGET" "-O2 -flto -fuse-linker-plugin tmpdir/pr16746d.o tmpdir/pr16746b.o"]
+ if { [ regexp "warning: \\.?foobar" $exec_output ] && ![ regexp "symbol from plugin" $exec_output ] } {
+ pass $testname
+ } {
+ fail $testname
+ }
+}
+
+run_cc_link_tests [list \
+ [list \
+ "Build pr28138.a" \
+ "-T" "" \
+ {pr28138-1.c pr28138-2.c pr28138-3.c pr28138-4.c pr28138-5.c \
+ pr28138-6.c pr28138-7.c} {} "pr28138.a" \
+ ] \
+ [list \
+ "Build pr28138.o" \
+ "" "" \
+ {pr28138.c} {} \
+ ] \
+]
+
+set exec_output [run_host_cmd "sh" \
+ "-c \"ulimit -n 20; \
+ $CC_FOR_TARGET -Btmpdir/ld -o tmpdir/pr28138 \
+ tmpdir/pr28138.o tmpdir/pr28138.a\""]
+set exec_output [prune_warnings $exec_output]
+if [string match "" $exec_output] then {
+ if { [isnative] } {
+ set exec_output [run_host_cmd "tmpdir/pr28138" ""]
+ if [string match "PASS" $exec_output] then {
+ pass "PR ld/28138 (build & run)"
+ } else {
+ fail "PR ld/28138 (built ok, run failed)"
+ }
+ } else {
+ pass "PR ld/28138 (build only)"
+ }
+} else {
+ fail "PR ld/28138 (build only)"
+}
+
+set testname "Build liblto-11.a"
+remote_file host delete "tmpdir/liblto-11.a"
+set catch_output [run_host_cmd "$ar" "rc $plug_opt tmpdir/liblto-11.a tmpdir/lto-11a.o tmpdir/lto-11b.o tmpdir/lto-11c.o"]
+if {![string match "" $catch_output]} {
+ fail $testname
+ restore_notify
+ return
+}
+
+if { [at_least_gcc_version 4 7] } {
+ # Check expected LTO linker errors.
+ # Since the asm symbol name hack in pr12365b.c doesn't work on all
+ # targets, run PR ld/12365 tests only for known targets.
+ if { ([istarget "i?86-*-elf*"]
+ || [istarget "i?86-*-linux*"]
+ || [istarget "i?86-*-gnu*"]
+ || [istarget "x86_64-*-linux*"]
+ || [istarget "amd64-*-linux*"]) } {
+ set testname "PR ld/12365"
+ set exec_output [run_host_cmd "$CC_FOR_TARGET" "-O2 -flto -flto-partition=none -fuse-linker-plugin -o tmpdir/pr12365 tmpdir/pr12365a.o tmpdir/pr12365b.o tmpdir/pr12365c.o"]
+ set exec_output [prune_warnings $exec_output]
+ if { [ regexp "undefined reference to `my_bcopy'" $exec_output ] } {
+ # Linker should catch the reference to undefined `my_bcopy'
+ # error caused by a GCC bug.
+ pass $testname
+ } elseif { [ string match "" $exec_output ] } {
+ global READELF
+ set exec_output [run_host_cmd "$READELF" "-s -W tmpdir/pr12365"]
+ if { [ regexp "my_bcopy" $exec_output ] } {
+ # Verify that there is no `my_bcopy' symbol in executable.
+ fail $testname
+ } {
+ pass $testname
+ }
+ } {
+ fail $testname
+ }
+
+ run_cc_link_tests [list \
+ [list \
+ "Build pr22721a.so" \
+ "-shared $NOSANITIZE_CFLAGS -nostdlib -nostartfiles \
+ -Wl,-version-script,pr22721.t" \
+ "" \
+ {pr22721a.s} \
+ {} \
+ "pr22721a.so" \
+ ] \
+ [list \
+ "Build pr22721b.o" \
+ "$plug_opt $NOSANITIZE_CFLAGS" \
+ "-O2 -fPIC -flto $lto_no_fat" \
+ {pr22721b.c} \
+ ] \
+ [list \
+ "Build PR ld/pr22721" \
+ "-O2 -flto -fuse-linker-plugin -nostdlib -nostartfiles \
+ $NOSANITIZE_CFLAGS \
+ -Wl,-e,_start tmpdir/pr22721b.o tmpdir/pr22721a.so" \
+ "$NOSANITIZE_CFLAGS" \
+ {dummy.c} \
+ {} \
+ "pr22721.exe"
+ ] \
+ ]
+ }
+ set testname "PR ld/12942 (3)"
+ set exec_output [run_host_cmd "$CXX_FOR_TARGET" "-O2 -flto -fuse-linker-plugin tmpdir/pr12942b.o tmpdir/pr12942a.o"]
+ if { [ regexp "undefined reference to `\\.?link_error\\(\\)'" $exec_output ] } {
+ pass $testname
+ } {
+ fail $testname
+ }
+
+ run_cc_link_tests [list \
+ [list \
+ "Build pr23460*.o" \
+ "$plug_opt" \
+ "-O2 -fPIC -flto $lto_no_fat" \
+ {pr23460a.c pr23460b.c pr23460c.c \
+ pr23460d.c pr23460e.c pr23460f.c} \
+ ] \
+ ]
+ set exec_output [run_host_cmd "sh" \
+ "-c \"ulimit -n 20; \
+ $ar -rc $plug_opt \
+ tmpdir/libpr23460.a \
+ tmpdir/pr23460a.o \
+ tmpdir/pr23460b.o \
+ tmpdir/pr23460c.o \
+ tmpdir/pr23460d.o \
+ tmpdir/pr23460e.o \
+ tmpdir/pr23460f.o\""]
+ set exec_output [prune_warnings $exec_output]
+ if [string match "" $exec_output] then {
+ pass "PR binutils/23460"
+ } else {
+ fail "PR binutils/23460"
+ }
+ set exec_output [run_host_cmd "$RANLIB" "$plug_opt tmpdir/libpr23460.a"]
+ set exec_output [prune_warnings $exec_output]
+ if [string match "" $exec_output] then {
+ pass "PR binutils/23460"
+ } else {
+ fail "PR binutils/23460"
+ }
+}
+
+# Fedora specific binutils patches break some of the tests that follow...
+restore_notify
+return
+
+# Run "ld -r" to generate inputs for complex LTO tests.
+run_dump_test "lto-3r"
+remote_exec host "mv" "tmpdir/dump tmpdir/lto-3.o"
+run_dump_test "lto-5r"
+remote_exec host "mv" "tmpdir/dump tmpdir/lto-5.o"
+
+run_cc_link_tests $lto_link_symbol_tests
+
+run_ld_link_tests [list \
+ [list "PR ld/19317 (2)" \
+ "-r tmpdir/pr19317.o" "" "" \
+ {dummy.s} {} "pr19317-r.o"] \
+]
+
+run_ld_link_exec_tests $lto_run_tests
+
+if { [is_elf_format] } {
+ run_ld_link_exec_tests $lto_run_elf_tests
+
+ # Note - it is not guaranteed that the ordering of symbols in the dynamic
+ # symbol table will match the ordering of the symbols specified by the
+ # --dynamic-list command line option.
+ #
+ # For PR22983 we want to make sure that all four symbols specified in
+ # pr222983.t are present in the output, but a simple sequences of regexps
+ # will not work as we do not know the order of the symbols. (Readelf
+ # does not have a symbol sorting option and the run_cc_list_tests proc
+ # does not allow for the output of the dump program to piped into `sort`).
+ #
+ # So instead we run readelf four times, each time checking for the
+ # presence of a specific symbol from the pr22983.t file.
+ run_cc_link_tests [list \
+ [list \
+ "Build pr22983" \
+ "-Wl,--dynamic-list,pr22983.t" \
+ "-flto" \
+ {pr22983a.c pr22983b.c} \
+ {{readelf {--dyn-syms --wide} pr22983.1.d} \
+ {readelf {--dyn-syms --wide} pr22983.2.d} \
+ {readelf {--dyn-syms --wide} pr22983.3.d} \
+ {readelf {--dyn-syms --wide} pr22983.4.d}} \
+ "pr22983" \
+ ] \
+ ]
+}
+
+if { [is_elf_format] && [check_lto_shared_available] } {
+ run_ld_link_exec_tests $lto_run_elf_shared_tests
+}
+
+proc pr20103 {cflags libs} {
+ global CC_FOR_TARGET
+
+ set testname "PR ld/20103 ($cflags $libs)"
+ set exec_output [run_host_cmd "$CC_FOR_TARGET" "$cflags $libs"]
+ if { [ regexp "undefined reference to `\\.?dead'" $exec_output ] } {
+ pass "$testname (1)"
+ } {
+ fail "$testname (1)"
+ }
+ if { [ regexp "plugin needed to handle lto object" $exec_output ] } {
+ fail "$testname (2)"
+ } {
+ pass "$testname (2)"
+ }
+}
+
+if { [check_lto_fat_available] } {
+ run_cc_link_tests [list \
+ [list \
+ "Build fatpr20103a.a" \
+ "$plug_opt" "-flto -ffat-lto-objects" \
+ {pr20103a.c} {} "fatpr20103a.a"
+ ] \
+ [list \
+ "Build fatpr20103b.a" \
+ "$plug_opt" "-flto -ffat-lto-objects" \
+ {pr20103b.c} {} "fatpr20103b.a"
+ ] \
+ [list \
+ "Build fatpr20103c.a" \
+ "$plug_opt" "-flto -ffat-lto-objects" \
+ {pr20103c.c} {} "fatpr20103c.a" \
+ ] \
+ [list \
+ "Build thinpr20103a.a" \
+ "$plug_opt" "-flto -fno-fat-lto-objects" \
+ {pr20103a.c} {} "thinpr20103a.a"
+ ] \
+ [list \
+ "Build thinpr20103b.a" \
+ "$plug_opt" "-flto -fno-fat-lto-objects" \
+ {pr20103b.c} {} "thinpr20103b.a"
+ ] \
+ [list \
+ "Build thinpr20103c.a" \
+ "$plug_opt" "-flto -fno-fat-lto-objects" \
+ {pr20103c.c} {} "thinpr20103c.a" \
+ ] \
+ [list \
+ "Build pr20103a" \
+ "-O2 -flto -Wl,--start-group tmpdir/thinpr20103a.a tmpdir/thinpr20103b.a tmpdir/thinpr20103c.a -Wl,--end-group" \
+ "-O2 -flto" \
+ {dummy.c} {} "pr20103a" \
+ ] \
+ [list \
+ "Build pr20103b" \
+ "-O2 -flto -Wl,--start-group tmpdir/fatpr20103a.a tmpdir/fatpr20103b.a tmpdir/fatpr20103c.a -Wl,--end-group" \
+ "-O2 -flto" \
+ {dummy.c} {} "pr20103b" \
+ ] \
+ [list \
+ "Build pr20103c" \
+ "-O2 -Wl,--start-group tmpdir/fatpr20103a.a tmpdir/fatpr20103b.a tmpdir/fatpr20103c.a -Wl,--end-group" \
+ "-O2" \
+ {dummy.c} {} "pr20103c" \
+ ] \
+ ]
+ pr20103 "-O2 -flto" "tmpdir/thinpr20103a.a tmpdir/thinpr20103b.a tmpdir/thinpr20103c.a"
+ pr20103 "-O2 -flto" "tmpdir/fatpr20103a.a tmpdir/fatpr20103b.a tmpdir/fatpr20103c.a"
+ pr20103 "-O2" "tmpdir/fatpr20103a.a tmpdir/fatpr20103b.a tmpdir/fatpr20103c.a"
+
+ if { [at_least_gcc_version 4 9] } {
+ run_cc_link_tests [list \
+ [list \
+ "Build pr20103d" \
+ "-O2 -Wl,--start-group tmpdir/thinpr20103a.a tmpdir/thinpr20103b.a tmpdir/thinpr20103c.a -Wl,--end-group" \
+ "-O2" \
+ {dummy.c} {} "pr20103d" \
+ ] \
+ ]
+ pr20103 "-O2" "tmpdir/thinpr20103a.a tmpdir/thinpr20103b.a tmpdir/thinpr20103c.a"
+ }
+}
+
+restore_notify
Index: GNU/binutils/create-2.40-cleansweep-patch/binutils-2.40-new/ld/testsuite/ld-size/size.exp
===================================================================
--- GNU/binutils/create-2.40-cleansweep-patch/binutils-2.40-new/ld/testsuite/ld-size/size.exp (nonexistent)
+++ GNU/binutils/create-2.40-cleansweep-patch/binutils-2.40-new/ld/testsuite/ld-size/size.exp (revision 33)
@@ -0,0 +1,279 @@
+# Expect script for linker support of size relocations.
+#
+# Copyright (C) 2013-2023 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+
+# Size relocations have only been implemented for the ix86 and x86_64,
+# so far.
+if {!(([istarget "i?86-*-*"]
+ || [istarget "x86_64-*-*"])
+ && ([istarget "*-*-elf*"]
+ || [istarget "*-*-nacl*"]
+ || [istarget "*-*-linux*"]
+ || [istarget "*-*-gnu*"])) } {
+ verbose "Size relocations tests not run - no target support"
+ return
+}
+
+# Skip when -shared is not supported
+if { ![check_shared_lib_support] } {
+ verbose "Size relocation tests not run - shared support disabled"
+ return
+}
+
+# So as to avoid rewriting every last test case here in a nacl variant,
+# we use black magic to massage the generic cases into nacl-variant cases.
+if [istarget "*-*-nacl*"] {
+ # Change all the -melf_i386 to -melf_i386_nacl so linking can succeed.
+ set options_regsub(ld) {-m(\\S+) -m\\1_nacl}
+}
+
+set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+foreach t $test_list {
+ # We need to strip the ".d", but can leave the dirname.
+ verbose [file rootname $t]
+ run_dump_test [file rootname $t]
+}
+
+# We need a working compiler.
+if { ![check_compiler_available] } {
+ verbose "Native size relocation tests not run - no compiler available"
+ return
+}
+
+run_cc_link_tests [list \
+ [list \
+ "Build libsize-1.so" \
+ "-shared" \
+ "-fPIC" \
+ {size-1a.c size-1b.c} \
+ {} \
+ "libsize-1.so" \
+ ] \
+ [list \
+ "Build libsize-2.so" \
+ "-shared" \
+ "-fPIC" \
+ {size-2a.c size-2b.c} \
+ {} \
+ "libsize-2.so" \
+ ] \
+ [list \
+ "Build libsize-3a.so" \
+ "-shared" "-fPIC" \
+ {size-3a.c} \
+ {} \
+ "libsize-3a.so" \
+ ] \
+ [list \
+ "Build libsize-3b.so" \
+ "-shared" \
+ "-fPIC" \
+ {size-3b.c} \
+ {} \
+ "libsize-3b.so" \
+ ] \
+ [list \
+ "Build libsize-3c.so" \
+ "-shared" \
+ "-fPIC" \
+ {size-3c.c} \
+ {} \
+ "libsize-3c.so" \
+ ] \
+ [list \
+ "Build libsize-6b.so" \
+ "-shared" \
+ "-fPIC" \
+ {size-6b.c} \
+ {} \
+ "libsize-6b.so" \
+ ] \
+ [list \
+ "Build libsize-9.so" \
+ "-shared $NOSANITIZE_CFLAGS" \
+ "-fPIC $NOSANITIZE_CFLAGS" \
+ {size-9b.c} \
+ {{readelf -rW size-9.rd}} \
+ "libsize-9.so" \
+ ] \
+ [list \
+ "Build libsize-10.so" \
+ "-shared" \
+ "-fPIC" \
+ {size-10b.c} \
+ {{readelf -rW size-10.rd}} \
+ "libsize-10.so" \
+ ] \
+]
+
+return
+
+# Check if size relocation works at run-time.
+catch "exec tmpdir/size-7.exe > tmpdir/dump.out" exec_output
+if ![string match "" $exec_output] then {
+ send_log "No run-time size relocation support: $exec_output\n"
+ verbose "No run-time size relocation support: $exec_output" 1
+ return
+}
+
+if { [regexp_diff "tmpdir/dump.out" "$srcdir/$subdir/size-7.out" ] } then {
+ verbose "output is [file_contents "tmpdir/dump.out"]" 2
+ fail "Run-time size relocation"
+ return
+}
+
+# Run-time size relocation tests.
+run_ld_link_exec_tests [list \
+ [list \
+ "Run size-1" \
+ "-Wl,--no-as-needed tmpdir/libsize-1.so" \
+ "" \
+ {size-1.c} \
+ "size-1" \
+ "size-1.out" \
+ ] \
+ [list \
+ "Run size-2" \
+ "-Wl,--no-as-needed tmpdir/libsize-2.so" \
+ "" \
+ {size-2.c} \
+ "size-2" \
+ "size-2.out" \
+ ] \
+ [list \
+ "Run size-3a" \
+ "" \
+ "" \
+ {size-3.c size-3a.c} \
+ "size-3a" \
+ "size-3.out" \
+ ] \
+ [list \
+ "Run size-3b" \
+ "-Wl,--no-as-needed tmpdir/libsize-3a.so" \
+ "" \
+ {size-3.c} \
+ "size-3b" \
+ "size-3.out" \
+ ] \
+ [list \
+ "Run size-3c" \
+ "" \
+ "" \
+ {size-3.c size-3b.c} \
+ "size-3c" \
+ "size-3.out" \
+ ] \
+ [list \
+ "Run size-3d (1)" \
+ "-Wl,--no-as-needed tmpdir/libsize-3b.so" \
+ "" \
+ {size-3.c} \
+ "size-3d1" \
+ "size-3.out" \
+ ] \
+ [list \
+ "Run size-3d (2)" \
+ "" \
+ "" \
+ {size-3.c size-3c.c} \
+ "size-3d2" \
+ "size-3.out" \
+ ] \
+ [list \
+ {"Run size-3e" \
+ "-Wl,--no-as-needed tmpdir/libsize-3c.so" "" \
+ {size-3.c} "size-3e" "size-3.out"} \
+ ] \
+ [list \
+ "Run size-4a" \
+ "$NOPIE_LDFLAGS" \
+ "" \
+ {size-4a.c size-4b.c} \
+ "size-4a" \
+ "size-4.out" \
+ "$NOPIE_CFLAGS" \
+ ] \
+ [list \
+ "Run size-4b" \
+ "$NOPIE_LDFLAGS" \
+ "" \
+ {size-4b.c size-4a.c} \
+ "size-4b" \
+ "size-4.out" \
+ "$NOPIE_CFLAGS" \
+ ] \
+ [list \
+ "Run size-5a" \
+ "$NOPIE_LDFLAGS" \
+ "" \
+ {size-5a.c size-5b.c} \
+ "size-5a" \
+ "size-5.out" \
+ "$NOPIE_CFLAGS" \
+ ] \
+ [list \
+ "Run size-5b" \
+ "$NOPIE_LDFLAGS" \
+ "" \
+ {size-5b.c size-5a.c} \
+ "size-5b" \
+ "size-5.out" \
+ "$NOPIE_CFLAGS" \
+ ] \
+ [list \
+ "Run size-6" \
+ "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libsize-6b.so" \
+ "" \
+ {size-6a.c} \
+ "size-6" \
+ "size-6.out" \
+ "$NOPIE_CFLAGS" \
+ ] \
+ [list \
+ "Run size-8" \
+ "$NOPIE_LDFLAGS -Wl,--no-as-needed,--hash-style=gnu,-z,notext \
+ tmpdir/libsize-8.so" \
+ "" \
+ {size-8a.c} \
+ "size-8" \
+ "size-8.out" \
+ "$NOPIE_CFLAGS" \
+ ] \
+ [list \
+ "Run size-9" \
+ "-Wl,--no-as-needed tmpdir/libsize-9.so $NOSANITIZE_CFLAGS" \
+ "" \
+ {size-9a.c} \
+ "size-9" \
+ "size-9.out" \
+ "$NOSANITIZE_CFLAGS" \
+ ] \
+ [list \
+ "Run size-10" \
+ "-Wl,--no-as-needed tmpdir/libsize-10.so" \
+ "" \
+ {size-10a.c} \
+ "size-10" \
+ "size-10.out" \
+ ] \
+]
Index: GNU/binutils/create-2.40-cleansweep-patch/create.patch.sh
===================================================================
--- GNU/binutils/create-2.40-cleansweep-patch/create.patch.sh (nonexistent)
+++ GNU/binutils/create-2.40-cleansweep-patch/create.patch.sh (revision 33)
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+VERSION=2.40
+
+tar --files-from=file.list -xJvf ../binutils-$VERSION.tar.xz
+mv binutils-$VERSION binutils-$VERSION-orig
+
+cp -rf ./binutils-$VERSION-new ./binutils-$VERSION
+
+diff --unified -Nr binutils-$VERSION-orig binutils-$VERSION > binutils-$VERSION-cleansweep.patch
+
+mv binutils-$VERSION-cleansweep.patch ../patches
+
+rm -rf ./binutils-$VERSION
+rm -rf ./binutils-$VERSION-orig
Property changes on: GNU/binutils/create-2.40-cleansweep-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: GNU/binutils/create-2.40-cleansweep-patch/file.list
===================================================================
--- GNU/binutils/create-2.40-cleansweep-patch/file.list (nonexistent)
+++ GNU/binutils/create-2.40-cleansweep-patch/file.list (revision 33)
@@ -0,0 +1,2 @@
+binutils-2.40/ld/testsuite/ld-plugin/lto.exp
+binutils-2.40/ld/testsuite/ld-size/size.exp
Index: GNU/binutils/create-2.40-copy-osabi-patch/binutils-2.40-new/bfd/elf.c
===================================================================
--- GNU/binutils/create-2.40-copy-osabi-patch/binutils-2.40-new/bfd/elf.c (nonexistent)
+++ GNU/binutils/create-2.40-copy-osabi-patch/binutils-2.40-new/bfd/elf.c (revision 33)
@@ -0,0 +1,13627 @@
+/* ELF executable support for BFD.
+
+ Copyright (C) 1993-2023 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+
+/*
+SECTION
+ ELF backends
+
+ BFD support for ELF formats is being worked on.
+ Currently, the best supported back ends are for sparc and i386
+ (running svr4 or Solaris 2).
+
+ Documentation of the internals of the support code still needs
+ to be written. The code is changing quickly enough that we
+ haven't bothered yet. */
+
+/* For sparc64-cross-sparc32. */
+#define _SYSCALL32
+#include "sysdep.h"
+#include <limits.h>
+#include "bfd.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#define ARCH_SIZE 0
+#include "elf-bfd.h"
+#include "libiberty.h"
+#include "safe-ctype.h"
+#include "elf-linux-core.h"
+
+#ifdef CORE_HEADER
+#include CORE_HEADER
+#endif
+
+static int elf_sort_sections (const void *, const void *);
+static bool assign_file_positions_except_relocs (bfd *, struct bfd_link_info *);
+static bool swap_out_syms (bfd *, struct elf_strtab_hash **, int,
+ struct bfd_link_info *);
+static bool elf_parse_notes (bfd *abfd, char *buf, size_t size,
+ file_ptr offset, size_t align);
+
+/* Swap version information in and out. The version information is
+ currently size independent. If that ever changes, this code will
+ need to move into elfcode.h. */
+
+/* Swap in a Verdef structure. */
+
+void
+_bfd_elf_swap_verdef_in (bfd *abfd,
+ const Elf_External_Verdef *src,
+ Elf_Internal_Verdef *dst)
+{
+ dst->vd_version = H_GET_16 (abfd, src->vd_version);
+ dst->vd_flags = H_GET_16 (abfd, src->vd_flags);
+ dst->vd_ndx = H_GET_16 (abfd, src->vd_ndx);
+ dst->vd_cnt = H_GET_16 (abfd, src->vd_cnt);
+ dst->vd_hash = H_GET_32 (abfd, src->vd_hash);
+ dst->vd_aux = H_GET_32 (abfd, src->vd_aux);
+ dst->vd_next = H_GET_32 (abfd, src->vd_next);
+}
+
+/* Swap out a Verdef structure. */
+
+void
+_bfd_elf_swap_verdef_out (bfd *abfd,
+ const Elf_Internal_Verdef *src,
+ Elf_External_Verdef *dst)
+{
+ H_PUT_16 (abfd, src->vd_version, dst->vd_version);
+ H_PUT_16 (abfd, src->vd_flags, dst->vd_flags);
+ H_PUT_16 (abfd, src->vd_ndx, dst->vd_ndx);
+ H_PUT_16 (abfd, src->vd_cnt, dst->vd_cnt);
+ H_PUT_32 (abfd, src->vd_hash, dst->vd_hash);
+ H_PUT_32 (abfd, src->vd_aux, dst->vd_aux);
+ H_PUT_32 (abfd, src->vd_next, dst->vd_next);
+}
+
+/* Swap in a Verdaux structure. */
+
+void
+_bfd_elf_swap_verdaux_in (bfd *abfd,
+ const Elf_External_Verdaux *src,
+ Elf_Internal_Verdaux *dst)
+{
+ dst->vda_name = H_GET_32 (abfd, src->vda_name);
+ dst->vda_next = H_GET_32 (abfd, src->vda_next);
+}
+
+/* Swap out a Verdaux structure. */
+
+void
+_bfd_elf_swap_verdaux_out (bfd *abfd,
+ const Elf_Internal_Verdaux *src,
+ Elf_External_Verdaux *dst)
+{
+ H_PUT_32 (abfd, src->vda_name, dst->vda_name);
+ H_PUT_32 (abfd, src->vda_next, dst->vda_next);
+}
+
+/* Swap in a Verneed structure. */
+
+void
+_bfd_elf_swap_verneed_in (bfd *abfd,
+ const Elf_External_Verneed *src,
+ Elf_Internal_Verneed *dst)
+{
+ dst->vn_version = H_GET_16 (abfd, src->vn_version);
+ dst->vn_cnt = H_GET_16 (abfd, src->vn_cnt);
+ dst->vn_file = H_GET_32 (abfd, src->vn_file);
+ dst->vn_aux = H_GET_32 (abfd, src->vn_aux);
+ dst->vn_next = H_GET_32 (abfd, src->vn_next);
+}
+
+/* Swap out a Verneed structure. */
+
+void
+_bfd_elf_swap_verneed_out (bfd *abfd,
+ const Elf_Internal_Verneed *src,
+ Elf_External_Verneed *dst)
+{
+ H_PUT_16 (abfd, src->vn_version, dst->vn_version);
+ H_PUT_16 (abfd, src->vn_cnt, dst->vn_cnt);
+ H_PUT_32 (abfd, src->vn_file, dst->vn_file);
+ H_PUT_32 (abfd, src->vn_aux, dst->vn_aux);
+ H_PUT_32 (abfd, src->vn_next, dst->vn_next);
+}
+
+/* Swap in a Vernaux structure. */
+
+void
+_bfd_elf_swap_vernaux_in (bfd *abfd,
+ const Elf_External_Vernaux *src,
+ Elf_Internal_Vernaux *dst)
+{
+ dst->vna_hash = H_GET_32 (abfd, src->vna_hash);
+ dst->vna_flags = H_GET_16 (abfd, src->vna_flags);
+ dst->vna_other = H_GET_16 (abfd, src->vna_other);
+ dst->vna_name = H_GET_32 (abfd, src->vna_name);
+ dst->vna_next = H_GET_32 (abfd, src->vna_next);
+}
+
+/* Swap out a Vernaux structure. */
+
+void
+_bfd_elf_swap_vernaux_out (bfd *abfd,
+ const Elf_Internal_Vernaux *src,
+ Elf_External_Vernaux *dst)
+{
+ H_PUT_32 (abfd, src->vna_hash, dst->vna_hash);
+ H_PUT_16 (abfd, src->vna_flags, dst->vna_flags);
+ H_PUT_16 (abfd, src->vna_other, dst->vna_other);
+ H_PUT_32 (abfd, src->vna_name, dst->vna_name);
+ H_PUT_32 (abfd, src->vna_next, dst->vna_next);
+}
+
+/* Swap in a Versym structure. */
+
+void
+_bfd_elf_swap_versym_in (bfd *abfd,
+ const Elf_External_Versym *src,
+ Elf_Internal_Versym *dst)
+{
+ dst->vs_vers = H_GET_16 (abfd, src->vs_vers);
+}
+
+/* Swap out a Versym structure. */
+
+void
+_bfd_elf_swap_versym_out (bfd *abfd,
+ const Elf_Internal_Versym *src,
+ Elf_External_Versym *dst)
+{
+ H_PUT_16 (abfd, src->vs_vers, dst->vs_vers);
+}
+
+/* Standard ELF hash function. Do not change this function; you will
+ cause invalid hash tables to be generated. */
+
+unsigned long
+bfd_elf_hash (const char *namearg)
+{
+ const unsigned char *name = (const unsigned char *) namearg;
+ unsigned long h = 0;
+ unsigned long g;
+ int ch;
+
+ while ((ch = *name++) != '\0')
+ {
+ h = (h << 4) + ch;
+ if ((g = (h & 0xf0000000)) != 0)
+ {
+ h ^= g >> 24;
+ /* The ELF ABI says `h &= ~g', but this is equivalent in
+ this case and on some machines one insn instead of two. */
+ h ^= g;
+ }
+ }
+ return h & 0xffffffff;
+}
+
+/* DT_GNU_HASH hash function. Do not change this function; you will
+ cause invalid hash tables to be generated. */
+
+unsigned long
+bfd_elf_gnu_hash (const char *namearg)
+{
+ const unsigned char *name = (const unsigned char *) namearg;
+ unsigned long h = 5381;
+ unsigned char ch;
+
+ while ((ch = *name++) != '\0')
+ h = (h << 5) + h + ch;
+ return h & 0xffffffff;
+}
+
+/* Create a tdata field OBJECT_SIZE bytes in length, zeroed out and with
+ the object_id field of an elf_obj_tdata field set to OBJECT_ID. */
+bool
+bfd_elf_allocate_object (bfd *abfd,
+ size_t object_size,
+ enum elf_target_id object_id)
+{
+ BFD_ASSERT (object_size >= sizeof (struct elf_obj_tdata));
+ abfd->tdata.any = bfd_zalloc (abfd, object_size);
+ if (abfd->tdata.any == NULL)
+ return false;
+
+ elf_object_id (abfd) = object_id;
+ if (abfd->direction != read_direction)
+ {
+ struct output_elf_obj_tdata *o = bfd_zalloc (abfd, sizeof *o);
+ if (o == NULL)
+ return false;
+ elf_tdata (abfd)->o = o;
+ elf_program_header_size (abfd) = (bfd_size_type) -1;
+ }
+ return true;
+}
+
+
+bool
+bfd_elf_make_object (bfd *abfd)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata),
+ bed->target_id);
+}
+
+bool
+bfd_elf_mkcorefile (bfd *abfd)
+{
+ /* I think this can be done just like an object file. */
+ if (!abfd->xvec->_bfd_set_format[(int) bfd_object] (abfd))
+ return false;
+ elf_tdata (abfd)->core = bfd_zalloc (abfd, sizeof (*elf_tdata (abfd)->core));
+ return elf_tdata (abfd)->core != NULL;
+}
+
+char *
+bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
+{
+ Elf_Internal_Shdr **i_shdrp;
+ bfd_byte *shstrtab = NULL;
+ file_ptr offset;
+ bfd_size_type shstrtabsize;
+
+ i_shdrp = elf_elfsections (abfd);
+ if (i_shdrp == 0
+ || shindex >= elf_numsections (abfd)
+ || i_shdrp[shindex] == 0)
+ return NULL;
+
+ shstrtab = i_shdrp[shindex]->contents;
+ if (shstrtab == NULL)
+ {
+ /* No cached one, attempt to read, and cache what we read. */
+ offset = i_shdrp[shindex]->sh_offset;
+ shstrtabsize = i_shdrp[shindex]->sh_size;
+
+ /* Allocate and clear an extra byte at the end, to prevent crashes
+ in case the string table is not terminated. */
+ if (shstrtabsize + 1 <= 1
+ || bfd_seek (abfd, offset, SEEK_SET) != 0
+ || (shstrtab = _bfd_alloc_and_read (abfd, shstrtabsize + 1,
+ shstrtabsize)) == NULL)
+ {
+ /* Once we've failed to read it, make sure we don't keep
+ trying. Otherwise, we'll keep allocating space for
+ the string table over and over. */
+ i_shdrp[shindex]->sh_size = 0;
+ }
+ else
+ shstrtab[shstrtabsize] = '\0';
+ i_shdrp[shindex]->contents = shstrtab;
+ }
+ return (char *) shstrtab;
+}
+
+char *
+bfd_elf_string_from_elf_section (bfd *abfd,
+ unsigned int shindex,
+ unsigned int strindex)
+{
+ Elf_Internal_Shdr *hdr;
+
+ if (strindex == 0)
+ return "";
+
+ if (elf_elfsections (abfd) == NULL || shindex >= elf_numsections (abfd))
+ return NULL;
+
+ hdr = elf_elfsections (abfd)[shindex];
+
+ if (hdr->contents == NULL)
+ {
+ if (hdr->sh_type != SHT_STRTAB && hdr->sh_type < SHT_LOOS)
+ {
+ /* PR 17512: file: f057ec89. */
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: attempt to load strings from"
+ " a non-string section (number %d)"),
+ abfd, shindex);
+ return NULL;
+ }
+
+ if (bfd_elf_get_str_section (abfd, shindex) == NULL)
+ return NULL;
+ }
+ else
+ {
+ /* PR 24273: The string section's contents may have already
+ been loaded elsewhere, eg because a corrupt file has the
+ string section index in the ELF header pointing at a group
+ section. So be paranoid, and test that the last byte of
+ the section is zero. */
+ if (hdr->sh_size == 0 || hdr->contents[hdr->sh_size - 1] != 0)
+ return NULL;
+ }
+
+ if (strindex >= hdr->sh_size)
+ {
+ unsigned int shstrndx = elf_elfheader(abfd)->e_shstrndx;
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: invalid string offset %u >= %" PRIu64 " for section `%s'"),
+ abfd, strindex, (uint64_t) hdr->sh_size,
+ (shindex == shstrndx && strindex == hdr->sh_name
+ ? ".shstrtab"
+ : bfd_elf_string_from_elf_section (abfd, shstrndx, hdr->sh_name)));
+ return NULL;
+ }
+
+ return ((char *) hdr->contents) + strindex;
+}
+
+/* Read and convert symbols to internal format.
+ SYMCOUNT specifies the number of symbols to read, starting from
+ symbol SYMOFFSET. If any of INTSYM_BUF, EXTSYM_BUF or EXTSHNDX_BUF
+ are non-NULL, they are used to store the internal symbols, external
+ symbols, and symbol section index extensions, respectively.
+ Returns a pointer to the internal symbol buffer (malloced if necessary)
+ or NULL if there were no symbols or some kind of problem. */
+
+Elf_Internal_Sym *
+bfd_elf_get_elf_syms (bfd *ibfd,
+ Elf_Internal_Shdr *symtab_hdr,
+ size_t symcount,
+ size_t symoffset,
+ Elf_Internal_Sym *intsym_buf,
+ void *extsym_buf,
+ Elf_External_Sym_Shndx *extshndx_buf)
+{
+ Elf_Internal_Shdr *shndx_hdr;
+ void *alloc_ext;
+ const bfd_byte *esym;
+ Elf_External_Sym_Shndx *alloc_extshndx;
+ Elf_External_Sym_Shndx *shndx;
+ Elf_Internal_Sym *alloc_intsym;
+ Elf_Internal_Sym *isym;
+ Elf_Internal_Sym *isymend;
+ const struct elf_backend_data *bed;
+ size_t extsym_size;
+ size_t amt;
+ file_ptr pos;
+
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+ abort ();
+
+ if (symcount == 0)
+ return intsym_buf;
+
+ /* Normal syms might have section extension entries. */
+ shndx_hdr = NULL;
+ if (elf_symtab_shndx_list (ibfd) != NULL)
+ {
+ elf_section_list * entry;
+ Elf_Internal_Shdr **sections = elf_elfsections (ibfd);
+
+ /* Find an index section that is linked to this symtab section. */
+ for (entry = elf_symtab_shndx_list (ibfd); entry != NULL; entry = entry->next)
+ {
+ /* PR 20063. */
+ if (entry->hdr.sh_link >= elf_numsections (ibfd))
+ continue;
+
+ if (sections[entry->hdr.sh_link] == symtab_hdr)
+ {
+ shndx_hdr = & entry->hdr;
+ break;
+ };
+ }
+
+ if (shndx_hdr == NULL)
+ {
+ if (symtab_hdr == &elf_symtab_hdr (ibfd))
+ /* Not really accurate, but this was how the old code used
+ to work. */
+ shndx_hdr = &elf_symtab_shndx_list (ibfd)->hdr;
+ /* Otherwise we do nothing. The assumption is that
+ the index table will not be needed. */
+ }
+ }
+
+ /* Read the symbols. */
+ alloc_ext = NULL;
+ alloc_extshndx = NULL;
+ alloc_intsym = NULL;
+ bed = get_elf_backend_data (ibfd);
+ extsym_size = bed->s->sizeof_sym;
+ if (_bfd_mul_overflow (symcount, extsym_size, &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ intsym_buf = NULL;
+ goto out;
+ }
+ pos = symtab_hdr->sh_offset + symoffset * extsym_size;
+ if (extsym_buf == NULL)
+ {
+ alloc_ext = bfd_malloc (amt);
+ extsym_buf = alloc_ext;
+ }
+ if (extsym_buf == NULL
+ || bfd_seek (ibfd, pos, SEEK_SET) != 0
+ || bfd_bread (extsym_buf, amt, ibfd) != amt)
+ {
+ intsym_buf = NULL;
+ goto out;
+ }
+
+ if (shndx_hdr == NULL || shndx_hdr->sh_size == 0)
+ extshndx_buf = NULL;
+ else
+ {
+ if (_bfd_mul_overflow (symcount, sizeof (Elf_External_Sym_Shndx), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ intsym_buf = NULL;
+ goto out;
+ }
+ pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx);
+ if (extshndx_buf == NULL)
+ {
+ alloc_extshndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+ extshndx_buf = alloc_extshndx;
+ }
+ if (extshndx_buf == NULL
+ || bfd_seek (ibfd, pos, SEEK_SET) != 0
+ || bfd_bread (extshndx_buf, amt, ibfd) != amt)
+ {
+ intsym_buf = NULL;
+ goto out;
+ }
+ }
+
+ if (intsym_buf == NULL)
+ {
+ if (_bfd_mul_overflow (symcount, sizeof (Elf_Internal_Sym), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto out;
+ }
+ alloc_intsym = (Elf_Internal_Sym *) bfd_malloc (amt);
+ intsym_buf = alloc_intsym;
+ if (intsym_buf == NULL)
+ goto out;
+ }
+
+ /* Convert the symbols to internal form. */
+ isymend = intsym_buf + symcount;
+ for (esym = (const bfd_byte *) extsym_buf, isym = intsym_buf,
+ shndx = extshndx_buf;
+ isym < isymend;
+ esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL)
+ if (!(*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym))
+ {
+ symoffset += (esym - (bfd_byte *) extsym_buf) / extsym_size;
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB symbol number %lu references"
+ " nonexistent SHT_SYMTAB_SHNDX section"),
+ ibfd, (unsigned long) symoffset);
+ free (alloc_intsym);
+ intsym_buf = NULL;
+ goto out;
+ }
+
+ out:
+ free (alloc_ext);
+ free (alloc_extshndx);
+
+ return intsym_buf;
+}
+
+/* Look up a symbol name. */
+const char *
+bfd_elf_sym_name (bfd *abfd,
+ Elf_Internal_Shdr *symtab_hdr,
+ Elf_Internal_Sym *isym,
+ asection *sym_sec)
+{
+ const char *name;
+ unsigned int iname = isym->st_name;
+ unsigned int shindex = symtab_hdr->sh_link;
+
+ if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION
+ /* Check for a bogus st_shndx to avoid crashing. */
+ && isym->st_shndx < elf_numsections (abfd))
+ {
+ iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name;
+ shindex = elf_elfheader (abfd)->e_shstrndx;
+ }
+
+ name = bfd_elf_string_from_elf_section (abfd, shindex, iname);
+ if (name == NULL)
+ name = "(null)";
+ else if (sym_sec && *name == '\0')
+ name = bfd_section_name (sym_sec);
+
+ return name;
+}
+
+/* Elf_Internal_Shdr->contents is an array of these for SHT_GROUP
+ sections. The first element is the flags, the rest are section
+ pointers. */
+
+typedef union elf_internal_group {
+ Elf_Internal_Shdr *shdr;
+ unsigned int flags;
+} Elf_Internal_Group;
+
+/* Return the name of the group signature symbol. Why isn't the
+ signature just a string? */
+
+static const char *
+group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr)
+{
+ Elf_Internal_Shdr *hdr;
+ unsigned char esym[sizeof (Elf64_External_Sym)];
+ Elf_External_Sym_Shndx eshndx;
+ Elf_Internal_Sym isym;
+
+ /* First we need to ensure the symbol table is available. Make sure
+ that it is a symbol table section. */
+ if (ghdr->sh_link >= elf_numsections (abfd))
+ return NULL;
+ hdr = elf_elfsections (abfd) [ghdr->sh_link];
+ if (hdr->sh_type != SHT_SYMTAB
+ || ! bfd_section_from_shdr (abfd, ghdr->sh_link))
+ return NULL;
+
+ /* Go read the symbol. */
+ hdr = &elf_tdata (abfd)->symtab_hdr;
+ if (bfd_elf_get_elf_syms (abfd, hdr, 1, ghdr->sh_info,
+ &isym, esym, &eshndx) == NULL)
+ return NULL;
+
+ return bfd_elf_sym_name (abfd, hdr, &isym, NULL);
+}
+
+/* Set next_in_group list pointer, and group name for NEWSECT. */
+
+static bool
+setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
+{
+ unsigned int num_group = elf_tdata (abfd)->num_group;
+
+ /* If num_group is zero, read in all SHT_GROUP sections. The count
+ is set to -1 if there are no SHT_GROUP sections. */
+ if (num_group == 0)
+ {
+ unsigned int i, shnum;
+
+ /* First count the number of groups. If we have a SHT_GROUP
+ section with just a flag word (ie. sh_size is 4), ignore it. */
+ shnum = elf_numsections (abfd);
+ num_group = 0;
+
+#define IS_VALID_GROUP_SECTION_HEADER(shdr, minsize) \
+ ( (shdr)->sh_type == SHT_GROUP \
+ && (shdr)->sh_size >= minsize \
+ && (shdr)->sh_entsize == GRP_ENTRY_SIZE \
+ && ((shdr)->sh_size % GRP_ENTRY_SIZE) == 0)
+
+ for (i = 0; i < shnum; i++)
+ {
+ Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
+
+ if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE))
+ num_group += 1;
+ }
+
+ if (num_group == 0)
+ {
+ num_group = (unsigned) -1;
+ elf_tdata (abfd)->num_group = num_group;
+ elf_tdata (abfd)->group_sect_ptr = NULL;
+ }
+ else
+ {
+ /* We keep a list of elf section headers for group sections,
+ so we can find them quickly. */
+ size_t amt;
+
+ elf_tdata (abfd)->num_group = num_group;
+ amt = num_group * sizeof (Elf_Internal_Shdr *);
+ elf_tdata (abfd)->group_sect_ptr
+ = (Elf_Internal_Shdr **) bfd_zalloc (abfd, amt);
+ if (elf_tdata (abfd)->group_sect_ptr == NULL)
+ return false;
+ num_group = 0;
+
+ for (i = 0; i < shnum; i++)
+ {
+ Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
+
+ if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE))
+ {
+ unsigned char *src;
+ Elf_Internal_Group *dest;
+
+ /* Make sure the group section has a BFD section
+ attached to it. */
+ if (!bfd_section_from_shdr (abfd, i))
+ return false;
+
+ /* Add to list of sections. */
+ elf_tdata (abfd)->group_sect_ptr[num_group] = shdr;
+ num_group += 1;
+
+ /* Read the raw contents. */
+ BFD_ASSERT (sizeof (*dest) >= 4 && sizeof (*dest) % 4 == 0);
+ shdr->contents = NULL;
+ if (_bfd_mul_overflow (shdr->sh_size,
+ sizeof (*dest) / 4, &amt)
+ || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0
+ || !(shdr->contents
+ = _bfd_alloc_and_read (abfd, amt, shdr->sh_size)))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: invalid size field in group section"
+ " header: %#" PRIx64 ""),
+ abfd, (uint64_t) shdr->sh_size);
+ bfd_set_error (bfd_error_bad_value);
+ -- num_group;
+ continue;
+ }
+
+ /* Translate raw contents, a flag word followed by an
+ array of elf section indices all in target byte order,
+ to the flag word followed by an array of elf section
+ pointers. */
+ src = shdr->contents + shdr->sh_size;
+ dest = (Elf_Internal_Group *) (shdr->contents + amt);
+
+ while (1)
+ {
+ unsigned int idx;
+
+ src -= 4;
+ --dest;
+ idx = H_GET_32 (abfd, src);
+ if (src == shdr->contents)
+ {
+ dest->shdr = NULL;
+ dest->flags = idx;
+ if (shdr->bfd_section != NULL && (idx & GRP_COMDAT))
+ shdr->bfd_section->flags
+ |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+ break;
+ }
+ if (idx < shnum)
+ {
+ dest->shdr = elf_elfsections (abfd)[idx];
+ /* PR binutils/23199: All sections in a
+ section group should be marked with
+ SHF_GROUP. But some tools generate
+ broken objects without SHF_GROUP. Fix
+ them up here. */
+ dest->shdr->sh_flags |= SHF_GROUP;
+ }
+ if (idx >= shnum
+ || dest->shdr->sh_type == SHT_GROUP)
+ {
+ _bfd_error_handler
+ (_("%pB: invalid entry in SHT_GROUP section [%u]"),
+ abfd, i);
+ dest->shdr = NULL;
+ }
+ }
+ }
+ }
+
+ /* PR 17510: Corrupt binaries might contain invalid groups. */
+ if (num_group != (unsigned) elf_tdata (abfd)->num_group)
+ {
+ elf_tdata (abfd)->num_group = num_group;
+
+ /* If all groups are invalid then fail. */
+ if (num_group == 0)
+ {
+ elf_tdata (abfd)->group_sect_ptr = NULL;
+ elf_tdata (abfd)->num_group = num_group = -1;
+ _bfd_error_handler
+ (_("%pB: no valid group sections found"), abfd);
+ bfd_set_error (bfd_error_bad_value);
+ }
+ }
+ }
+ }
+
+ if (num_group != (unsigned) -1)
+ {
+ unsigned int search_offset = elf_tdata (abfd)->group_search_offset;
+ unsigned int j;
+
+ for (j = 0; j < num_group; j++)
+ {
+ /* Begin search from previous found group. */
+ unsigned i = (j + search_offset) % num_group;
+
+ Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
+ Elf_Internal_Group *idx;
+ bfd_size_type n_elt;
+
+ if (shdr == NULL)
+ continue;
+
+ idx = (Elf_Internal_Group *) shdr->contents;
+ if (idx == NULL || shdr->sh_size < 4)
+ {
+ /* See PR 21957 for a reproducer. */
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: group section '%pA' has no contents"),
+ abfd, shdr->bfd_section);
+ elf_tdata (abfd)->group_sect_ptr[i] = NULL;
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ n_elt = shdr->sh_size / 4;
+
+ /* Look through this group's sections to see if current
+ section is a member. */
+ while (--n_elt != 0)
+ if ((++idx)->shdr == hdr)
+ {
+ asection *s = NULL;
+
+ /* We are a member of this group. Go looking through
+ other members to see if any others are linked via
+ next_in_group. */
+ idx = (Elf_Internal_Group *) shdr->contents;
+ n_elt = shdr->sh_size / 4;
+ while (--n_elt != 0)
+ if ((++idx)->shdr != NULL
+ && (s = idx->shdr->bfd_section) != NULL
+ && elf_next_in_group (s) != NULL)
+ break;
+ if (n_elt != 0)
+ {
+ /* Snarf the group name from other member, and
+ insert current section in circular list. */
+ elf_group_name (newsect) = elf_group_name (s);
+ elf_next_in_group (newsect) = elf_next_in_group (s);
+ elf_next_in_group (s) = newsect;
+ }
+ else
+ {
+ const char *gname;
+
+ gname = group_signature (abfd, shdr);
+ if (gname == NULL)
+ return false;
+ elf_group_name (newsect) = gname;
+
+ /* Start a circular list with one element. */
+ elf_next_in_group (newsect) = newsect;
+ }
+
+ /* If the group section has been created, point to the
+ new member. */
+ if (shdr->bfd_section != NULL)
+ elf_next_in_group (shdr->bfd_section) = newsect;
+
+ elf_tdata (abfd)->group_search_offset = i;
+ j = num_group - 1;
+ break;
+ }
+ }
+ }
+
+ if (elf_group_name (newsect) == NULL)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: no group info for section '%pA'"),
+ abfd, newsect);
+ /* PR 29532: Return true here, even though the group info has not been
+ read. Separate debug info files can have empty group sections, but
+ we do not want this to prevent them from being loaded as otherwise
+ GDB will not be able to use them. */
+ return true;
+ }
+ return true;
+}
+
+bool
+_bfd_elf_setup_sections (bfd *abfd)
+{
+ unsigned int i;
+ unsigned int num_group = elf_tdata (abfd)->num_group;
+ bool result = true;
+ asection *s;
+
+ /* Process SHF_LINK_ORDER. */
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ Elf_Internal_Shdr *this_hdr = &elf_section_data (s)->this_hdr;
+ if ((this_hdr->sh_flags & SHF_LINK_ORDER) != 0)
+ {
+ unsigned int elfsec = this_hdr->sh_link;
+ /* An sh_link value of 0 is now allowed. It indicates that linked
+ to section has already been discarded, but that the current
+ section has been retained for some other reason. This linking
+ section is still a candidate for later garbage collection
+ however. */
+ if (elfsec == 0)
+ {
+ elf_linked_to_section (s) = NULL;
+ }
+ else
+ {
+ asection *linksec = NULL;
+
+ if (elfsec < elf_numsections (abfd))
+ {
+ this_hdr = elf_elfsections (abfd)[elfsec];
+ linksec = this_hdr->bfd_section;
+ }
+
+ /* PR 1991, 2008:
+ Some strip/objcopy may leave an incorrect value in
+ sh_link. We don't want to proceed. */
+ if (linksec == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: sh_link [%d] in section `%pA' is incorrect"),
+ s->owner, elfsec, s);
+ result = false;
+ }
+
+ elf_linked_to_section (s) = linksec;
+ }
+ }
+ else if (this_hdr->sh_type == SHT_GROUP
+ && elf_next_in_group (s) == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: SHT_GROUP section [index %d] has no SHF_GROUP sections"),
+ abfd, elf_section_data (s)->this_idx);
+ result = false;
+ }
+ }
+
+ /* Process section groups. */
+ if (num_group == (unsigned) -1)
+ return result;
+
+ for (i = 0; i < num_group; i++)
+ {
+ Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
+ Elf_Internal_Group *idx;
+ unsigned int n_elt;
+
+ /* PR binutils/18758: Beware of corrupt binaries with invalid
+ group data. */
+ if (shdr == NULL || shdr->bfd_section == NULL || shdr->contents == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: section group entry number %u is corrupt"),
+ abfd, i);
+ result = false;
+ continue;
+ }
+
+ idx = (Elf_Internal_Group *) shdr->contents;
+ n_elt = shdr->sh_size / 4;
+
+ while (--n_elt != 0)
+ {
+ ++ idx;
+
+ if (idx->shdr == NULL)
+ continue;
+ else if (idx->shdr->bfd_section)
+ elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section;
+ else if (idx->shdr->sh_type != SHT_RELA
+ && idx->shdr->sh_type != SHT_REL)
+ {
+ /* There are some unknown sections in the group. */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: unknown type [%#x] section `%s' in group [%pA]"),
+ abfd,
+ idx->shdr->sh_type,
+ bfd_elf_string_from_elf_section (abfd,
+ (elf_elfheader (abfd)
+ ->e_shstrndx),
+ idx->shdr->sh_name),
+ shdr->bfd_section);
+ result = false;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec)
+{
+ return elf_next_in_group (sec) != NULL;
+}
+
+const char *
+bfd_elf_group_name (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec)
+{
+ if (elf_sec_group (sec) != NULL)
+ return elf_group_name (sec);
+ return NULL;
+}
+
+/* This a copy of lto_section defined in GCC (lto-streamer.h). */
+
+struct lto_section
+{
+ int16_t major_version;
+ int16_t minor_version;
+ unsigned char slim_object;
+
+ /* Flags is a private field that is not defined publicly. */
+ uint16_t flags;
+};
+
+/* Make a BFD section from an ELF section. We store a pointer to the
+ BFD section in the bfd_section field of the header. */
+
+bool
+_bfd_elf_make_section_from_shdr (bfd *abfd,
+ Elf_Internal_Shdr *hdr,
+ const char *name,
+ int shindex)
+{
+ asection *newsect;
+ flagword flags;
+ const struct elf_backend_data *bed;
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
+
+ if (hdr->bfd_section != NULL)
+ return true;
+
+ newsect = bfd_make_section_anyway (abfd, name);
+ if (newsect == NULL)
+ return false;
+
+ hdr->bfd_section = newsect;
+ elf_section_data (newsect)->this_hdr = *hdr;
+ elf_section_data (newsect)->this_idx = shindex;
+
+ /* Always use the real type/flags. */
+ elf_section_type (newsect) = hdr->sh_type;
+ elf_section_flags (newsect) = hdr->sh_flags;
+
+ newsect->filepos = hdr->sh_offset;
+
+ flags = SEC_NO_FLAGS;
+ if (hdr->sh_type != SHT_NOBITS)
+ flags |= SEC_HAS_CONTENTS;
+ if (hdr->sh_type == SHT_GROUP)
+ flags |= SEC_GROUP;
+ if ((hdr->sh_flags & SHF_ALLOC) != 0)
+ {
+ flags |= SEC_ALLOC;
+ if (hdr->sh_type != SHT_NOBITS)
+ flags |= SEC_LOAD;
+ }
+ if ((hdr->sh_flags & SHF_WRITE) == 0)
+ flags |= SEC_READONLY;
+ if ((hdr->sh_flags & SHF_EXECINSTR) != 0)
+ flags |= SEC_CODE;
+ else if ((flags & SEC_LOAD) != 0)
+ flags |= SEC_DATA;
+ if ((hdr->sh_flags & SHF_MERGE) != 0)
+ {
+ flags |= SEC_MERGE;
+ newsect->entsize = hdr->sh_entsize;
+ }
+ if ((hdr->sh_flags & SHF_STRINGS) != 0)
+ flags |= SEC_STRINGS;
+ if (hdr->sh_flags & SHF_GROUP)
+ if (!setup_group (abfd, hdr, newsect))
+ return false;
+ if ((hdr->sh_flags & SHF_TLS) != 0)
+ flags |= SEC_THREAD_LOCAL;
+ if ((hdr->sh_flags & SHF_EXCLUDE) != 0)
+ flags |= SEC_EXCLUDE;
+
+ switch (elf_elfheader (abfd)->e_ident[EI_OSABI])
+ {
+ /* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE,
+ but binutils as of 2019-07-23 did not set the EI_OSABI header
+ byte. */
+ case ELFOSABI_GNU:
+ case ELFOSABI_FREEBSD:
+ if ((hdr->sh_flags & SHF_GNU_RETAIN) != 0)
+ elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_retain;
+ /* Fall through */
+ case ELFOSABI_NONE:
+ if ((hdr->sh_flags & SHF_GNU_MBIND) != 0)
+ elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+ break;
+ }
+
+ if ((flags & SEC_ALLOC) == 0)
+ {
+ /* The debugging sections appear to be recognized only by name,
+ not any sort of flag. Their SEC_ALLOC bits are cleared. */
+ if (name [0] == '.')
+ {
+ if (startswith (name, ".debug")
+ || startswith (name, ".gnu.debuglto_.debug_")
+ || startswith (name, ".gnu.linkonce.wi.")
+ || startswith (name, ".zdebug"))
+ flags |= SEC_DEBUGGING | SEC_ELF_OCTETS;
+ else if (startswith (name, GNU_BUILD_ATTRS_SECTION_NAME)
+ || startswith (name, ".note.gnu"))
+ {
+ flags |= SEC_ELF_OCTETS;
+ opb = 1;
+ }
+ else if (startswith (name, ".line")
+ || startswith (name, ".stab")
+ || strcmp (name, ".gdb_index") == 0)
+ flags |= SEC_DEBUGGING;
+ }
+ }
+
+ if (!bfd_set_section_vma (newsect, hdr->sh_addr / opb)
+ || !bfd_set_section_size (newsect, hdr->sh_size)
+ || !bfd_set_section_alignment (newsect, bfd_log2 (hdr->sh_addralign
+ & -hdr->sh_addralign)))
+ return false;
+
+ /* As a GNU extension, if the name begins with .gnu.linkonce, we
+ only link a single copy of the section. This is used to support
+ g++. g++ will emit each template expansion in its own section.
+ The symbols will be defined as weak, so that multiple definitions
+ are permitted. The GNU linker extension is to actually discard
+ all but one of the sections. */
+ if (startswith (name, ".gnu.linkonce")
+ && elf_next_in_group (newsect) == NULL)
+ flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+
+ if (!bfd_set_section_flags (newsect, flags))
+ return false;
+
+ bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_section_flags)
+ if (!bed->elf_backend_section_flags (hdr))
+ return false;
+
+ /* We do not parse the PT_NOTE segments as we are interested even in the
+ separate debug info files which may have the segments offsets corrupted.
+ PT_NOTEs from the core files are currently not parsed using BFD. */
+ if (hdr->sh_type == SHT_NOTE && hdr->sh_size != 0)
+ {
+ bfd_byte *contents;
+
+ if (!bfd_malloc_and_get_section (abfd, newsect, &contents))
+ return false;
+
+ elf_parse_notes (abfd, (char *) contents, hdr->sh_size,
+ hdr->sh_offset, hdr->sh_addralign);
+ free (contents);
+ }
+
+ if ((newsect->flags & SEC_ALLOC) != 0)
+ {
+ Elf_Internal_Phdr *phdr;
+ unsigned int i, nload;
+
+ /* Some ELF linkers produce binaries with all the program header
+ p_paddr fields zero. If we have such a binary with more than
+ one PT_LOAD header, then leave the section lma equal to vma
+ so that we don't create sections with overlapping lma. */
+ phdr = elf_tdata (abfd)->phdr;
+ for (nload = 0, i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
+ if (phdr->p_paddr != 0)
+ break;
+ else if (phdr->p_type == PT_LOAD && phdr->p_memsz != 0)
+ ++nload;
+ if (i >= elf_elfheader (abfd)->e_phnum && nload > 1)
+ return true;
+
+ phdr = elf_tdata (abfd)->phdr;
+ for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
+ {
+ if (((phdr->p_type == PT_LOAD
+ && (hdr->sh_flags & SHF_TLS) == 0)
+ || phdr->p_type == PT_TLS)
+ && ELF_SECTION_IN_SEGMENT (hdr, phdr))
+ {
+ if ((newsect->flags & SEC_LOAD) == 0)
+ newsect->lma = (phdr->p_paddr
+ + hdr->sh_addr - phdr->p_vaddr) / opb;
+ else
+ /* We used to use the same adjustment for SEC_LOAD
+ sections, but that doesn't work if the segment
+ is packed with code from multiple VMAs.
+ Instead we calculate the section LMA based on
+ the segment LMA. It is assumed that the
+ segment will contain sections with contiguous
+ LMAs, even if the VMAs are not. */
+ newsect->lma = (phdr->p_paddr
+ + hdr->sh_offset - phdr->p_offset) / opb;
+
+ /* With contiguous segments, we can't tell from file
+ offsets whether a section with zero size should
+ be placed at the end of one segment or the
+ beginning of the next. Decide based on vaddr. */
+ if (hdr->sh_addr >= phdr->p_vaddr
+ && (hdr->sh_addr + hdr->sh_size
+ <= phdr->p_vaddr + phdr->p_memsz))
+ break;
+ }
+ }
+ }
+
+ /* Compress/decompress DWARF debug sections with names: .debug_*,
+ .zdebug_*, .gnu.debuglto_.debug_, after the section flags is set. */
+ if ((newsect->flags & SEC_DEBUGGING) != 0
+ && (newsect->flags & SEC_HAS_CONTENTS) != 0
+ && (newsect->flags & SEC_ELF_OCTETS) != 0)
+ {
+ enum { nothing, compress, decompress } action = nothing;
+ int compression_header_size;
+ bfd_size_type uncompressed_size;
+ unsigned int uncompressed_align_power;
+ enum compression_type ch_type = ch_none;
+ bool compressed
+ = bfd_is_section_compressed_info (abfd, newsect,
+ &compression_header_size,
+ &uncompressed_size,
+ &uncompressed_align_power,
+ &ch_type);
+
+ /* Should we decompress? */
+ if ((abfd->flags & BFD_DECOMPRESS) != 0 && compressed)
+ action = decompress;
+
+ /* Should we compress? Or convert to a different compression? */
+ else if ((abfd->flags & BFD_COMPRESS) != 0
+ && newsect->size != 0
+ && compression_header_size >= 0
+ && uncompressed_size > 0)
+ {
+ if (!compressed)
+ action = compress;
+ else
+ {
+ enum compression_type new_ch_type = ch_none;
+ if ((abfd->flags & BFD_COMPRESS_GABI) != 0)
+ new_ch_type = ((abfd->flags & BFD_COMPRESS_ZSTD) != 0
+ ? ch_compress_zstd : ch_compress_zlib);
+ if (new_ch_type != ch_type)
+ action = compress;
+ }
+ }
+
+ if (action == compress)
+ {
+ if (!bfd_init_section_compress_status (abfd, newsect))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: unable to compress section %s"), abfd, name);
+ return false;
+ }
+ }
+ else if (action == decompress)
+ {
+ if (!bfd_init_section_decompress_status (abfd, newsect))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: unable to decompress section %s"), abfd, name);
+ return false;
+ }
+#ifndef HAVE_ZSTD
+ if (newsect->compress_status == DECOMPRESS_SECTION_ZSTD)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_ ("%pB: section %s is compressed with zstd, but BFD "
+ "is not built with zstd support"),
+ abfd, name);
+ newsect->compress_status = COMPRESS_SECTION_NONE;
+ return false;
+ }
+#endif
+ if (abfd->is_linker_input
+ && name[1] == 'z')
+ {
+ /* Rename section from .zdebug_* to .debug_* so that ld
+ scripts will see this section as a debug section. */
+ char *new_name = bfd_zdebug_name_to_debug (abfd, name);
+ if (new_name == NULL)
+ return false;
+ bfd_rename_section (newsect, new_name);
+ }
+ }
+ }
+
+ /* GCC uses .gnu.lto_.lto.<some_hash> as a LTO bytecode information
+ section. */
+ if (startswith (name, ".gnu.lto_.lto."))
+ {
+ struct lto_section lsection;
+ if (bfd_get_section_contents (abfd, newsect, &lsection, 0,
+ sizeof (struct lto_section)))
+ abfd->lto_slim_object = lsection.slim_object;
+ }
+
+ return true;
+}
+
+const char *const bfd_elf_section_type_names[] =
+{
+ "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
+ "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE",
+ "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM",
+};
+
+/* ELF relocs are against symbols. If we are producing relocatable
+ output, and the reloc is against an external symbol, and nothing
+ has given us any additional addend, the resulting reloc will also
+ be against the same symbol. In such a case, we don't want to
+ change anything about the way the reloc is handled, since it will
+ all be done at final link time. Rather than put special case code
+ into bfd_perform_relocation, all the reloc types use this howto
+ function, or should call this function for relocatable output. */
+
+bfd_reloc_status_type
+bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *reloc_entry,
+ asymbol *symbol,
+ void *data ATTRIBUTE_UNUSED,
+ asection *input_section,
+ bfd *output_bfd,
+ char **error_message ATTRIBUTE_UNUSED)
+{
+ if (output_bfd != NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && (! reloc_entry->howto->partial_inplace
+ || reloc_entry->addend == 0))
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ /* In some cases the relocation should be treated as output section
+ relative, as when linking ELF DWARF into PE COFF. Many ELF
+ targets lack section relative relocations and instead use
+ ordinary absolute relocations for references between DWARF
+ sections. That is arguably a bug in those targets but it happens
+ to work for the usual case of linking to non-loaded ELF debug
+ sections with VMAs forced to zero. PE COFF on the other hand
+ doesn't allow a section VMA of zero. */
+ if (output_bfd == NULL
+ && !reloc_entry->howto->pc_relative
+ && (symbol->section->flags & SEC_DEBUGGING) != 0
+ && (input_section->flags & SEC_DEBUGGING) != 0)
+ reloc_entry->addend -= symbol->section->output_section->vma;
+
+ return bfd_reloc_continue;
+}
+
+/* Returns TRUE if section A matches section B.
+ Names, addresses and links may be different, but everything else
+ should be the same. */
+
+static bool
+section_match (const Elf_Internal_Shdr * a,
+ const Elf_Internal_Shdr * b)
+{
+ if (a->sh_type != b->sh_type
+ || ((a->sh_flags ^ b->sh_flags) & ~SHF_INFO_LINK) != 0
+ || a->sh_addralign != b->sh_addralign
+ || a->sh_entsize != b->sh_entsize)
+ return false;
+ if (a->sh_type == SHT_SYMTAB
+ || a->sh_type == SHT_STRTAB)
+ return true;
+ return a->sh_size == b->sh_size;
+}
+
+/* Find a section in OBFD that has the same characteristics
+ as IHEADER. Return the index of this section or SHN_UNDEF if
+ none can be found. Check's section HINT first, as this is likely
+ to be the correct section. */
+
+static unsigned int
+find_link (const bfd *obfd, const Elf_Internal_Shdr *iheader,
+ const unsigned int hint)
+{
+ Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd);
+ unsigned int i;
+
+ BFD_ASSERT (iheader != NULL);
+
+ /* See PR 20922 for a reproducer of the NULL test. */
+ if (hint < elf_numsections (obfd)
+ && oheaders[hint] != NULL
+ && section_match (oheaders[hint], iheader))
+ return hint;
+
+ for (i = 1; i < elf_numsections (obfd); i++)
+ {
+ Elf_Internal_Shdr * oheader = oheaders[i];
+
+ if (oheader == NULL)
+ continue;
+ if (section_match (oheader, iheader))
+ /* FIXME: Do we care if there is a potential for
+ multiple matches ? */
+ return i;
+ }
+
+ return SHN_UNDEF;
+}
+
+/* PR 19938: Attempt to set the ELF section header fields of an OS or
+ Processor specific section, based upon a matching input section.
+ Returns TRUE upon success, FALSE otherwise. */
+
+static bool
+copy_special_section_fields (const bfd *ibfd,
+ bfd *obfd,
+ const Elf_Internal_Shdr *iheader,
+ Elf_Internal_Shdr *oheader,
+ const unsigned int secnum)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+ const Elf_Internal_Shdr **iheaders
+ = (const Elf_Internal_Shdr **) elf_elfsections (ibfd);
+ bool changed = false;
+ unsigned int sh_link;
+
+ if (oheader->sh_type == SHT_NOBITS)
+ {
+ /* This is a feature for objcopy --only-keep-debug:
+ When a section's type is changed to NOBITS, we preserve
+ the sh_link and sh_info fields so that they can be
+ matched up with the original.
+
+ Note: Strictly speaking these assignments are wrong.
+ The sh_link and sh_info fields should point to the
+ relevent sections in the output BFD, which may not be in
+ the same location as they were in the input BFD. But
+ the whole point of this action is to preserve the
+ original values of the sh_link and sh_info fields, so
+ that they can be matched up with the section headers in
+ the original file. So strictly speaking we may be
+ creating an invalid ELF file, but it is only for a file
+ that just contains debug info and only for sections
+ without any contents. */
+ if (oheader->sh_link == 0)
+ oheader->sh_link = iheader->sh_link;
+ if (oheader->sh_info == 0)
+ oheader->sh_info = iheader->sh_info;
+ return true;
+ }
+
+ /* Allow the target a chance to decide how these fields should be set. */
+ if (bed->elf_backend_copy_special_section_fields (ibfd, obfd,
+ iheader, oheader))
+ return true;
+
+ /* We have an iheader which might match oheader, and which has non-zero
+ sh_info and/or sh_link fields. Attempt to follow those links and find
+ the section in the output bfd which corresponds to the linked section
+ in the input bfd. */
+ if (iheader->sh_link != SHN_UNDEF)
+ {
+ /* See PR 20931 for a reproducer. */
+ if (iheader->sh_link >= elf_numsections (ibfd))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: invalid sh_link field (%d) in section number %d"),
+ ibfd, iheader->sh_link, secnum);
+ return false;
+ }
+
+ sh_link = find_link (obfd, iheaders[iheader->sh_link], iheader->sh_link);
+ if (sh_link != SHN_UNDEF)
+ {
+ oheader->sh_link = sh_link;
+ changed = true;
+ }
+ else
+ /* FIXME: Should we install iheader->sh_link
+ if we could not find a match ? */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: failed to find link section for section %d"), obfd, secnum);
+ }
+
+ if (iheader->sh_info)
+ {
+ /* The sh_info field can hold arbitrary information, but if the
+ SHF_LINK_INFO flag is set then it should be interpreted as a
+ section index. */
+ if (iheader->sh_flags & SHF_INFO_LINK)
+ {
+ sh_link = find_link (obfd, iheaders[iheader->sh_info],
+ iheader->sh_info);
+ if (sh_link != SHN_UNDEF)
+ oheader->sh_flags |= SHF_INFO_LINK;
+ }
+ else
+ /* No idea what it means - just copy it. */
+ sh_link = iheader->sh_info;
+
+ if (sh_link != SHN_UNDEF)
+ {
+ oheader->sh_info = sh_link;
+ changed = true;
+ }
+ else
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: failed to find info section for section %d"), obfd, secnum);
+ }
+
+ return changed;
+}
+
+/* Copy the program header and other data from one object module to
+ another. */
+
+bool
+_bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+ const Elf_Internal_Shdr **iheaders
+ = (const Elf_Internal_Shdr **) elf_elfsections (ibfd);
+ Elf_Internal_Shdr **oheaders = elf_elfsections (obfd);
+ const struct elf_backend_data *bed;
+ unsigned int i;
+
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return true;
+
+ if (!elf_flags_init (obfd))
+ {
+ elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
+ elf_flags_init (obfd) = true;
+ }
+
+ elf_gp (obfd) = elf_gp (ibfd);
+
+ /* Also copy the EI_OSABI field. */
+ elf_elfheader (obfd)->e_ident[EI_OSABI] =
+ elf_elfheader (ibfd)->e_ident[EI_OSABI];
+
+ /* If set, copy the EI_ABIVERSION field. */
+ if (elf_elfheader (ibfd)->e_ident[EI_ABIVERSION])
+ elf_elfheader (obfd)->e_ident[EI_ABIVERSION]
+ = elf_elfheader (ibfd)->e_ident[EI_ABIVERSION];
+
+ /* Copy object attributes. */
+ _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+ if (iheaders == NULL || oheaders == NULL)
+ return true;
+
+ bed = get_elf_backend_data (obfd);
+
+ /* Possibly copy other fields in the section header. */
+ for (i = 1; i < elf_numsections (obfd); i++)
+ {
+ unsigned int j;
+ Elf_Internal_Shdr * oheader = oheaders[i];
+
+ /* Ignore ordinary sections. SHT_NOBITS sections are considered however
+ because of a special case need for generating separate debug info
+ files. See below for more details. */
+ if (oheader == NULL
+ || (oheader->sh_type != SHT_NOBITS
+ && oheader->sh_type < SHT_LOOS))
+ continue;
+
+ /* Ignore empty sections, and sections whose
+ fields have already been initialised. */
+ if (oheader->sh_size == 0
+ || (oheader->sh_info != 0 && oheader->sh_link != 0))
+ continue;
+
+ /* Scan for the matching section in the input bfd.
+ First we try for a direct mapping between the input and
+ output sections. */
+ for (j = 1; j < elf_numsections (ibfd); j++)
+ {
+ const Elf_Internal_Shdr * iheader = iheaders[j];
+
+ if (iheader == NULL)
+ continue;
+
+ if (oheader->bfd_section != NULL
+ && iheader->bfd_section != NULL
+ && iheader->bfd_section->output_section != NULL
+ && iheader->bfd_section->output_section == oheader->bfd_section)
+ {
+ /* We have found a connection from the input section to
+ the output section. Attempt to copy the header fields.
+ If this fails then do not try any further sections -
+ there should only be a one-to-one mapping between
+ input and output. */
+ if (!copy_special_section_fields (ibfd, obfd,
+ iheader, oheader, i))
+ j = elf_numsections (ibfd);
+ break;
+ }
+ }
+
+ if (j < elf_numsections (ibfd))
+ continue;
+
+ /* That failed. So try to deduce the corresponding input section.
+ Unfortunately we cannot compare names as the output string table
+ is empty, so instead we check size, address and type. */
+ for (j = 1; j < elf_numsections (ibfd); j++)
+ {
+ const Elf_Internal_Shdr * iheader = iheaders[j];
+
+ if (iheader == NULL)
+ continue;
+
+ /* Try matching fields in the input section's header.
+ Since --only-keep-debug turns all non-debug sections into
+ SHT_NOBITS sections, the output SHT_NOBITS type matches any
+ input type. */
+ if ((oheader->sh_type == SHT_NOBITS
+ || iheader->sh_type == oheader->sh_type)
+ && (iheader->sh_flags & ~ SHF_INFO_LINK)
+ == (oheader->sh_flags & ~ SHF_INFO_LINK)
+ && iheader->sh_addralign == oheader->sh_addralign
+ && iheader->sh_entsize == oheader->sh_entsize
+ && iheader->sh_size == oheader->sh_size
+ && iheader->sh_addr == oheader->sh_addr
+ && (iheader->sh_info != oheader->sh_info
+ || iheader->sh_link != oheader->sh_link))
+ {
+ if (copy_special_section_fields (ibfd, obfd, iheader, oheader, i))
+ break;
+ }
+ }
+
+ if (j == elf_numsections (ibfd) && oheader->sh_type >= SHT_LOOS)
+ {
+ /* Final attempt. Call the backend copy function
+ with a NULL input section. */
+ (void) bed->elf_backend_copy_special_section_fields (ibfd, obfd,
+ NULL, oheader);
+ }
+ }
+
+ /* If the input BFD has the OSABI field set and the
+ output BFD does not, then copy the value. */
+ if (elf_elfheader (ibfd)->e_ident [EI_OSABI] != ELFOSABI_NONE
+ && elf_elfheader (obfd)->e_ident [EI_OSABI] == ELFOSABI_NONE)
+ elf_elfheader (obfd)->e_ident [EI_OSABI] =
+ elf_elfheader (ibfd)->e_ident [EI_OSABI];
+
+ return true;
+}
+
+static const char *
+get_segment_type (unsigned int p_type)
+{
+ const char *pt;
+ switch (p_type)
+ {
+ case PT_NULL: pt = "NULL"; break;
+ case PT_LOAD: pt = "LOAD"; break;
+ case PT_DYNAMIC: pt = "DYNAMIC"; break;
+ case PT_INTERP: pt = "INTERP"; break;
+ case PT_NOTE: pt = "NOTE"; break;
+ case PT_SHLIB: pt = "SHLIB"; break;
+ case PT_PHDR: pt = "PHDR"; break;
+ case PT_TLS: pt = "TLS"; break;
+ case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
+ case PT_GNU_STACK: pt = "STACK"; break;
+ case PT_GNU_RELRO: pt = "RELRO"; break;
+ case PT_GNU_SFRAME: pt = "SFRAME"; break;
+ default: pt = NULL; break;
+ }
+ return pt;
+}
+
+/* Print out the program headers. */
+
+bool
+_bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
+{
+ FILE *f = (FILE *) farg;
+ Elf_Internal_Phdr *p;
+ asection *s;
+ bfd_byte *dynbuf = NULL;
+
+ p = elf_tdata (abfd)->phdr;
+ if (p != NULL)
+ {
+ unsigned int i, c;
+
+ fprintf (f, _("\nProgram Header:\n"));
+ c = elf_elfheader (abfd)->e_phnum;
+ for (i = 0; i < c; i++, p++)
+ {
+ const char *pt = get_segment_type (p->p_type);
+ char buf[20];
+
+ if (pt == NULL)
+ {
+ sprintf (buf, "0x%lx", p->p_type);
+ pt = buf;
+ }
+ fprintf (f, "%8s off 0x", pt);
+ bfd_fprintf_vma (abfd, f, p->p_offset);
+ fprintf (f, " vaddr 0x");
+ bfd_fprintf_vma (abfd, f, p->p_vaddr);
+ fprintf (f, " paddr 0x");
+ bfd_fprintf_vma (abfd, f, p->p_paddr);
+ fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align));
+ fprintf (f, " filesz 0x");
+ bfd_fprintf_vma (abfd, f, p->p_filesz);
+ fprintf (f, " memsz 0x");
+ bfd_fprintf_vma (abfd, f, p->p_memsz);
+ fprintf (f, " flags %c%c%c",
+ (p->p_flags & PF_R) != 0 ? 'r' : '-',
+ (p->p_flags & PF_W) != 0 ? 'w' : '-',
+ (p->p_flags & PF_X) != 0 ? 'x' : '-');
+ if ((p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X)) != 0)
+ fprintf (f, " %lx", p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X));
+ fprintf (f, "\n");
+ }
+ }
+
+ s = bfd_get_section_by_name (abfd, ".dynamic");
+ if (s != NULL)
+ {
+ unsigned int elfsec;
+ unsigned long shlink;
+ bfd_byte *extdyn, *extdynend;
+ size_t extdynsize;
+ void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
+
+ fprintf (f, _("\nDynamic Section:\n"));
+
+ if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
+ goto error_return;
+
+ elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
+ if (elfsec == SHN_BAD)
+ goto error_return;
+ shlink = elf_elfsections (abfd)[elfsec]->sh_link;
+
+ extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
+ swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
+
+ for (extdyn = dynbuf, extdynend = dynbuf + s->size;
+ (size_t) (extdynend - extdyn) >= extdynsize;
+ extdyn += extdynsize)
+ {
+ Elf_Internal_Dyn dyn;
+ const char *name = "";
+ char ab[20];
+ bool stringp;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ (*swap_dyn_in) (abfd, extdyn, &dyn);
+
+ if (dyn.d_tag == DT_NULL)
+ break;
+
+ stringp = false;
+ switch (dyn.d_tag)
+ {
+ default:
+ if (bed->elf_backend_get_target_dtag)
+ name = (*bed->elf_backend_get_target_dtag) (dyn.d_tag);
+
+ if (!strcmp (name, ""))
+ {
+ sprintf (ab, "%#" PRIx64, (uint64_t) dyn.d_tag);
+ name = ab;
+ }
+ break;
+
+ case DT_NEEDED: name = "NEEDED"; stringp = true; break;
+ case DT_PLTRELSZ: name = "PLTRELSZ"; break;
+ case DT_PLTGOT: name = "PLTGOT"; break;
+ case DT_HASH: name = "HASH"; break;
+ case DT_STRTAB: name = "STRTAB"; break;
+ case DT_SYMTAB: name = "SYMTAB"; break;
+ case DT_RELA: name = "RELA"; break;
+ case DT_RELASZ: name = "RELASZ"; break;
+ case DT_RELAENT: name = "RELAENT"; break;
+ case DT_STRSZ: name = "STRSZ"; break;
+ case DT_SYMENT: name = "SYMENT"; break;
+ case DT_INIT: name = "INIT"; break;
+ case DT_FINI: name = "FINI"; break;
+ case DT_SONAME: name = "SONAME"; stringp = true; break;
+ case DT_RPATH: name = "RPATH"; stringp = true; break;
+ case DT_SYMBOLIC: name = "SYMBOLIC"; break;
+ case DT_REL: name = "REL"; break;
+ case DT_RELSZ: name = "RELSZ"; break;
+ case DT_RELENT: name = "RELENT"; break;
+ case DT_RELR: name = "RELR"; break;
+ case DT_RELRSZ: name = "RELRSZ"; break;
+ case DT_RELRENT: name = "RELRENT"; break;
+ case DT_PLTREL: name = "PLTREL"; break;
+ case DT_DEBUG: name = "DEBUG"; break;
+ case DT_TEXTREL: name = "TEXTREL"; break;
+ case DT_JMPREL: name = "JMPREL"; break;
+ case DT_BIND_NOW: name = "BIND_NOW"; break;
+ case DT_INIT_ARRAY: name = "INIT_ARRAY"; break;
+ case DT_FINI_ARRAY: name = "FINI_ARRAY"; break;
+ case DT_INIT_ARRAYSZ: name = "INIT_ARRAYSZ"; break;
+ case DT_FINI_ARRAYSZ: name = "FINI_ARRAYSZ"; break;
+ case DT_RUNPATH: name = "RUNPATH"; stringp = true; break;
+ case DT_FLAGS: name = "FLAGS"; break;
+ case DT_PREINIT_ARRAY: name = "PREINIT_ARRAY"; break;
+ case DT_PREINIT_ARRAYSZ: name = "PREINIT_ARRAYSZ"; break;
+ case DT_CHECKSUM: name = "CHECKSUM"; break;
+ case DT_PLTPADSZ: name = "PLTPADSZ"; break;
+ case DT_MOVEENT: name = "MOVEENT"; break;
+ case DT_MOVESZ: name = "MOVESZ"; break;
+ case DT_FEATURE: name = "FEATURE"; break;
+ case DT_POSFLAG_1: name = "POSFLAG_1"; break;
+ case DT_SYMINSZ: name = "SYMINSZ"; break;
+ case DT_SYMINENT: name = "SYMINENT"; break;
+ case DT_CONFIG: name = "CONFIG"; stringp = true; break;
+ case DT_DEPAUDIT: name = "DEPAUDIT"; stringp = true; break;
+ case DT_AUDIT: name = "AUDIT"; stringp = true; break;
+ case DT_PLTPAD: name = "PLTPAD"; break;
+ case DT_MOVETAB: name = "MOVETAB"; break;
+ case DT_SYMINFO: name = "SYMINFO"; break;
+ case DT_RELACOUNT: name = "RELACOUNT"; break;
+ case DT_RELCOUNT: name = "RELCOUNT"; break;
+ case DT_FLAGS_1: name = "FLAGS_1"; break;
+ case DT_VERSYM: name = "VERSYM"; break;
+ case DT_VERDEF: name = "VERDEF"; break;
+ case DT_VERDEFNUM: name = "VERDEFNUM"; break;
+ case DT_VERNEED: name = "VERNEED"; break;
+ case DT_VERNEEDNUM: name = "VERNEEDNUM"; break;
+ case DT_AUXILIARY: name = "AUXILIARY"; stringp = true; break;
+ case DT_USED: name = "USED"; break;
+ case DT_FILTER: name = "FILTER"; stringp = true; break;
+ case DT_GNU_HASH: name = "GNU_HASH"; break;
+ }
+
+ fprintf (f, " %-20s ", name);
+ if (! stringp)
+ {
+ fprintf (f, "0x");
+ bfd_fprintf_vma (abfd, f, dyn.d_un.d_val);
+ }
+ else
+ {
+ const char *string;
+ unsigned int tagv = dyn.d_un.d_val;
+
+ string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+ if (string == NULL)
+ goto error_return;
+ fprintf (f, "%s", string);
+ }
+ fprintf (f, "\n");
+ }
+
+ free (dynbuf);
+ dynbuf = NULL;
+ }
+
+ if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL)
+ || (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL))
+ {
+ if (! _bfd_elf_slurp_version_tables (abfd, false))
+ return false;
+ }
+
+ if (elf_dynverdef (abfd) != 0)
+ {
+ Elf_Internal_Verdef *t;
+
+ fprintf (f, _("\nVersion definitions:\n"));
+ for (t = elf_tdata (abfd)->verdef; t != NULL; t = t->vd_nextdef)
+ {
+ fprintf (f, "%d 0x%2.2x 0x%8.8lx %s\n", t->vd_ndx,
+ t->vd_flags, t->vd_hash,
+ t->vd_nodename ? t->vd_nodename : "<corrupt>");
+ if (t->vd_auxptr != NULL && t->vd_auxptr->vda_nextptr != NULL)
+ {
+ Elf_Internal_Verdaux *a;
+
+ fprintf (f, "\t");
+ for (a = t->vd_auxptr->vda_nextptr;
+ a != NULL;
+ a = a->vda_nextptr)
+ fprintf (f, "%s ",
+ a->vda_nodename ? a->vda_nodename : "<corrupt>");
+ fprintf (f, "\n");
+ }
+ }
+ }
+
+ if (elf_dynverref (abfd) != 0)
+ {
+ Elf_Internal_Verneed *t;
+
+ fprintf (f, _("\nVersion References:\n"));
+ for (t = elf_tdata (abfd)->verref; t != NULL; t = t->vn_nextref)
+ {
+ Elf_Internal_Vernaux *a;
+
+ fprintf (f, _(" required from %s:\n"),
+ t->vn_filename ? t->vn_filename : "<corrupt>");
+ for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ fprintf (f, " 0x%8.8lx 0x%2.2x %2.2d %s\n", a->vna_hash,
+ a->vna_flags, a->vna_other,
+ a->vna_nodename ? a->vna_nodename : "<corrupt>");
+ }
+ }
+
+ return true;
+
+ error_return:
+ free (dynbuf);
+ return false;
+}
+
+/* Get version name. If BASE_P is TRUE, return "Base" for VER_FLG_BASE
+ and return symbol version for symbol version itself. */
+
+const char *
+_bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol,
+ bool base_p,
+ bool *hidden)
+{
+ const char *version_string = NULL;
+ if (elf_dynversym (abfd) != 0
+ && (elf_dynverdef (abfd) != 0 || elf_dynverref (abfd) != 0))
+ {
+ unsigned int vernum = ((elf_symbol_type *) symbol)->version;
+
+ *hidden = (vernum & VERSYM_HIDDEN) != 0;
+ vernum &= VERSYM_VERSION;
+
+ if (vernum == 0)
+ version_string = "";
+ else if (vernum == 1
+ && (vernum > elf_tdata (abfd)->cverdefs
+ || (elf_tdata (abfd)->verdef[0].vd_flags
+ == VER_FLG_BASE)))
+ version_string = base_p ? "Base" : "";
+ else if (vernum <= elf_tdata (abfd)->cverdefs)
+ {
+ const char *nodename
+ = elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
+ version_string = "";
+ if (base_p
+ || nodename == NULL
+ || symbol->name == NULL
+ || strcmp (symbol->name, nodename) != 0)
+ version_string = nodename;
+ }
+ else
+ {
+ Elf_Internal_Verneed *t;
+
+ version_string = _("<corrupt>");
+ for (t = elf_tdata (abfd)->verref;
+ t != NULL;
+ t = t->vn_nextref)
+ {
+ Elf_Internal_Vernaux *a;
+
+ for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ {
+ if (a->vna_other == vernum)
+ {
+ *hidden = true;
+ version_string = a->vna_nodename;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return version_string;
+}
+
+/* Display ELF-specific fields of a symbol. */
+
+void
+bfd_elf_print_symbol (bfd *abfd,
+ void *filep,
+ asymbol *symbol,
+ bfd_print_symbol_type how)
+{
+ FILE *file = (FILE *) filep;
+ switch (how)
+ {
+ case bfd_print_symbol_name:
+ fprintf (file, "%s", symbol->name);
+ break;
+ case bfd_print_symbol_more:
+ fprintf (file, "elf ");
+ bfd_fprintf_vma (abfd, file, symbol->value);
+ fprintf (file, " %x", symbol->flags);
+ break;
+ case bfd_print_symbol_all:
+ {
+ const char *section_name;
+ const char *name = NULL;
+ const struct elf_backend_data *bed;
+ unsigned char st_other;
+ bfd_vma val;
+ const char *version_string;
+ bool hidden;
+
+ section_name = symbol->section ? symbol->section->name : "(*none*)";
+
+ bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_print_symbol_all)
+ name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol);
+
+ if (name == NULL)
+ {
+ name = symbol->name;
+ bfd_print_symbol_vandf (abfd, file, symbol);
+ }
+
+ fprintf (file, " %s\t", section_name);
+ /* Print the "other" value for a symbol. For common symbols,
+ we've already printed the size; now print the alignment.
+ For other symbols, we have no specified alignment, and
+ we've printed the address; now print the size. */
+ if (symbol->section && bfd_is_com_section (symbol->section))
+ val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value;
+ else
+ val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_size;
+ bfd_fprintf_vma (abfd, file, val);
+
+ /* If we have version information, print it. */
+ version_string = _bfd_elf_get_symbol_version_string (abfd,
+ symbol,
+ true,
+ &hidden);
+ if (version_string)
+ {
+ if (!hidden)
+ fprintf (file, " %-11s", version_string);
+ else
+ {
+ int i;
+
+ fprintf (file, " (%s)", version_string);
+ for (i = 10 - strlen (version_string); i > 0; --i)
+ putc (' ', file);
+ }
+ }
+
+ /* If the st_other field is not zero, print it. */
+ st_other = ((elf_symbol_type *) symbol)->internal_elf_sym.st_other;
+
+ switch (st_other)
+ {
+ case 0: break;
+ case STV_INTERNAL: fprintf (file, " .internal"); break;
+ case STV_HIDDEN: fprintf (file, " .hidden"); break;
+ case STV_PROTECTED: fprintf (file, " .protected"); break;
+ default:
+ /* Some other non-defined flags are also present, so print
+ everything hex. */
+ fprintf (file, " 0x%02x", (unsigned int) st_other);
+ }
+
+ fprintf (file, " %s", name);
+ }
+ break;
+ }
+}
+
+/* ELF .o/exec file reading */
+
+/* Create a new bfd section from an ELF section header. */
+
+bool
+bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
+{
+ Elf_Internal_Shdr *hdr;
+ Elf_Internal_Ehdr *ehdr;
+ const struct elf_backend_data *bed;
+ const char *name;
+ bool ret = true;
+
+ if (shindex >= elf_numsections (abfd))
+ return false;
+
+ /* PR17512: A corrupt ELF binary might contain a loop of sections via
+ sh_link or sh_info. Detect this here, by refusing to load a
+ section that we are already in the process of loading. */
+ if (elf_tdata (abfd)->being_created[shindex])
+ {
+ _bfd_error_handler
+ (_("%pB: warning: loop in section dependencies detected"), abfd);
+ return false;
+ }
+ elf_tdata (abfd)->being_created[shindex] = true;
+
+ hdr = elf_elfsections (abfd)[shindex];
+ ehdr = elf_elfheader (abfd);
+ name = bfd_elf_string_from_elf_section (abfd, ehdr->e_shstrndx,
+ hdr->sh_name);
+ if (name == NULL)
+ goto fail;
+
+ bed = get_elf_backend_data (abfd);
+ switch (hdr->sh_type)
+ {
+ case SHT_NULL:
+ /* Inactive section. Throw it away. */
+ goto success;
+
+ case SHT_PROGBITS: /* Normal section with contents. */
+ case SHT_NOBITS: /* .bss section. */
+ case SHT_HASH: /* .hash section. */
+ case SHT_NOTE: /* .note section. */
+ case SHT_INIT_ARRAY: /* .init_array section. */
+ case SHT_FINI_ARRAY: /* .fini_array section. */
+ case SHT_PREINIT_ARRAY: /* .preinit_array section. */
+ case SHT_GNU_LIBLIST: /* .gnu.liblist section. */
+ case SHT_GNU_HASH: /* .gnu.hash section. */
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ goto success;
+
+ case SHT_DYNAMIC: /* Dynamic linking information. */
+ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+ goto fail;
+
+ if (hdr->sh_link > elf_numsections (abfd))
+ {
+ /* PR 10478: Accept Solaris binaries with a sh_link field
+ set to SHN_BEFORE (LORESERVE) or SHN_AFTER (LORESERVE+1). */
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_i386:
+ case bfd_arch_sparc:
+ if (hdr->sh_link == (SHN_LORESERVE & 0xffff)
+ || hdr->sh_link == ((SHN_LORESERVE + 1) & 0xffff))
+ break;
+ /* Otherwise fall through. */
+ default:
+ goto fail;
+ }
+ }
+ else if (elf_elfsections (abfd)[hdr->sh_link] == NULL)
+ goto fail;
+ else if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB)
+ {
+ Elf_Internal_Shdr *dynsymhdr;
+
+ /* The shared libraries distributed with hpux11 have a bogus
+ sh_link field for the ".dynamic" section. Find the
+ string table for the ".dynsym" section instead. */
+ if (elf_dynsymtab (abfd) != 0)
+ {
+ dynsymhdr = elf_elfsections (abfd)[elf_dynsymtab (abfd)];
+ hdr->sh_link = dynsymhdr->sh_link;
+ }
+ else
+ {
+ unsigned int i, num_sec;
+
+ num_sec = elf_numsections (abfd);
+ for (i = 1; i < num_sec; i++)
+ {
+ dynsymhdr = elf_elfsections (abfd)[i];
+ if (dynsymhdr->sh_type == SHT_DYNSYM)
+ {
+ hdr->sh_link = dynsymhdr->sh_link;
+ break;
+ }
+ }
+ }
+ }
+ goto success;
+
+ case SHT_SYMTAB: /* A symbol table. */
+ if (elf_onesymtab (abfd) == shindex)
+ goto success;
+
+ if (hdr->sh_entsize != bed->s->sizeof_sym)
+ goto fail;
+
+ if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
+ {
+ if (hdr->sh_size != 0)
+ goto fail;
+ /* Some assemblers erroneously set sh_info to one with a
+ zero sh_size. ld sees this as a global symbol count
+ of (unsigned) -1. Fix it here. */
+ hdr->sh_info = 0;
+ goto success;
+ }
+
+ /* PR 18854: A binary might contain more than one symbol table.
+ Unusual, but possible. Warn, but continue. */
+ if (elf_onesymtab (abfd) != 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: multiple symbol tables detected"
+ " - ignoring the table in section %u"),
+ abfd, shindex);
+ goto success;
+ }
+ elf_onesymtab (abfd) = shindex;
+ elf_symtab_hdr (abfd) = *hdr;
+ elf_elfsections (abfd)[shindex] = hdr = & elf_symtab_hdr (abfd);
+ abfd->flags |= HAS_SYMS;
+
+ /* Sometimes a shared object will map in the symbol table. If
+ SHF_ALLOC is set, and this is a shared object, then we also
+ treat this section as a BFD section. We can not base the
+ decision purely on SHF_ALLOC, because that flag is sometimes
+ set in a relocatable object file, which would confuse the
+ linker. */
+ if ((hdr->sh_flags & SHF_ALLOC) != 0
+ && (abfd->flags & DYNAMIC) != 0
+ && ! _bfd_elf_make_section_from_shdr (abfd, hdr, name,
+ shindex))
+ goto fail;
+
+ /* Go looking for SHT_SYMTAB_SHNDX too, since if there is one we
+ can't read symbols without that section loaded as well. It
+ is most likely specified by the next section header. */
+ {
+ elf_section_list * entry;
+ unsigned int i, num_sec;
+
+ for (entry = elf_symtab_shndx_list (abfd); entry; entry = entry->next)
+ if (entry->hdr.sh_link == shindex)
+ goto success;
+
+ num_sec = elf_numsections (abfd);
+ for (i = shindex + 1; i < num_sec; i++)
+ {
+ Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+
+ if (hdr2->sh_type == SHT_SYMTAB_SHNDX
+ && hdr2->sh_link == shindex)
+ break;
+ }
+
+ if (i == num_sec)
+ for (i = 1; i < shindex; i++)
+ {
+ Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+
+ if (hdr2->sh_type == SHT_SYMTAB_SHNDX
+ && hdr2->sh_link == shindex)
+ break;
+ }
+
+ if (i != shindex)
+ ret = bfd_section_from_shdr (abfd, i);
+ /* else FIXME: we have failed to find the symbol table.
+ Should we issue an error? */
+ goto success;
+ }
+
+ case SHT_DYNSYM: /* A dynamic symbol table. */
+ if (elf_dynsymtab (abfd) == shindex)
+ goto success;
+
+ if (hdr->sh_entsize != bed->s->sizeof_sym)
+ goto fail;
+
+ if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
+ {
+ if (hdr->sh_size != 0)
+ goto fail;
+
+ /* Some linkers erroneously set sh_info to one with a
+ zero sh_size. ld sees this as a global symbol count
+ of (unsigned) -1. Fix it here. */
+ hdr->sh_info = 0;
+ goto success;
+ }
+
+ /* PR 18854: A binary might contain more than one dynamic symbol table.
+ Unusual, but possible. Warn, but continue. */
+ if (elf_dynsymtab (abfd) != 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: multiple dynamic symbol tables detected"
+ " - ignoring the table in section %u"),
+ abfd, shindex);
+ goto success;
+ }
+ elf_dynsymtab (abfd) = shindex;
+ elf_tdata (abfd)->dynsymtab_hdr = *hdr;
+ elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+ abfd->flags |= HAS_SYMS;
+
+ /* Besides being a symbol table, we also treat this as a regular
+ section, so that objcopy can handle it. */
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ goto success;
+
+ case SHT_SYMTAB_SHNDX: /* Symbol section indices when >64k sections. */
+ {
+ elf_section_list * entry;
+
+ for (entry = elf_symtab_shndx_list (abfd); entry; entry = entry->next)
+ if (entry->ndx == shindex)
+ goto success;
+
+ entry = bfd_alloc (abfd, sizeof (*entry));
+ if (entry == NULL)
+ goto fail;
+ entry->ndx = shindex;
+ entry->hdr = * hdr;
+ entry->next = elf_symtab_shndx_list (abfd);
+ elf_symtab_shndx_list (abfd) = entry;
+ elf_elfsections (abfd)[shindex] = & entry->hdr;
+ goto success;
+ }
+
+ case SHT_STRTAB: /* A string table. */
+ if (hdr->bfd_section != NULL)
+ goto success;
+
+ if (ehdr->e_shstrndx == shindex)
+ {
+ elf_tdata (abfd)->shstrtab_hdr = *hdr;
+ elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->shstrtab_hdr;
+ goto success;
+ }
+
+ if (elf_elfsections (abfd)[elf_onesymtab (abfd)]->sh_link == shindex)
+ {
+ symtab_strtab:
+ elf_tdata (abfd)->strtab_hdr = *hdr;
+ elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->strtab_hdr;
+ goto success;
+ }
+
+ if (elf_elfsections (abfd)[elf_dynsymtab (abfd)]->sh_link == shindex)
+ {
+ dynsymtab_strtab:
+ elf_tdata (abfd)->dynstrtab_hdr = *hdr;
+ hdr = &elf_tdata (abfd)->dynstrtab_hdr;
+ elf_elfsections (abfd)[shindex] = hdr;
+ /* We also treat this as a regular section, so that objcopy
+ can handle it. */
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name,
+ shindex);
+ goto success;
+ }
+
+ /* If the string table isn't one of the above, then treat it as a
+ regular section. We need to scan all the headers to be sure,
+ just in case this strtab section appeared before the above. */
+ if (elf_onesymtab (abfd) == 0 || elf_dynsymtab (abfd) == 0)
+ {
+ unsigned int i, num_sec;
+
+ num_sec = elf_numsections (abfd);
+ for (i = 1; i < num_sec; i++)
+ {
+ Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+ if (hdr2->sh_link == shindex)
+ {
+ /* Prevent endless recursion on broken objects. */
+ if (i == shindex)
+ goto fail;
+ if (! bfd_section_from_shdr (abfd, i))
+ goto fail;
+ if (elf_onesymtab (abfd) == i)
+ goto symtab_strtab;
+ if (elf_dynsymtab (abfd) == i)
+ goto dynsymtab_strtab;
+ }
+ }
+ }
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ goto success;
+
+ case SHT_REL:
+ case SHT_RELA:
+ case SHT_RELR:
+ /* *These* do a lot of work -- but build no sections! */
+ {
+ asection *target_sect;
+ Elf_Internal_Shdr *hdr2, **p_hdr;
+ unsigned int num_sec = elf_numsections (abfd);
+ struct bfd_elf_section_data *esdt;
+ bfd_size_type size;
+
+ if (hdr->sh_type == SHT_REL)
+ size = bed->s->sizeof_rel;
+ else if (hdr->sh_type == SHT_RELA)
+ size = bed->s->sizeof_rela;
+ else
+ size = bed->s->arch_size / 8;
+ if (hdr->sh_entsize != size)
+ goto fail;
+
+ /* Check for a bogus link to avoid crashing. */
+ if (hdr->sh_link >= num_sec)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: invalid link %u for reloc section %s (index %u)"),
+ abfd, hdr->sh_link, name, shindex);
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ goto success;
+ }
+
+ /* Get the symbol table. */
+ if ((elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_SYMTAB
+ || elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_DYNSYM)
+ && ! bfd_section_from_shdr (abfd, hdr->sh_link))
+ goto fail;
+
+ /* If this is an alloc section in an executable or shared
+ library, or the reloc section does not use the main symbol
+ table we don't treat it as a reloc section. BFD can't
+ adequately represent such a section, so at least for now,
+ we don't try. We just present it as a normal section. We
+ also can't use it as a reloc section if it points to the
+ null section, an invalid section, another reloc section, or
+ its sh_link points to the null section. */
+ if (((abfd->flags & (DYNAMIC | EXEC_P)) != 0
+ && (hdr->sh_flags & SHF_ALLOC) != 0)
+ || hdr->sh_type == SHT_RELR
+ || hdr->sh_link == SHN_UNDEF
+ || hdr->sh_link != elf_onesymtab (abfd)
+ || hdr->sh_info == SHN_UNDEF
+ || hdr->sh_info >= num_sec
+ || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL
+ || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA)
+ {
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ goto success;
+ }
+
+ if (! bfd_section_from_shdr (abfd, hdr->sh_info))
+ goto fail;
+
+ target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info);
+ if (target_sect == NULL)
+ goto fail;
+
+ esdt = elf_section_data (target_sect);
+ if (hdr->sh_type == SHT_RELA)
+ p_hdr = &esdt->rela.hdr;
+ else
+ p_hdr = &esdt->rel.hdr;
+
+ /* PR 17512: file: 0b4f81b7.
+ Also see PR 24456, for a file which deliberately has two reloc
+ sections. */
+ if (*p_hdr != NULL)
+ {
+ if (!bed->init_secondary_reloc_section (abfd, hdr, name, shindex))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: secondary relocation section '%s' "
+ "for section %pA found - ignoring"),
+ abfd, name, target_sect);
+ }
+ else
+ esdt->has_secondary_relocs = true;
+ goto success;
+ }
+
+ hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2));
+ if (hdr2 == NULL)
+ goto fail;
+ *hdr2 = *hdr;
+ *p_hdr = hdr2;
+ elf_elfsections (abfd)[shindex] = hdr2;
+ target_sect->reloc_count += (NUM_SHDR_ENTRIES (hdr)
+ * bed->s->int_rels_per_ext_rel);
+ target_sect->flags |= SEC_RELOC;
+ target_sect->relocation = NULL;
+ target_sect->rel_filepos = hdr->sh_offset;
+ /* In the section to which the relocations apply, mark whether
+ its relocations are of the REL or RELA variety. */
+ if (hdr->sh_size != 0)
+ {
+ if (hdr->sh_type == SHT_RELA)
+ target_sect->use_rela_p = 1;
+ }
+ abfd->flags |= HAS_RELOC;
+ goto success;
+ }
+
+ case SHT_GNU_verdef:
+ if (hdr->sh_info != 0)
+ elf_dynverdef (abfd) = shindex;
+ elf_tdata (abfd)->dynverdef_hdr = *hdr;
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ goto success;
+
+ case SHT_GNU_versym:
+ if (hdr->sh_entsize != sizeof (Elf_External_Versym))
+ goto fail;
+
+ elf_dynversym (abfd) = shindex;
+ elf_tdata (abfd)->dynversym_hdr = *hdr;
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ goto success;
+
+ case SHT_GNU_verneed:
+ if (hdr->sh_info != 0)
+ elf_dynverref (abfd) = shindex;
+ elf_tdata (abfd)->dynverref_hdr = *hdr;
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ goto success;
+
+ case SHT_SHLIB:
+ goto success;
+
+ case SHT_GROUP:
+ if (! IS_VALID_GROUP_SECTION_HEADER (hdr, GRP_ENTRY_SIZE))
+ goto fail;
+
+ if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+ goto fail;
+
+ goto success;
+
+ default:
+ /* Possibly an attributes section. */
+ if (hdr->sh_type == SHT_GNU_ATTRIBUTES
+ || hdr->sh_type == bed->obj_attrs_section_type)
+ {
+ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+ goto fail;
+ _bfd_elf_parse_attributes (abfd, hdr);
+ goto success;
+ }
+
+ /* Check for any processor-specific section types. */
+ if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex))
+ goto success;
+
+ if (hdr->sh_type >= SHT_LOUSER && hdr->sh_type <= SHT_HIUSER)
+ {
+ if ((hdr->sh_flags & SHF_ALLOC) != 0)
+ /* FIXME: How to properly handle allocated section reserved
+ for applications? */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: unknown type [%#x] section `%s'"),
+ abfd, hdr->sh_type, name);
+ else
+ {
+ /* Allow sections reserved for applications. */
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ goto success;
+ }
+ }
+ else if (hdr->sh_type >= SHT_LOPROC
+ && hdr->sh_type <= SHT_HIPROC)
+ /* FIXME: We should handle this section. */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: unknown type [%#x] section `%s'"),
+ abfd, hdr->sh_type, name);
+ else if (hdr->sh_type >= SHT_LOOS && hdr->sh_type <= SHT_HIOS)
+ {
+ /* Unrecognised OS-specific sections. */
+ if ((hdr->sh_flags & SHF_OS_NONCONFORMING) != 0)
+ /* SHF_OS_NONCONFORMING indicates that special knowledge is
+ required to correctly process the section and the file should
+ be rejected with an error message. */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: unknown type [%#x] section `%s'"),
+ abfd, hdr->sh_type, name);
+ else
+ {
+ /* Otherwise it should be processed. */
+ ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ goto success;
+ }
+ }
+ else
+ /* FIXME: We should handle this section. */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: unknown type [%#x] section `%s'"),
+ abfd, hdr->sh_type, name);
+
+ goto fail;
+ }
+
+ fail:
+ ret = false;
+ success:
+ elf_tdata (abfd)->being_created[shindex] = false;
+ return ret;
+}
+
+/* Return the local symbol specified by ABFD, R_SYMNDX. */
+
+Elf_Internal_Sym *
+bfd_sym_from_r_symndx (struct sym_cache *cache,
+ bfd *abfd,
+ unsigned long r_symndx)
+{
+ unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE;
+
+ if (cache->abfd != abfd || cache->indx[ent] != r_symndx)
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+ unsigned char esym[sizeof (Elf64_External_Sym)];
+ Elf_External_Sym_Shndx eshndx;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx,
+ &cache->sym[ent], esym, &eshndx) == NULL)
+ return NULL;
+
+ if (cache->abfd != abfd)
+ {
+ memset (cache->indx, -1, sizeof (cache->indx));
+ cache->abfd = abfd;
+ }
+ cache->indx[ent] = r_symndx;
+ }
+
+ return &cache->sym[ent];
+}
+
+/* Given an ELF section number, retrieve the corresponding BFD
+ section. */
+
+asection *
+bfd_section_from_elf_index (bfd *abfd, unsigned int sec_index)
+{
+ if (sec_index >= elf_numsections (abfd))
+ return NULL;
+ return elf_elfsections (abfd)[sec_index]->bfd_section;
+}
+
+static const struct bfd_elf_special_section special_sections_b[] =
+{
+ { STRING_COMMA_LEN (".bss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_c[] =
+{
+ { STRING_COMMA_LEN (".comment"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".ctf"), 0, SHT_PROGBITS, 0 },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_d[] =
+{
+ { STRING_COMMA_LEN (".data"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".data1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ /* There are more DWARF sections than these, but they needn't be added here
+ unless you have to cope with broken compilers that don't emit section
+ attributes or you want to help the user writing assembler. */
+ { STRING_COMMA_LEN (".debug"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".debug_line"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".debug_info"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".debug_abbrev"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".debug_aranges"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".dynamic"), 0, SHT_DYNAMIC, SHF_ALLOC },
+ { STRING_COMMA_LEN (".dynstr"), 0, SHT_STRTAB, SHF_ALLOC },
+ { STRING_COMMA_LEN (".dynsym"), 0, SHT_DYNSYM, SHF_ALLOC },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_f[] =
+{
+ { STRING_COMMA_LEN (".fini"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { STRING_COMMA_LEN (".fini_array"), -2, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE },
+ { NULL, 0 , 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_g[] =
+{
+ { STRING_COMMA_LEN (".gnu.linkonce.b"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".gnu.linkonce.n"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".gnu.linkonce.p"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".gnu.lto_"), -1, SHT_PROGBITS, SHF_EXCLUDE },
+ { STRING_COMMA_LEN (".got"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".gnu.version"), 0, SHT_GNU_versym, 0 },
+ { STRING_COMMA_LEN (".gnu.version_d"), 0, SHT_GNU_verdef, 0 },
+ { STRING_COMMA_LEN (".gnu.version_r"), 0, SHT_GNU_verneed, 0 },
+ { STRING_COMMA_LEN (".gnu.liblist"), 0, SHT_GNU_LIBLIST, SHF_ALLOC },
+ { STRING_COMMA_LEN (".gnu.conflict"), 0, SHT_RELA, SHF_ALLOC },
+ { STRING_COMMA_LEN (".gnu.hash"), 0, SHT_GNU_HASH, SHF_ALLOC },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_h[] =
+{
+ { STRING_COMMA_LEN (".hash"), 0, SHT_HASH, SHF_ALLOC },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_i[] =
+{
+ { STRING_COMMA_LEN (".init"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { STRING_COMMA_LEN (".init_array"), -2, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".interp"), 0, SHT_PROGBITS, 0 },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_l[] =
+{
+ { STRING_COMMA_LEN (".line"), 0, SHT_PROGBITS, 0 },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_n[] =
+{
+ { STRING_COMMA_LEN (".noinit"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".note.GNU-stack"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".note"), -1, SHT_NOTE, 0 },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_p[] =
+{
+ { STRING_COMMA_LEN (".persistent.bss"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".persistent"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".preinit_array"), -2, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_r[] =
+{
+ { STRING_COMMA_LEN (".rodata"), -2, SHT_PROGBITS, SHF_ALLOC },
+ { STRING_COMMA_LEN (".rodata1"), 0, SHT_PROGBITS, SHF_ALLOC },
+ { STRING_COMMA_LEN (".relr.dyn"), 0, SHT_RELR, SHF_ALLOC },
+ { STRING_COMMA_LEN (".rela"), -1, SHT_RELA, 0 },
+ { STRING_COMMA_LEN (".rel"), -1, SHT_REL, 0 },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_s[] =
+{
+ { STRING_COMMA_LEN (".shstrtab"), 0, SHT_STRTAB, 0 },
+ { STRING_COMMA_LEN (".strtab"), 0, SHT_STRTAB, 0 },
+ { STRING_COMMA_LEN (".symtab"), 0, SHT_SYMTAB, 0 },
+ /* See struct bfd_elf_special_section declaration for the semantics of
+ this special case where .prefix_length != strlen (.prefix). */
+ { ".stabstr", 5, 3, SHT_STRTAB, 0 },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_t[] =
+{
+ { STRING_COMMA_LEN (".text"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { STRING_COMMA_LEN (".tbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS },
+ { STRING_COMMA_LEN (".tdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section special_sections_z[] =
+{
+ { STRING_COMMA_LEN (".zdebug_line"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".zdebug_info"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".zdebug_abbrev"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".zdebug_aranges"), 0, SHT_PROGBITS, 0 },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static const struct bfd_elf_special_section * const special_sections[] =
+{
+ special_sections_b, /* 'b' */
+ special_sections_c, /* 'c' */
+ special_sections_d, /* 'd' */
+ NULL, /* 'e' */
+ special_sections_f, /* 'f' */
+ special_sections_g, /* 'g' */
+ special_sections_h, /* 'h' */
+ special_sections_i, /* 'i' */
+ NULL, /* 'j' */
+ NULL, /* 'k' */
+ special_sections_l, /* 'l' */
+ NULL, /* 'm' */
+ special_sections_n, /* 'n' */
+ NULL, /* 'o' */
+ special_sections_p, /* 'p' */
+ NULL, /* 'q' */
+ special_sections_r, /* 'r' */
+ special_sections_s, /* 's' */
+ special_sections_t, /* 't' */
+ NULL, /* 'u' */
+ NULL, /* 'v' */
+ NULL, /* 'w' */
+ NULL, /* 'x' */
+ NULL, /* 'y' */
+ special_sections_z /* 'z' */
+};
+
+const struct bfd_elf_special_section *
+_bfd_elf_get_special_section (const char *name,
+ const struct bfd_elf_special_section *spec,
+ unsigned int rela)
+{
+ int i;
+ int len;
+
+ len = strlen (name);
+
+ for (i = 0; spec[i].prefix != NULL; i++)
+ {
+ int suffix_len;
+ int prefix_len = spec[i].prefix_length;
+
+ if (len < prefix_len)
+ continue;
+ if (memcmp (name, spec[i].prefix, prefix_len) != 0)
+ continue;
+
+ suffix_len = spec[i].suffix_length;
+ if (suffix_len <= 0)
+ {
+ if (name[prefix_len] != 0)
+ {
+ if (suffix_len == 0)
+ continue;
+ if (name[prefix_len] != '.'
+ && (suffix_len == -2
+ || (rela && spec[i].type == SHT_REL)))
+ continue;
+ }
+ }
+ else
+ {
+ if (len < prefix_len + suffix_len)
+ continue;
+ if (memcmp (name + len - suffix_len,
+ spec[i].prefix + prefix_len,
+ suffix_len) != 0)
+ continue;
+ }
+ return &spec[i];
+ }
+
+ return NULL;
+}
+
+const struct bfd_elf_special_section *
+_bfd_elf_get_sec_type_attr (bfd *abfd, asection *sec)
+{
+ int i;
+ const struct bfd_elf_special_section *spec;
+ const struct elf_backend_data *bed;
+
+ /* See if this is one of the special sections. */
+ if (sec->name == NULL)
+ return NULL;
+
+ bed = get_elf_backend_data (abfd);
+ spec = bed->special_sections;
+ if (spec)
+ {
+ spec = _bfd_elf_get_special_section (sec->name,
+ bed->special_sections,
+ sec->use_rela_p);
+ if (spec != NULL)
+ return spec;
+ }
+
+ if (sec->name[0] != '.')
+ return NULL;
+
+ i = sec->name[1] - 'b';
+ if (i < 0 || i > 'z' - 'b')
+ return NULL;
+
+ spec = special_sections[i];
+
+ if (spec == NULL)
+ return NULL;
+
+ return _bfd_elf_get_special_section (sec->name, spec, sec->use_rela_p);
+}
+
+bool
+_bfd_elf_new_section_hook (bfd *abfd, asection *sec)
+{
+ struct bfd_elf_section_data *sdata;
+ const struct elf_backend_data *bed;
+ const struct bfd_elf_special_section *ssect;
+
+ sdata = (struct bfd_elf_section_data *) sec->used_by_bfd;
+ if (sdata == NULL)
+ {
+ sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd,
+ sizeof (*sdata));
+ if (sdata == NULL)
+ return false;
+ sec->used_by_bfd = sdata;
+ }
+
+ /* Indicate whether or not this section should use RELA relocations. */
+ bed = get_elf_backend_data (abfd);
+ sec->use_rela_p = bed->default_use_rela_p;
+
+ /* Set up ELF section type and flags for newly created sections, if
+ there is an ABI mandated section. */
+ ssect = (*bed->get_sec_type_attr) (abfd, sec);
+ if (ssect != NULL)
+ {
+ elf_section_type (sec) = ssect->type;
+ elf_section_flags (sec) = ssect->attr;
+ }
+
+ return _bfd_generic_new_section_hook (abfd, sec);
+}
+
+/* Create a new bfd section from an ELF program header.
+
+ Since program segments have no names, we generate a synthetic name
+ of the form segment<NUM>, where NUM is generally the index in the
+ program header table. For segments that are split (see below) we
+ generate the names segment<NUM>a and segment<NUM>b.
+
+ Note that some program segments may have a file size that is different than
+ (less than) the memory size. All this means is that at execution the
+ system must allocate the amount of memory specified by the memory size,
+ but only initialize it with the first "file size" bytes read from the
+ file. This would occur for example, with program segments consisting
+ of combined data+bss.
+
+ To handle the above situation, this routine generates TWO bfd sections
+ for the single program segment. The first has the length specified by
+ the file size of the segment, and the second has the length specified
+ by the difference between the two sizes. In effect, the segment is split
+ into its initialized and uninitialized parts. */
+
+bool
+_bfd_elf_make_section_from_phdr (bfd *abfd,
+ Elf_Internal_Phdr *hdr,
+ int hdr_index,
+ const char *type_name)
+{
+ asection *newsect;
+ char *name;
+ char namebuf[64];
+ size_t len;
+ int split;
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
+
+ split = ((hdr->p_memsz > 0)
+ && (hdr->p_filesz > 0)
+ && (hdr->p_memsz > hdr->p_filesz));
+
+ if (hdr->p_filesz > 0)
+ {
+ sprintf (namebuf, "%s%d%s", type_name, hdr_index, split ? "a" : "");
+ len = strlen (namebuf) + 1;
+ name = (char *) bfd_alloc (abfd, len);
+ if (!name)
+ return false;
+ memcpy (name, namebuf, len);
+ newsect = bfd_make_section (abfd, name);
+ if (newsect == NULL)
+ return false;
+ newsect->vma = hdr->p_vaddr / opb;
+ newsect->lma = hdr->p_paddr / opb;
+ newsect->size = hdr->p_filesz;
+ newsect->filepos = hdr->p_offset;
+ newsect->flags |= SEC_HAS_CONTENTS;
+ newsect->alignment_power = bfd_log2 (hdr->p_align);
+ if (hdr->p_type == PT_LOAD)
+ {
+ newsect->flags |= SEC_ALLOC;
+ newsect->flags |= SEC_LOAD;
+ if (hdr->p_flags & PF_X)
+ {
+ /* FIXME: all we known is that it has execute PERMISSION,
+ may be data. */
+ newsect->flags |= SEC_CODE;
+ }
+ }
+ if (!(hdr->p_flags & PF_W))
+ {
+ newsect->flags |= SEC_READONLY;
+ }
+ }
+
+ if (hdr->p_memsz > hdr->p_filesz)
+ {
+ bfd_vma align;
+
+ sprintf (namebuf, "%s%d%s", type_name, hdr_index, split ? "b" : "");
+ len = strlen (namebuf) + 1;
+ name = (char *) bfd_alloc (abfd, len);
+ if (!name)
+ return false;
+ memcpy (name, namebuf, len);
+ newsect = bfd_make_section (abfd, name);
+ if (newsect == NULL)
+ return false;
+ newsect->vma = (hdr->p_vaddr + hdr->p_filesz) / opb;
+ newsect->lma = (hdr->p_paddr + hdr->p_filesz) / opb;
+ newsect->size = hdr->p_memsz - hdr->p_filesz;
+ newsect->filepos = hdr->p_offset + hdr->p_filesz;
+ align = newsect->vma & -newsect->vma;
+ if (align == 0 || align > hdr->p_align)
+ align = hdr->p_align;
+ newsect->alignment_power = bfd_log2 (align);
+ if (hdr->p_type == PT_LOAD)
+ {
+ newsect->flags |= SEC_ALLOC;
+ if (hdr->p_flags & PF_X)
+ newsect->flags |= SEC_CODE;
+ }
+ if (!(hdr->p_flags & PF_W))
+ newsect->flags |= SEC_READONLY;
+ }
+
+ return true;
+}
+
+static bool
+_bfd_elf_core_find_build_id (bfd *templ, bfd_vma offset)
+{
+ /* The return value is ignored. Build-ids are considered optional. */
+ if (templ->xvec->flavour == bfd_target_elf_flavour)
+ return (*get_elf_backend_data (templ)->elf_backend_core_find_build_id)
+ (templ, offset);
+ return false;
+}
+
+bool
+bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index)
+{
+ const struct elf_backend_data *bed;
+
+ switch (hdr->p_type)
+ {
+ case PT_NULL:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "null");
+
+ case PT_LOAD:
+ if (! _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "load"))
+ return false;
+ if (bfd_get_format (abfd) == bfd_core && abfd->build_id == NULL)
+ _bfd_elf_core_find_build_id (abfd, hdr->p_offset);
+ return true;
+
+ case PT_DYNAMIC:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "dynamic");
+
+ case PT_INTERP:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "interp");
+
+ case PT_NOTE:
+ if (! _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "note"))
+ return false;
+ if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz,
+ hdr->p_align))
+ return false;
+ return true;
+
+ case PT_SHLIB:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "shlib");
+
+ case PT_PHDR:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "phdr");
+
+ case PT_GNU_EH_FRAME:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index,
+ "eh_frame_hdr");
+
+ case PT_GNU_STACK:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "stack");
+
+ case PT_GNU_RELRO:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "relro");
+
+ case PT_GNU_SFRAME:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index,
+ "sframe");
+
+ default:
+ /* Check for any processor-specific program segment types. */
+ bed = get_elf_backend_data (abfd);
+ return bed->elf_backend_section_from_phdr (abfd, hdr, hdr_index, "proc");
+ }
+}
+
+/* Return the REL_HDR for SEC, assuming there is only a single one, either
+ REL or RELA. */
+
+Elf_Internal_Shdr *
+_bfd_elf_single_rel_hdr (asection *sec)
+{
+ if (elf_section_data (sec)->rel.hdr)
+ {
+ BFD_ASSERT (elf_section_data (sec)->rela.hdr == NULL);
+ return elf_section_data (sec)->rel.hdr;
+ }
+ else
+ return elf_section_data (sec)->rela.hdr;
+}
+
+static bool
+_bfd_elf_set_reloc_sh_name (bfd *abfd,
+ Elf_Internal_Shdr *rel_hdr,
+ const char *sec_name,
+ bool use_rela_p)
+{
+ char *name = (char *) bfd_alloc (abfd,
+ sizeof ".rela" + strlen (sec_name));
+ if (name == NULL)
+ return false;
+
+ sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", sec_name);
+ rel_hdr->sh_name =
+ (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name,
+ false);
+ if (rel_hdr->sh_name == (unsigned int) -1)
+ return false;
+
+ return true;
+}
+
+/* Allocate and initialize a section-header for a new reloc section,
+ containing relocations against ASECT. It is stored in RELDATA. If
+ USE_RELA_P is TRUE, we use RELA relocations; otherwise, we use REL
+ relocations. */
+
+static bool
+_bfd_elf_init_reloc_shdr (bfd *abfd,
+ struct bfd_elf_section_reloc_data *reldata,
+ const char *sec_name,
+ bool use_rela_p,
+ bool delay_st_name_p)
+{
+ Elf_Internal_Shdr *rel_hdr;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ BFD_ASSERT (reldata->hdr == NULL);
+ rel_hdr = bfd_zalloc (abfd, sizeof (*rel_hdr));
+ reldata->hdr = rel_hdr;
+
+ if (delay_st_name_p)
+ rel_hdr->sh_name = (unsigned int) -1;
+ else if (!_bfd_elf_set_reloc_sh_name (abfd, rel_hdr, sec_name,
+ use_rela_p))
+ return false;
+ rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
+ rel_hdr->sh_entsize = (use_rela_p
+ ? bed->s->sizeof_rela
+ : bed->s->sizeof_rel);
+ rel_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
+ rel_hdr->sh_flags = 0;
+ rel_hdr->sh_addr = 0;
+ rel_hdr->sh_size = 0;
+ rel_hdr->sh_offset = 0;
+
+ return true;
+}
+
+/* Return the default section type based on the passed in section flags. */
+
+int
+bfd_elf_get_default_section_type (flagword flags)
+{
+ if ((flags & (SEC_ALLOC | SEC_IS_COMMON)) != 0
+ && (flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+ return SHT_NOBITS;
+ return SHT_PROGBITS;
+}
+
+struct fake_section_arg
+{
+ struct bfd_link_info *link_info;
+ bool failed;
+};
+
+/* Set up an ELF internal section header for a section. */
+
+static void
+elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
+{
+ struct fake_section_arg *arg = (struct fake_section_arg *)fsarg;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ struct bfd_elf_section_data *esd = elf_section_data (asect);
+ Elf_Internal_Shdr *this_hdr;
+ unsigned int sh_type;
+ const char *name = asect->name;
+ bool delay_st_name_p = false;
+ bfd_vma mask;
+
+ if (arg->failed)
+ {
+ /* We already failed; just get out of the bfd_map_over_sections
+ loop. */
+ return;
+ }
+
+ this_hdr = &esd->this_hdr;
+
+ /* ld: compress DWARF debug sections with names: .debug_*. */
+ if (arg->link_info
+ && (abfd->flags & BFD_COMPRESS) != 0
+ && (asect->flags & SEC_DEBUGGING) != 0
+ && name[1] == 'd'
+ && name[6] == '_')
+ {
+ /* If this section will be compressed, delay adding section
+ name to section name section after it is compressed in
+ _bfd_elf_assign_file_positions_for_non_load. */
+ delay_st_name_p = true;
+ }
+
+ if (delay_st_name_p)
+ this_hdr->sh_name = (unsigned int) -1;
+ else
+ {
+ this_hdr->sh_name
+ = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+ name, false);
+ if (this_hdr->sh_name == (unsigned int) -1)
+ {
+ arg->failed = true;
+ return;
+ }
+ }
+
+ /* Don't clear sh_flags. Assembler may set additional bits. */
+
+ if ((asect->flags & SEC_ALLOC) != 0
+ || asect->user_set_vma)
+ this_hdr->sh_addr = asect->vma * bfd_octets_per_byte (abfd, asect);
+ else
+ this_hdr->sh_addr = 0;
+
+ this_hdr->sh_offset = 0;
+ this_hdr->sh_size = asect->size;
+ this_hdr->sh_link = 0;
+ /* PR 17512: file: 0eb809fe, 8b0535ee. */
+ if (asect->alignment_power >= (sizeof (bfd_vma) * 8) - 1)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: error: alignment power %d of section `%pA' is too big"),
+ abfd, asect->alignment_power, asect);
+ arg->failed = true;
+ return;
+ }
+ /* Set sh_addralign to the highest power of two given by alignment
+ consistent with the section VMA. Linker scripts can force VMA. */
+ mask = ((bfd_vma) 1 << asect->alignment_power) | this_hdr->sh_addr;
+ this_hdr->sh_addralign = mask & -mask;
+ /* The sh_entsize and sh_info fields may have been set already by
+ copy_private_section_data. */
+
+ this_hdr->bfd_section = asect;
+ this_hdr->contents = NULL;
+
+ /* If the section type is unspecified, we set it based on
+ asect->flags. */
+ if (asect->type != 0)
+ sh_type = asect->type;
+ else if ((asect->flags & SEC_GROUP) != 0)
+ sh_type = SHT_GROUP;
+ else
+ sh_type = bfd_elf_get_default_section_type (asect->flags);
+
+ if (this_hdr->sh_type == SHT_NULL)
+ this_hdr->sh_type = sh_type;
+ else if (this_hdr->sh_type == SHT_NOBITS
+ && sh_type == SHT_PROGBITS
+ && (asect->flags & SEC_ALLOC) != 0)
+ {
+ /* Warn if we are changing a NOBITS section to PROGBITS, but
+ allow the link to proceed. This can happen when users link
+ non-bss input sections to bss output sections, or emit data
+ to a bss output section via a linker script. */
+ _bfd_error_handler
+ (_("warning: section `%pA' type changed to PROGBITS"), asect);
+ this_hdr->sh_type = sh_type;
+ }
+
+ switch (this_hdr->sh_type)
+ {
+ default:
+ break;
+
+ case SHT_STRTAB:
+ case SHT_NOTE:
+ case SHT_NOBITS:
+ case SHT_PROGBITS:
+ break;
+
+ case SHT_INIT_ARRAY:
+ case SHT_FINI_ARRAY:
+ case SHT_PREINIT_ARRAY:
+ this_hdr->sh_entsize = bed->s->arch_size / 8;
+ break;
+
+ case SHT_HASH:
+ this_hdr->sh_entsize = bed->s->sizeof_hash_entry;
+ break;
+
+ case SHT_DYNSYM:
+ this_hdr->sh_entsize = bed->s->sizeof_sym;
+ break;
+
+ case SHT_DYNAMIC:
+ this_hdr->sh_entsize = bed->s->sizeof_dyn;
+ break;
+
+ case SHT_RELA:
+ if (get_elf_backend_data (abfd)->may_use_rela_p)
+ this_hdr->sh_entsize = bed->s->sizeof_rela;
+ break;
+
+ case SHT_REL:
+ if (get_elf_backend_data (abfd)->may_use_rel_p)
+ this_hdr->sh_entsize = bed->s->sizeof_rel;
+ break;
+
+ case SHT_GNU_versym:
+ this_hdr->sh_entsize = sizeof (Elf_External_Versym);
+ break;
+
+ case SHT_GNU_verdef:
+ this_hdr->sh_entsize = 0;
+ /* objcopy or strip will copy over sh_info, but may not set
+ cverdefs. The linker will set cverdefs, but sh_info will be
+ zero. */
+ if (this_hdr->sh_info == 0)
+ this_hdr->sh_info = elf_tdata (abfd)->cverdefs;
+ else
+ BFD_ASSERT (elf_tdata (abfd)->cverdefs == 0
+ || this_hdr->sh_info == elf_tdata (abfd)->cverdefs);
+ break;
+
+ case SHT_GNU_verneed:
+ this_hdr->sh_entsize = 0;
+ /* objcopy or strip will copy over sh_info, but may not set
+ cverrefs. The linker will set cverrefs, but sh_info will be
+ zero. */
+ if (this_hdr->sh_info == 0)
+ this_hdr->sh_info = elf_tdata (abfd)->cverrefs;
+ else
+ BFD_ASSERT (elf_tdata (abfd)->cverrefs == 0
+ || this_hdr->sh_info == elf_tdata (abfd)->cverrefs);
+ break;
+
+ case SHT_GROUP:
+ this_hdr->sh_entsize = GRP_ENTRY_SIZE;
+ break;
+
+ case SHT_GNU_HASH:
+ this_hdr->sh_entsize = bed->s->arch_size == 64 ? 0 : 4;
+ break;
+ }
+
+ if ((asect->flags & SEC_ALLOC) != 0)
+ this_hdr->sh_flags |= SHF_ALLOC;
+ if ((asect->flags & SEC_READONLY) == 0)
+ this_hdr->sh_flags |= SHF_WRITE;
+ if ((asect->flags & SEC_CODE) != 0)
+ this_hdr->sh_flags |= SHF_EXECINSTR;
+ if ((asect->flags & SEC_MERGE) != 0)
+ {
+ this_hdr->sh_flags |= SHF_MERGE;
+ this_hdr->sh_entsize = asect->entsize;
+ }
+ if ((asect->flags & SEC_STRINGS) != 0)
+ this_hdr->sh_flags |= SHF_STRINGS;
+ if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
+ this_hdr->sh_flags |= SHF_GROUP;
+ if ((asect->flags & SEC_THREAD_LOCAL) != 0)
+ {
+ this_hdr->sh_flags |= SHF_TLS;
+ if (asect->size == 0
+ && (asect->flags & SEC_HAS_CONTENTS) == 0)
+ {
+ struct bfd_link_order *o = asect->map_tail.link_order;
+
+ this_hdr->sh_size = 0;
+ if (o != NULL)
+ {
+ this_hdr->sh_size = o->offset + o->size;
+ if (this_hdr->sh_size != 0)
+ this_hdr->sh_type = SHT_NOBITS;
+ }
+ }
+ }
+ if ((asect->flags & (SEC_GROUP | SEC_EXCLUDE)) == SEC_EXCLUDE)
+ this_hdr->sh_flags |= SHF_EXCLUDE;
+
+ /* If the section has relocs, set up a section header for the
+ SHT_REL[A] section. If two relocation sections are required for
+ this section, it is up to the processor-specific back-end to
+ create the other. */
+ if ((asect->flags & SEC_RELOC) != 0)
+ {
+ /* When doing a relocatable link, create both REL and RELA sections if
+ needed. */
+ if (arg->link_info
+ /* Do the normal setup if we wouldn't create any sections here. */
+ && esd->rel.count + esd->rela.count > 0
+ && (bfd_link_relocatable (arg->link_info)
+ || arg->link_info->emitrelocations))
+ {
+ if (esd->rel.count && esd->rel.hdr == NULL
+ && !_bfd_elf_init_reloc_shdr (abfd, &esd->rel, name,
+ false, delay_st_name_p))
+ {
+ arg->failed = true;
+ return;
+ }
+ if (esd->rela.count && esd->rela.hdr == NULL
+ && !_bfd_elf_init_reloc_shdr (abfd, &esd->rela, name,
+ true, delay_st_name_p))
+ {
+ arg->failed = true;
+ return;
+ }
+ }
+ else if (!_bfd_elf_init_reloc_shdr (abfd,
+ (asect->use_rela_p
+ ? &esd->rela : &esd->rel),
+ name,
+ asect->use_rela_p,
+ delay_st_name_p))
+ {
+ arg->failed = true;
+ return;
+ }
+ }
+
+ /* Check for processor-specific section types. */
+ sh_type = this_hdr->sh_type;
+ if (bed->elf_backend_fake_sections
+ && !(*bed->elf_backend_fake_sections) (abfd, this_hdr, asect))
+ {
+ arg->failed = true;
+ return;
+ }
+
+ if (sh_type == SHT_NOBITS && asect->size != 0)
+ {
+ /* Don't change the header type from NOBITS if we are being
+ called for objcopy --only-keep-debug. */
+ this_hdr->sh_type = sh_type;
+ }
+}
+
+/* Fill in the contents of a SHT_GROUP section. Called from
+ _bfd_elf_compute_section_file_positions for gas, objcopy, and
+ when ELF targets use the generic linker, ld. Called for ld -r
+ from bfd_elf_final_link. */
+
+void
+bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
+{
+ bool *failedptr = (bool *) failedptrarg;
+ asection *elt, *first;
+ unsigned char *loc;
+ bool gas;
+
+ /* Ignore linker created group section. See elfNN_ia64_object_p in
+ elfxx-ia64.c. */
+ if ((sec->flags & (SEC_GROUP | SEC_LINKER_CREATED)) != SEC_GROUP
+ || sec->size == 0
+ || *failedptr)
+ return;
+
+ if (elf_section_data (sec)->this_hdr.sh_info == 0)
+ {
+ unsigned long symindx = 0;
+
+ /* elf_group_id will have been set up by objcopy and the
+ generic linker. */
+ if (elf_group_id (sec) != NULL)
+ symindx = elf_group_id (sec)->udata.i;
+
+ if (symindx == 0)
+ {
+ /* If called from the assembler, swap_out_syms will have set up
+ elf_section_syms.
+ PR 25699: A corrupt input file could contain bogus group info. */
+ if (sec->index >= elf_num_section_syms (abfd)
+ || elf_section_syms (abfd)[sec->index] == NULL)
+ {
+ *failedptr = true;
+ return;
+ }
+ symindx = elf_section_syms (abfd)[sec->index]->udata.i;
+ }
+ elf_section_data (sec)->this_hdr.sh_info = symindx;
+ }
+ else if (elf_section_data (sec)->this_hdr.sh_info == (unsigned int) -2)
+ {
+ /* The ELF backend linker sets sh_info to -2 when the group
+ signature symbol is global, and thus the index can't be
+ set until all local symbols are output. */
+ asection *igroup;
+ struct bfd_elf_section_data *sec_data;
+ unsigned long symndx;
+ unsigned long extsymoff;
+ struct elf_link_hash_entry *h;
+
+ /* The point of this little dance to the first SHF_GROUP section
+ then back to the SHT_GROUP section is that this gets us to
+ the SHT_GROUP in the input object. */
+ igroup = elf_sec_group (elf_next_in_group (sec));
+ sec_data = elf_section_data (igroup);
+ symndx = sec_data->this_hdr.sh_info;
+ extsymoff = 0;
+ if (!elf_bad_symtab (igroup->owner))
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+
+ symtab_hdr = &elf_tdata (igroup->owner)->symtab_hdr;
+ extsymoff = symtab_hdr->sh_info;
+ }
+ h = elf_sym_hashes (igroup->owner)[symndx - extsymoff];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ elf_section_data (sec)->this_hdr.sh_info = h->indx;
+ }
+
+ /* The contents won't be allocated for "ld -r" or objcopy. */
+ gas = true;
+ if (sec->contents == NULL)
+ {
+ gas = false;
+ sec->contents = (unsigned char *) bfd_alloc (abfd, sec->size);
+
+ /* Arrange for the section to be written out. */
+ elf_section_data (sec)->this_hdr.contents = sec->contents;
+ if (sec->contents == NULL)
+ {
+ *failedptr = true;
+ return;
+ }
+ }
+
+ loc = sec->contents + sec->size;
+
+ /* Get the pointer to the first section in the group that gas
+ squirreled away here. objcopy arranges for this to be set to the
+ start of the input section group. */
+ first = elt = elf_next_in_group (sec);
+
+ /* First element is a flag word. Rest of section is elf section
+ indices for all the sections of the group. Write them backwards
+ just to keep the group in the same order as given in .section
+ directives, not that it matters. */
+ while (elt != NULL)
+ {
+ asection *s;
+
+ s = elt;
+ if (!gas)
+ s = s->output_section;
+ if (s != NULL
+ && !bfd_is_abs_section (s))
+ {
+ struct bfd_elf_section_data *elf_sec = elf_section_data (s);
+ struct bfd_elf_section_data *input_elf_sec = elf_section_data (elt);
+
+ if (elf_sec->rel.hdr != NULL
+ && (gas
+ || (input_elf_sec->rel.hdr != NULL
+ && input_elf_sec->rel.hdr->sh_flags & SHF_GROUP) != 0))
+ {
+ elf_sec->rel.hdr->sh_flags |= SHF_GROUP;
+ loc -= 4;
+ if (loc == sec->contents)
+ break;
+ H_PUT_32 (abfd, elf_sec->rel.idx, loc);
+ }
+ if (elf_sec->rela.hdr != NULL
+ && (gas
+ || (input_elf_sec->rela.hdr != NULL
+ && input_elf_sec->rela.hdr->sh_flags & SHF_GROUP) != 0))
+ {
+ elf_sec->rela.hdr->sh_flags |= SHF_GROUP;
+ loc -= 4;
+ if (loc == sec->contents)
+ break;
+ H_PUT_32 (abfd, elf_sec->rela.idx, loc);
+ }
+ loc -= 4;
+ if (loc == sec->contents)
+ break;
+ H_PUT_32 (abfd, elf_sec->this_idx, loc);
+ }
+ elt = elf_next_in_group (elt);
+ if (elt == first)
+ break;
+ }
+
+ /* We should always get here with loc == sec->contents + 4, but it is
+ possible to craft bogus SHT_GROUP sections that will cause segfaults
+ in objcopy without checking loc here and in the loop above. */
+ if (loc == sec->contents)
+ BFD_ASSERT (0);
+ else
+ {
+ loc -= 4;
+ if (loc != sec->contents)
+ {
+ BFD_ASSERT (0);
+ memset (sec->contents + 4, 0, loc - sec->contents);
+ loc = sec->contents;
+ }
+ }
+
+ H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
+}
+
+/* Given NAME, the name of a relocation section stripped of its
+ .rel/.rela prefix, return the section in ABFD to which the
+ relocations apply. */
+
+asection *
+_bfd_elf_plt_get_reloc_section (bfd *abfd, const char *name)
+{
+ /* If a target needs .got.plt section, relocations in rela.plt/rel.plt
+ section likely apply to .got.plt or .got section. */
+ if (get_elf_backend_data (abfd)->want_got_plt
+ && strcmp (name, ".plt") == 0)
+ {
+ asection *sec;
+
+ name = ".got.plt";
+ sec = bfd_get_section_by_name (abfd, name);
+ if (sec != NULL)
+ return sec;
+ name = ".got";
+ }
+
+ return bfd_get_section_by_name (abfd, name);
+}
+
+/* Return the section to which RELOC_SEC applies. */
+
+static asection *
+elf_get_reloc_section (asection *reloc_sec)
+{
+ const char *name;
+ unsigned int type;
+ bfd *abfd;
+ const struct elf_backend_data *bed;
+
+ type = elf_section_data (reloc_sec)->this_hdr.sh_type;
+ if (type != SHT_REL && type != SHT_RELA)
+ return NULL;
+
+ /* We look up the section the relocs apply to by name. */
+ name = reloc_sec->name;
+ if (!startswith (name, ".rel"))
+ return NULL;
+ name += 4;
+ if (type == SHT_RELA && *name++ != 'a')
+ return NULL;
+
+ abfd = reloc_sec->owner;
+ bed = get_elf_backend_data (abfd);
+ return bed->get_reloc_section (abfd, name);
+}
+
+/* Assign all ELF section numbers. The dummy first section is handled here
+ too. The link/info pointers for the standard section types are filled
+ in here too, while we're at it. LINK_INFO will be 0 when arriving
+ here for gas, objcopy, and when using the generic ELF linker. */
+
+static bool
+assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
+{
+ struct elf_obj_tdata *t = elf_tdata (abfd);
+ asection *sec;
+ unsigned int section_number;
+ Elf_Internal_Shdr **i_shdrp;
+ struct bfd_elf_section_data *d;
+ bool need_symtab;
+ size_t amt;
+
+ section_number = 1;
+
+ _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd));
+
+ /* SHT_GROUP sections are in relocatable files only. */
+ if (link_info == NULL || !link_info->resolve_section_groups)
+ {
+ size_t reloc_count = 0;
+
+ /* Put SHT_GROUP sections first. */
+ for (sec = abfd->sections; sec != NULL; sec = sec->next)
+ {
+ d = elf_section_data (sec);
+
+ if (d->this_hdr.sh_type == SHT_GROUP)
+ {
+ if (sec->flags & SEC_LINKER_CREATED)
+ {
+ /* Remove the linker created SHT_GROUP sections. */
+ bfd_section_list_remove (abfd, sec);
+ abfd->section_count--;
+ }
+ else
+ d->this_idx = section_number++;
+ }
+
+ /* Count relocations. */
+ reloc_count += sec->reloc_count;
+ }
+
+ /* Set/clear HAS_RELOC depending on whether there are relocations. */
+ if (reloc_count == 0)
+ abfd->flags &= ~HAS_RELOC;
+ else
+ abfd->flags |= HAS_RELOC;
+ }
+
+ for (sec = abfd->sections; sec; sec = sec->next)
+ {
+ d = elf_section_data (sec);
+
+ if (d->this_hdr.sh_type != SHT_GROUP)
+ d->this_idx = section_number++;
+ if (d->this_hdr.sh_name != (unsigned int) -1)
+ _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name);
+ if (d->rel.hdr)
+ {
+ d->rel.idx = section_number++;
+ if (d->rel.hdr->sh_name != (unsigned int) -1)
+ _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel.hdr->sh_name);
+ }
+ else
+ d->rel.idx = 0;
+
+ if (d->rela.hdr)
+ {
+ d->rela.idx = section_number++;
+ if (d->rela.hdr->sh_name != (unsigned int) -1)
+ _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rela.hdr->sh_name);
+ }
+ else
+ d->rela.idx = 0;
+ }
+
+ need_symtab = (bfd_get_symcount (abfd) > 0
+ || (link_info == NULL
+ && ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC))
+ == HAS_RELOC)));
+ if (need_symtab)
+ {
+ elf_onesymtab (abfd) = section_number++;
+ _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name);
+ if (section_number > ((SHN_LORESERVE - 2) & 0xFFFF))
+ {
+ elf_section_list *entry;
+
+ BFD_ASSERT (elf_symtab_shndx_list (abfd) == NULL);
+
+ entry = bfd_zalloc (abfd, sizeof (*entry));
+ entry->ndx = section_number++;
+ elf_symtab_shndx_list (abfd) = entry;
+ entry->hdr.sh_name
+ = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+ ".symtab_shndx", false);
+ if (entry->hdr.sh_name == (unsigned int) -1)
+ return false;
+ }
+ elf_strtab_sec (abfd) = section_number++;
+ _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
+ }
+
+ elf_shstrtab_sec (abfd) = section_number++;
+ _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
+ elf_elfheader (abfd)->e_shstrndx = elf_shstrtab_sec (abfd);
+
+ if (section_number >= SHN_LORESERVE)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: too many sections: %u"),
+ abfd, section_number);
+ return false;
+ }
+
+ elf_numsections (abfd) = section_number;
+ elf_elfheader (abfd)->e_shnum = section_number;
+
+ /* Set up the list of section header pointers, in agreement with the
+ indices. */
+ amt = section_number * sizeof (Elf_Internal_Shdr *);
+ i_shdrp = (Elf_Internal_Shdr **) bfd_zalloc (abfd, amt);
+ if (i_shdrp == NULL)
+ return false;
+
+ i_shdrp[0] = (Elf_Internal_Shdr *) bfd_zalloc (abfd,
+ sizeof (Elf_Internal_Shdr));
+ if (i_shdrp[0] == NULL)
+ {
+ bfd_release (abfd, i_shdrp);
+ return false;
+ }
+
+ elf_elfsections (abfd) = i_shdrp;
+
+ i_shdrp[elf_shstrtab_sec (abfd)] = &t->shstrtab_hdr;
+ if (need_symtab)
+ {
+ i_shdrp[elf_onesymtab (abfd)] = &t->symtab_hdr;
+ if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
+ {
+ elf_section_list * entry = elf_symtab_shndx_list (abfd);
+ BFD_ASSERT (entry != NULL);
+ i_shdrp[entry->ndx] = & entry->hdr;
+ entry->hdr.sh_link = elf_onesymtab (abfd);
+ }
+ i_shdrp[elf_strtab_sec (abfd)] = &t->strtab_hdr;
+ t->symtab_hdr.sh_link = elf_strtab_sec (abfd);
+ }
+
+ for (sec = abfd->sections; sec; sec = sec->next)
+ {
+ asection *s;
+
+ d = elf_section_data (sec);
+
+ i_shdrp[d->this_idx] = &d->this_hdr;
+ if (d->rel.idx != 0)
+ i_shdrp[d->rel.idx] = d->rel.hdr;
+ if (d->rela.idx != 0)
+ i_shdrp[d->rela.idx] = d->rela.hdr;
+
+ /* Fill in the sh_link and sh_info fields while we're at it. */
+
+ /* sh_link of a reloc section is the section index of the symbol
+ table. sh_info is the section index of the section to which
+ the relocation entries apply. */
+ if (d->rel.idx != 0)
+ {
+ d->rel.hdr->sh_link = elf_onesymtab (abfd);
+ d->rel.hdr->sh_info = d->this_idx;
+ d->rel.hdr->sh_flags |= SHF_INFO_LINK;
+ }
+ if (d->rela.idx != 0)
+ {
+ d->rela.hdr->sh_link = elf_onesymtab (abfd);
+ d->rela.hdr->sh_info = d->this_idx;
+ d->rela.hdr->sh_flags |= SHF_INFO_LINK;
+ }
+
+ /* We need to set up sh_link for SHF_LINK_ORDER. */
+ if ((d->this_hdr.sh_flags & SHF_LINK_ORDER) != 0)
+ {
+ s = elf_linked_to_section (sec);
+ /* We can now have a NULL linked section pointer.
+ This happens when the sh_link field is 0, which is done
+ when a linked to section is discarded but the linking
+ section has been retained for some reason. */
+ if (s)
+ {
+ /* Check discarded linkonce section. */
+ if (discarded_section (s))
+ {
+ asection *kept;
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: sh_link of section `%pA' points to"
+ " discarded section `%pA' of `%pB'"),
+ abfd, d->this_hdr.bfd_section, s, s->owner);
+ /* Point to the kept section if it has the same
+ size as the discarded one. */
+ kept = _bfd_elf_check_kept_section (s, link_info);
+ if (kept == NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ s = kept;
+ }
+ /* Handle objcopy. */
+ else if (s->output_section == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: sh_link of section `%pA' points to"
+ " removed section `%pA' of `%pB'"),
+ abfd, d->this_hdr.bfd_section, s, s->owner);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ s = s->output_section;
+ d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+ }
+ }
+
+ switch (d->this_hdr.sh_type)
+ {
+ case SHT_REL:
+ case SHT_RELA:
+ /* A reloc section which we are treating as a normal BFD
+ section. sh_link is the section index of the symbol
+ table. sh_info is the section index of the section to
+ which the relocation entries apply. We assume that an
+ allocated reloc section uses the dynamic symbol table
+ if there is one. Otherwise we guess the normal symbol
+ table. FIXME: How can we be sure? */
+ if (d->this_hdr.sh_link == 0 && (sec->flags & SEC_ALLOC) != 0)
+ {
+ s = bfd_get_section_by_name (abfd, ".dynsym");
+ if (s != NULL)
+ d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+ }
+ if (d->this_hdr.sh_link == 0)
+ d->this_hdr.sh_link = elf_onesymtab (abfd);
+
+ s = elf_get_reloc_section (sec);
+ if (s != NULL)
+ {
+ d->this_hdr.sh_info = elf_section_data (s)->this_idx;
+ d->this_hdr.sh_flags |= SHF_INFO_LINK;
+ }
+ break;
+
+ case SHT_STRTAB:
+ /* We assume that a section named .stab*str is a stabs
+ string section. We look for a section with the same name
+ but without the trailing ``str'', and set its sh_link
+ field to point to this section. */
+ if (startswith (sec->name, ".stab")
+ && strcmp (sec->name + strlen (sec->name) - 3, "str") == 0)
+ {
+ size_t len;
+ char *alc;
+
+ len = strlen (sec->name);
+ alc = (char *) bfd_malloc (len - 2);
+ if (alc == NULL)
+ return false;
+ memcpy (alc, sec->name, len - 3);
+ alc[len - 3] = '\0';
+ s = bfd_get_section_by_name (abfd, alc);
+ free (alc);
+ if (s != NULL)
+ {
+ elf_section_data (s)->this_hdr.sh_link = d->this_idx;
+
+ /* This is a .stab section. */
+ elf_section_data (s)->this_hdr.sh_entsize = 12;
+ }
+ }
+ break;
+
+ case SHT_DYNAMIC:
+ case SHT_DYNSYM:
+ case SHT_GNU_verneed:
+ case SHT_GNU_verdef:
+ /* sh_link is the section header index of the string table
+ used for the dynamic entries, or the symbol table, or the
+ version strings. */
+ s = bfd_get_section_by_name (abfd, ".dynstr");
+ if (s != NULL)
+ d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+ break;
+
+ case SHT_GNU_LIBLIST:
+ /* sh_link is the section header index of the prelink library
+ list used for the dynamic entries, or the symbol table, or
+ the version strings. */
+ s = bfd_get_section_by_name (abfd, ((sec->flags & SEC_ALLOC)
+ ? ".dynstr" : ".gnu.libstr"));
+ if (s != NULL)
+ d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+ break;
+
+ case SHT_HASH:
+ case SHT_GNU_HASH:
+ case SHT_GNU_versym:
+ /* sh_link is the section header index of the symbol table
+ this hash table or version table is for. */
+ s = bfd_get_section_by_name (abfd, ".dynsym");
+ if (s != NULL)
+ d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+ break;
+
+ case SHT_GROUP:
+ d->this_hdr.sh_link = elf_onesymtab (abfd);
+ }
+ }
+
+ /* Delay setting sh_name to _bfd_elf_write_object_contents so that
+ _bfd_elf_assign_file_positions_for_non_load can convert DWARF
+ debug section name from .debug_* to .zdebug_* if needed. */
+
+ return true;
+}
+
+static bool
+sym_is_global (bfd *abfd, asymbol *sym)
+{
+ /* If the backend has a special mapping, use it. */
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_sym_is_global)
+ return (*bed->elf_backend_sym_is_global) (abfd, sym);
+
+ return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0
+ || bfd_is_und_section (bfd_asymbol_section (sym))
+ || bfd_is_com_section (bfd_asymbol_section (sym)));
+}
+
+/* Filter global symbols of ABFD to include in the import library. All
+ SYMCOUNT symbols of ABFD can be examined from their pointers in
+ SYMS. Pointers of symbols to keep should be stored contiguously at
+ the beginning of that array.
+
+ Returns the number of symbols to keep. */
+
+unsigned int
+_bfd_elf_filter_global_symbols (bfd *abfd, struct bfd_link_info *info,
+ asymbol **syms, long symcount)
+{
+ long src_count, dst_count = 0;
+
+ for (src_count = 0; src_count < symcount; src_count++)
+ {
+ asymbol *sym = syms[src_count];
+ char *name = (char *) bfd_asymbol_name (sym);
+ struct bfd_link_hash_entry *h;
+
+ if (!sym_is_global (abfd, sym))
+ continue;
+
+ h = bfd_link_hash_lookup (info->hash, name, false, false, false);
+ if (h == NULL)
+ continue;
+ if (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak)
+ continue;
+ if (h->linker_def || h->ldscript_def)
+ continue;
+
+ syms[dst_count++] = sym;
+ }
+
+ syms[dst_count] = NULL;
+
+ return dst_count;
+}
+
+/* Don't output section symbols for sections that are not going to be
+ output, that are duplicates or there is no BFD section. */
+
+static bool
+ignore_section_sym (bfd *abfd, asymbol *sym)
+{
+ elf_symbol_type *type_ptr;
+
+ if (sym == NULL)
+ return false;
+
+ if ((sym->flags & BSF_SECTION_SYM) == 0)
+ return false;
+
+ /* Ignore the section symbol if it isn't used. */
+ if ((sym->flags & BSF_SECTION_SYM_USED) == 0)
+ return true;
+
+ if (sym->section == NULL)
+ return true;
+
+ type_ptr = elf_symbol_from (sym);
+ return ((type_ptr != NULL
+ && type_ptr->internal_elf_sym.st_shndx != 0
+ && bfd_is_abs_section (sym->section))
+ || !(sym->section->owner == abfd
+ || (sym->section->output_section != NULL
+ && sym->section->output_section->owner == abfd
+ && sym->section->output_offset == 0)
+ || bfd_is_abs_section (sym->section)));
+}
+
+/* Map symbol from it's internal number to the external number, moving
+ all local symbols to be at the head of the list. */
+
+static bool
+elf_map_symbols (bfd *abfd, unsigned int *pnum_locals)
+{
+ unsigned int symcount = bfd_get_symcount (abfd);
+ asymbol **syms = bfd_get_outsymbols (abfd);
+ asymbol **sect_syms;
+ unsigned int num_locals = 0;
+ unsigned int num_globals = 0;
+ unsigned int num_locals2 = 0;
+ unsigned int num_globals2 = 0;
+ unsigned int max_index = 0;
+ unsigned int idx;
+ asection *asect;
+ asymbol **new_syms;
+ size_t amt;
+
+#ifdef DEBUG
+ fprintf (stderr, "elf_map_symbols\n");
+ fflush (stderr);
+#endif
+
+ for (asect = abfd->sections; asect; asect = asect->next)
+ {
+ if (max_index < asect->index)
+ max_index = asect->index;
+ }
+
+ max_index++;
+ amt = max_index * sizeof (asymbol *);
+ sect_syms = (asymbol **) bfd_zalloc (abfd, amt);
+ if (sect_syms == NULL)
+ return false;
+ elf_section_syms (abfd) = sect_syms;
+ elf_num_section_syms (abfd) = max_index;
+
+ /* Init sect_syms entries for any section symbols we have already
+ decided to output. */
+ for (idx = 0; idx < symcount; idx++)
+ {
+ asymbol *sym = syms[idx];
+
+ if ((sym->flags & BSF_SECTION_SYM) != 0
+ && sym->value == 0
+ && !ignore_section_sym (abfd, sym)
+ && !bfd_is_abs_section (sym->section))
+ {
+ asection *sec = sym->section;
+
+ if (sec->owner != abfd)
+ sec = sec->output_section;
+
+ sect_syms[sec->index] = syms[idx];
+ }
+ }
+
+ /* Classify all of the symbols. */
+ for (idx = 0; idx < symcount; idx++)
+ {
+ if (sym_is_global (abfd, syms[idx]))
+ num_globals++;
+ else if (!ignore_section_sym (abfd, syms[idx]))
+ num_locals++;
+ }
+
+ /* We will be adding a section symbol for each normal BFD section. Most
+ sections will already have a section symbol in outsymbols, but
+ eg. SHT_GROUP sections will not, and we need the section symbol mapped
+ at least in that case. */
+ for (asect = abfd->sections; asect; asect = asect->next)
+ {
+ asymbol *sym = asect->symbol;
+ /* Don't include ignored section symbols. */
+ if (!ignore_section_sym (abfd, sym)
+ && sect_syms[asect->index] == NULL)
+ {
+ if (!sym_is_global (abfd, asect->symbol))
+ num_locals++;
+ else
+ num_globals++;
+ }
+ }
+
+ /* Now sort the symbols so the local symbols are first. */
+ amt = (num_locals + num_globals) * sizeof (asymbol *);
+ new_syms = (asymbol **) bfd_alloc (abfd, amt);
+ if (new_syms == NULL)
+ return false;
+
+ for (idx = 0; idx < symcount; idx++)
+ {
+ asymbol *sym = syms[idx];
+ unsigned int i;
+
+ if (sym_is_global (abfd, sym))
+ i = num_locals + num_globals2++;
+ /* Don't include ignored section symbols. */
+ else if (!ignore_section_sym (abfd, sym))
+ i = num_locals2++;
+ else
+ continue;
+ new_syms[i] = sym;
+ sym->udata.i = i + 1;
+ }
+ for (asect = abfd->sections; asect; asect = asect->next)
+ {
+ asymbol *sym = asect->symbol;
+ if (!ignore_section_sym (abfd, sym)
+ && sect_syms[asect->index] == NULL)
+ {
+ unsigned int i;
+
+ sect_syms[asect->index] = sym;
+ if (!sym_is_global (abfd, sym))
+ i = num_locals2++;
+ else
+ i = num_locals + num_globals2++;
+ new_syms[i] = sym;
+ sym->udata.i = i + 1;
+ }
+ }
+
+ bfd_set_symtab (abfd, new_syms, num_locals + num_globals);
+
+ *pnum_locals = num_locals;
+ return true;
+}
+
+/* Align to the maximum file alignment that could be required for any
+ ELF data structure. */
+
+static inline file_ptr
+align_file_position (file_ptr off, int align)
+{
+ return (off + align - 1) & ~(align - 1);
+}
+
+/* Assign a file position to a section, optionally aligning to the
+ required section alignment. */
+
+file_ptr
+_bfd_elf_assign_file_position_for_section (Elf_Internal_Shdr *i_shdrp,
+ file_ptr offset,
+ bool align)
+{
+ if (align && i_shdrp->sh_addralign > 1)
+ offset = BFD_ALIGN (offset, i_shdrp->sh_addralign & -i_shdrp->sh_addralign);
+ i_shdrp->sh_offset = offset;
+ if (i_shdrp->bfd_section != NULL)
+ i_shdrp->bfd_section->filepos = offset;
+ if (i_shdrp->sh_type != SHT_NOBITS)
+ offset += i_shdrp->sh_size;
+ return offset;
+}
+
+/* Compute the file positions we are going to put the sections at, and
+ otherwise prepare to begin writing out the ELF file. If LINK_INFO
+ is not NULL, this is being called by the ELF backend linker. */
+
+bool
+_bfd_elf_compute_section_file_positions (bfd *abfd,
+ struct bfd_link_info *link_info)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ struct fake_section_arg fsargs;
+ bool failed;
+ struct elf_strtab_hash *strtab = NULL;
+ Elf_Internal_Shdr *shstrtab_hdr;
+ bool need_symtab;
+
+ if (abfd->output_has_begun)
+ return true;
+
+ /* Do any elf backend specific processing first. */
+ if (bed->elf_backend_begin_write_processing)
+ (*bed->elf_backend_begin_write_processing) (abfd, link_info);
+
+ if (!(*bed->elf_backend_init_file_header) (abfd, link_info))
+ return false;
+
+ fsargs.failed = false;
+ fsargs.link_info = link_info;
+ bfd_map_over_sections (abfd, elf_fake_sections, &fsargs);
+ if (fsargs.failed)
+ return false;
+
+ if (!assign_section_numbers (abfd, link_info))
+ return false;
+
+ /* The backend linker builds symbol table information itself. */
+ need_symtab = (link_info == NULL
+ && (bfd_get_symcount (abfd) > 0
+ || ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC))
+ == HAS_RELOC)));
+ if (need_symtab)
+ {
+ /* Non-zero if doing a relocatable link. */
+ int relocatable_p = ! (abfd->flags & (EXEC_P | DYNAMIC));
+
+ if (! swap_out_syms (abfd, &strtab, relocatable_p, link_info))
+ return false;
+ }
+
+ failed = false;
+ if (link_info == NULL)
+ {
+ bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed);
+ if (failed)
+ return false;
+ }
+
+ shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr;
+ /* sh_name was set in init_file_header. */
+ shstrtab_hdr->sh_type = SHT_STRTAB;
+ shstrtab_hdr->sh_flags = bed->elf_strtab_flags;
+ shstrtab_hdr->sh_addr = 0;
+ /* sh_size is set in _bfd_elf_assign_file_positions_for_non_load. */
+ shstrtab_hdr->sh_entsize = 0;
+ shstrtab_hdr->sh_link = 0;
+ shstrtab_hdr->sh_info = 0;
+ /* sh_offset is set in _bfd_elf_assign_file_positions_for_non_load. */
+ shstrtab_hdr->sh_addralign = 1;
+
+ if (!assign_file_positions_except_relocs (abfd, link_info))
+ return false;
+
+ if (need_symtab)
+ {
+ file_ptr off;
+ Elf_Internal_Shdr *hdr;
+
+ off = elf_next_file_pos (abfd);
+
+ hdr = & elf_symtab_hdr (abfd);
+ off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+
+ if (elf_symtab_shndx_list (abfd) != NULL)
+ {
+ hdr = & elf_symtab_shndx_list (abfd)->hdr;
+ if (hdr->sh_size != 0)
+ off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+ /* FIXME: What about other symtab_shndx sections in the list ? */
+ }
+
+ hdr = &elf_tdata (abfd)->strtab_hdr;
+ off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+
+ elf_next_file_pos (abfd) = off;
+
+ /* Now that we know where the .strtab section goes, write it
+ out. */
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
+ || ! _bfd_elf_strtab_emit (abfd, strtab))
+ return false;
+ _bfd_elf_strtab_free (strtab);
+ }
+
+ abfd->output_has_begun = true;
+
+ return true;
+}
+
+/* Retrieve .eh_frame_hdr. Prior to size_dynamic_sections the
+ function effectively returns whether --eh-frame-hdr is given on the
+ command line. After size_dynamic_sections the result reflects
+ whether .eh_frame_hdr will actually be output (sizing isn't done
+ until ldemul_after_allocation). */
+
+static asection *
+elf_eh_frame_hdr (const struct bfd_link_info *info)
+{
+ if (info != NULL && is_elf_hash_table (info->hash))
+ return elf_hash_table (info)->eh_info.hdr_sec;
+ return NULL;
+}
+
+/* Make an initial estimate of the size of the program header. If we
+ get the number wrong here, we'll redo section placement. */
+
+static bfd_size_type
+get_program_header_size (bfd *abfd, struct bfd_link_info *info)
+{
+ size_t segs;
+ asection *s;
+ const struct elf_backend_data *bed;
+
+ /* Assume we will need exactly two PT_LOAD segments: one for text
+ and one for data. */
+ segs = 2;
+
+ s = bfd_get_section_by_name (abfd, ".interp");
+ if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->size != 0)
+ {
+ /* If we have a loadable interpreter section, we need a
+ PT_INTERP segment. In this case, assume we also need a
+ PT_PHDR segment, although that may not be true for all
+ targets. */
+ segs += 2;
+ }
+
+ if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
+ {
+ /* We need a PT_DYNAMIC segment. */
+ ++segs;
+ }
+
+ if (info != NULL && info->relro)
+ {
+ /* We need a PT_GNU_RELRO segment. */
+ ++segs;
+ }
+
+ if (elf_eh_frame_hdr (info))
+ {
+ /* We need a PT_GNU_EH_FRAME segment. */
+ ++segs;
+ }
+
+ if (elf_stack_flags (abfd))
+ {
+ /* We need a PT_GNU_STACK segment. */
+ ++segs;
+ }
+
+ if (elf_sframe (abfd))
+ {
+ /* We need a PT_GNU_SFRAME segment. */
+ ++segs;
+ }
+
+ s = bfd_get_section_by_name (abfd,
+ NOTE_GNU_PROPERTY_SECTION_NAME);
+ if (s != NULL && s->size != 0)
+ {
+ /* We need a PT_GNU_PROPERTY segment. */
+ ++segs;
+ }
+
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) != 0
+ && elf_section_type (s) == SHT_NOTE)
+ {
+ unsigned int alignment_power;
+ /* We need a PT_NOTE segment. */
+ ++segs;
+ /* Try to create just one PT_NOTE segment for all adjacent
+ loadable SHT_NOTE sections. gABI requires that within a
+ PT_NOTE segment (and also inside of each SHT_NOTE section)
+ each note should have the same alignment. So we check
+ whether the sections are correctly aligned. */
+ alignment_power = s->alignment_power;
+ while (s->next != NULL
+ && s->next->alignment_power == alignment_power
+ && (s->next->flags & SEC_LOAD) != 0
+ && elf_section_type (s->next) == SHT_NOTE)
+ s = s->next;
+ }
+ }
+
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if (s->flags & SEC_THREAD_LOCAL)
+ {
+ /* We need a PT_TLS segment. */
+ ++segs;
+ break;
+ }
+ }
+
+ bed = get_elf_backend_data (abfd);
+
+ if ((abfd->flags & D_PAGED) != 0
+ && (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_mbind) != 0)
+ {
+ /* Add a PT_GNU_MBIND segment for each mbind section. */
+ bfd_vma commonpagesize;
+ unsigned int page_align_power;
+
+ if (info != NULL)
+ commonpagesize = info->commonpagesize;
+ else
+ commonpagesize = bed->commonpagesize;
+ page_align_power = bfd_log2 (commonpagesize);
+ for (s = abfd->sections; s != NULL; s = s->next)
+ if (elf_section_flags (s) & SHF_GNU_MBIND)
+ {
+ if (elf_section_data (s)->this_hdr.sh_info > PT_GNU_MBIND_NUM)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: GNU_MBIND section `%pA' has invalid "
+ "sh_info field: %d"),
+ abfd, s, elf_section_data (s)->this_hdr.sh_info);
+ continue;
+ }
+ /* Align mbind section to page size. */
+ if (s->alignment_power < page_align_power)
+ s->alignment_power = page_align_power;
+ segs ++;
+ }
+ }
+
+ /* Let the backend count up any program headers it might need. */
+ if (bed->elf_backend_additional_program_headers)
+ {
+ int a;
+
+ a = (*bed->elf_backend_additional_program_headers) (abfd, info);
+ if (a == -1)
+ abort ();
+ segs += a;
+ }
+
+ return segs * bed->s->sizeof_phdr;
+}
+
+/* Find the segment that contains the output_section of section. */
+
+Elf_Internal_Phdr *
+_bfd_elf_find_segment_containing_section (bfd * abfd, asection * section)
+{
+ struct elf_segment_map *m;
+ Elf_Internal_Phdr *p;
+
+ for (m = elf_seg_map (abfd), p = elf_tdata (abfd)->phdr;
+ m != NULL;
+ m = m->next, p++)
+ {
+ int i;
+
+ for (i = m->count - 1; i >= 0; i--)
+ if (m->sections[i] == section)
+ return p;
+ }
+
+ return NULL;
+}
+
+/* Create a mapping from a set of sections to a program segment. */
+
+static struct elf_segment_map *
+make_mapping (bfd *abfd,
+ asection **sections,
+ unsigned int from,
+ unsigned int to,
+ bool phdr)
+{
+ struct elf_segment_map *m;
+ unsigned int i;
+ asection **hdrpp;
+ size_t amt;
+
+ amt = sizeof (struct elf_segment_map) - sizeof (asection *);
+ amt += (to - from) * sizeof (asection *);
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ return NULL;
+ m->next = NULL;
+ m->p_type = PT_LOAD;
+ for (i = from, hdrpp = sections + from; i < to; i++, hdrpp++)
+ m->sections[i - from] = *hdrpp;
+ m->count = to - from;
+
+ if (from == 0 && phdr)
+ {
+ /* Include the headers in the first PT_LOAD segment. */
+ m->includes_filehdr = 1;
+ m->includes_phdrs = 1;
+ }
+
+ return m;
+}
+
+/* Create the PT_DYNAMIC segment, which includes DYNSEC. Returns NULL
+ on failure. */
+
+struct elf_segment_map *
+_bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec)
+{
+ struct elf_segment_map *m;
+
+ m = (struct elf_segment_map *) bfd_zalloc (abfd,
+ sizeof (struct elf_segment_map));
+ if (m == NULL)
+ return NULL;
+ m->next = NULL;
+ m->p_type = PT_DYNAMIC;
+ m->count = 1;
+ m->sections[0] = dynsec;
+
+ return m;
+}
+
+/* Possibly add or remove segments from the segment map. */
+
+static bool
+elf_modify_segment_map (bfd *abfd,
+ struct bfd_link_info *info,
+ bool remove_empty_load)
+{
+ struct elf_segment_map **m;
+ const struct elf_backend_data *bed;
+
+ /* The placement algorithm assumes that non allocated sections are
+ not in PT_LOAD segments. We ensure this here by removing such
+ sections from the segment map. We also remove excluded
+ sections. Finally, any PT_LOAD segment without sections is
+ removed. */
+ m = &elf_seg_map (abfd);
+ while (*m)
+ {
+ unsigned int i, new_count;
+
+ for (new_count = 0, i = 0; i < (*m)->count; i++)
+ {
+ if (((*m)->sections[i]->flags & SEC_EXCLUDE) == 0
+ && (((*m)->sections[i]->flags & SEC_ALLOC) != 0
+ || (*m)->p_type != PT_LOAD))
+ {
+ (*m)->sections[new_count] = (*m)->sections[i];
+ new_count++;
+ }
+ }
+ (*m)->count = new_count;
+
+ if (remove_empty_load
+ && (*m)->p_type == PT_LOAD
+ && (*m)->count == 0
+ && !(*m)->includes_phdrs)
+ *m = (*m)->next;
+ else
+ m = &(*m)->next;
+ }
+
+ bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_modify_segment_map != NULL)
+ {
+ if (!(*bed->elf_backend_modify_segment_map) (abfd, info))
+ return false;
+ }
+
+ return true;
+}
+
+#define IS_TBSS(s) \
+ ((s->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) == SEC_THREAD_LOCAL)
+
+/* Set up a mapping from BFD sections to program segments. Update
+ NEED_LAYOUT if the section layout is changed. */
+
+bool
+_bfd_elf_map_sections_to_segments (bfd *abfd,
+ struct bfd_link_info *info,
+ bool *need_layout)
+{
+ unsigned int count;
+ struct elf_segment_map *m;
+ asection **sections = NULL;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ bool no_user_phdrs;
+
+ no_user_phdrs = elf_seg_map (abfd) == NULL;
+
+ if (info != NULL)
+ {
+ info->user_phdrs = !no_user_phdrs;
+
+ /* Size the relative relocations if DT_RELR is enabled. */
+ if (info->enable_dt_relr
+ && need_layout != NULL
+ && bed->size_relative_relocs
+ && !bed->size_relative_relocs (info, need_layout))
+ info->callbacks->einfo
+ (_("%F%P: failed to size relative relocations\n"));
+ }
+
+ if (no_user_phdrs && bfd_count_sections (abfd) != 0)
+ {
+ asection *s;
+ unsigned int i;
+ struct elf_segment_map *mfirst;
+ struct elf_segment_map **pm;
+ asection *last_hdr;
+ bfd_vma last_size;
+ unsigned int hdr_index;
+ bfd_vma maxpagesize;
+ asection **hdrpp;
+ bool phdr_in_segment;
+ bool writable;
+ bool executable;
+ unsigned int tls_count = 0;
+ asection *first_tls = NULL;
+ asection *first_mbind = NULL;
+ asection *dynsec, *eh_frame_hdr;
+ asection *sframe;
+ size_t amt;
+ bfd_vma addr_mask, wrap_to = 0; /* Bytes. */
+ bfd_size_type phdr_size; /* Octets/bytes. */
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
+
+ /* Select the allocated sections, and sort them. */
+
+ amt = bfd_count_sections (abfd) * sizeof (asection *);
+ sections = (asection **) bfd_malloc (amt);
+ if (sections == NULL)
+ goto error_return;
+
+ /* Calculate top address, avoiding undefined behaviour of shift
+ left operator when shift count is equal to size of type
+ being shifted. */
+ addr_mask = ((bfd_vma) 1 << (bfd_arch_bits_per_address (abfd) - 1)) - 1;
+ addr_mask = (addr_mask << 1) + 1;
+
+ i = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_ALLOC) != 0)
+ {
+ /* target_index is unused until bfd_elf_final_link
+ starts output of section symbols. Use it to make
+ qsort stable. */
+ s->target_index = i;
+ sections[i] = s;
+ ++i;
+ /* A wrapping section potentially clashes with header. */
+ if (((s->lma + s->size / opb) & addr_mask) < (s->lma & addr_mask))
+ wrap_to = (s->lma + s->size / opb) & addr_mask;
+ }
+ }
+ BFD_ASSERT (i <= bfd_count_sections (abfd));
+ count = i;
+
+ qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections);
+
+ phdr_size = elf_program_header_size (abfd);
+ if (phdr_size == (bfd_size_type) -1)
+ phdr_size = get_program_header_size (abfd, info);
+ phdr_size += bed->s->sizeof_ehdr;
+ /* phdr_size is compared to LMA values which are in bytes. */
+ phdr_size /= opb;
+ if (info != NULL)
+ maxpagesize = info->maxpagesize;
+ else
+ maxpagesize = bed->maxpagesize;
+ if (maxpagesize == 0)
+ maxpagesize = 1;
+ phdr_in_segment = info != NULL && info->load_phdrs;
+ if (count != 0
+ && (((sections[0]->lma & addr_mask) & (maxpagesize - 1))
+ >= (phdr_size & (maxpagesize - 1))))
+ /* For compatibility with old scripts that may not be using
+ SIZEOF_HEADERS, add headers when it looks like space has
+ been left for them. */
+ phdr_in_segment = true;
+
+ /* Build the mapping. */
+ mfirst = NULL;
+ pm = &mfirst;
+
+ /* If we have a .interp section, then create a PT_PHDR segment for
+ the program headers and a PT_INTERP segment for the .interp
+ section. */
+ s = bfd_get_section_by_name (abfd, ".interp");
+ if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->size != 0)
+ {
+ amt = sizeof (struct elf_segment_map);
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_PHDR;
+ m->p_flags = PF_R;
+ m->p_flags_valid = 1;
+ m->includes_phdrs = 1;
+ phdr_in_segment = true;
+ *pm = m;
+ pm = &m->next;
+
+ amt = sizeof (struct elf_segment_map);
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_INTERP;
+ m->count = 1;
+ m->sections[0] = s;
+
+ *pm = m;
+ pm = &m->next;
+ }
+
+ /* Look through the sections. We put sections in the same program
+ segment when the start of the second section can be placed within
+ a few bytes of the end of the first section. */
+ last_hdr = NULL;
+ last_size = 0;
+ hdr_index = 0;
+ writable = false;
+ executable = false;
+ dynsec = bfd_get_section_by_name (abfd, ".dynamic");
+ if (dynsec != NULL
+ && (dynsec->flags & SEC_LOAD) == 0)
+ dynsec = NULL;
+
+ if ((abfd->flags & D_PAGED) == 0)
+ phdr_in_segment = false;
+
+ /* Deal with -Ttext or something similar such that the first section
+ is not adjacent to the program headers. This is an
+ approximation, since at this point we don't know exactly how many
+ program headers we will need. */
+ if (phdr_in_segment && count > 0)
+ {
+ bfd_vma phdr_lma; /* Bytes. */
+ bool separate_phdr = false;
+
+ phdr_lma = (sections[0]->lma - phdr_size) & addr_mask & -maxpagesize;
+ if (info != NULL
+ && info->separate_code
+ && (sections[0]->flags & SEC_CODE) != 0)
+ {
+ /* If data sections should be separate from code and
+ thus not executable, and the first section is
+ executable then put the file and program headers in
+ their own PT_LOAD. */
+ separate_phdr = true;
+ if ((((phdr_lma + phdr_size - 1) & addr_mask & -maxpagesize)
+ == (sections[0]->lma & addr_mask & -maxpagesize)))
+ {
+ /* The file and program headers are currently on the
+ same page as the first section. Put them on the
+ previous page if we can. */
+ if (phdr_lma >= maxpagesize)
+ phdr_lma -= maxpagesize;
+ else
+ separate_phdr = false;
+ }
+ }
+ if ((sections[0]->lma & addr_mask) < phdr_lma
+ || (sections[0]->lma & addr_mask) < phdr_size)
+ /* If file and program headers would be placed at the end
+ of memory then it's probably better to omit them. */
+ phdr_in_segment = false;
+ else if (phdr_lma < wrap_to)
+ /* If a section wraps around to where we'll be placing
+ file and program headers, then the headers will be
+ overwritten. */
+ phdr_in_segment = false;
+ else if (separate_phdr)
+ {
+ m = make_mapping (abfd, sections, 0, 0, phdr_in_segment);
+ if (m == NULL)
+ goto error_return;
+ m->p_paddr = phdr_lma * opb;
+ m->p_vaddr_offset
+ = (sections[0]->vma - phdr_size) & addr_mask & -maxpagesize;
+ m->p_paddr_valid = 1;
+ *pm = m;
+ pm = &m->next;
+ phdr_in_segment = false;
+ }
+ }
+
+ for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
+ {
+ asection *hdr;
+ bool new_segment;
+
+ hdr = *hdrpp;
+
+ /* See if this section and the last one will fit in the same
+ segment. */
+
+ if (last_hdr == NULL)
+ {
+ /* If we don't have a segment yet, then we don't need a new
+ one (we build the last one after this loop). */
+ new_segment = false;
+ }
+ else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma)
+ {
+ /* If this section has a different relation between the
+ virtual address and the load address, then we need a new
+ segment. */
+ new_segment = true;
+ }
+ else if (hdr->lma < last_hdr->lma + last_size
+ || last_hdr->lma + last_size < last_hdr->lma)
+ {
+ /* If this section has a load address that makes it overlap
+ the previous section, then we need a new segment. */
+ new_segment = true;
+ }
+ else if ((abfd->flags & D_PAGED) != 0
+ && (((last_hdr->lma + last_size - 1) & -maxpagesize)
+ == (hdr->lma & -maxpagesize)))
+ {
+ /* If we are demand paged then we can't map two disk
+ pages onto the same memory page. */
+ new_segment = false;
+ }
+ /* In the next test we have to be careful when last_hdr->lma is close
+ to the end of the address space. If the aligned address wraps
+ around to the start of the address space, then there are no more
+ pages left in memory and it is OK to assume that the current
+ section can be included in the current segment. */
+ else if ((BFD_ALIGN (last_hdr->lma + last_size, maxpagesize)
+ + maxpagesize > last_hdr->lma)
+ && (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize)
+ + maxpagesize <= hdr->lma))
+ {
+ /* If putting this section in this segment would force us to
+ skip a page in the segment, then we need a new segment. */
+ new_segment = true;
+ }
+ else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0
+ && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0)
+ {
+ /* We don't want to put a loaded section after a
+ nonloaded (ie. bss style) section in the same segment
+ as that will force the non-loaded section to be loaded.
+ Consider .tbss sections as loaded for this purpose. */
+ new_segment = true;
+ }
+ else if ((abfd->flags & D_PAGED) == 0)
+ {
+ /* If the file is not demand paged, which means that we
+ don't require the sections to be correctly aligned in the
+ file, then there is no other reason for a new segment. */
+ new_segment = false;
+ }
+ else if (info != NULL
+ && info->separate_code
+ && executable != ((hdr->flags & SEC_CODE) != 0))
+ {
+ new_segment = true;
+ }
+ else if (! writable
+ && (hdr->flags & SEC_READONLY) == 0)
+ {
+ /* We don't want to put a writable section in a read only
+ segment. */
+ new_segment = true;
+ }
+ else
+ {
+ /* Otherwise, we can use the same segment. */
+ new_segment = false;
+ }
+
+ /* Allow interested parties a chance to override our decision. */
+ if (last_hdr != NULL
+ && info != NULL
+ && info->callbacks->override_segment_assignment != NULL)
+ new_segment
+ = info->callbacks->override_segment_assignment (info, abfd, hdr,
+ last_hdr,
+ new_segment);
+
+ if (! new_segment)
+ {
+ if ((hdr->flags & SEC_READONLY) == 0)
+ writable = true;
+ if ((hdr->flags & SEC_CODE) != 0)
+ executable = true;
+ last_hdr = hdr;
+ /* .tbss sections effectively have zero size. */
+ last_size = (!IS_TBSS (hdr) ? hdr->size : 0) / opb;
+ continue;
+ }
+
+ /* We need a new program segment. We must create a new program
+ header holding all the sections from hdr_index until hdr. */
+
+ m = make_mapping (abfd, sections, hdr_index, i, phdr_in_segment);
+ if (m == NULL)
+ goto error_return;
+
+ *pm = m;
+ pm = &m->next;
+
+ if ((hdr->flags & SEC_READONLY) == 0)
+ writable = true;
+ else
+ writable = false;
+
+ if ((hdr->flags & SEC_CODE) == 0)
+ executable = false;
+ else
+ executable = true;
+
+ last_hdr = hdr;
+ /* .tbss sections effectively have zero size. */
+ last_size = (!IS_TBSS (hdr) ? hdr->size : 0) / opb;
+ hdr_index = i;
+ phdr_in_segment = false;
+ }
+
+ /* Create a final PT_LOAD program segment, but not if it's just
+ for .tbss. */
+ if (last_hdr != NULL
+ && (i - hdr_index != 1
+ || !IS_TBSS (last_hdr)))
+ {
+ m = make_mapping (abfd, sections, hdr_index, i, phdr_in_segment);
+ if (m == NULL)
+ goto error_return;
+
+ *pm = m;
+ pm = &m->next;
+ }
+
+ /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */
+ if (dynsec != NULL)
+ {
+ m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
+ if (m == NULL)
+ goto error_return;
+ *pm = m;
+ pm = &m->next;
+ }
+
+ /* For each batch of consecutive loadable SHT_NOTE sections,
+ add a PT_NOTE segment. We don't use bfd_get_section_by_name,
+ because if we link together nonloadable .note sections and
+ loadable .note sections, we will generate two .note sections
+ in the output file. */
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) != 0
+ && elf_section_type (s) == SHT_NOTE)
+ {
+ asection *s2;
+ unsigned int alignment_power = s->alignment_power;
+
+ count = 1;
+ for (s2 = s; s2->next != NULL; s2 = s2->next)
+ {
+ if (s2->next->alignment_power == alignment_power
+ && (s2->next->flags & SEC_LOAD) != 0
+ && elf_section_type (s2->next) == SHT_NOTE
+ && align_power (s2->lma + s2->size / opb,
+ alignment_power)
+ == s2->next->lma)
+ count++;
+ else
+ break;
+ }
+ amt = sizeof (struct elf_segment_map) - sizeof (asection *);
+ amt += count * sizeof (asection *);
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_NOTE;
+ m->count = count;
+ while (count > 1)
+ {
+ m->sections[m->count - count--] = s;
+ BFD_ASSERT ((s->flags & SEC_THREAD_LOCAL) == 0);
+ s = s->next;
+ }
+ m->sections[m->count - 1] = s;
+ BFD_ASSERT ((s->flags & SEC_THREAD_LOCAL) == 0);
+ *pm = m;
+ pm = &m->next;
+ }
+ if (s->flags & SEC_THREAD_LOCAL)
+ {
+ if (! tls_count)
+ first_tls = s;
+ tls_count++;
+ }
+ if (first_mbind == NULL
+ && (elf_section_flags (s) & SHF_GNU_MBIND) != 0)
+ first_mbind = s;
+ }
+
+ /* If there are any SHF_TLS output sections, add PT_TLS segment. */
+ if (tls_count > 0)
+ {
+ amt = sizeof (struct elf_segment_map) - sizeof (asection *);
+ amt += tls_count * sizeof (asection *);
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_TLS;
+ m->count = tls_count;
+ /* Mandated PF_R. */
+ m->p_flags = PF_R;
+ m->p_flags_valid = 1;
+ s = first_tls;
+ for (i = 0; i < tls_count; ++i)
+ {
+ if ((s->flags & SEC_THREAD_LOCAL) == 0)
+ {
+ _bfd_error_handler
+ (_("%pB: TLS sections are not adjacent:"), abfd);
+ s = first_tls;
+ i = 0;
+ while (i < tls_count)
+ {
+ if ((s->flags & SEC_THREAD_LOCAL) != 0)
+ {
+ _bfd_error_handler (_(" TLS: %pA"), s);
+ i++;
+ }
+ else
+ _bfd_error_handler (_(" non-TLS: %pA"), s);
+ s = s->next;
+ }
+ bfd_set_error (bfd_error_bad_value);
+ goto error_return;
+ }
+ m->sections[i] = s;
+ s = s->next;
+ }
+
+ *pm = m;
+ pm = &m->next;
+ }
+
+ if (first_mbind
+ && (abfd->flags & D_PAGED) != 0
+ && (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_mbind) != 0)
+ for (s = first_mbind; s != NULL; s = s->next)
+ if ((elf_section_flags (s) & SHF_GNU_MBIND) != 0
+ && elf_section_data (s)->this_hdr.sh_info <= PT_GNU_MBIND_NUM)
+ {
+ /* Mandated PF_R. */
+ unsigned long p_flags = PF_R;
+ if ((s->flags & SEC_READONLY) == 0)
+ p_flags |= PF_W;
+ if ((s->flags & SEC_CODE) != 0)
+ p_flags |= PF_X;
+
+ amt = sizeof (struct elf_segment_map) + sizeof (asection *);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = (PT_GNU_MBIND_LO
+ + elf_section_data (s)->this_hdr.sh_info);
+ m->count = 1;
+ m->p_flags_valid = 1;
+ m->sections[0] = s;
+ m->p_flags = p_flags;
+
+ *pm = m;
+ pm = &m->next;
+ }
+
+ s = bfd_get_section_by_name (abfd,
+ NOTE_GNU_PROPERTY_SECTION_NAME);
+ if (s != NULL && s->size != 0)
+ {
+ amt = sizeof (struct elf_segment_map) + sizeof (asection *);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_GNU_PROPERTY;
+ m->count = 1;
+ m->p_flags_valid = 1;
+ m->sections[0] = s;
+ m->p_flags = PF_R;
+ *pm = m;
+ pm = &m->next;
+ }
+
+ /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
+ segment. */
+ eh_frame_hdr = elf_eh_frame_hdr (info);
+ if (eh_frame_hdr != NULL
+ && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0)
+ {
+ amt = sizeof (struct elf_segment_map);
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_GNU_EH_FRAME;
+ m->count = 1;
+ m->sections[0] = eh_frame_hdr->output_section;
+
+ *pm = m;
+ pm = &m->next;
+ }
+
+ /* If there is a .sframe section, throw in a PT_GNU_SFRAME
+ segment. */
+ sframe = elf_sframe (abfd);
+ if (sframe != NULL
+ && (sframe->output_section->flags & SEC_LOAD) != 0
+ && sframe->size != 0)
+ {
+ amt = sizeof (struct elf_segment_map);
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_GNU_SFRAME;
+ m->count = 1;
+ m->sections[0] = sframe->output_section;
+
+ *pm = m;
+ pm = &m->next;
+ }
+
+ if (elf_stack_flags (abfd))
+ {
+ amt = sizeof (struct elf_segment_map);
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_GNU_STACK;
+ m->p_flags = elf_stack_flags (abfd);
+ m->p_align = bed->stack_align;
+ m->p_flags_valid = 1;
+ m->p_align_valid = m->p_align != 0;
+ if (info->stacksize > 0)
+ {
+ m->p_size = info->stacksize;
+ m->p_size_valid = 1;
+ }
+
+ *pm = m;
+ pm = &m->next;
+ }
+
+ if (info != NULL && info->relro)
+ {
+ for (m = mfirst; m != NULL; m = m->next)
+ {
+ if (m->p_type == PT_LOAD
+ && m->count != 0
+ && m->sections[0]->vma >= info->relro_start
+ && m->sections[0]->vma < info->relro_end)
+ {
+ i = m->count;
+ while (--i != (unsigned) -1)
+ {
+ if (m->sections[i]->size > 0
+ && (m->sections[i]->flags & SEC_LOAD) != 0
+ && (m->sections[i]->flags & SEC_HAS_CONTENTS) != 0)
+ break;
+ }
+
+ if (i != (unsigned) -1)
+ break;
+ }
+ }
+
+ /* Make a PT_GNU_RELRO segment only when it isn't empty. */
+ if (m != NULL)
+ {
+ amt = sizeof (struct elf_segment_map);
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_GNU_RELRO;
+ *pm = m;
+ pm = &m->next;
+ }
+ }
+
+ free (sections);
+ elf_seg_map (abfd) = mfirst;
+ }
+
+ if (!elf_modify_segment_map (abfd, info, no_user_phdrs))
+ return false;
+
+ for (count = 0, m = elf_seg_map (abfd); m != NULL; m = m->next)
+ ++count;
+ elf_program_header_size (abfd) = count * bed->s->sizeof_phdr;
+
+ return true;
+
+ error_return:
+ free (sections);
+ return false;
+}
+
+/* Sort sections by address. */
+
+static int
+elf_sort_sections (const void *arg1, const void *arg2)
+{
+ const asection *sec1 = *(const asection **) arg1;
+ const asection *sec2 = *(const asection **) arg2;
+ bfd_size_type size1, size2;
+
+ /* Sort by LMA first, since this is the address used to
+ place the section into a segment. */
+ if (sec1->lma < sec2->lma)
+ return -1;
+ else if (sec1->lma > sec2->lma)
+ return 1;
+
+ /* Then sort by VMA. Normally the LMA and the VMA will be
+ the same, and this will do nothing. */
+ if (sec1->vma < sec2->vma)
+ return -1;
+ else if (sec1->vma > sec2->vma)
+ return 1;
+
+ /* Put !SEC_LOAD sections after SEC_LOAD ones. */
+
+#define TOEND(x) (((x)->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0 \
+ && (x)->size != 0)
+
+ if (TOEND (sec1))
+ {
+ if (!TOEND (sec2))
+ return 1;
+ }
+ else if (TOEND (sec2))
+ return -1;
+
+#undef TOEND
+
+ /* Sort by size, to put zero sized sections
+ before others at the same address. */
+
+ size1 = (sec1->flags & SEC_LOAD) ? sec1->size : 0;
+ size2 = (sec2->flags & SEC_LOAD) ? sec2->size : 0;
+
+ if (size1 < size2)
+ return -1;
+ if (size1 > size2)
+ return 1;
+
+ return sec1->target_index - sec2->target_index;
+}
+
+/* This qsort comparison functions sorts PT_LOAD segments first and
+ by p_paddr, for assign_file_positions_for_load_sections. */
+
+static int
+elf_sort_segments (const void *arg1, const void *arg2)
+{
+ const struct elf_segment_map *m1 = *(const struct elf_segment_map **) arg1;
+ const struct elf_segment_map *m2 = *(const struct elf_segment_map **) arg2;
+
+ if (m1->p_type != m2->p_type)
+ {
+ if (m1->p_type == PT_NULL)
+ return 1;
+ if (m2->p_type == PT_NULL)
+ return -1;
+ return m1->p_type < m2->p_type ? -1 : 1;
+ }
+ if (m1->includes_filehdr != m2->includes_filehdr)
+ return m1->includes_filehdr ? -1 : 1;
+ if (m1->no_sort_lma != m2->no_sort_lma)
+ return m1->no_sort_lma ? -1 : 1;
+ if (m1->p_type == PT_LOAD && !m1->no_sort_lma)
+ {
+ bfd_vma lma1, lma2; /* Octets. */
+ lma1 = 0;
+ if (m1->p_paddr_valid)
+ lma1 = m1->p_paddr;
+ else if (m1->count != 0)
+ {
+ unsigned int opb = bfd_octets_per_byte (m1->sections[0]->owner,
+ m1->sections[0]);
+ lma1 = (m1->sections[0]->lma + m1->p_vaddr_offset) * opb;
+ }
+ lma2 = 0;
+ if (m2->p_paddr_valid)
+ lma2 = m2->p_paddr;
+ else if (m2->count != 0)
+ {
+ unsigned int opb = bfd_octets_per_byte (m2->sections[0]->owner,
+ m2->sections[0]);
+ lma2 = (m2->sections[0]->lma + m2->p_vaddr_offset) * opb;
+ }
+ if (lma1 != lma2)
+ return lma1 < lma2 ? -1 : 1;
+ }
+ if (m1->idx != m2->idx)
+ return m1->idx < m2->idx ? -1 : 1;
+ return 0;
+}
+
+/* Ian Lance Taylor writes:
+
+ We shouldn't be using % with a negative signed number. That's just
+ not good. We have to make sure either that the number is not
+ negative, or that the number has an unsigned type. When the types
+ are all the same size they wind up as unsigned. When file_ptr is a
+ larger signed type, the arithmetic winds up as signed long long,
+ which is wrong.
+
+ What we're trying to say here is something like ``increase OFF by
+ the least amount that will cause it to be equal to the VMA modulo
+ the page size.'' */
+/* In other words, something like:
+
+ vma_offset = m->sections[0]->vma % bed->maxpagesize;
+ off_offset = off % bed->maxpagesize;
+ if (vma_offset < off_offset)
+ adjustment = vma_offset + bed->maxpagesize - off_offset;
+ else
+ adjustment = vma_offset - off_offset;
+
+ which can be collapsed into the expression below. */
+
+static file_ptr
+vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize)
+{
+ /* PR binutils/16199: Handle an alignment of zero. */
+ if (maxpagesize == 0)
+ maxpagesize = 1;
+ return ((vma - off) % maxpagesize);
+}
+
+static void
+print_segment_map (const struct elf_segment_map *m)
+{
+ unsigned int j;
+ const char *pt = get_segment_type (m->p_type);
+ char buf[32];
+
+ if (pt == NULL)
+ {
+ if (m->p_type >= PT_LOPROC && m->p_type <= PT_HIPROC)
+ sprintf (buf, "LOPROC+%7.7x",
+ (unsigned int) (m->p_type - PT_LOPROC));
+ else if (m->p_type >= PT_LOOS && m->p_type <= PT_HIOS)
+ sprintf (buf, "LOOS+%7.7x",
+ (unsigned int) (m->p_type - PT_LOOS));
+ else
+ snprintf (buf, sizeof (buf), "%8.8x",
+ (unsigned int) m->p_type);
+ pt = buf;
+ }
+ fflush (stdout);
+ fprintf (stderr, "%s:", pt);
+ for (j = 0; j < m->count; j++)
+ fprintf (stderr, " %s", m->sections [j]->name);
+ putc ('\n',stderr);
+ fflush (stderr);
+}
+
+static bool
+write_zeros (bfd *abfd, file_ptr pos, bfd_size_type len)
+{
+ void *buf;
+ bool ret;
+
+ if (bfd_seek (abfd, pos, SEEK_SET) != 0)
+ return false;
+ buf = bfd_zmalloc (len);
+ if (buf == NULL)
+ return false;
+ ret = bfd_bwrite (buf, len, abfd) == len;
+ free (buf);
+ return ret;
+}
+
+/* Assign file positions to the sections based on the mapping from
+ sections to segments. This function also sets up some fields in
+ the file header. */
+
+static bool
+assign_file_positions_for_load_sections (bfd *abfd,
+ struct bfd_link_info *link_info)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ struct elf_segment_map *m;
+ struct elf_segment_map *phdr_load_seg;
+ Elf_Internal_Phdr *phdrs;
+ Elf_Internal_Phdr *p;
+ file_ptr off; /* Octets. */
+ bfd_size_type maxpagesize;
+ unsigned int alloc, actual;
+ unsigned int i, j;
+ struct elf_segment_map **sorted_seg_map;
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
+
+ if (link_info == NULL
+ && !_bfd_elf_map_sections_to_segments (abfd, link_info, NULL))
+ return false;
+
+ alloc = 0;
+ for (m = elf_seg_map (abfd); m != NULL; m = m->next)
+ m->idx = alloc++;
+
+ if (alloc)
+ {
+ elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr;
+ elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
+ }
+ else
+ {
+ /* PR binutils/12467. */
+ elf_elfheader (abfd)->e_phoff = 0;
+ elf_elfheader (abfd)->e_phentsize = 0;
+ }
+
+ elf_elfheader (abfd)->e_phnum = alloc;
+
+ if (elf_program_header_size (abfd) == (bfd_size_type) -1)
+ {
+ actual = alloc;
+ elf_program_header_size (abfd) = alloc * bed->s->sizeof_phdr;
+ }
+ else
+ {
+ actual = elf_program_header_size (abfd) / bed->s->sizeof_phdr;
+ BFD_ASSERT (elf_program_header_size (abfd)
+ == actual * bed->s->sizeof_phdr);
+ BFD_ASSERT (actual >= alloc);
+ }
+
+ if (alloc == 0)
+ {
+ elf_next_file_pos (abfd) = bed->s->sizeof_ehdr;
+ return true;
+ }
+
+ /* We're writing the size in elf_program_header_size (abfd),
+ see assign_file_positions_except_relocs, so make sure we have
+ that amount allocated, with trailing space cleared.
+ The variable alloc contains the computed need, while
+ elf_program_header_size (abfd) contains the size used for the
+ layout.
+ See ld/emultempl/elf-generic.em:gld${EMULATION_NAME}_map_segments
+ where the layout is forced to according to a larger size in the
+ last iterations for the testcase ld-elf/header. */
+ phdrs = bfd_zalloc (abfd, (actual * sizeof (*phdrs)
+ + alloc * sizeof (*sorted_seg_map)));
+ sorted_seg_map = (struct elf_segment_map **) (phdrs + actual);
+ elf_tdata (abfd)->phdr = phdrs;
+ if (phdrs == NULL)
+ return false;
+
+ for (m = elf_seg_map (abfd), j = 0; m != NULL; m = m->next, j++)
+ {
+ sorted_seg_map[j] = m;
+ /* If elf_segment_map is not from map_sections_to_segments, the
+ sections may not be correctly ordered. NOTE: sorting should
+ not be done to the PT_NOTE section of a corefile, which may
+ contain several pseudo-sections artificially created by bfd.
+ Sorting these pseudo-sections breaks things badly. */
+ if (m->count > 1
+ && !(elf_elfheader (abfd)->e_type == ET_CORE
+ && m->p_type == PT_NOTE))
+ {
+ for (i = 0; i < m->count; i++)
+ m->sections[i]->target_index = i;
+ qsort (m->sections, (size_t) m->count, sizeof (asection *),
+ elf_sort_sections);
+ }
+ }
+ if (alloc > 1)
+ qsort (sorted_seg_map, alloc, sizeof (*sorted_seg_map),
+ elf_sort_segments);
+
+ maxpagesize = 1;
+ if ((abfd->flags & D_PAGED) != 0)
+ {
+ if (link_info != NULL)
+ maxpagesize = link_info->maxpagesize;
+ else
+ maxpagesize = bed->maxpagesize;
+ }
+
+ /* Sections must map to file offsets past the ELF file header. */
+ off = bed->s->sizeof_ehdr;
+ /* And if one of the PT_LOAD headers doesn't include the program
+ headers then we'll be mapping program headers in the usual
+ position after the ELF file header. */
+ phdr_load_seg = NULL;
+ for (j = 0; j < alloc; j++)
+ {
+ m = sorted_seg_map[j];
+ if (m->p_type != PT_LOAD)
+ break;
+ if (m->includes_phdrs)
+ {
+ phdr_load_seg = m;
+ break;
+ }
+ }
+ if (phdr_load_seg == NULL)
+ off += actual * bed->s->sizeof_phdr;
+
+ for (j = 0; j < alloc; j++)
+ {
+ asection **secpp;
+ bfd_vma off_adjust; /* Octets. */
+ bool no_contents;
+ bfd_size_type p_align;
+ bool p_align_p;
+
+ /* An ELF segment (described by Elf_Internal_Phdr) may contain a
+ number of sections with contents contributing to both p_filesz
+ and p_memsz, followed by a number of sections with no contents
+ that just contribute to p_memsz. In this loop, OFF tracks next
+ available file offset for PT_LOAD and PT_NOTE segments. */
+ m = sorted_seg_map[j];
+ p = phdrs + m->idx;
+ p->p_type = m->p_type;
+ p->p_flags = m->p_flags;
+ p_align = bed->p_align;
+ p_align_p = false;
+
+ if (m->count == 0)
+ p->p_vaddr = m->p_vaddr_offset * opb;
+ else
+ p->p_vaddr = (m->sections[0]->vma + m->p_vaddr_offset) * opb;
+
+ if (m->p_paddr_valid)
+ p->p_paddr = m->p_paddr;
+ else if (m->count == 0)
+ p->p_paddr = 0;
+ else
+ p->p_paddr = (m->sections[0]->lma + m->p_vaddr_offset) * opb;
+
+ if (p->p_type == PT_LOAD
+ && (abfd->flags & D_PAGED) != 0)
+ {
+ /* p_align in demand paged PT_LOAD segments effectively stores
+ the maximum page size. When copying an executable with
+ objcopy, we set m->p_align from the input file. Use this
+ value for maxpagesize rather than bed->maxpagesize, which
+ may be different. Note that we use maxpagesize for PT_TLS
+ segment alignment later in this function, so we are relying
+ on at least one PT_LOAD segment appearing before a PT_TLS
+ segment. */
+ if (m->p_align_valid)
+ maxpagesize = m->p_align;
+ else if (p_align != 0
+ && (link_info == NULL
+ || !link_info->maxpagesize_is_set))
+ /* Set p_align to the default p_align value while laying
+ out segments aligning to the maximum page size or the
+ largest section alignment. The run-time loader can
+ align segments to the default p_align value or the
+ maximum page size, depending on system page size. */
+ p_align_p = true;
+
+ p->p_align = maxpagesize;
+ }
+ else if (m->p_align_valid)
+ p->p_align = m->p_align;
+ else if (m->count == 0)
+ p->p_align = 1 << bed->s->log_file_align;
+
+ if (m == phdr_load_seg)
+ {
+ if (!m->includes_filehdr)
+ p->p_offset = off;
+ off += actual * bed->s->sizeof_phdr;
+ }
+
+ no_contents = false;
+ off_adjust = 0;
+ if (p->p_type == PT_LOAD
+ && m->count > 0)
+ {
+ bfd_size_type align; /* Bytes. */
+ unsigned int align_power = 0;
+
+ if (m->p_align_valid)
+ align = p->p_align;
+ else
+ {
+ for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+ {
+ unsigned int secalign;
+
+ secalign = bfd_section_alignment (*secpp);
+ if (secalign > align_power)
+ align_power = secalign;
+ }
+ align = (bfd_size_type) 1 << align_power;
+ if (align < maxpagesize)
+ {
+ /* If a section requires alignment higher than the
+ default p_align value, don't set p_align to the
+ default p_align value. */
+ if (align > p_align)
+ p_align_p = false;
+ align = maxpagesize;
+ }
+ else
+ {
+ /* If a section requires alignment higher than the
+ maximum page size, set p_align to the section
+ alignment. */
+ p_align_p = true;
+ p_align = align;
+ }
+ }
+
+ for (i = 0; i < m->count; i++)
+ if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+ /* If we aren't making room for this section, then
+ it must be SHT_NOBITS regardless of what we've
+ set via struct bfd_elf_special_section. */
+ elf_section_type (m->sections[i]) = SHT_NOBITS;
+
+ /* Find out whether this segment contains any loadable
+ sections. */
+ no_contents = true;
+ for (i = 0; i < m->count; i++)
+ if (elf_section_type (m->sections[i]) != SHT_NOBITS)
+ {
+ no_contents = false;
+ break;
+ }
+
+ off_adjust = vma_page_aligned_bias (p->p_vaddr, off, align * opb);
+
+ /* Broken hardware and/or kernel require that files do not
+ map the same page with different permissions on some hppa
+ processors. */
+ if (j != 0
+ && (abfd->flags & D_PAGED) != 0
+ && bed->no_page_alias
+ && (off & (maxpagesize - 1)) != 0
+ && ((off & -maxpagesize)
+ == ((off + off_adjust) & -maxpagesize)))
+ off_adjust += maxpagesize;
+ off += off_adjust;
+ if (no_contents)
+ {
+ /* We shouldn't need to align the segment on disk since
+ the segment doesn't need file space, but the gABI
+ arguably requires the alignment and glibc ld.so
+ checks it. So to comply with the alignment
+ requirement but not waste file space, we adjust
+ p_offset for just this segment. (OFF_ADJUST is
+ subtracted from OFF later.) This may put p_offset
+ past the end of file, but that shouldn't matter. */
+ }
+ else
+ off_adjust = 0;
+ }
+ /* Make sure the .dynamic section is the first section in the
+ PT_DYNAMIC segment. */
+ else if (p->p_type == PT_DYNAMIC
+ && m->count > 1
+ && strcmp (m->sections[0]->name, ".dynamic") != 0)
+ {
+ _bfd_error_handler
+ (_("%pB: The first section in the PT_DYNAMIC segment"
+ " is not the .dynamic section"),
+ abfd);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ /* Set the note section type to SHT_NOTE. */
+ else if (p->p_type == PT_NOTE)
+ for (i = 0; i < m->count; i++)
+ elf_section_type (m->sections[i]) = SHT_NOTE;
+
+ if (m->includes_filehdr)
+ {
+ if (!m->p_flags_valid)
+ p->p_flags |= PF_R;
+ p->p_filesz = bed->s->sizeof_ehdr;
+ p->p_memsz = bed->s->sizeof_ehdr;
+ if (p->p_type == PT_LOAD)
+ {
+ if (m->count > 0)
+ {
+ if (p->p_vaddr < (bfd_vma) off
+ || (!m->p_paddr_valid
+ && p->p_paddr < (bfd_vma) off))
+ {
+ _bfd_error_handler
+ (_("%pB: not enough room for program headers,"
+ " try linking with -N"),
+ abfd);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ p->p_vaddr -= off;
+ if (!m->p_paddr_valid)
+ p->p_paddr -= off;
+ }
+ }
+ else if (sorted_seg_map[0]->includes_filehdr)
+ {
+ Elf_Internal_Phdr *filehdr = phdrs + sorted_seg_map[0]->idx;
+ p->p_vaddr = filehdr->p_vaddr;
+ if (!m->p_paddr_valid)
+ p->p_paddr = filehdr->p_paddr;
+ }
+ }
+
+ if (m->includes_phdrs)
+ {
+ if (!m->p_flags_valid)
+ p->p_flags |= PF_R;
+ p->p_filesz += actual * bed->s->sizeof_phdr;
+ p->p_memsz += actual * bed->s->sizeof_phdr;
+ if (!m->includes_filehdr)
+ {
+ if (p->p_type == PT_LOAD)
+ {
+ elf_elfheader (abfd)->e_phoff = p->p_offset;
+ if (m->count > 0)
+ {
+ p->p_vaddr -= off - p->p_offset;
+ if (!m->p_paddr_valid)
+ p->p_paddr -= off - p->p_offset;
+ }
+ }
+ else if (phdr_load_seg != NULL)
+ {
+ Elf_Internal_Phdr *phdr = phdrs + phdr_load_seg->idx;
+ bfd_vma phdr_off = 0; /* Octets. */
+ if (phdr_load_seg->includes_filehdr)
+ phdr_off = bed->s->sizeof_ehdr;
+ p->p_vaddr = phdr->p_vaddr + phdr_off;
+ if (!m->p_paddr_valid)
+ p->p_paddr = phdr->p_paddr + phdr_off;
+ p->p_offset = phdr->p_offset + phdr_off;
+ }
+ else
+ p->p_offset = bed->s->sizeof_ehdr;
+ }
+ }
+
+ if (p->p_type == PT_LOAD
+ || (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core))
+ {
+ if (!m->includes_filehdr && !m->includes_phdrs)
+ {
+ p->p_offset = off;
+ if (no_contents)
+ {
+ /* Put meaningless p_offset for PT_LOAD segments
+ without file contents somewhere within the first
+ page, in an attempt to not point past EOF. */
+ bfd_size_type align = maxpagesize;
+ if (align < p->p_align)
+ align = p->p_align;
+ if (align < 1)
+ align = 1;
+ p->p_offset = off % align;
+ }
+ }
+ else
+ {
+ file_ptr adjust; /* Octets. */
+
+ adjust = off - (p->p_offset + p->p_filesz);
+ if (!no_contents)
+ p->p_filesz += adjust;
+ p->p_memsz += adjust;
+ }
+ }
+
+ /* Set up p_filesz, p_memsz, p_align and p_flags from the section
+ maps. Set filepos for sections in PT_LOAD segments, and in
+ core files, for sections in PT_NOTE segments.
+ assign_file_positions_for_non_load_sections will set filepos
+ for other sections and update p_filesz for other segments. */
+ for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+ {
+ asection *sec;
+ bfd_size_type align;
+ Elf_Internal_Shdr *this_hdr;
+
+ sec = *secpp;
+ this_hdr = &elf_section_data (sec)->this_hdr;
+ align = (bfd_size_type) 1 << bfd_section_alignment (sec);
+
+ if ((p->p_type == PT_LOAD
+ || p->p_type == PT_TLS)
+ && (this_hdr->sh_type != SHT_NOBITS
+ || ((this_hdr->sh_flags & SHF_ALLOC) != 0
+ && ((this_hdr->sh_flags & SHF_TLS) == 0
+ || p->p_type == PT_TLS))))
+ {
+ bfd_vma p_start = p->p_paddr; /* Octets. */
+ bfd_vma p_end = p_start + p->p_memsz; /* Octets. */
+ bfd_vma s_start = sec->lma * opb; /* Octets. */
+ bfd_vma adjust = s_start - p_end; /* Octets. */
+
+ if (adjust != 0
+ && (s_start < p_end
+ || p_end < p_start))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: section %pA lma %#" PRIx64
+ " adjusted to %#" PRIx64),
+ abfd, sec, (uint64_t) s_start / opb,
+ (uint64_t) p_end / opb);
+ adjust = 0;
+ sec->lma = p_end / opb;
+ }
+ p->p_memsz += adjust;
+
+ if (p->p_type == PT_LOAD)
+ {
+ if (this_hdr->sh_type != SHT_NOBITS)
+ {
+ off_adjust = 0;
+ if (p->p_filesz + adjust < p->p_memsz)
+ {
+ /* We have a PROGBITS section following NOBITS ones.
+ Allocate file space for the NOBITS section(s) and
+ zero it. */
+ adjust = p->p_memsz - p->p_filesz;
+ if (!write_zeros (abfd, off, adjust))
+ return false;
+ }
+ }
+ /* We only adjust sh_offset in SHT_NOBITS sections
+ as would seem proper for their address when the
+ section is first in the segment. sh_offset
+ doesn't really have any significance for
+ SHT_NOBITS anyway, apart from a notional position
+ relative to other sections. Historically we
+ didn't bother with adjusting sh_offset and some
+ programs depend on it not being adjusted. See
+ pr12921 and pr25662. */
+ if (this_hdr->sh_type != SHT_NOBITS || i == 0)
+ {
+ off += adjust;
+ if (this_hdr->sh_type == SHT_NOBITS)
+ off_adjust += adjust;
+ }
+ }
+ if (this_hdr->sh_type != SHT_NOBITS)
+ p->p_filesz += adjust;
+ }
+
+ if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)
+ {
+ /* The section at i == 0 is the one that actually contains
+ everything. */
+ if (i == 0)
+ {
+ this_hdr->sh_offset = sec->filepos = off;
+ off += this_hdr->sh_size;
+ p->p_filesz = this_hdr->sh_size;
+ p->p_memsz = 0;
+ p->p_align = 1;
+ }
+ else
+ {
+ /* The rest are fake sections that shouldn't be written. */
+ sec->filepos = 0;
+ sec->size = 0;
+ sec->flags = 0;
+ continue;
+ }
+ }
+ else
+ {
+ if (p->p_type == PT_LOAD)
+ {
+ this_hdr->sh_offset = sec->filepos = off;
+ if (this_hdr->sh_type != SHT_NOBITS)
+ off += this_hdr->sh_size;
+ }
+ else if (this_hdr->sh_type == SHT_NOBITS
+ && (this_hdr->sh_flags & SHF_TLS) != 0
+ && this_hdr->sh_offset == 0)
+ {
+ /* This is a .tbss section that didn't get a PT_LOAD.
+ (See _bfd_elf_map_sections_to_segments "Create a
+ final PT_LOAD".) Set sh_offset to the value it
+ would have if we had created a zero p_filesz and
+ p_memsz PT_LOAD header for the section. This
+ also makes the PT_TLS header have the same
+ p_offset value. */
+ bfd_vma adjust = vma_page_aligned_bias (this_hdr->sh_addr,
+ off, align);
+ this_hdr->sh_offset = sec->filepos = off + adjust;
+ }
+
+ if (this_hdr->sh_type != SHT_NOBITS)
+ {
+ p->p_filesz += this_hdr->sh_size;
+ /* A load section without SHF_ALLOC is something like
+ a note section in a PT_NOTE segment. These take
+ file space but are not loaded into memory. */
+ if ((this_hdr->sh_flags & SHF_ALLOC) != 0)
+ p->p_memsz += this_hdr->sh_size;
+ }
+ else if ((this_hdr->sh_flags & SHF_ALLOC) != 0)
+ {
+ if (p->p_type == PT_TLS)
+ p->p_memsz += this_hdr->sh_size;
+
+ /* .tbss is special. It doesn't contribute to p_memsz of
+ normal segments. */
+ else if ((this_hdr->sh_flags & SHF_TLS) == 0)
+ p->p_memsz += this_hdr->sh_size;
+ }
+
+ if (align > p->p_align
+ && !m->p_align_valid
+ && (p->p_type != PT_LOAD
+ || (abfd->flags & D_PAGED) == 0))
+ p->p_align = align;
+ }
+
+ if (!m->p_flags_valid)
+ {
+ p->p_flags |= PF_R;
+ if ((this_hdr->sh_flags & SHF_EXECINSTR) != 0)
+ p->p_flags |= PF_X;
+ if ((this_hdr->sh_flags & SHF_WRITE) != 0)
+ p->p_flags |= PF_W;
+ }
+ }
+
+ off -= off_adjust;
+
+ /* PR ld/20815 - Check that the program header segment, if
+ present, will be loaded into memory. */
+ if (p->p_type == PT_PHDR
+ && phdr_load_seg == NULL
+ && !(bed->elf_backend_allow_non_load_phdr != NULL
+ && bed->elf_backend_allow_non_load_phdr (abfd, phdrs, alloc)))
+ {
+ /* The fix for this error is usually to edit the linker script being
+ used and set up the program headers manually. Either that or
+ leave room for the headers at the start of the SECTIONS. */
+ _bfd_error_handler (_("%pB: error: PHDR segment not covered"
+ " by LOAD segment"),
+ abfd);
+ if (link_info == NULL)
+ return false;
+ /* Arrange for the linker to exit with an error, deleting
+ the output file unless --noinhibit-exec is given. */
+ link_info->callbacks->info ("%X");
+ }
+
+ /* Check that all sections are in a PT_LOAD segment.
+ Don't check funky gdb generated core files. */
+ if (p->p_type == PT_LOAD && bfd_get_format (abfd) != bfd_core)
+ {
+ bool check_vma = true;
+
+ for (i = 1; i < m->count; i++)
+ if (m->sections[i]->vma == m->sections[i - 1]->vma
+ && ELF_SECTION_SIZE (&(elf_section_data (m->sections[i])
+ ->this_hdr), p) != 0
+ && ELF_SECTION_SIZE (&(elf_section_data (m->sections[i - 1])
+ ->this_hdr), p) != 0)
+ {
+ /* Looks like we have overlays packed into the segment. */
+ check_vma = false;
+ break;
+ }
+
+ for (i = 0; i < m->count; i++)
+ {
+ Elf_Internal_Shdr *this_hdr;
+ asection *sec;
+
+ sec = m->sections[i];
+ this_hdr = &(elf_section_data(sec)->this_hdr);
+ if (!ELF_SECTION_IN_SEGMENT_1 (this_hdr, p, check_vma, 0)
+ && !ELF_TBSS_SPECIAL (this_hdr, p))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: section `%pA' can't be allocated in segment %d"),
+ abfd, sec, j);
+ print_segment_map (m);
+ }
+ }
+
+ if (p_align_p)
+ p->p_align = p_align;
+ }
+ }
+
+ elf_next_file_pos (abfd) = off;
+
+ if (link_info != NULL
+ && phdr_load_seg != NULL
+ && phdr_load_seg->includes_filehdr)
+ {
+ /* There is a segment that contains both the file headers and the
+ program headers, so provide a symbol __ehdr_start pointing there.
+ A program can use this to examine itself robustly. */
+
+ struct elf_link_hash_entry *hash
+ = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start",
+ false, false, true);
+ /* If the symbol was referenced and not defined, define it. */
+ if (hash != NULL
+ && (hash->root.type == bfd_link_hash_new
+ || hash->root.type == bfd_link_hash_undefined
+ || hash->root.type == bfd_link_hash_undefweak
+ || hash->root.type == bfd_link_hash_common))
+ {
+ asection *s = NULL;
+ bfd_vma filehdr_vaddr = phdrs[phdr_load_seg->idx].p_vaddr / opb;
+
+ if (phdr_load_seg->count != 0)
+ /* The segment contains sections, so use the first one. */
+ s = phdr_load_seg->sections[0];
+ else
+ /* Use the first (i.e. lowest-addressed) section in any segment. */
+ for (m = elf_seg_map (abfd); m != NULL; m = m->next)
+ if (m->p_type == PT_LOAD && m->count != 0)
+ {
+ s = m->sections[0];
+ break;
+ }
+
+ if (s != NULL)
+ {
+ hash->root.u.def.value = filehdr_vaddr - s->vma;
+ hash->root.u.def.section = s;
+ }
+ else
+ {
+ hash->root.u.def.value = filehdr_vaddr;
+ hash->root.u.def.section = bfd_abs_section_ptr;
+ }
+
+ hash->root.type = bfd_link_hash_defined;
+ hash->def_regular = 1;
+ hash->non_elf = 0;
+ }
+ }
+
+ return true;
+}
+
+/* Determine if a bfd is a debuginfo file. Unfortunately there
+ is no defined method for detecting such files, so we have to
+ use heuristics instead. */
+
+bool
+is_debuginfo_file (bfd *abfd)
+{
+ if (abfd == NULL || bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ return false;
+
+ Elf_Internal_Shdr **start_headers = elf_elfsections (abfd);
+ Elf_Internal_Shdr **end_headers = start_headers + elf_numsections (abfd);
+ Elf_Internal_Shdr **headerp;
+
+ for (headerp = start_headers; headerp < end_headers; headerp ++)
+ {
+ Elf_Internal_Shdr *header = * headerp;
+
+ /* Debuginfo files do not have any allocated SHT_PROGBITS sections.
+ The only allocated sections are SHT_NOBITS or SHT_NOTES. */
+ if ((header->sh_flags & SHF_ALLOC) == SHF_ALLOC
+ && header->sh_type != SHT_NOBITS
+ && header->sh_type != SHT_NOTE)
+ return false;
+ }
+
+ return true;
+}
+
+/* Assign file positions for other sections, except for compressed debug
+ and sections assigned in _bfd_elf_assign_file_positions_for_non_load. */
+
+static bool
+assign_file_positions_for_non_load_sections (bfd *abfd,
+ struct bfd_link_info *link_info)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ Elf_Internal_Shdr **i_shdrpp;
+ Elf_Internal_Shdr **hdrpp, **end_hdrpp;
+ Elf_Internal_Phdr *phdrs;
+ Elf_Internal_Phdr *p;
+ struct elf_segment_map *m;
+ file_ptr off;
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
+ bfd_vma maxpagesize;
+
+ if (link_info != NULL)
+ maxpagesize = link_info->maxpagesize;
+ else
+ maxpagesize = bed->maxpagesize;
+ i_shdrpp = elf_elfsections (abfd);
+ end_hdrpp = i_shdrpp + elf_numsections (abfd);
+ off = elf_next_file_pos (abfd);
+ for (hdrpp = i_shdrpp + 1; hdrpp < end_hdrpp; hdrpp++)
+ {
+ Elf_Internal_Shdr *hdr;
+ bfd_vma align;
+
+ hdr = *hdrpp;
+ if (hdr->bfd_section != NULL
+ && (hdr->bfd_section->filepos != 0
+ || (hdr->sh_type == SHT_NOBITS
+ && hdr->contents == NULL)))
+ BFD_ASSERT (hdr->sh_offset == hdr->bfd_section->filepos);
+ else if ((hdr->sh_flags & SHF_ALLOC) != 0)
+ {
+ if (hdr->sh_size != 0
+ /* PR 24717 - debuginfo files are known to be not strictly
+ compliant with the ELF standard. In particular they often
+ have .note.gnu.property sections that are outside of any
+ loadable segment. This is not a problem for such files,
+ so do not warn about them. */
+ && ! is_debuginfo_file (abfd))
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: allocated section `%s' not in segment"),
+ abfd,
+ (hdr->bfd_section == NULL
+ ? "*unknown*"
+ : hdr->bfd_section->name));
+ /* We don't need to page align empty sections. */
+ if ((abfd->flags & D_PAGED) != 0 && hdr->sh_size != 0)
+ align = maxpagesize;
+ else
+ align = hdr->sh_addralign & -hdr->sh_addralign;
+ off += vma_page_aligned_bias (hdr->sh_addr, off, align);
+ off = _bfd_elf_assign_file_position_for_section (hdr, off,
+ false);
+ }
+ else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
+ && hdr->bfd_section == NULL)
+ /* We don't know the offset of these sections yet:
+ their size has not been decided. */
+ || (abfd->is_linker_output
+ && hdr->bfd_section != NULL
+ && (hdr->sh_name == -1u
+ || bfd_section_is_ctf (hdr->bfd_section)))
+ || hdr == i_shdrpp[elf_onesymtab (abfd)]
+ || (elf_symtab_shndx_list (abfd) != NULL
+ && hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx])
+ || hdr == i_shdrpp[elf_strtab_sec (abfd)]
+ || hdr == i_shdrpp[elf_shstrtab_sec (abfd)])
+ hdr->sh_offset = -1;
+ else
+ off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+ }
+ elf_next_file_pos (abfd) = off;
+
+ /* Now that we have set the section file positions, we can set up
+ the file positions for the non PT_LOAD segments. */
+ phdrs = elf_tdata (abfd)->phdr;
+ for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++)
+ {
+ if (p->p_type == PT_GNU_RELRO)
+ {
+ bfd_vma start, end; /* Bytes. */
+ bool ok;
+
+ if (link_info != NULL)
+ {
+ /* During linking the range of the RELRO segment is passed
+ in link_info. Note that there may be padding between
+ relro_start and the first RELRO section. */
+ start = link_info->relro_start;
+ end = link_info->relro_end;
+ }
+ else if (m->count != 0)
+ {
+ if (!m->p_size_valid)
+ abort ();
+ start = m->sections[0]->vma;
+ end = start + m->p_size / opb;
+ }
+ else
+ {
+ start = 0;
+ end = 0;
+ }
+
+ ok = false;
+ if (start < end)
+ {
+ struct elf_segment_map *lm;
+ const Elf_Internal_Phdr *lp;
+ unsigned int i;
+
+ /* Find a LOAD segment containing a section in the RELRO
+ segment. */
+ for (lm = elf_seg_map (abfd), lp = phdrs;
+ lm != NULL;
+ lm = lm->next, lp++)
+ {
+ if (lp->p_type == PT_LOAD
+ && lm->count != 0
+ && (lm->sections[lm->count - 1]->vma
+ + (!IS_TBSS (lm->sections[lm->count - 1])
+ ? lm->sections[lm->count - 1]->size / opb
+ : 0)) > start
+ && lm->sections[0]->vma < end)
+ break;
+ }
+
+ if (lm != NULL)
+ {
+ /* Find the section starting the RELRO segment. */
+ for (i = 0; i < lm->count; i++)
+ {
+ asection *s = lm->sections[i];
+ if (s->vma >= start
+ && s->vma < end
+ && s->size != 0)
+ break;
+ }
+
+ if (i < lm->count)
+ {
+ p->p_vaddr = lm->sections[i]->vma * opb;
+ p->p_paddr = lm->sections[i]->lma * opb;
+ p->p_offset = lm->sections[i]->filepos;
+ p->p_memsz = end * opb - p->p_vaddr;
+ p->p_filesz = p->p_memsz;
+
+ /* The RELRO segment typically ends a few bytes
+ into .got.plt but other layouts are possible.
+ In cases where the end does not match any
+ loaded section (for instance is in file
+ padding), trim p_filesz back to correspond to
+ the end of loaded section contents. */
+ if (p->p_filesz > lp->p_vaddr + lp->p_filesz - p->p_vaddr)
+ p->p_filesz = lp->p_vaddr + lp->p_filesz - p->p_vaddr;
+
+ /* Preserve the alignment and flags if they are
+ valid. The gold linker generates RW/4 for
+ the PT_GNU_RELRO section. It is better for
+ objcopy/strip to honor these attributes
+ otherwise gdb will choke when using separate
+ debug files. */
+ if (!m->p_align_valid)
+ p->p_align = 1;
+ if (!m->p_flags_valid)
+ p->p_flags = PF_R;
+ ok = true;
+ }
+ }
+ }
+
+ if (!ok)
+ {
+ if (link_info != NULL)
+ _bfd_error_handler
+ (_("%pB: warning: unable to allocate any sections"
+ " to PT_GNU_RELRO segment"),
+ abfd);
+ memset (p, 0, sizeof *p);
+ }
+ }
+ else if (p->p_type == PT_GNU_STACK)
+ {
+ if (m->p_size_valid)
+ p->p_memsz = m->p_size;
+ }
+ else if (m->count != 0)
+ {
+ unsigned int i;
+
+ if (p->p_type != PT_LOAD
+ && (p->p_type != PT_NOTE
+ || bfd_get_format (abfd) != bfd_core))
+ {
+ /* A user specified segment layout may include a PHDR
+ segment that overlaps with a LOAD segment... */
+ if (p->p_type == PT_PHDR)
+ {
+ m->count = 0;
+ continue;
+ }
+
+ if (m->includes_filehdr || m->includes_phdrs)
+ {
+ /* PR 17512: file: 2195325e. */
+ _bfd_error_handler
+ (_("%pB: error: non-load segment %d includes file header "
+ "and/or program header"),
+ abfd, (int) (p - phdrs));
+ return false;
+ }
+
+ p->p_filesz = 0;
+ p->p_offset = m->sections[0]->filepos;
+ for (i = m->count; i-- != 0;)
+ {
+ asection *sect = m->sections[i];
+ Elf_Internal_Shdr *hdr = &elf_section_data (sect)->this_hdr;
+ if (hdr->sh_type != SHT_NOBITS)
+ {
+ p->p_filesz = sect->filepos - p->p_offset + hdr->sh_size;
+ /* NB: p_memsz of the loadable PT_NOTE segment
+ should be the same as p_filesz. */
+ if (p->p_type == PT_NOTE
+ && (hdr->sh_flags & SHF_ALLOC) != 0)
+ p->p_memsz = p->p_filesz;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static elf_section_list *
+find_section_in_list (unsigned int i, elf_section_list * list)
+{
+ for (;list != NULL; list = list->next)
+ if (list->ndx == i)
+ break;
+ return list;
+}
+
+/* Work out the file positions of all the sections. This is called by
+ _bfd_elf_compute_section_file_positions. All the section sizes and
+ VMAs must be known before this is called.
+
+ Reloc sections come in two flavours: Those processed specially as
+ "side-channel" data attached to a section to which they apply, and
+ those that bfd doesn't process as relocations. The latter sort are
+ stored in a normal bfd section by bfd_section_from_shdr. We don't
+ consider the former sort here, unless they form part of the loadable
+ image. Reloc sections not assigned here (and compressed debugging
+ sections and CTF sections which nothing else in the file can rely
+ upon) will be handled later by assign_file_positions_for_relocs.
+
+ We also don't set the positions of the .symtab and .strtab here. */
+
+static bool
+assign_file_positions_except_relocs (bfd *abfd,
+ struct bfd_link_info *link_info)
+{
+ struct elf_obj_tdata *tdata = elf_tdata (abfd);
+ Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ unsigned int alloc;
+
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0
+ && bfd_get_format (abfd) != bfd_core)
+ {
+ Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd);
+ unsigned int num_sec = elf_numsections (abfd);
+ Elf_Internal_Shdr **hdrpp;
+ unsigned int i;
+ file_ptr off;
+
+ /* Start after the ELF header. */
+ off = i_ehdrp->e_ehsize;
+
+ /* We are not creating an executable, which means that we are
+ not creating a program header, and that the actual order of
+ the sections in the file is unimportant. */
+ for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++)
+ {
+ Elf_Internal_Shdr *hdr;
+
+ hdr = *hdrpp;
+ if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
+ && hdr->bfd_section == NULL)
+ /* Do not assign offsets for these sections yet: we don't know
+ their sizes. */
+ || (abfd->is_linker_output
+ && hdr->bfd_section != NULL
+ && (hdr->sh_name == -1u
+ || bfd_section_is_ctf (hdr->bfd_section)))
+ || i == elf_onesymtab (abfd)
+ || (elf_symtab_shndx_list (abfd) != NULL
+ && hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx])
+ || i == elf_strtab_sec (abfd)
+ || i == elf_shstrtab_sec (abfd))
+ {
+ hdr->sh_offset = -1;
+ }
+ else
+ off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+ }
+
+ elf_next_file_pos (abfd) = off;
+ elf_program_header_size (abfd) = 0;
+ }
+ else
+ {
+ /* Assign file positions for the loaded sections based on the
+ assignment of sections to segments. */
+ if (!assign_file_positions_for_load_sections (abfd, link_info))
+ return false;
+
+ /* And for non-load sections. */
+ if (!assign_file_positions_for_non_load_sections (abfd, link_info))
+ return false;
+ }
+
+ if (!(*bed->elf_backend_modify_headers) (abfd, link_info))
+ return false;
+
+ /* Write out the program headers. */
+ alloc = i_ehdrp->e_phnum;
+ if (alloc != 0)
+ {
+ if (link_info != NULL && ! link_info->no_warn_rwx_segments)
+ {
+ /* Memory resident segments with non-zero size and RWX
+ permissions are a security risk, so we generate a warning
+ here if we are creating any. */
+ unsigned int i;
+
+ for (i = 0; i < alloc; i++)
+ {
+ const Elf_Internal_Phdr * phdr = tdata->phdr + i;
+
+ if (phdr->p_memsz == 0)
+ continue;
+
+ if (phdr->p_type == PT_TLS && (phdr->p_flags & PF_X))
+ _bfd_error_handler (_("warning: %pB has a TLS segment"
+ " with execute permission"),
+ abfd);
+ else if (phdr->p_type == PT_LOAD
+ && ((phdr->p_flags & (PF_R | PF_W | PF_X))
+ == (PF_R | PF_W | PF_X)))
+ _bfd_error_handler (_("warning: %pB has a LOAD segment"
+ " with RWX permissions"),
+ abfd);
+ }
+ }
+
+ if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) != 0
+ || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0)
+ return false;
+ }
+
+ return true;
+}
+
+bool
+_bfd_elf_init_file_header (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+ Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form. */
+ struct elf_strtab_hash *shstrtab;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ i_ehdrp = elf_elfheader (abfd);
+
+ shstrtab = _bfd_elf_strtab_init ();
+ if (shstrtab == NULL)
+ return false;
+
+ elf_shstrtab (abfd) = shstrtab;
+
+ i_ehdrp->e_ident[EI_MAG0] = ELFMAG0;
+ i_ehdrp->e_ident[EI_MAG1] = ELFMAG1;
+ i_ehdrp->e_ident[EI_MAG2] = ELFMAG2;
+ i_ehdrp->e_ident[EI_MAG3] = ELFMAG3;
+
+ i_ehdrp->e_ident[EI_CLASS] = bed->s->elfclass;
+ i_ehdrp->e_ident[EI_DATA] =
+ bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB;
+ i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current;
+
+ if ((abfd->flags & DYNAMIC) != 0)
+ i_ehdrp->e_type = ET_DYN;
+ else if ((abfd->flags & EXEC_P) != 0)
+ i_ehdrp->e_type = ET_EXEC;
+ else if (bfd_get_format (abfd) == bfd_core)
+ i_ehdrp->e_type = ET_CORE;
+ else
+ i_ehdrp->e_type = ET_REL;
+
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_unknown:
+ i_ehdrp->e_machine = EM_NONE;
+ break;
+
+ /* There used to be a long list of cases here, each one setting
+ e_machine to the same EM_* macro #defined as ELF_MACHINE_CODE
+ in the corresponding bfd definition. To avoid duplication,
+ the switch was removed. Machines that need special handling
+ can generally do it in elf_backend_final_write_processing(),
+ unless they need the information earlier than the final write.
+ Such need can generally be supplied by replacing the tests for
+ e_machine with the conditions used to determine it. */
+ default:
+ i_ehdrp->e_machine = bed->elf_machine_code;
+ }
+
+ i_ehdrp->e_version = bed->s->ev_current;
+ i_ehdrp->e_ehsize = bed->s->sizeof_ehdr;
+
+ /* No program header, for now. */
+ i_ehdrp->e_phoff = 0;
+ i_ehdrp->e_phentsize = 0;
+ i_ehdrp->e_phnum = 0;
+
+ /* Each bfd section is section header entry. */
+ i_ehdrp->e_entry = bfd_get_start_address (abfd);
+ i_ehdrp->e_shentsize = bed->s->sizeof_shdr;
+
+ elf_tdata (abfd)->symtab_hdr.sh_name =
+ (unsigned int) _bfd_elf_strtab_add (shstrtab, ".symtab", false);
+ elf_tdata (abfd)->strtab_hdr.sh_name =
+ (unsigned int) _bfd_elf_strtab_add (shstrtab, ".strtab", false);
+ elf_tdata (abfd)->shstrtab_hdr.sh_name =
+ (unsigned int) _bfd_elf_strtab_add (shstrtab, ".shstrtab", false);
+ if (elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1
+ || elf_tdata (abfd)->strtab_hdr.sh_name == (unsigned int) -1
+ || elf_tdata (abfd)->shstrtab_hdr.sh_name == (unsigned int) -1)
+ return false;
+
+ return true;
+}
+
+/* Set e_type in ELF header to ET_EXEC for -pie -Ttext-segment=.
+
+ FIXME: We used to have code here to sort the PT_LOAD segments into
+ ascending order, as per the ELF spec. But this breaks some programs,
+ including the Linux kernel. But really either the spec should be
+ changed or the programs updated. */
+
+bool
+_bfd_elf_modify_headers (bfd *obfd, struct bfd_link_info *link_info)
+{
+ if (link_info != NULL && bfd_link_pie (link_info))
+ {
+ Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (obfd);
+ unsigned int num_segments = i_ehdrp->e_phnum;
+ struct elf_obj_tdata *tdata = elf_tdata (obfd);
+ Elf_Internal_Phdr *segment = tdata->phdr;
+ Elf_Internal_Phdr *end_segment = &segment[num_segments];
+
+ /* Find the lowest p_vaddr in PT_LOAD segments. */
+ bfd_vma p_vaddr = (bfd_vma) -1;
+ for (; segment < end_segment; segment++)
+ if (segment->p_type == PT_LOAD && p_vaddr > segment->p_vaddr)
+ p_vaddr = segment->p_vaddr;
+
+ /* Set e_type to ET_EXEC if the lowest p_vaddr in PT_LOAD
+ segments is non-zero. */
+ if (p_vaddr)
+ i_ehdrp->e_type = ET_EXEC;
+ }
+ return true;
+}
+
+/* Assign file positions for all the reloc sections which are not part
+ of the loadable file image, and the file position of section headers. */
+
+static bool
+_bfd_elf_assign_file_positions_for_non_load (bfd *abfd)
+{
+ file_ptr off;
+ Elf_Internal_Shdr **shdrpp, **end_shdrpp;
+ Elf_Internal_Shdr *shdrp;
+ Elf_Internal_Ehdr *i_ehdrp;
+ const struct elf_backend_data *bed;
+
+ off = elf_next_file_pos (abfd);
+
+ shdrpp = elf_elfsections (abfd);
+ end_shdrpp = shdrpp + elf_numsections (abfd);
+ for (shdrpp++; shdrpp < end_shdrpp; shdrpp++)
+ {
+ shdrp = *shdrpp;
+ if (shdrp->sh_offset == -1)
+ {
+ asection *sec = shdrp->bfd_section;
+ if (sec == NULL
+ || shdrp->sh_type == SHT_REL
+ || shdrp->sh_type == SHT_RELA)
+ ;
+ else if (bfd_section_is_ctf (sec))
+ {
+ /* Update section size and contents. */
+ shdrp->sh_size = sec->size;
+ shdrp->contents = sec->contents;
+ }
+ else if (shdrp->sh_name == -1u)
+ {
+ const char *name = sec->name;
+ struct bfd_elf_section_data *d;
+
+ /* Compress DWARF debug sections. */
+ if (!bfd_compress_section (abfd, sec, shdrp->contents))
+ return false;
+
+ if (sec->compress_status == COMPRESS_SECTION_DONE
+ && (abfd->flags & BFD_COMPRESS_GABI) == 0
+ && name[1] == 'd')
+ {
+ /* If section is compressed with zlib-gnu, convert
+ section name from .debug_* to .zdebug_*. */
+ char *new_name = bfd_debug_name_to_zdebug (abfd, name);
+ if (new_name == NULL)
+ return false;
+ name = new_name;
+ }
+ /* Add section name to section name section. */
+ shdrp->sh_name
+ = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+ name, false);
+ d = elf_section_data (sec);
+
+ /* Add reloc section name to section name section. */
+ if (d->rel.hdr
+ && !_bfd_elf_set_reloc_sh_name (abfd, d->rel.hdr,
+ name, false))
+ return false;
+ if (d->rela.hdr
+ && !_bfd_elf_set_reloc_sh_name (abfd, d->rela.hdr,
+ name, true))
+ return false;
+
+ /* Update section size and contents. */
+ shdrp->sh_size = sec->size;
+ shdrp->contents = sec->contents;
+ sec->contents = NULL;
+ }
+
+ off = _bfd_elf_assign_file_position_for_section (shdrp, off, true);
+ }
+ }
+
+ /* Place section name section after DWARF debug sections have been
+ compressed. */
+ _bfd_elf_strtab_finalize (elf_shstrtab (abfd));
+ shdrp = &elf_tdata (abfd)->shstrtab_hdr;
+ shdrp->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
+ off = _bfd_elf_assign_file_position_for_section (shdrp, off, true);
+
+ /* Place the section headers. */
+ i_ehdrp = elf_elfheader (abfd);
+ bed = get_elf_backend_data (abfd);
+ off = align_file_position (off, 1 << bed->s->log_file_align);
+ i_ehdrp->e_shoff = off;
+ off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize;
+ elf_next_file_pos (abfd) = off;
+
+ return true;
+}
+
+bool
+_bfd_elf_write_object_contents (bfd *abfd)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ Elf_Internal_Shdr **i_shdrp;
+ bool failed;
+ unsigned int count, num_sec;
+ struct elf_obj_tdata *t;
+
+ if (! abfd->output_has_begun
+ && ! _bfd_elf_compute_section_file_positions (abfd, NULL))
+ return false;
+ /* Do not rewrite ELF data when the BFD has been opened for update.
+ abfd->output_has_begun was set to TRUE on opening, so creation of
+ new sections, and modification of existing section sizes was
+ restricted. This means the ELF header, program headers and
+ section headers can't have changed. If the contents of any
+ sections has been modified, then those changes have already been
+ written to the BFD. */
+ else if (abfd->direction == both_direction)
+ {
+ BFD_ASSERT (abfd->output_has_begun);
+ return true;
+ }
+
+ i_shdrp = elf_elfsections (abfd);
+
+ failed = false;
+ bfd_map_over_sections (abfd, bed->s->write_relocs, &failed);
+ if (failed)
+ return false;
+
+ if (!_bfd_elf_assign_file_positions_for_non_load (abfd))
+ return false;
+
+ /* After writing the headers, we need to write the sections too... */
+ num_sec = elf_numsections (abfd);
+ for (count = 1; count < num_sec; count++)
+ {
+ i_shdrp[count]->sh_name
+ = _bfd_elf_strtab_offset (elf_shstrtab (abfd),
+ i_shdrp[count]->sh_name);
+ if (bed->elf_backend_section_processing)
+ if (!(*bed->elf_backend_section_processing) (abfd, i_shdrp[count]))
+ return false;
+ if (i_shdrp[count]->contents)
+ {
+ bfd_size_type amt = i_shdrp[count]->sh_size;
+
+ if (bfd_seek (abfd, i_shdrp[count]->sh_offset, SEEK_SET) != 0
+ || bfd_bwrite (i_shdrp[count]->contents, amt, abfd) != amt)
+ return false;
+ }
+ }
+
+ /* Write out the section header names. */
+ t = elf_tdata (abfd);
+ if (elf_shstrtab (abfd) != NULL
+ && (bfd_seek (abfd, t->shstrtab_hdr.sh_offset, SEEK_SET) != 0
+ || !_bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd))))
+ return false;
+
+ if (!(*bed->elf_backend_final_write_processing) (abfd))
+ return false;
+
+ if (!bed->s->write_shdrs_and_ehdr (abfd))
+ return false;
+
+ /* This is last since write_shdrs_and_ehdr can touch i_shdrp[0]. */
+ if (t->o->build_id.after_write_object_contents != NULL
+ && !(*t->o->build_id.after_write_object_contents) (abfd))
+ return false;
+ if (t->o->package_metadata.after_write_object_contents != NULL
+ && !(*t->o->package_metadata.after_write_object_contents) (abfd))
+ return false;
+
+ return true;
+}
+
+bool
+_bfd_elf_write_corefile_contents (bfd *abfd)
+{
+ /* Hopefully this can be done just like an object file. */
+ return _bfd_elf_write_object_contents (abfd);
+}
+
+/* Given a section, search the header to find them. */
+
+unsigned int
+_bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect)
+{
+ const struct elf_backend_data *bed;
+ unsigned int sec_index;
+
+ if (elf_section_data (asect) != NULL
+ && elf_section_data (asect)->this_idx != 0)
+ return elf_section_data (asect)->this_idx;
+
+ if (bfd_is_abs_section (asect))
+ sec_index = SHN_ABS;
+ else if (bfd_is_com_section (asect))
+ sec_index = SHN_COMMON;
+ else if (bfd_is_und_section (asect))
+ sec_index = SHN_UNDEF;
+ else
+ sec_index = SHN_BAD;
+
+ bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_section_from_bfd_section)
+ {
+ int retval = sec_index;
+
+ if ((*bed->elf_backend_section_from_bfd_section) (abfd, asect, &retval))
+ return retval;
+ }
+
+ if (sec_index == SHN_BAD)
+ bfd_set_error (bfd_error_nonrepresentable_section);
+
+ return sec_index;
+}
+
+/* Given a BFD symbol, return the index in the ELF symbol table, or -1
+ on error. */
+
+int
+_bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr)
+{
+ asymbol *asym_ptr = *asym_ptr_ptr;
+ int idx;
+ flagword flags = asym_ptr->flags;
+
+ /* When gas creates relocations against local labels, it creates its
+ own symbol for the section, but does put the symbol into the
+ symbol chain, so udata is 0. When the linker is generating
+ relocatable output, this section symbol may be for one of the
+ input sections rather than the output section. */
+ if (asym_ptr->udata.i == 0
+ && (flags & BSF_SECTION_SYM)
+ && asym_ptr->section)
+ {
+ asection *sec;
+
+ sec = asym_ptr->section;
+ if (sec->owner != abfd && sec->output_section != NULL)
+ sec = sec->output_section;
+ if (sec->owner == abfd
+ && sec->index < elf_num_section_syms (abfd)
+ && elf_section_syms (abfd)[sec->index] != NULL)
+ asym_ptr->udata.i = elf_section_syms (abfd)[sec->index]->udata.i;
+ }
+
+ idx = asym_ptr->udata.i;
+
+ if (idx == 0)
+ {
+ /* This case can occur when using --strip-symbol on a symbol
+ which is used in a relocation entry. */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: symbol `%s' required but not present"),
+ abfd, bfd_asymbol_name (asym_ptr));
+ bfd_set_error (bfd_error_no_symbols);
+ return -1;
+ }
+
+#if DEBUG & 4
+ {
+ fprintf (stderr,
+ "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d,"
+ " flags = 0x%.8x\n",
+ (long) asym_ptr, asym_ptr->name, idx, flags);
+ fflush (stderr);
+ }
+#endif
+
+ return idx;
+}
+
+static inline bfd_vma
+segment_size (Elf_Internal_Phdr *segment)
+{
+ return (segment->p_memsz > segment->p_filesz
+ ? segment->p_memsz : segment->p_filesz);
+}
+
+
+/* Returns the end address of the segment + 1. */
+static inline bfd_vma
+segment_end (Elf_Internal_Phdr *segment, bfd_vma start)
+{
+ return start + segment_size (segment);
+}
+
+static inline bfd_size_type
+section_size (asection *section, Elf_Internal_Phdr *segment)
+{
+ if ((section->flags & SEC_HAS_CONTENTS) != 0
+ || (section->flags & SEC_THREAD_LOCAL) == 0
+ || segment->p_type == PT_TLS)
+ return section->size;
+ return 0;
+}
+
+/* Returns TRUE if the given section is contained within the given
+ segment. LMA addresses are compared against PADDR when
+ bed->want_p_paddr_set_to_zero is false, VMA against VADDR when true. */
+static bool
+is_contained_by (asection *section, Elf_Internal_Phdr *segment,
+ bfd_vma paddr, bfd_vma vaddr, unsigned int opb,
+ const struct elf_backend_data *bed)
+{
+ bfd_vma seg_addr = !bed->want_p_paddr_set_to_zero ? paddr : vaddr;
+ bfd_vma addr = !bed->want_p_paddr_set_to_zero ? section->lma : section->vma;
+ bfd_vma octet;
+ if (_bfd_mul_overflow (addr, opb, &octet))
+ return false;
+ /* The third and fourth lines below are testing that the section end
+ address is within the segment. It's written this way to avoid
+ overflow. Add seg_addr + section_size to both sides of the
+ inequality to make it obvious. */
+ return (octet >= seg_addr
+ && segment_size (segment) >= section_size (section, segment)
+ && (octet - seg_addr
+ <= segment_size (segment) - section_size (section, segment)));
+}
+
+/* Handle PT_NOTE segment. */
+static bool
+is_note (asection *s, Elf_Internal_Phdr *p)
+{
+ return (p->p_type == PT_NOTE
+ && elf_section_type (s) == SHT_NOTE
+ && (ufile_ptr) s->filepos >= p->p_offset
+ && p->p_filesz >= s->size
+ && (ufile_ptr) s->filepos - p->p_offset <= p->p_filesz - s->size);
+}
+
+/* Rewrite program header information. */
+
+static bool
+rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize)
+{
+ Elf_Internal_Ehdr *iehdr;
+ struct elf_segment_map *map;
+ struct elf_segment_map *map_first;
+ struct elf_segment_map **pointer_to_map;
+ Elf_Internal_Phdr *segment;
+ asection *section;
+ unsigned int i;
+ unsigned int num_segments;
+ bool phdr_included = false;
+ bool p_paddr_valid;
+ struct elf_segment_map *phdr_adjust_seg = NULL;
+ unsigned int phdr_adjust_num = 0;
+ const struct elf_backend_data *bed;
+ unsigned int opb = bfd_octets_per_byte (ibfd, NULL);
+
+ bed = get_elf_backend_data (ibfd);
+ iehdr = elf_elfheader (ibfd);
+
+ map_first = NULL;
+ pointer_to_map = &map_first;
+
+ num_segments = elf_elfheader (ibfd)->e_phnum;
+
+ /* The complicated case when p_vaddr is 0 is to handle the Solaris
+ linker, which generates a PT_INTERP section with p_vaddr and
+ p_memsz set to 0. */
+#define IS_SOLARIS_PT_INTERP(p, s) \
+ (p->p_vaddr == 0 \
+ && p->p_paddr == 0 \
+ && p->p_memsz == 0 \
+ && p->p_filesz > 0 \
+ && (s->flags & SEC_HAS_CONTENTS) != 0 \
+ && s->size > 0 \
+ && (bfd_vma) s->filepos >= p->p_offset \
+ && ((bfd_vma) s->filepos + s->size \
+ <= p->p_offset + p->p_filesz))
+
+ /* Decide if the given section should be included in the given segment.
+ A section will be included if:
+ 1. It is within the address space of the segment -- we use the LMA
+ if that is set for the segment and the VMA otherwise,
+ 2. It is an allocated section or a NOTE section in a PT_NOTE
+ segment.
+ 3. There is an output section associated with it,
+ 4. The section has not already been allocated to a previous segment.
+ 5. PT_GNU_STACK segments do not include any sections.
+ 6. PT_TLS segment includes only SHF_TLS sections.
+ 7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.
+ 8. PT_DYNAMIC should not contain empty sections at the beginning
+ (with the possible exception of .dynamic). */
+#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed, opb) \
+ (((is_contained_by (section, segment, segment->p_paddr, \
+ segment->p_vaddr, opb, bed) \
+ && (section->flags & SEC_ALLOC) != 0) \
+ || is_note (section, segment)) \
+ && segment->p_type != PT_GNU_STACK \
+ && (segment->p_type != PT_TLS \
+ || (section->flags & SEC_THREAD_LOCAL)) \
+ && (segment->p_type == PT_LOAD \
+ || segment->p_type == PT_TLS \
+ || (section->flags & SEC_THREAD_LOCAL) == 0) \
+ && (segment->p_type != PT_DYNAMIC \
+ || section_size (section, segment) > 0 \
+ || (segment->p_paddr \
+ ? segment->p_paddr != section->lma * (opb) \
+ : segment->p_vaddr != section->vma * (opb)) \
+ || (strcmp (bfd_section_name (section), ".dynamic") == 0)) \
+ && (segment->p_type != PT_LOAD || !section->segment_mark))
+
+/* If the output section of a section in the input segment is NULL,
+ it is removed from the corresponding output segment. */
+#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed, opb) \
+ (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed, opb) \
+ && section->output_section != NULL)
+
+ /* Returns TRUE iff seg1 starts after the end of seg2. */
+#define SEGMENT_AFTER_SEGMENT(seg1, seg2, field) \
+ (seg1->field >= segment_end (seg2, seg2->field))
+
+ /* Returns TRUE iff seg1 and seg2 overlap. Segments overlap iff both
+ their VMA address ranges and their LMA address ranges overlap.
+ It is possible to have overlapping VMA ranges without overlapping LMA
+ ranges. RedBoot images for example can have both .data and .bss mapped
+ to the same VMA range, but with the .data section mapped to a different
+ LMA. */
+#define SEGMENT_OVERLAPS(seg1, seg2) \
+ ( !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_vaddr) \
+ || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_vaddr)) \
+ && !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_paddr) \
+ || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_paddr)))
+
+ /* Initialise the segment mark field, and discard stupid alignment. */
+ for (section = ibfd->sections; section != NULL; section = section->next)
+ {
+ asection *o = section->output_section;
+ if (o != NULL && o->alignment_power >= (sizeof (bfd_vma) * 8) - 1)
+ o->alignment_power = 0;
+ section->segment_mark = false;
+ }
+
+ /* The Solaris linker creates program headers in which all the
+ p_paddr fields are zero. When we try to objcopy or strip such a
+ file, we get confused. Check for this case, and if we find it
+ don't set the p_paddr_valid fields. */
+ p_paddr_valid = false;
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ if (segment->p_paddr != 0)
+ {
+ p_paddr_valid = true;
+ break;
+ }
+
+ /* Scan through the segments specified in the program header
+ of the input BFD. For this first scan we look for overlaps
+ in the loadable segments. These can be created by weird
+ parameters to objcopy. Also, fix some solaris weirdness. */
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ {
+ unsigned int j;
+ Elf_Internal_Phdr *segment2;
+
+ if (segment->p_type == PT_INTERP)
+ for (section = ibfd->sections; section; section = section->next)
+ if (IS_SOLARIS_PT_INTERP (segment, section))
+ {
+ /* Mininal change so that the normal section to segment
+ assignment code will work. */
+ segment->p_vaddr = section->vma * opb;
+ break;
+ }
+
+ if (segment->p_type != PT_LOAD)
+ {
+ /* Remove PT_GNU_RELRO segment. */
+ if (segment->p_type == PT_GNU_RELRO)
+ segment->p_type = PT_NULL;
+ continue;
+ }
+
+ /* Determine if this segment overlaps any previous segments. */
+ for (j = 0, segment2 = elf_tdata (ibfd)->phdr; j < i; j++, segment2++)
+ {
+ bfd_signed_vma extra_length;
+
+ if (segment2->p_type != PT_LOAD
+ || !SEGMENT_OVERLAPS (segment, segment2))
+ continue;
+
+ /* Merge the two segments together. */
+ if (segment2->p_vaddr < segment->p_vaddr)
+ {
+ /* Extend SEGMENT2 to include SEGMENT and then delete
+ SEGMENT. */
+ extra_length = (segment_end (segment, segment->p_vaddr)
+ - segment_end (segment2, segment2->p_vaddr));
+
+ if (extra_length > 0)
+ {
+ segment2->p_memsz += extra_length;
+ segment2->p_filesz += extra_length;
+ }
+
+ segment->p_type = PT_NULL;
+
+ /* Since we have deleted P we must restart the outer loop. */
+ i = 0;
+ segment = elf_tdata (ibfd)->phdr;
+ break;
+ }
+ else
+ {
+ /* Extend SEGMENT to include SEGMENT2 and then delete
+ SEGMENT2. */
+ extra_length = (segment_end (segment2, segment2->p_vaddr)
+ - segment_end (segment, segment->p_vaddr));
+
+ if (extra_length > 0)
+ {
+ segment->p_memsz += extra_length;
+ segment->p_filesz += extra_length;
+ }
+
+ segment2->p_type = PT_NULL;
+ }
+ }
+ }
+
+ /* The second scan attempts to assign sections to segments. */
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ {
+ unsigned int section_count;
+ asection **sections;
+ asection *output_section;
+ unsigned int isec;
+ asection *matching_lma;
+ asection *suggested_lma;
+ unsigned int j;
+ size_t amt;
+ asection *first_section;
+
+ if (segment->p_type == PT_NULL)
+ continue;
+
+ first_section = NULL;
+ /* Compute how many sections might be placed into this segment. */
+ for (section = ibfd->sections, section_count = 0;
+ section != NULL;
+ section = section->next)
+ {
+ /* Find the first section in the input segment, which may be
+ removed from the corresponding output segment. */
+ if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed, opb))
+ {
+ if (first_section == NULL)
+ first_section = section;
+ if (section->output_section != NULL)
+ ++section_count;
+ }
+ }
+
+ /* Allocate a segment map big enough to contain
+ all of the sections we have selected. */
+ amt = sizeof (struct elf_segment_map) - sizeof (asection *);
+ amt += section_count * sizeof (asection *);
+ map = (struct elf_segment_map *) bfd_zalloc (obfd, amt);
+ if (map == NULL)
+ return false;
+
+ /* Initialise the fields of the segment map. Default to
+ using the physical address of the segment in the input BFD. */
+ map->next = NULL;
+ map->p_type = segment->p_type;
+ map->p_flags = segment->p_flags;
+ map->p_flags_valid = 1;
+
+ if (map->p_type == PT_LOAD
+ && (ibfd->flags & D_PAGED) != 0
+ && maxpagesize > 1
+ && segment->p_align > 1)
+ {
+ map->p_align = segment->p_align;
+ if (segment->p_align > maxpagesize)
+ map->p_align = maxpagesize;
+ map->p_align_valid = 1;
+ }
+
+ /* If the first section in the input segment is removed, there is
+ no need to preserve segment physical address in the corresponding
+ output segment. */
+ if (!first_section || first_section->output_section != NULL)
+ {
+ map->p_paddr = segment->p_paddr;
+ map->p_paddr_valid = p_paddr_valid;
+ }
+
+ /* Determine if this segment contains the ELF file header
+ and if it contains the program headers themselves. */
+ map->includes_filehdr = (segment->p_offset == 0
+ && segment->p_filesz >= iehdr->e_ehsize);
+ map->includes_phdrs = 0;
+
+ if (!phdr_included || segment->p_type != PT_LOAD)
+ {
+ map->includes_phdrs =
+ (segment->p_offset <= (bfd_vma) iehdr->e_phoff
+ && (segment->p_offset + segment->p_filesz
+ >= ((bfd_vma) iehdr->e_phoff
+ + iehdr->e_phnum * iehdr->e_phentsize)));
+
+ if (segment->p_type == PT_LOAD && map->includes_phdrs)
+ phdr_included = true;
+ }
+
+ if (section_count == 0)
+ {
+ /* Special segments, such as the PT_PHDR segment, may contain
+ no sections, but ordinary, loadable segments should contain
+ something. They are allowed by the ELF spec however, so only
+ a warning is produced.
+ There is however the valid use case of embedded systems which
+ have segments with p_filesz of 0 and a p_memsz > 0 to initialize
+ flash memory with zeros. No warning is shown for that case. */
+ if (segment->p_type == PT_LOAD
+ && (segment->p_filesz > 0 || segment->p_memsz == 0))
+ /* xgettext:c-format */
+ _bfd_error_handler
+ (_("%pB: warning: empty loadable segment detected"
+ " at vaddr=%#" PRIx64 ", is this intentional?"),
+ ibfd, (uint64_t) segment->p_vaddr);
+
+ map->p_vaddr_offset = segment->p_vaddr / opb;
+ map->count = 0;
+ *pointer_to_map = map;
+ pointer_to_map = &map->next;
+
+ continue;
+ }
+
+ /* Now scan the sections in the input BFD again and attempt
+ to add their corresponding output sections to the segment map.
+ The problem here is how to handle an output section which has
+ been moved (ie had its LMA changed). There are four possibilities:
+
+ 1. None of the sections have been moved.
+ In this case we can continue to use the segment LMA from the
+ input BFD.
+
+ 2. All of the sections have been moved by the same amount.
+ In this case we can change the segment's LMA to match the LMA
+ of the first section.
+
+ 3. Some of the sections have been moved, others have not.
+ In this case those sections which have not been moved can be
+ placed in the current segment which will have to have its size,
+ and possibly its LMA changed, and a new segment or segments will
+ have to be created to contain the other sections.
+
+ 4. The sections have been moved, but not by the same amount.
+ In this case we can change the segment's LMA to match the LMA
+ of the first section and we will have to create a new segment
+ or segments to contain the other sections.
+
+ In order to save time, we allocate an array to hold the section
+ pointers that we are interested in. As these sections get assigned
+ to a segment, they are removed from this array. */
+
+ amt = section_count * sizeof (asection *);
+ sections = (asection **) bfd_malloc (amt);
+ if (sections == NULL)
+ return false;
+
+ /* Step One: Scan for segment vs section LMA conflicts.
+ Also add the sections to the section array allocated above.
+ Also add the sections to the current segment. In the common
+ case, where the sections have not been moved, this means that
+ we have completely filled the segment, and there is nothing
+ more to do. */
+ isec = 0;
+ matching_lma = NULL;
+ suggested_lma = NULL;
+
+ for (section = first_section, j = 0;
+ section != NULL;
+ section = section->next)
+ {
+ if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed, opb))
+ {
+ output_section = section->output_section;
+
+ sections[j++] = section;
+
+ /* The Solaris native linker always sets p_paddr to 0.
+ We try to catch that case here, and set it to the
+ correct value. Note - some backends require that
+ p_paddr be left as zero. */
+ if (!p_paddr_valid
+ && segment->p_vaddr != 0
+ && !bed->want_p_paddr_set_to_zero
+ && isec == 0
+ && output_section->lma != 0
+ && (align_power (segment->p_vaddr
+ + (map->includes_filehdr
+ ? iehdr->e_ehsize : 0)
+ + (map->includes_phdrs
+ ? iehdr->e_phnum * iehdr->e_phentsize
+ : 0),
+ output_section->alignment_power * opb)
+ == (output_section->vma * opb)))
+ map->p_paddr = segment->p_vaddr;
+
+ /* Match up the physical address of the segment with the
+ LMA address of the output section. */
+ if (is_contained_by (output_section, segment, map->p_paddr,
+ map->p_paddr + map->p_vaddr_offset, opb, bed)
+ || is_note (section, segment))
+ {
+ if (matching_lma == NULL
+ || output_section->lma < matching_lma->lma)
+ matching_lma = output_section;
+
+ /* We assume that if the section fits within the segment
+ then it does not overlap any other section within that
+ segment. */
+ map->sections[isec++] = output_section;
+ }
+ else if (suggested_lma == NULL)
+ suggested_lma = output_section;
+
+ if (j == section_count)
+ break;
+ }
+ }
+
+ BFD_ASSERT (j == section_count);
+
+ /* Step Two: Adjust the physical address of the current segment,
+ if necessary. */
+ if (isec == section_count)
+ {
+ /* All of the sections fitted within the segment as currently
+ specified. This is the default case. Add the segment to
+ the list of built segments and carry on to process the next
+ program header in the input BFD. */
+ map->count = section_count;
+ *pointer_to_map = map;
+ pointer_to_map = &map->next;
+
+ if (p_paddr_valid
+ && !bed->want_p_paddr_set_to_zero)
+ {
+ bfd_vma hdr_size = 0;
+ if (map->includes_filehdr)
+ hdr_size = iehdr->e_ehsize;
+ if (map->includes_phdrs)
+ hdr_size += iehdr->e_phnum * iehdr->e_phentsize;
+
+ /* Account for padding before the first section in the
+ segment. */
+ map->p_vaddr_offset = ((map->p_paddr + hdr_size) / opb
+ - matching_lma->lma);
+ }
+
+ free (sections);
+ continue;
+ }
+ else
+ {
+ /* Change the current segment's physical address to match
+ the LMA of the first section that fitted, or if no
+ section fitted, the first section. */
+ if (matching_lma == NULL)
+ matching_lma = suggested_lma;
+
+ map->p_paddr = matching_lma->lma * opb;
+
+ /* Offset the segment physical address from the lma
+ to allow for space taken up by elf headers. */
+ if (map->includes_phdrs)
+ {
+ map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize;
+
+ /* iehdr->e_phnum is just an estimate of the number
+ of program headers that we will need. Make a note
+ here of the number we used and the segment we chose
+ to hold these headers, so that we can adjust the
+ offset when we know the correct value. */
+ phdr_adjust_num = iehdr->e_phnum;
+ phdr_adjust_seg = map;
+ }
+
+ if (map->includes_filehdr)
+ {
+ bfd_vma align = (bfd_vma) 1 << matching_lma->alignment_power;
+ map->p_paddr -= iehdr->e_ehsize;
+ /* We've subtracted off the size of headers from the
+ first section lma, but there may have been some
+ alignment padding before that section too. Try to
+ account for that by adjusting the segment lma down to
+ the same alignment. */
+ if (segment->p_align != 0 && segment->p_align < align)
+ align = segment->p_align;
+ map->p_paddr &= -(align * opb);
+ }
+ }
+
+ /* Step Three: Loop over the sections again, this time assigning
+ those that fit to the current segment and removing them from the
+ sections array; but making sure not to leave large gaps. Once all
+ possible sections have been assigned to the current segment it is
+ added to the list of built segments and if sections still remain
+ to be assigned, a new segment is constructed before repeating
+ the loop. */
+ isec = 0;
+ do
+ {
+ map->count = 0;
+ suggested_lma = NULL;
+
+ /* Fill the current segment with sections that fit. */
+ for (j = 0; j < section_count; j++)
+ {
+ section = sections[j];
+
+ if (section == NULL)
+ continue;
+
+ output_section = section->output_section;
+
+ BFD_ASSERT (output_section != NULL);
+
+ if (is_contained_by (output_section, segment, map->p_paddr,
+ map->p_paddr + map->p_vaddr_offset, opb, bed)
+ || is_note (section, segment))
+ {
+ if (map->count == 0)
+ {
+ /* If the first section in a segment does not start at
+ the beginning of the segment, then something is
+ wrong. */
+ if (align_power (map->p_paddr
+ + (map->includes_filehdr
+ ? iehdr->e_ehsize : 0)
+ + (map->includes_phdrs
+ ? iehdr->e_phnum * iehdr->e_phentsize
+ : 0),
+ output_section->alignment_power * opb)
+ != output_section->lma * opb)
+ goto sorry;
+ }
+ else
+ {
+ asection *prev_sec;
+
+ prev_sec = map->sections[map->count - 1];
+
+ /* If the gap between the end of the previous section
+ and the start of this section is more than
+ maxpagesize then we need to start a new segment. */
+ if ((BFD_ALIGN (prev_sec->lma + prev_sec->size,
+ maxpagesize)
+ < BFD_ALIGN (output_section->lma, maxpagesize))
+ || (prev_sec->lma + prev_sec->size
+ > output_section->lma))
+ {
+ if (suggested_lma == NULL)
+ suggested_lma = output_section;
+
+ continue;
+ }
+ }
+
+ map->sections[map->count++] = output_section;
+ ++isec;
+ sections[j] = NULL;
+ if (segment->p_type == PT_LOAD)
+ section->segment_mark = true;
+ }
+ else if (suggested_lma == NULL)
+ suggested_lma = output_section;
+ }
+
+ /* PR 23932. A corrupt input file may contain sections that cannot
+ be assigned to any segment - because for example they have a
+ negative size - or segments that do not contain any sections.
+ But there are also valid reasons why a segment can be empty.
+ So allow a count of zero. */
+
+ /* Add the current segment to the list of built segments. */
+ *pointer_to_map = map;
+ pointer_to_map = &map->next;
+
+ if (isec < section_count)
+ {
+ /* We still have not allocated all of the sections to
+ segments. Create a new segment here, initialise it
+ and carry on looping. */
+ amt = sizeof (struct elf_segment_map) - sizeof (asection *);
+ amt += section_count * sizeof (asection *);
+ map = (struct elf_segment_map *) bfd_zalloc (obfd, amt);
+ if (map == NULL)
+ {
+ free (sections);
+ return false;
+ }
+
+ /* Initialise the fields of the segment map. Set the physical
+ physical address to the LMA of the first section that has
+ not yet been assigned. */
+ map->next = NULL;
+ map->p_type = segment->p_type;
+ map->p_flags = segment->p_flags;
+ map->p_flags_valid = 1;
+ map->p_paddr = suggested_lma->lma * opb;
+ map->p_paddr_valid = p_paddr_valid;
+ map->includes_filehdr = 0;
+ map->includes_phdrs = 0;
+ }
+
+ continue;
+ sorry:
+ bfd_set_error (bfd_error_sorry);
+ free (sections);
+ return false;
+ }
+ while (isec < section_count);
+
+ free (sections);
+ }
+
+ elf_seg_map (obfd) = map_first;
+
+ /* If we had to estimate the number of program headers that were
+ going to be needed, then check our estimate now and adjust
+ the offset if necessary. */
+ if (phdr_adjust_seg != NULL)
+ {
+ unsigned int count;
+
+ for (count = 0, map = map_first; map != NULL; map = map->next)
+ count++;
+
+ if (count > phdr_adjust_num)
+ phdr_adjust_seg->p_paddr
+ -= (count - phdr_adjust_num) * iehdr->e_phentsize;
+
+ for (map = map_first; map != NULL; map = map->next)
+ if (map->p_type == PT_PHDR)
+ {
+ bfd_vma adjust
+ = phdr_adjust_seg->includes_filehdr ? iehdr->e_ehsize : 0;
+ map->p_paddr = phdr_adjust_seg->p_paddr + adjust;
+ break;
+ }
+ }
+
+#undef IS_SOLARIS_PT_INTERP
+#undef IS_SECTION_IN_INPUT_SEGMENT
+#undef INCLUDE_SECTION_IN_SEGMENT
+#undef SEGMENT_AFTER_SEGMENT
+#undef SEGMENT_OVERLAPS
+ return true;
+}
+
+/* Return true if p_align in the ELF program header in ABFD is valid. */
+
+static bool
+elf_is_p_align_valid (bfd *abfd)
+{
+ unsigned int i;
+ Elf_Internal_Phdr *segment;
+ unsigned int num_segments;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ bfd_size_type maxpagesize = bed->maxpagesize;
+ bfd_size_type p_align = bed->p_align;
+
+ /* Return true if the default p_align value isn't set or the maximum
+ page size is the same as the minimum page size. */
+ if (p_align == 0 || maxpagesize == bed->minpagesize)
+ return true;
+
+ /* When the default p_align value is set, p_align may be set to the
+ default p_align value while segments are aligned to the maximum
+ page size. In this case, the input p_align will be ignored and
+ the maximum page size will be used to align the output segments. */
+ segment = elf_tdata (abfd)->phdr;
+ num_segments = elf_elfheader (abfd)->e_phnum;
+ for (i = 0; i < num_segments; i++, segment++)
+ if (segment->p_type == PT_LOAD
+ && (segment->p_align != p_align
+ || vma_page_aligned_bias (segment->p_vaddr,
+ segment->p_offset,
+ maxpagesize) != 0))
+ return true;
+
+ return false;
+}
+
+/* Copy ELF program header information. */
+
+static bool
+copy_elf_program_header (bfd *ibfd, bfd *obfd)
+{
+ Elf_Internal_Ehdr *iehdr;
+ struct elf_segment_map *map;
+ struct elf_segment_map *map_first;
+ struct elf_segment_map **pointer_to_map;
+ Elf_Internal_Phdr *segment;
+ unsigned int i;
+ unsigned int num_segments;
+ bool phdr_included = false;
+ bool p_paddr_valid;
+ bool p_palign_valid;
+ unsigned int opb = bfd_octets_per_byte (ibfd, NULL);
+
+ iehdr = elf_elfheader (ibfd);
+
+ map_first = NULL;
+ pointer_to_map = &map_first;
+
+ /* If all the segment p_paddr fields are zero, don't set
+ map->p_paddr_valid. */
+ p_paddr_valid = false;
+ num_segments = elf_elfheader (ibfd)->e_phnum;
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ if (segment->p_paddr != 0)
+ {
+ p_paddr_valid = true;
+ break;
+ }
+
+ p_palign_valid = elf_is_p_align_valid (ibfd);
+
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ {
+ asection *section;
+ unsigned int section_count;
+ size_t amt;
+ Elf_Internal_Shdr *this_hdr;
+ asection *first_section = NULL;
+ asection *lowest_section;
+
+ /* Compute how many sections are in this segment. */
+ for (section = ibfd->sections, section_count = 0;
+ section != NULL;
+ section = section->next)
+ {
+ this_hdr = &(elf_section_data(section)->this_hdr);
+ if (ELF_SECTION_IN_SEGMENT (this_hdr, segment))
+ {
+ if (first_section == NULL)
+ first_section = section;
+ section_count++;
+ }
+ }
+
+ /* Allocate a segment map big enough to contain
+ all of the sections we have selected. */
+ amt = sizeof (struct elf_segment_map) - sizeof (asection *);
+ amt += section_count * sizeof (asection *);
+ map = (struct elf_segment_map *) bfd_zalloc (obfd, amt);
+ if (map == NULL)
+ return false;
+
+ /* Initialize the fields of the output segment map with the
+ input segment. */
+ map->next = NULL;
+ map->p_type = segment->p_type;
+ map->p_flags = segment->p_flags;
+ map->p_flags_valid = 1;
+ map->p_paddr = segment->p_paddr;
+ map->p_paddr_valid = p_paddr_valid;
+ map->p_align = segment->p_align;
+ /* Keep p_align of PT_GNU_STACK for stack alignment. */
+ map->p_align_valid = (map->p_type == PT_GNU_STACK
+ || p_palign_valid);
+ map->p_vaddr_offset = 0;
+
+ if (map->p_type == PT_GNU_RELRO
+ || map->p_type == PT_GNU_STACK)
+ {
+ /* The PT_GNU_RELRO segment may contain the first a few
+ bytes in the .got.plt section even if the whole .got.plt
+ section isn't in the PT_GNU_RELRO segment. We won't
+ change the size of the PT_GNU_RELRO segment.
+ Similarly, PT_GNU_STACK size is significant on uclinux
+ systems. */
+ map->p_size = segment->p_memsz;
+ map->p_size_valid = 1;
+ }
+
+ /* Determine if this segment contains the ELF file header
+ and if it contains the program headers themselves. */
+ map->includes_filehdr = (segment->p_offset == 0
+ && segment->p_filesz >= iehdr->e_ehsize);
+
+ map->includes_phdrs = 0;
+ if (! phdr_included || segment->p_type != PT_LOAD)
+ {
+ map->includes_phdrs =
+ (segment->p_offset <= (bfd_vma) iehdr->e_phoff
+ && (segment->p_offset + segment->p_filesz
+ >= ((bfd_vma) iehdr->e_phoff
+ + iehdr->e_phnum * iehdr->e_phentsize)));
+
+ if (segment->p_type == PT_LOAD && map->includes_phdrs)
+ phdr_included = true;
+ }
+
+ lowest_section = NULL;
+ if (section_count != 0)
+ {
+ unsigned int isec = 0;
+
+ for (section = first_section;
+ section != NULL;
+ section = section->next)
+ {
+ this_hdr = &(elf_section_data(section)->this_hdr);
+ if (ELF_SECTION_IN_SEGMENT (this_hdr, segment))
+ {
+ map->sections[isec++] = section->output_section;
+ if ((section->flags & SEC_ALLOC) != 0)
+ {
+ bfd_vma seg_off;
+
+ if (lowest_section == NULL
+ || section->lma < lowest_section->lma)
+ lowest_section = section;
+
+ /* Section lmas are set up from PT_LOAD header
+ p_paddr in _bfd_elf_make_section_from_shdr.
+ If this header has a p_paddr that disagrees
+ with the section lma, flag the p_paddr as
+ invalid. */
+ if ((section->flags & SEC_LOAD) != 0)
+ seg_off = this_hdr->sh_offset - segment->p_offset;
+ else
+ seg_off = this_hdr->sh_addr - segment->p_vaddr;
+ if (section->lma * opb - segment->p_paddr != seg_off)
+ map->p_paddr_valid = false;
+ }
+ if (isec == section_count)
+ break;
+ }
+ }
+ }
+
+ if (section_count == 0)
+ map->p_vaddr_offset = segment->p_vaddr / opb;
+ else if (map->p_paddr_valid)
+ {
+ /* Account for padding before the first section in the segment. */
+ bfd_vma hdr_size = 0;
+ if (map->includes_filehdr)
+ hdr_size = iehdr->e_ehsize;
+ if (map->includes_phdrs)
+ hdr_size += iehdr->e_phnum * iehdr->e_phentsize;
+
+ map->p_vaddr_offset = ((map->p_paddr + hdr_size) / opb
+ - (lowest_section ? lowest_section->lma : 0));
+ }
+
+ map->count = section_count;
+ *pointer_to_map = map;
+ pointer_to_map = &map->next;
+ }
+
+ elf_seg_map (obfd) = map_first;
+ return true;
+}
+
+/* Copy private BFD data. This copies or rewrites ELF program header
+ information. */
+
+static bool
+copy_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+ bfd_vma maxpagesize;
+
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return true;
+
+ if (elf_tdata (ibfd)->phdr == NULL)
+ return true;
+
+ if (ibfd->xvec == obfd->xvec)
+ {
+ /* Check to see if any sections in the input BFD
+ covered by ELF program header have changed. */
+ Elf_Internal_Phdr *segment;
+ asection *section, *osec;
+ unsigned int i, num_segments;
+ Elf_Internal_Shdr *this_hdr;
+ const struct elf_backend_data *bed;
+
+ bed = get_elf_backend_data (ibfd);
+
+ /* Regenerate the segment map if p_paddr is set to 0. */
+ if (bed->want_p_paddr_set_to_zero)
+ goto rewrite;
+
+ /* Initialize the segment mark field. */
+ for (section = obfd->sections; section != NULL;
+ section = section->next)
+ section->segment_mark = false;
+
+ num_segments = elf_elfheader (ibfd)->e_phnum;
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ {
+ /* PR binutils/3535. The Solaris linker always sets the p_paddr
+ and p_memsz fields of special segments (DYNAMIC, INTERP) to 0
+ which severly confuses things, so always regenerate the segment
+ map in this case. */
+ if (segment->p_paddr == 0
+ && segment->p_memsz == 0
+ && (segment->p_type == PT_INTERP
+ || segment->p_type == PT_DYNAMIC))
+ goto rewrite;
+
+ for (section = ibfd->sections;
+ section != NULL; section = section->next)
+ {
+ /* We mark the output section so that we know it comes
+ from the input BFD. */
+ osec = section->output_section;
+ if (osec)
+ osec->segment_mark = true;
+
+ /* Check if this section is covered by the segment. */
+ this_hdr = &(elf_section_data(section)->this_hdr);
+ if (ELF_SECTION_IN_SEGMENT (this_hdr, segment))
+ {
+ /* FIXME: Check if its output section is changed or
+ removed. What else do we need to check? */
+ if (osec == NULL
+ || section->flags != osec->flags
+ || section->lma != osec->lma
+ || section->vma != osec->vma
+ || section->size != osec->size
+ || section->rawsize != osec->rawsize
+ || section->alignment_power != osec->alignment_power)
+ goto rewrite;
+ }
+ }
+ }
+
+ /* Check to see if any output section do not come from the
+ input BFD. */
+ for (section = obfd->sections; section != NULL;
+ section = section->next)
+ {
+ if (!section->segment_mark)
+ goto rewrite;
+ else
+ section->segment_mark = false;
+ }
+
+ return copy_elf_program_header (ibfd, obfd);
+ }
+
+ rewrite:
+ maxpagesize = 0;
+ if (ibfd->xvec == obfd->xvec)
+ {
+ /* When rewriting program header, set the output maxpagesize to
+ the maximum alignment of input PT_LOAD segments. */
+ Elf_Internal_Phdr *segment;
+ unsigned int i;
+ unsigned int num_segments = elf_elfheader (ibfd)->e_phnum;
+
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ if (segment->p_type == PT_LOAD
+ && maxpagesize < segment->p_align)
+ {
+ /* PR 17512: file: f17299af. */
+ if (segment->p_align > (bfd_vma) 1 << ((sizeof (bfd_vma) * 8) - 2))
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: warning: segment alignment of %#"
+ PRIx64 " is too large"),
+ ibfd, (uint64_t) segment->p_align);
+ else
+ maxpagesize = segment->p_align;
+ }
+ }
+ if (maxpagesize == 0)
+ maxpagesize = get_elf_backend_data (obfd)->maxpagesize;
+
+ return rewrite_elf_program_header (ibfd, obfd, maxpagesize);
+}
+
+/* Initialize private output section information from input section. */
+
+bool
+_bfd_elf_init_private_section_data (bfd *ibfd,
+ asection *isec,
+ bfd *obfd,
+ asection *osec,
+ struct bfd_link_info *link_info)
+
+{
+ Elf_Internal_Shdr *ihdr, *ohdr;
+ bool final_link = (link_info != NULL
+ && !bfd_link_relocatable (link_info));
+
+ if (ibfd->xvec->flavour != bfd_target_elf_flavour
+ || obfd->xvec->flavour != bfd_target_elf_flavour)
+ return true;
+
+ BFD_ASSERT (elf_section_data (osec) != NULL);
+
+ /* If this is a known ABI section, ELF section type and flags may
+ have been set up when OSEC was created. For normal sections we
+ allow the user to override the type and flags other than
+ SHF_MASKOS and SHF_MASKPROC. */
+ if (elf_section_type (osec) == SHT_PROGBITS
+ || elf_section_type (osec) == SHT_NOTE
+ || elf_section_type (osec) == SHT_NOBITS)
+ elf_section_type (osec) = SHT_NULL;
+ /* For objcopy and relocatable link, copy the ELF section type from
+ the input file if the BFD section flags are the same. (If they
+ are different the user may be doing something like
+ "objcopy --set-section-flags .text=alloc,data".) For a final
+ link allow some flags that the linker clears to differ. */
+ if (elf_section_type (osec) == SHT_NULL
+ && (osec->flags == isec->flags
+ || (final_link
+ && ((osec->flags ^ isec->flags)
+ & ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC)) == 0)))
+ elf_section_type (osec) = elf_section_type (isec);
+
+ /* FIXME: Is this correct for all OS/PROC specific flags? */
+ elf_section_flags (osec) = (elf_section_flags (isec)
+ & (SHF_MASKOS | SHF_MASKPROC));
+
+ /* Copy sh_info from input for mbind section. */
+ if ((elf_tdata (ibfd)->has_gnu_osabi & elf_gnu_osabi_mbind) != 0
+ && elf_section_flags (isec) & SHF_GNU_MBIND)
+ elf_section_data (osec)->this_hdr.sh_info
+ = elf_section_data (isec)->this_hdr.sh_info;
+
+ /* Set things up for objcopy and relocatable link. The output
+ SHT_GROUP section will have its elf_next_in_group pointing back
+ to the input group members. Ignore linker created group section.
+ See elfNN_ia64_object_p in elfxx-ia64.c. */
+ if ((link_info == NULL
+ || !link_info->resolve_section_groups)
+ && (elf_sec_group (isec) == NULL
+ || (elf_sec_group (isec)->flags & SEC_LINKER_CREATED) == 0))
+ {
+ if (elf_section_flags (isec) & SHF_GROUP)
+ elf_section_flags (osec) |= SHF_GROUP;
+ elf_next_in_group (osec) = elf_next_in_group (isec);
+ elf_section_data (osec)->group = elf_section_data (isec)->group;
+ }
+
+ /* If not decompress, preserve SHF_COMPRESSED. */
+ if (!final_link && (ibfd->flags & BFD_DECOMPRESS) == 0)
+ elf_section_flags (osec) |= (elf_section_flags (isec)
+ & SHF_COMPRESSED);
+
+ ihdr = &elf_section_data (isec)->this_hdr;
+
+ /* We need to handle elf_linked_to_section for SHF_LINK_ORDER. We
+ don't use the output section of the linked-to section since it
+ may be NULL at this point. */
+ if ((ihdr->sh_flags & SHF_LINK_ORDER) != 0)
+ {
+ ohdr = &elf_section_data (osec)->this_hdr;
+ ohdr->sh_flags |= SHF_LINK_ORDER;
+ elf_linked_to_section (osec) = elf_linked_to_section (isec);
+ }
+
+ osec->use_rela_p = isec->use_rela_p;
+
+ return true;
+}
+
+/* Copy private section information. This copies over the entsize
+ field, and sometimes the info field. */
+
+bool
+_bfd_elf_copy_private_section_data (bfd *ibfd,
+ asection *isec,
+ bfd *obfd,
+ asection *osec)
+{
+ Elf_Internal_Shdr *ihdr, *ohdr;
+
+ if (ibfd->xvec->flavour != bfd_target_elf_flavour
+ || obfd->xvec->flavour != bfd_target_elf_flavour)
+ return true;
+
+ ihdr = &elf_section_data (isec)->this_hdr;
+ ohdr = &elf_section_data (osec)->this_hdr;
+
+ ohdr->sh_entsize = ihdr->sh_entsize;
+
+ if (ihdr->sh_type == SHT_SYMTAB
+ || ihdr->sh_type == SHT_DYNSYM
+ || ihdr->sh_type == SHT_GNU_verneed
+ || ihdr->sh_type == SHT_GNU_verdef)
+ ohdr->sh_info = ihdr->sh_info;
+
+ return _bfd_elf_init_private_section_data (ibfd, isec, obfd, osec,
+ NULL);
+}
+
+/* Look at all the SHT_GROUP sections in IBFD, making any adjustments
+ necessary if we are removing either the SHT_GROUP section or any of
+ the group member sections. DISCARDED is the value that a section's
+ output_section has if the section will be discarded, NULL when this
+ function is called from objcopy, bfd_abs_section_ptr when called
+ from the linker. */
+
+bool
+_bfd_elf_fixup_group_sections (bfd *ibfd, asection *discarded)
+{
+ asection *isec;
+
+ for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+ if (elf_section_type (isec) == SHT_GROUP)
+ {
+ asection *first = elf_next_in_group (isec);
+ asection *s = first;
+ bfd_size_type removed = 0;
+
+ while (s != NULL)
+ {
+ /* If this member section is being output but the
+ SHT_GROUP section is not, then clear the group info
+ set up by _bfd_elf_copy_private_section_data. */
+ if (s->output_section != discarded
+ && isec->output_section == discarded)
+ {
+ elf_section_flags (s->output_section) &= ~SHF_GROUP;
+ elf_group_name (s->output_section) = NULL;
+ }
+ else
+ {
+ struct bfd_elf_section_data *elf_sec = elf_section_data (s);
+ if (s->output_section == discarded
+ && isec->output_section != discarded)
+ {
+ /* Conversely, if the member section is not being
+ output but the SHT_GROUP section is, then adjust
+ its size. */
+ removed += 4;
+ if (elf_sec->rel.hdr != NULL
+ && (elf_sec->rel.hdr->sh_flags & SHF_GROUP) != 0)
+ removed += 4;
+ if (elf_sec->rela.hdr != NULL
+ && (elf_sec->rela.hdr->sh_flags & SHF_GROUP) != 0)
+ removed += 4;
+ }
+ else
+ {
+ /* Also adjust for zero-sized relocation member
+ section. */
+ if (elf_sec->rel.hdr != NULL
+ && elf_sec->rel.hdr->sh_size == 0)
+ removed += 4;
+ if (elf_sec->rela.hdr != NULL
+ && elf_sec->rela.hdr->sh_size == 0)
+ removed += 4;
+ }
+ }
+ s = elf_next_in_group (s);
+ if (s == first)
+ break;
+ }
+ if (removed != 0)
+ {
+ if (discarded != NULL)
+ {
+ /* If we've been called for ld -r, then we need to
+ adjust the input section size. */
+ if (isec->rawsize == 0)
+ isec->rawsize = isec->size;
+ isec->size = isec->rawsize - removed;
+ if (isec->size <= 4)
+ {
+ isec->size = 0;
+ isec->flags |= SEC_EXCLUDE;
+ }
+ }
+ else if (isec->output_section != NULL)
+ {
+ /* Adjust the output section size when called from
+ objcopy. */
+ isec->output_section->size -= removed;
+ if (isec->output_section->size <= 4)
+ {
+ isec->output_section->size = 0;
+ isec->output_section->flags |= SEC_EXCLUDE;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/* Copy private header information. */
+
+bool
+_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd)
+{
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return true;
+
+ /* Copy over private BFD data if it has not already been copied.
+ This must be done here, rather than in the copy_private_bfd_data
+ entry point, because the latter is called after the section
+ contents have been set, which means that the program headers have
+ already been worked out. */
+ if (elf_seg_map (obfd) == NULL && elf_tdata (ibfd)->phdr != NULL)
+ {
+ if (! copy_private_bfd_data (ibfd, obfd))
+ return false;
+ }
+
+ return _bfd_elf_fixup_group_sections (ibfd, NULL);
+}
+
+/* Copy private symbol information. If this symbol is in a section
+ which we did not map into a BFD section, try to map the section
+ index correctly. We use special macro definitions for the mapped
+ section indices; these definitions are interpreted by the
+ swap_out_syms function. */
+
+#define MAP_ONESYMTAB (SHN_HIOS + 1)
+#define MAP_DYNSYMTAB (SHN_HIOS + 2)
+#define MAP_STRTAB (SHN_HIOS + 3)
+#define MAP_SHSTRTAB (SHN_HIOS + 4)
+#define MAP_SYM_SHNDX (SHN_HIOS + 5)
+
+bool
+_bfd_elf_copy_private_symbol_data (bfd *ibfd,
+ asymbol *isymarg,
+ bfd *obfd,
+ asymbol *osymarg)
+{
+ elf_symbol_type *isym, *osym;
+
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return true;
+
+ isym = elf_symbol_from (isymarg);
+ osym = elf_symbol_from (osymarg);
+
+ if (isym != NULL
+ && isym->internal_elf_sym.st_shndx != 0
+ && osym != NULL
+ && bfd_is_abs_section (isym->symbol.section))
+ {
+ unsigned int shndx;
+
+ shndx = isym->internal_elf_sym.st_shndx;
+ if (shndx == elf_onesymtab (ibfd))
+ shndx = MAP_ONESYMTAB;
+ else if (shndx == elf_dynsymtab (ibfd))
+ shndx = MAP_DYNSYMTAB;
+ else if (shndx == elf_strtab_sec (ibfd))
+ shndx = MAP_STRTAB;
+ else if (shndx == elf_shstrtab_sec (ibfd))
+ shndx = MAP_SHSTRTAB;
+ else if (find_section_in_list (shndx, elf_symtab_shndx_list (ibfd)))
+ shndx = MAP_SYM_SHNDX;
+ osym->internal_elf_sym.st_shndx = shndx;
+ }
+
+ return true;
+}
+
+/* Swap out the symbols. */
+
+static bool
+swap_out_syms (bfd *abfd,
+ struct elf_strtab_hash **sttp,
+ int relocatable_p,
+ struct bfd_link_info *info)
+{
+ const struct elf_backend_data *bed;
+ unsigned int symcount;
+ asymbol **syms;
+ struct elf_strtab_hash *stt;
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Shdr *symtab_shndx_hdr;
+ Elf_Internal_Shdr *symstrtab_hdr;
+ struct elf_sym_strtab *symstrtab;
+ bfd_byte *outbound_syms;
+ bfd_byte *outbound_shndx;
+ unsigned long outbound_syms_index;
+ unsigned int idx;
+ unsigned int num_locals;
+ size_t amt;
+ bool name_local_sections;
+
+ if (!elf_map_symbols (abfd, &num_locals))
+ return false;
+
+ /* Dump out the symtabs. */
+ stt = _bfd_elf_strtab_init ();
+ if (stt == NULL)
+ return false;
+
+ bed = get_elf_backend_data (abfd);
+ symcount = bfd_get_symcount (abfd);
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ symtab_hdr->sh_type = SHT_SYMTAB;
+ symtab_hdr->sh_entsize = bed->s->sizeof_sym;
+ symtab_hdr->sh_size = symtab_hdr->sh_entsize * (symcount + 1);
+ symtab_hdr->sh_info = num_locals + 1;
+ symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
+
+ symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
+ symstrtab_hdr->sh_type = SHT_STRTAB;
+
+ /* Allocate buffer to swap out the .strtab section. */
+ if (_bfd_mul_overflow (symcount + 1, sizeof (*symstrtab), &amt)
+ || (symstrtab = (struct elf_sym_strtab *) bfd_malloc (amt)) == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ _bfd_elf_strtab_free (stt);
+ return false;
+ }
+
+ if (_bfd_mul_overflow (symcount + 1, bed->s->sizeof_sym, &amt)
+ || (outbound_syms = (bfd_byte *) bfd_alloc (abfd, amt)) == NULL)
+ {
+ error_no_mem:
+ bfd_set_error (bfd_error_no_memory);
+ error_return:
+ free (symstrtab);
+ _bfd_elf_strtab_free (stt);
+ return false;
+ }
+ symtab_hdr->contents = outbound_syms;
+ outbound_syms_index = 0;
+
+ outbound_shndx = NULL;
+
+ if (elf_symtab_shndx_list (abfd))
+ {
+ symtab_shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr;
+ if (symtab_shndx_hdr->sh_name != 0)
+ {
+ if (_bfd_mul_overflow (symcount + 1,
+ sizeof (Elf_External_Sym_Shndx), &amt))
+ goto error_no_mem;
+ outbound_shndx = (bfd_byte *) bfd_zalloc (abfd, amt);
+ if (outbound_shndx == NULL)
+ goto error_return;
+
+ symtab_shndx_hdr->contents = outbound_shndx;
+ symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
+ symtab_shndx_hdr->sh_size = amt;
+ symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
+ symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
+ }
+ /* FIXME: What about any other headers in the list ? */
+ }
+
+ /* Now generate the data (for "contents"). */
+ {
+ /* Fill in zeroth symbol and swap it out. */
+ Elf_Internal_Sym sym;
+ sym.st_name = 0;
+ sym.st_value = 0;
+ sym.st_size = 0;
+ sym.st_info = 0;
+ sym.st_other = 0;
+ sym.st_shndx = SHN_UNDEF;
+ sym.st_target_internal = 0;
+ symstrtab[0].sym = sym;
+ symstrtab[0].dest_index = outbound_syms_index;
+ outbound_syms_index++;
+ }
+
+ name_local_sections
+ = (bed->elf_backend_name_local_section_symbols
+ && bed->elf_backend_name_local_section_symbols (abfd));
+
+ syms = bfd_get_outsymbols (abfd);
+ for (idx = 0; idx < symcount;)
+ {
+ Elf_Internal_Sym sym;
+ bfd_vma value = syms[idx]->value;
+ elf_symbol_type *type_ptr;
+ flagword flags = syms[idx]->flags;
+ int type;
+
+ if (!name_local_sections
+ && (flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM)
+ {
+ /* Local section symbols have no name. */
+ sym.st_name = (unsigned long) -1;
+ }
+ else
+ {
+ /* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize
+ to get the final offset for st_name. */
+ sym.st_name
+ = (unsigned long) _bfd_elf_strtab_add (stt, syms[idx]->name,
+ false);
+ if (sym.st_name == (unsigned long) -1)
+ goto error_return;
+ }
+
+ type_ptr = elf_symbol_from (syms[idx]);
+
+ if ((flags & BSF_SECTION_SYM) == 0
+ && bfd_is_com_section (syms[idx]->section))
+ {
+ /* ELF common symbols put the alignment into the `value' field,
+ and the size into the `size' field. This is backwards from
+ how BFD handles it, so reverse it here. */
+ sym.st_size = value;
+ if (type_ptr == NULL
+ || type_ptr->internal_elf_sym.st_value == 0)
+ sym.st_value = value >= 16 ? 16 : (1 << bfd_log2 (value));
+ else
+ sym.st_value = type_ptr->internal_elf_sym.st_value;
+ sym.st_shndx = _bfd_elf_section_from_bfd_section
+ (abfd, syms[idx]->section);
+ }
+ else
+ {
+ asection *sec = syms[idx]->section;
+ unsigned int shndx;
+
+ if (sec->output_section)
+ {
+ value += sec->output_offset;
+ sec = sec->output_section;
+ }
+
+ /* Don't add in the section vma for relocatable output. */
+ if (! relocatable_p)
+ value += sec->vma;
+ sym.st_value = value;
+ sym.st_size = type_ptr ? type_ptr->internal_elf_sym.st_size : 0;
+
+ if (bfd_is_abs_section (sec)
+ && type_ptr != NULL
+ && type_ptr->internal_elf_sym.st_shndx != 0)
+ {
+ /* This symbol is in a real ELF section which we did
+ not create as a BFD section. Undo the mapping done
+ by copy_private_symbol_data. */
+ shndx = type_ptr->internal_elf_sym.st_shndx;
+ switch (shndx)
+ {
+ case MAP_ONESYMTAB:
+ shndx = elf_onesymtab (abfd);
+ break;
+ case MAP_DYNSYMTAB:
+ shndx = elf_dynsymtab (abfd);
+ break;
+ case MAP_STRTAB:
+ shndx = elf_strtab_sec (abfd);
+ break;
+ case MAP_SHSTRTAB:
+ shndx = elf_shstrtab_sec (abfd);
+ break;
+ case MAP_SYM_SHNDX:
+ if (elf_symtab_shndx_list (abfd))
+ shndx = elf_symtab_shndx_list (abfd)->ndx;
+ break;
+ case SHN_COMMON:
+ case SHN_ABS:
+ shndx = SHN_ABS;
+ break;
+ default:
+ if (shndx >= SHN_LOPROC && shndx <= SHN_HIOS)
+ {
+ if (bed->symbol_section_index)
+ shndx = bed->symbol_section_index (abfd, type_ptr);
+ /* Otherwise just leave the index alone. */
+ }
+ else
+ {
+ if (shndx > SHN_HIOS && shndx < SHN_HIRESERVE)
+ _bfd_error_handler (_("%pB: \
+Unable to handle section index %x in ELF symbol. Using ABS instead."),
+ abfd, shndx);
+ shndx = SHN_ABS;
+ }
+ break;
+ }
+ }
+ else
+ {
+ shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+
+ if (shndx == SHN_BAD)
+ {
+ asection *sec2;
+
+ /* Writing this would be a hell of a lot easier if
+ we had some decent documentation on bfd, and
+ knew what to expect of the library, and what to
+ demand of applications. For example, it
+ appears that `objcopy' might not set the
+ section of a symbol to be a section that is
+ actually in the output file. */
+ sec2 = bfd_get_section_by_name (abfd, sec->name);
+ if (sec2 != NULL)
+ shndx = _bfd_elf_section_from_bfd_section (abfd, sec2);
+ if (shndx == SHN_BAD)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler
+ (_("unable to find equivalent output section"
+ " for symbol '%s' from section '%s'"),
+ syms[idx]->name ? syms[idx]->name : "<Local sym>",
+ sec->name);
+ bfd_set_error (bfd_error_invalid_operation);
+ goto error_return;
+ }
+ }
+ }
+
+ sym.st_shndx = shndx;
+ }
+
+ if ((flags & BSF_THREAD_LOCAL) != 0)
+ type = STT_TLS;
+ else if ((flags & BSF_GNU_INDIRECT_FUNCTION) != 0)
+ type = STT_GNU_IFUNC;
+ else if ((flags & BSF_FUNCTION) != 0)
+ type = STT_FUNC;
+ else if ((flags & BSF_OBJECT) != 0)
+ type = STT_OBJECT;
+ else if ((flags & BSF_RELC) != 0)
+ type = STT_RELC;
+ else if ((flags & BSF_SRELC) != 0)
+ type = STT_SRELC;
+ else
+ type = STT_NOTYPE;
+
+ if (syms[idx]->section->flags & SEC_THREAD_LOCAL)
+ type = STT_TLS;
+
+ /* Processor-specific types. */
+ if (type_ptr != NULL
+ && bed->elf_backend_get_symbol_type)
+ type = ((*bed->elf_backend_get_symbol_type)
+ (&type_ptr->internal_elf_sym, type));
+
+ if (flags & BSF_SECTION_SYM)
+ {
+ if (flags & BSF_GLOBAL)
+ sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
+ else
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+ }
+ else if (bfd_is_com_section (syms[idx]->section))
+ {
+ if (type != STT_TLS)
+ {
+ if ((abfd->flags & BFD_CONVERT_ELF_COMMON))
+ type = ((abfd->flags & BFD_USE_ELF_STT_COMMON)
+ ? STT_COMMON : STT_OBJECT);
+ else
+ type = ((flags & BSF_ELF_COMMON) != 0
+ ? STT_COMMON : STT_OBJECT);
+ }
+ sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
+ }
+ else if (bfd_is_und_section (syms[idx]->section))
+ sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
+ ? STB_WEAK
+ : STB_GLOBAL),
+ type);
+ else if (flags & BSF_FILE)
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+ else
+ {
+ int bind = STB_LOCAL;
+
+ if (flags & BSF_LOCAL)
+ bind = STB_LOCAL;
+ else if (flags & BSF_GNU_UNIQUE)
+ bind = STB_GNU_UNIQUE;
+ else if (flags & BSF_WEAK)
+ bind = STB_WEAK;
+ else if (flags & BSF_GLOBAL)
+ bind = STB_GLOBAL;
+
+ sym.st_info = ELF_ST_INFO (bind, type);
+ }
+
+ if (type_ptr != NULL)
+ {
+ sym.st_other = type_ptr->internal_elf_sym.st_other;
+ sym.st_target_internal
+ = type_ptr->internal_elf_sym.st_target_internal;
+ }
+ else
+ {
+ sym.st_other = 0;
+ sym.st_target_internal = 0;
+ }
+
+ idx++;
+ symstrtab[idx].sym = sym;
+ symstrtab[idx].dest_index = outbound_syms_index;
+
+ outbound_syms_index++;
+ }
+
+ /* Finalize the .strtab section. */
+ _bfd_elf_strtab_finalize (stt);
+
+ /* Swap out the .strtab section. */
+ for (idx = 0; idx <= symcount; idx++)
+ {
+ struct elf_sym_strtab *elfsym = &symstrtab[idx];
+ if (elfsym->sym.st_name == (unsigned long) -1)
+ elfsym->sym.st_name = 0;
+ else
+ elfsym->sym.st_name = _bfd_elf_strtab_offset (stt,
+ elfsym->sym.st_name);
+ if (info && info->callbacks->ctf_new_symbol)
+ info->callbacks->ctf_new_symbol (elfsym->dest_index,
+ &elfsym->sym);
+
+ /* Inform the linker of the addition of this symbol. */
+
+ bed->s->swap_symbol_out (abfd, &elfsym->sym,
+ (outbound_syms
+ + (elfsym->dest_index
+ * bed->s->sizeof_sym)),
+ NPTR_ADD (outbound_shndx,
+ (elfsym->dest_index
+ * sizeof (Elf_External_Sym_Shndx))));
+ }
+ free (symstrtab);
+
+ *sttp = stt;
+ symstrtab_hdr->sh_size = _bfd_elf_strtab_size (stt);
+ symstrtab_hdr->sh_type = SHT_STRTAB;
+ symstrtab_hdr->sh_flags = bed->elf_strtab_flags;
+ symstrtab_hdr->sh_addr = 0;
+ symstrtab_hdr->sh_entsize = 0;
+ symstrtab_hdr->sh_link = 0;
+ symstrtab_hdr->sh_info = 0;
+ symstrtab_hdr->sh_addralign = 1;
+
+ return true;
+}
+
+/* Return the number of bytes required to hold the symtab vector.
+
+ Note that we base it on the count plus 1, since we will null terminate
+ the vector allocated based on this size. However, the ELF symbol table
+ always has a dummy entry as symbol #0, so it ends up even. */
+
+long
+_bfd_elf_get_symtab_upper_bound (bfd *abfd)
+{
+ bfd_size_type symcount;
+ long symtab_size;
+ Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->symtab_hdr;
+
+ symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym;
+ if (symcount > LONG_MAX / sizeof (asymbol *))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ return -1;
+ }
+ symtab_size = symcount * (sizeof (asymbol *));
+ if (symcount == 0)
+ symtab_size = sizeof (asymbol *);
+ else if (!bfd_write_p (abfd))
+ {
+ ufile_ptr filesize = bfd_get_file_size (abfd);
+
+ if (filesize != 0 && (unsigned long) symtab_size > filesize)
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
+ }
+
+ return symtab_size;
+}
+
+long
+_bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd)
+{
+ bfd_size_type symcount;
+ long symtab_size;
+ Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym;
+ if (symcount > LONG_MAX / sizeof (asymbol *))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ return -1;
+ }
+ symtab_size = symcount * (sizeof (asymbol *));
+ if (symcount == 0)
+ symtab_size = sizeof (asymbol *);
+ else if (!bfd_write_p (abfd))
+ {
+ ufile_ptr filesize = bfd_get_file_size (abfd);
+
+ if (filesize != 0 && (unsigned long) symtab_size > filesize)
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
+ }
+
+ return symtab_size;
+}
+
+long
+_bfd_elf_get_reloc_upper_bound (bfd *abfd, sec_ptr asect)
+{
+ if (asect->reloc_count != 0 && !bfd_write_p (abfd))
+ {
+ /* Sanity check reloc section size. */
+ ufile_ptr filesize = bfd_get_file_size (abfd);
+
+ if (filesize != 0)
+ {
+ struct bfd_elf_section_data *d = elf_section_data (asect);
+ bfd_size_type rel_size = d->rel.hdr ? d->rel.hdr->sh_size : 0;
+ bfd_size_type rela_size = d->rela.hdr ? d->rela.hdr->sh_size : 0;
+
+ if (rel_size + rela_size > filesize
+ || rel_size + rela_size < rel_size)
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
+ }
+ }
+
+#if SIZEOF_LONG == SIZEOF_INT
+ if (asect->reloc_count >= LONG_MAX / sizeof (arelent *))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ return -1;
+ }
+#endif
+ return (asect->reloc_count + 1L) * sizeof (arelent *);
+}
+
+/* Canonicalize the relocs. */
+
+long
+_bfd_elf_canonicalize_reloc (bfd *abfd,
+ sec_ptr section,
+ arelent **relptr,
+ asymbol **symbols)
+{
+ arelent *tblptr;
+ unsigned int i;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (! bed->s->slurp_reloc_table (abfd, section, symbols, false))
+ return -1;
+
+ tblptr = section->relocation;
+ for (i = 0; i < section->reloc_count; i++)
+ *relptr++ = tblptr++;
+
+ *relptr = NULL;
+
+ return section->reloc_count;
+}
+
+long
+_bfd_elf_canonicalize_symtab (bfd *abfd, asymbol **allocation)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ long symcount = bed->s->slurp_symbol_table (abfd, allocation, false);
+
+ if (symcount >= 0)
+ abfd->symcount = symcount;
+ return symcount;
+}
+
+long
+_bfd_elf_canonicalize_dynamic_symtab (bfd *abfd,
+ asymbol **allocation)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ long symcount = bed->s->slurp_symbol_table (abfd, allocation, true);
+
+ if (symcount >= 0)
+ abfd->dynsymcount = symcount;
+ return symcount;
+}
+
+/* Return the size required for the dynamic reloc entries. Any loadable
+ section that was actually installed in the BFD, and has type SHT_REL
+ or SHT_RELA, and uses the dynamic symbol table, is considered to be a
+ dynamic reloc section. */
+
+long
+_bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd)
+{
+ bfd_size_type count, ext_rel_size;
+ asection *s;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ count = 1;
+ ext_rel_size = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
+ || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+ {
+ ext_rel_size += s->size;
+ if (ext_rel_size < s->size)
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
+ count += s->size / elf_section_data (s)->this_hdr.sh_entsize;
+ if (count > LONG_MAX / sizeof (arelent *))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ return -1;
+ }
+ }
+ if (count > 1 && !bfd_write_p (abfd))
+ {
+ /* Sanity check reloc section sizes. */
+ ufile_ptr filesize = bfd_get_file_size (abfd);
+ if (filesize != 0 && ext_rel_size > filesize)
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
+ }
+ return count * sizeof (arelent *);
+}
+
+/* Canonicalize the dynamic relocation entries. Note that we return the
+ dynamic relocations as a single block, although they are actually
+ associated with particular sections; the interface, which was
+ designed for SunOS style shared libraries, expects that there is only
+ one set of dynamic relocs. Any loadable section that was actually
+ installed in the BFD, and has type SHT_REL or SHT_RELA, and uses the
+ dynamic symbol table, is considered to be a dynamic reloc section. */
+
+long
+_bfd_elf_canonicalize_dynamic_reloc (bfd *abfd,
+ arelent **storage,
+ asymbol **syms)
+{
+ bool (*slurp_relocs) (bfd *, asection *, asymbol **, bool);
+ asection *s;
+ long ret;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+ ret = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
+ || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+ {
+ arelent *p;
+ long count, i;
+
+ if (! (*slurp_relocs) (abfd, s, syms, true))
+ return -1;
+ count = s->size / elf_section_data (s)->this_hdr.sh_entsize;
+ p = s->relocation;
+ for (i = 0; i < count; i++)
+ *storage++ = p++;
+ ret += count;
+ }
+ }
+
+ *storage = NULL;
+
+ return ret;
+}
+
+/* Read in the version information. */
+
+bool
+_bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver)
+{
+ bfd_byte *contents = NULL;
+ unsigned int freeidx = 0;
+ size_t amt;
+
+ if (elf_dynverref (abfd) != 0)
+ {
+ Elf_Internal_Shdr *hdr;
+ Elf_External_Verneed *everneed;
+ Elf_Internal_Verneed *iverneed;
+ unsigned int i;
+ bfd_byte *contents_end;
+
+ hdr = &elf_tdata (abfd)->dynverref_hdr;
+
+ if (hdr->sh_info > hdr->sh_size / sizeof (Elf_External_Verneed))
+ {
+ error_return_bad_verref:
+ _bfd_error_handler
+ (_("%pB: .gnu.version_r invalid entry"), abfd);
+ bfd_set_error (bfd_error_bad_value);
+ error_return_verref:
+ elf_tdata (abfd)->verref = NULL;
+ elf_tdata (abfd)->cverrefs = 0;
+ goto error_return;
+ }
+
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0)
+ goto error_return_verref;
+ contents = _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size);
+ if (contents == NULL)
+ goto error_return_verref;
+
+ if (_bfd_mul_overflow (hdr->sh_info, sizeof (Elf_Internal_Verneed), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto error_return_verref;
+ }
+ if (amt == 0)
+ goto error_return_verref;
+ elf_tdata (abfd)->verref = (Elf_Internal_Verneed *) bfd_zalloc (abfd, amt);
+ if (elf_tdata (abfd)->verref == NULL)
+ goto error_return_verref;
+
+ BFD_ASSERT (sizeof (Elf_External_Verneed)
+ == sizeof (Elf_External_Vernaux));
+ contents_end = contents + hdr->sh_size - sizeof (Elf_External_Verneed);
+ everneed = (Elf_External_Verneed *) contents;
+ iverneed = elf_tdata (abfd)->verref;
+ for (i = 0; i < hdr->sh_info; i++, iverneed++)
+ {
+ Elf_External_Vernaux *evernaux;
+ Elf_Internal_Vernaux *ivernaux;
+ unsigned int j;
+
+ _bfd_elf_swap_verneed_in (abfd, everneed, iverneed);
+
+ iverneed->vn_bfd = abfd;
+
+ iverneed->vn_filename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ iverneed->vn_file);
+ if (iverneed->vn_filename == NULL)
+ goto error_return_bad_verref;
+
+ if (iverneed->vn_cnt == 0)
+ iverneed->vn_auxptr = NULL;
+ else
+ {
+ if (_bfd_mul_overflow (iverneed->vn_cnt,
+ sizeof (Elf_Internal_Vernaux), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto error_return_verref;
+ }
+ iverneed->vn_auxptr = (struct elf_internal_vernaux *)
+ bfd_alloc (abfd, amt);
+ if (iverneed->vn_auxptr == NULL)
+ goto error_return_verref;
+ }
+
+ if (iverneed->vn_aux
+ > (size_t) (contents_end - (bfd_byte *) everneed))
+ goto error_return_bad_verref;
+
+ evernaux = ((Elf_External_Vernaux *)
+ ((bfd_byte *) everneed + iverneed->vn_aux));
+ ivernaux = iverneed->vn_auxptr;
+ for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++)
+ {
+ _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux);
+
+ ivernaux->vna_nodename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ ivernaux->vna_name);
+ if (ivernaux->vna_nodename == NULL)
+ goto error_return_bad_verref;
+
+ if (ivernaux->vna_other > freeidx)
+ freeidx = ivernaux->vna_other;
+
+ ivernaux->vna_nextptr = NULL;
+ if (ivernaux->vna_next == 0)
+ {
+ iverneed->vn_cnt = j + 1;
+ break;
+ }
+ if (j + 1 < iverneed->vn_cnt)
+ ivernaux->vna_nextptr = ivernaux + 1;
+
+ if (ivernaux->vna_next
+ > (size_t) (contents_end - (bfd_byte *) evernaux))
+ goto error_return_bad_verref;
+
+ evernaux = ((Elf_External_Vernaux *)
+ ((bfd_byte *) evernaux + ivernaux->vna_next));
+ }
+
+ iverneed->vn_nextref = NULL;
+ if (iverneed->vn_next == 0)
+ break;
+ if (i + 1 < hdr->sh_info)
+ iverneed->vn_nextref = iverneed + 1;
+
+ if (iverneed->vn_next
+ > (size_t) (contents_end - (bfd_byte *) everneed))
+ goto error_return_bad_verref;
+
+ everneed = ((Elf_External_Verneed *)
+ ((bfd_byte *) everneed + iverneed->vn_next));
+ }
+ elf_tdata (abfd)->cverrefs = i;
+
+ free (contents);
+ contents = NULL;
+ }
+
+ if (elf_dynverdef (abfd) != 0)
+ {
+ Elf_Internal_Shdr *hdr;
+ Elf_External_Verdef *everdef;
+ Elf_Internal_Verdef *iverdef;
+ Elf_Internal_Verdef *iverdefarr;
+ Elf_Internal_Verdef iverdefmem;
+ unsigned int i;
+ unsigned int maxidx;
+ bfd_byte *contents_end_def, *contents_end_aux;
+
+ hdr = &elf_tdata (abfd)->dynverdef_hdr;
+
+ if (hdr->sh_size < sizeof (Elf_External_Verdef))
+ {
+ error_return_bad_verdef:
+ _bfd_error_handler
+ (_("%pB: .gnu.version_d invalid entry"), abfd);
+ bfd_set_error (bfd_error_bad_value);
+ error_return_verdef:
+ elf_tdata (abfd)->verdef = NULL;
+ elf_tdata (abfd)->cverdefs = 0;
+ goto error_return;
+ }
+
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0)
+ goto error_return_verdef;
+ contents = _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size);
+ if (contents == NULL)
+ goto error_return_verdef;
+
+ BFD_ASSERT (sizeof (Elf_External_Verdef)
+ >= sizeof (Elf_External_Verdaux));
+ contents_end_def = contents + hdr->sh_size
+ - sizeof (Elf_External_Verdef);
+ contents_end_aux = contents + hdr->sh_size
+ - sizeof (Elf_External_Verdaux);
+
+ /* We know the number of entries in the section but not the maximum
+ index. Therefore we have to run through all entries and find
+ the maximum. */
+ everdef = (Elf_External_Verdef *) contents;
+ maxidx = 0;
+ for (i = 0; i < hdr->sh_info; ++i)
+ {
+ _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem);
+
+ if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) == 0)
+ goto error_return_bad_verdef;
+ if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) > maxidx)
+ maxidx = iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION);
+
+ if (iverdefmem.vd_next == 0)
+ break;
+
+ if (iverdefmem.vd_next
+ > (size_t) (contents_end_def - (bfd_byte *) everdef))
+ goto error_return_bad_verdef;
+
+ everdef = ((Elf_External_Verdef *)
+ ((bfd_byte *) everdef + iverdefmem.vd_next));
+ }
+
+ if (default_imported_symver)
+ {
+ if (freeidx > maxidx)
+ maxidx = ++freeidx;
+ else
+ freeidx = ++maxidx;
+ }
+ if (_bfd_mul_overflow (maxidx, sizeof (Elf_Internal_Verdef), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto error_return_verdef;
+ }
+ elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) bfd_zalloc (abfd, amt);
+ if (elf_tdata (abfd)->verdef == NULL)
+ goto error_return_verdef;
+
+ elf_tdata (abfd)->cverdefs = maxidx;
+
+ everdef = (Elf_External_Verdef *) contents;
+ iverdefarr = elf_tdata (abfd)->verdef;
+ for (i = 0; i < hdr->sh_info; i++)
+ {
+ Elf_External_Verdaux *everdaux;
+ Elf_Internal_Verdaux *iverdaux;
+ unsigned int j;
+
+ _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem);
+
+ if ((iverdefmem.vd_ndx & VERSYM_VERSION) == 0)
+ goto error_return_bad_verdef;
+
+ iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1];
+ memcpy (iverdef, &iverdefmem, offsetof (Elf_Internal_Verdef, vd_bfd));
+
+ iverdef->vd_bfd = abfd;
+
+ if (iverdef->vd_cnt == 0)
+ iverdef->vd_auxptr = NULL;
+ else
+ {
+ if (_bfd_mul_overflow (iverdef->vd_cnt,
+ sizeof (Elf_Internal_Verdaux), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto error_return_verdef;
+ }
+ iverdef->vd_auxptr = (struct elf_internal_verdaux *)
+ bfd_alloc (abfd, amt);
+ if (iverdef->vd_auxptr == NULL)
+ goto error_return_verdef;
+ }
+
+ if (iverdef->vd_aux
+ > (size_t) (contents_end_aux - (bfd_byte *) everdef))
+ goto error_return_bad_verdef;
+
+ everdaux = ((Elf_External_Verdaux *)
+ ((bfd_byte *) everdef + iverdef->vd_aux));
+ iverdaux = iverdef->vd_auxptr;
+ for (j = 0; j < iverdef->vd_cnt; j++, iverdaux++)
+ {
+ _bfd_elf_swap_verdaux_in (abfd, everdaux, iverdaux);
+
+ iverdaux->vda_nodename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ iverdaux->vda_name);
+ if (iverdaux->vda_nodename == NULL)
+ goto error_return_bad_verdef;
+
+ iverdaux->vda_nextptr = NULL;
+ if (iverdaux->vda_next == 0)
+ {
+ iverdef->vd_cnt = j + 1;
+ break;
+ }
+ if (j + 1 < iverdef->vd_cnt)
+ iverdaux->vda_nextptr = iverdaux + 1;
+
+ if (iverdaux->vda_next
+ > (size_t) (contents_end_aux - (bfd_byte *) everdaux))
+ goto error_return_bad_verdef;
+
+ everdaux = ((Elf_External_Verdaux *)
+ ((bfd_byte *) everdaux + iverdaux->vda_next));
+ }
+
+ iverdef->vd_nodename = NULL;
+ if (iverdef->vd_cnt)
+ iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename;
+
+ iverdef->vd_nextdef = NULL;
+ if (iverdef->vd_next == 0)
+ break;
+ if ((size_t) (iverdef - iverdefarr) + 1 < maxidx)
+ iverdef->vd_nextdef = iverdef + 1;
+
+ everdef = ((Elf_External_Verdef *)
+ ((bfd_byte *) everdef + iverdef->vd_next));
+ }
+
+ free (contents);
+ contents = NULL;
+ }
+ else if (default_imported_symver)
+ {
+ if (freeidx < 3)
+ freeidx = 3;
+ else
+ freeidx++;
+
+ if (_bfd_mul_overflow (freeidx, sizeof (Elf_Internal_Verdef), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto error_return;
+ }
+ elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) bfd_zalloc (abfd, amt);
+ if (elf_tdata (abfd)->verdef == NULL)
+ goto error_return;
+
+ elf_tdata (abfd)->cverdefs = freeidx;
+ }
+
+ /* Create a default version based on the soname. */
+ if (default_imported_symver)
+ {
+ Elf_Internal_Verdef *iverdef;
+ Elf_Internal_Verdaux *iverdaux;
+
+ iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];
+
+ iverdef->vd_version = VER_DEF_CURRENT;
+ iverdef->vd_flags = 0;
+ iverdef->vd_ndx = freeidx;
+ iverdef->vd_cnt = 1;
+
+ iverdef->vd_bfd = abfd;
+
+ iverdef->vd_nodename = bfd_elf_get_dt_soname (abfd);
+ if (iverdef->vd_nodename == NULL)
+ goto error_return_verdef;
+ iverdef->vd_nextdef = NULL;
+ iverdef->vd_auxptr = ((struct elf_internal_verdaux *)
+ bfd_zalloc (abfd, sizeof (Elf_Internal_Verdaux)));
+ if (iverdef->vd_auxptr == NULL)
+ goto error_return_verdef;
+
+ iverdaux = iverdef->vd_auxptr;
+ iverdaux->vda_nodename = iverdef->vd_nodename;
+ }
+
+ return true;
+
+ error_return:
+ free (contents);
+ return false;
+}
+
+asymbol *
+_bfd_elf_make_empty_symbol (bfd *abfd)
+{
+ elf_symbol_type *newsym;
+
+ newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (*newsym));
+ if (!newsym)
+ return NULL;
+ newsym->symbol.the_bfd = abfd;
+ return &newsym->symbol;
+}
+
+void
+_bfd_elf_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
+ asymbol *symbol,
+ symbol_info *ret)
+{
+ bfd_symbol_info (symbol, ret);
+}
+
+/* Return whether a symbol name implies a local symbol. Most targets
+ use this function for the is_local_label_name entry point, but some
+ override it. */
+
+bool
+_bfd_elf_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *name)
+{
+ /* Normal local symbols start with ``.L''. */
+ if (name[0] == '.' && name[1] == 'L')
+ return true;
+
+ /* At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate
+ DWARF debugging symbols starting with ``..''. */
+ if (name[0] == '.' && name[1] == '.')
+ return true;
+
+ /* gcc will sometimes generate symbols beginning with ``_.L_'' when
+ emitting DWARF debugging output. I suspect this is actually a
+ small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call
+ ASM_GENERATE_INTERNAL_LABEL, and this causes the leading
+ underscore to be emitted on some ELF targets). For ease of use,
+ we treat such symbols as local. */
+ if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
+ return true;
+
+ /* Treat assembler generated fake symbols, dollar local labels and
+ forward-backward labels (aka local labels) as locals.
+ These labels have the form:
+
+ L0^A.* (fake symbols)
+
+ [.]?L[0123456789]+{^A|^B}[0123456789]* (local labels)
+
+ Versions which start with .L will have already been matched above,
+ so we only need to match the rest. */
+ if (name[0] == 'L' && ISDIGIT (name[1]))
+ {
+ bool ret = false;
+ const char * p;
+ char c;
+
+ for (p = name + 2; (c = *p); p++)
+ {
+ if (c == 1 || c == 2)
+ {
+ if (c == 1 && p == name + 2)
+ /* A fake symbol. */
+ return true;
+
+ /* FIXME: We are being paranoid here and treating symbols like
+ L0^Bfoo as if there were non-local, on the grounds that the
+ assembler will never generate them. But can any symbol
+ containing an ASCII value in the range 1-31 ever be anything
+ other than some kind of local ? */
+ ret = true;
+ }
+
+ if (! ISDIGIT (c))
+ {
+ ret = false;
+ break;
+ }
+ }
+ return ret;
+ }
+
+ return false;
+}
+
+alent *
+_bfd_elf_get_lineno (bfd *abfd ATTRIBUTE_UNUSED,
+ asymbol *symbol ATTRIBUTE_UNUSED)
+{
+ abort ();
+ return NULL;
+}
+
+bool
+_bfd_elf_set_arch_mach (bfd *abfd,
+ enum bfd_architecture arch,
+ unsigned long machine)
+{
+ /* If this isn't the right architecture for this backend, and this
+ isn't the generic backend, fail. */
+ if (arch != get_elf_backend_data (abfd)->arch
+ && arch != bfd_arch_unknown
+ && get_elf_backend_data (abfd)->arch != bfd_arch_unknown)
+ return false;
+
+ return bfd_default_set_arch_mach (abfd, arch, machine);
+}
+
+/* Find the nearest line to a particular section and offset,
+ for error reporting. */
+
+bool
+_bfd_elf_find_nearest_line (bfd *abfd,
+ asymbol **symbols,
+ asection *section,
+ bfd_vma offset,
+ const char **filename_ptr,
+ const char **functionname_ptr,
+ unsigned int *line_ptr,
+ unsigned int *discriminator_ptr)
+{
+ return _bfd_elf_find_nearest_line_with_alt (abfd, NULL, symbols, section,
+ offset, filename_ptr,
+ functionname_ptr, line_ptr,
+ discriminator_ptr);
+}
+
+/* Find the nearest line to a particular section and offset,
+ for error reporting. ALT_BFD representing a .gnu_debugaltlink file
+ can be optionally specified. */
+
+bool
+_bfd_elf_find_nearest_line_with_alt (bfd *abfd,
+ const char *alt_filename,
+ asymbol **symbols,
+ asection *section,
+ bfd_vma offset,
+ const char **filename_ptr,
+ const char **functionname_ptr,
+ unsigned int *line_ptr,
+ unsigned int *discriminator_ptr)
+{
+ bool found;
+
+ if (_bfd_dwarf2_find_nearest_line_with_alt (abfd, alt_filename, symbols, NULL,
+ section, offset, filename_ptr,
+ functionname_ptr, line_ptr,
+ discriminator_ptr,
+ dwarf_debug_sections,
+ &elf_tdata (abfd)->dwarf2_find_line_info))
+ return true;
+
+ if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
+ filename_ptr, functionname_ptr, line_ptr))
+ {
+ if (!*functionname_ptr)
+ _bfd_elf_find_function (abfd, symbols, section, offset,
+ *filename_ptr ? NULL : filename_ptr,
+ functionname_ptr);
+ 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 && (*functionname_ptr || *line_ptr))
+ return true;
+
+ if (symbols == NULL)
+ return false;
+
+ if (! _bfd_elf_find_function (abfd, symbols, section, offset,
+ filename_ptr, functionname_ptr))
+ return false;
+
+ *line_ptr = 0;
+ return true;
+}
+
+/* Find the line for a symbol. */
+
+bool
+_bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol,
+ const char **filename_ptr, unsigned int *line_ptr)
+{
+ struct elf_obj_tdata *tdata = elf_tdata (abfd);
+ return _bfd_dwarf2_find_nearest_line (abfd, symbols, symbol, NULL, 0,
+ filename_ptr, NULL, line_ptr, NULL,
+ dwarf_debug_sections,
+ &tdata->dwarf2_find_line_info);
+}
+
+/* After a call to bfd_find_nearest_line, successive calls to
+ bfd_find_inliner_info can be used to get source information about
+ each level of function inlining that terminated at the address
+ passed to bfd_find_nearest_line. Currently this is only supported
+ for DWARF2 with appropriate DWARF3 extensions. */
+
+bool
+_bfd_elf_find_inliner_info (bfd *abfd,
+ const char **filename_ptr,
+ const char **functionname_ptr,
+ unsigned int *line_ptr)
+{
+ struct elf_obj_tdata *tdata = elf_tdata (abfd);
+ return _bfd_dwarf2_find_inliner_info (abfd, filename_ptr,
+ functionname_ptr, line_ptr,
+ &tdata->dwarf2_find_line_info);
+}
+
+int
+_bfd_elf_sizeof_headers (bfd *abfd, struct bfd_link_info *info)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ int ret = bed->s->sizeof_ehdr;
+
+ if (!bfd_link_relocatable (info))
+ {
+ bfd_size_type phdr_size = elf_program_header_size (abfd);
+
+ if (phdr_size == (bfd_size_type) -1)
+ {
+ struct elf_segment_map *m;
+
+ phdr_size = 0;
+ for (m = elf_seg_map (abfd); m != NULL; m = m->next)
+ phdr_size += bed->s->sizeof_phdr;
+
+ if (phdr_size == 0)
+ phdr_size = get_program_header_size (abfd, info);
+ }
+
+ elf_program_header_size (abfd) = phdr_size;
+ ret += phdr_size;
+ }
+
+ return ret;
+}
+
+bool
+_bfd_elf_set_section_contents (bfd *abfd,
+ sec_ptr section,
+ const void *location,
+ file_ptr offset,
+ bfd_size_type count)
+{
+ Elf_Internal_Shdr *hdr;
+
+ if (! abfd->output_has_begun
+ && ! _bfd_elf_compute_section_file_positions (abfd, NULL))
+ return false;
+
+ if (!count)
+ return true;
+
+ hdr = &elf_section_data (section)->this_hdr;
+ if (hdr->sh_offset == (file_ptr) -1)
+ {
+ unsigned char *contents;
+
+ if (bfd_section_is_ctf (section))
+ /* Nothing to do with this section: the contents are generated
+ later. */
+ return true;
+
+ if ((offset + count) > hdr->sh_size)
+ {
+ _bfd_error_handler
+ (_("%pB:%pA: error: attempting to write"
+ " over the end of the section"),
+ abfd, section);
+
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ contents = hdr->contents;
+ if (contents == NULL)
+ {
+ _bfd_error_handler
+ (_("%pB:%pA: error: attempting to write"
+ " section into an empty buffer"),
+ abfd, section);
+
+ bfd_set_error (bfd_error_invalid_operation);
+ return false;
+ }
+
+ memcpy (contents + offset, location, count);
+ return true;
+ }
+
+ return _bfd_generic_set_section_contents (abfd, section,
+ location, offset, count);
+}
+
+bool
+_bfd_elf_no_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *cache_ptr ATTRIBUTE_UNUSED,
+ Elf_Internal_Rela *dst ATTRIBUTE_UNUSED)
+{
+ abort ();
+ return false;
+}
+
+/* Try to convert a non-ELF reloc into an ELF one. */
+
+bool
+_bfd_elf_validate_reloc (bfd *abfd, arelent *areloc)
+{
+ /* Check whether we really have an ELF howto. */
+
+ if ((*areloc->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec)
+ {
+ bfd_reloc_code_real_type code;
+ reloc_howto_type *howto;
+
+ /* Alien reloc: Try to determine its type to replace it with an
+ equivalent ELF reloc. */
+
+ if (areloc->howto->pc_relative)
+ {
+ switch (areloc->howto->bitsize)
+ {
+ case 8:
+ code = BFD_RELOC_8_PCREL;
+ break;
+ case 12:
+ code = BFD_RELOC_12_PCREL;
+ break;
+ case 16:
+ code = BFD_RELOC_16_PCREL;
+ break;
+ case 24:
+ code = BFD_RELOC_24_PCREL;
+ break;
+ case 32:
+ code = BFD_RELOC_32_PCREL;
+ break;
+ case 64:
+ code = BFD_RELOC_64_PCREL;
+ break;
+ default:
+ goto fail;
+ }
+
+ howto = bfd_reloc_type_lookup (abfd, code);
+
+ if (howto && areloc->howto->pcrel_offset != howto->pcrel_offset)
+ {
+ if (howto->pcrel_offset)
+ areloc->addend += areloc->address;
+ else
+ areloc->addend -= areloc->address; /* addend is unsigned!! */
+ }
+ }
+ else
+ {
+ switch (areloc->howto->bitsize)
+ {
+ case 8:
+ code = BFD_RELOC_8;
+ break;
+ case 14:
+ code = BFD_RELOC_14;
+ break;
+ case 16:
+ code = BFD_RELOC_16;
+ break;
+ case 26:
+ code = BFD_RELOC_26;
+ break;
+ case 32:
+ code = BFD_RELOC_32;
+ break;
+ case 64:
+ code = BFD_RELOC_64;
+ break;
+ default:
+ goto fail;
+ }
+
+ howto = bfd_reloc_type_lookup (abfd, code);
+ }
+
+ if (howto)
+ areloc->howto = howto;
+ else
+ goto fail;
+ }
+
+ return true;
+
+ fail:
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: %s unsupported"),
+ abfd, areloc->howto->name);
+ bfd_set_error (bfd_error_sorry);
+ return false;
+}
+
+bool
+_bfd_elf_close_and_cleanup (bfd *abfd)
+{
+ struct elf_obj_tdata *tdata = elf_tdata (abfd);
+ if (tdata != NULL
+ && (bfd_get_format (abfd) == bfd_object
+ || bfd_get_format (abfd) == bfd_core))
+ {
+ if (elf_tdata (abfd)->o != NULL && elf_shstrtab (abfd) != NULL)
+ _bfd_elf_strtab_free (elf_shstrtab (abfd));
+ _bfd_dwarf2_cleanup_debug_info (abfd, &tdata->dwarf2_find_line_info);
+ _bfd_stab_cleanup (abfd, &tdata->line_info);
+ }
+
+ return _bfd_generic_close_and_cleanup (abfd);
+}
+
+/* For Rel targets, we encode meaningful data for BFD_RELOC_VTABLE_ENTRY
+ in the relocation's offset. Thus we cannot allow any sort of sanity
+ range-checking to interfere. There is nothing else to do in processing
+ this reloc. */
+
+bfd_reloc_status_type
+_bfd_elf_rel_vtable_reloc_fn
+ (bfd *abfd ATTRIBUTE_UNUSED, arelent *re ATTRIBUTE_UNUSED,
+ struct bfd_symbol *symbol ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED, asection *is ATTRIBUTE_UNUSED,
+ bfd *obfd ATTRIBUTE_UNUSED, char **errmsg ATTRIBUTE_UNUSED)
+{
+ return bfd_reloc_ok;
+}
+
+/* Elf core file support. Much of this only works on native
+ toolchains, since we rely on knowing the
+ machine-dependent procfs structure in order to pick
+ out details about the corefile. */
+
+#ifdef HAVE_SYS_PROCFS_H
+# include <sys/procfs.h>
+#endif
+
+/* Return a PID that identifies a "thread" for threaded cores, or the
+ PID of the main process for non-threaded cores. */
+
+static int
+elfcore_make_pid (bfd *abfd)
+{
+ int pid;
+
+ pid = elf_tdata (abfd)->core->lwpid;
+ if (pid == 0)
+ pid = elf_tdata (abfd)->core->pid;
+
+ return pid;
+}
+
+/* If there isn't a section called NAME, make one, using data from
+ SECT. Note, this function will generate a reference to NAME, so
+ you shouldn't deallocate or overwrite it. */
+
+static bool
+elfcore_maybe_make_sect (bfd *abfd, char *name, asection *sect)
+{
+ asection *sect2;
+
+ if (bfd_get_section_by_name (abfd, name) != NULL)
+ return true;
+
+ sect2 = bfd_make_section_with_flags (abfd, name, sect->flags);
+ if (sect2 == NULL)
+ return false;
+
+ sect2->size = sect->size;
+ sect2->filepos = sect->filepos;
+ sect2->alignment_power = sect->alignment_power;
+ return true;
+}
+
+/* Create a pseudosection containing SIZE bytes at FILEPOS. This
+ actually creates up to two pseudosections:
+ - For the single-threaded case, a section named NAME, unless
+ such a section already exists.
+ - For the multi-threaded case, a section named "NAME/PID", where
+ PID is elfcore_make_pid (abfd).
+ Both pseudosections have identical contents. */
+bool
+_bfd_elfcore_make_pseudosection (bfd *abfd,
+ char *name,
+ size_t size,
+ ufile_ptr filepos)
+{
+ char buf[100];
+ char *threaded_name;
+ size_t len;
+ asection *sect;
+
+ /* Build the section name. */
+
+ sprintf (buf, "%s/%d", name, elfcore_make_pid (abfd));
+ len = strlen (buf) + 1;
+ threaded_name = (char *) bfd_alloc (abfd, len);
+ if (threaded_name == NULL)
+ return false;
+ memcpy (threaded_name, buf, len);
+
+ sect = bfd_make_section_anyway_with_flags (abfd, threaded_name,
+ SEC_HAS_CONTENTS);
+ if (sect == NULL)
+ return false;
+ sect->size = size;
+ sect->filepos = filepos;
+ sect->alignment_power = 2;
+
+ return elfcore_maybe_make_sect (abfd, name, sect);
+}
+
+static bool
+elfcore_make_auxv_note_section (bfd *abfd, Elf_Internal_Note *note,
+ size_t offs)
+{
+ asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv",
+ SEC_HAS_CONTENTS);
+
+ if (sect == NULL)
+ return false;
+
+ sect->size = note->descsz - offs;
+ sect->filepos = note->descpos + offs;
+ sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
+
+ return true;
+}
+
+/* prstatus_t exists on:
+ solaris 2.5+
+ linux 2.[01] + glibc
+ unixware 4.2
+*/
+
+#if defined (HAVE_PRSTATUS_T)
+
+static bool
+elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+ size_t size;
+ int offset;
+
+ if (note->descsz == sizeof (prstatus_t))
+ {
+ prstatus_t prstat;
+
+ size = sizeof (prstat.pr_reg);
+ offset = offsetof (prstatus_t, pr_reg);
+ memcpy (&prstat, note->descdata, sizeof (prstat));
+
+ /* Do not overwrite the core signal if it
+ has already been set by another thread. */
+ if (elf_tdata (abfd)->core->signal == 0)
+ elf_tdata (abfd)->core->signal = prstat.pr_cursig;
+ if (elf_tdata (abfd)->core->pid == 0)
+ elf_tdata (abfd)->core->pid = prstat.pr_pid;
+
+ /* pr_who exists on:
+ solaris 2.5+
+ unixware 4.2
+ pr_who doesn't exist on:
+ linux 2.[01]
+ */
+#if defined (HAVE_PRSTATUS_T_PR_WHO)
+ elf_tdata (abfd)->core->lwpid = prstat.pr_who;
+#else
+ elf_tdata (abfd)->core->lwpid = prstat.pr_pid;
+#endif
+ }
+#if defined (HAVE_PRSTATUS32_T)
+ else if (note->descsz == sizeof (prstatus32_t))
+ {
+ /* 64-bit host, 32-bit corefile */
+ prstatus32_t prstat;
+
+ size = sizeof (prstat.pr_reg);
+ offset = offsetof (prstatus32_t, pr_reg);
+ memcpy (&prstat, note->descdata, sizeof (prstat));
+
+ /* Do not overwrite the core signal if it
+ has already been set by another thread. */
+ if (elf_tdata (abfd)->core->signal == 0)
+ elf_tdata (abfd)->core->signal = prstat.pr_cursig;
+ if (elf_tdata (abfd)->core->pid == 0)
+ elf_tdata (abfd)->core->pid = prstat.pr_pid;
+
+ /* pr_who exists on:
+ solaris 2.5+
+ unixware 4.2
+ pr_who doesn't exist on:
+ linux 2.[01]
+ */
+#if defined (HAVE_PRSTATUS32_T_PR_WHO)
+ elf_tdata (abfd)->core->lwpid = prstat.pr_who;
+#else
+ elf_tdata (abfd)->core->lwpid = prstat.pr_pid;
+#endif
+ }
+#endif /* HAVE_PRSTATUS32_T */
+ else
+ {
+ /* Fail - we don't know how to handle any other
+ note size (ie. data object type). */
+ return true;
+ }
+
+ /* Make a ".reg/999" section and a ".reg" section. */
+ return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+ size, note->descpos + offset);
+}
+#endif /* defined (HAVE_PRSTATUS_T) */
+
+/* Create a pseudosection containing the exact contents of NOTE. */
+static bool
+elfcore_make_note_pseudosection (bfd *abfd,
+ char *name,
+ Elf_Internal_Note *note)
+{
+ return _bfd_elfcore_make_pseudosection (abfd, name,
+ note->descsz, note->descpos);
+}
+
+/* There isn't a consistent prfpregset_t across platforms,
+ but it doesn't matter, because we don't have to pick this
+ data structure apart. */
+
+static bool
+elfcore_grok_prfpreg (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+}
+
+/* Linux dumps the Intel SSE regs in a note named "LINUX" with a note
+ type of NT_PRXFPREG. Just include the whole note's contents
+ literally. */
+
+static bool
+elfcore_grok_prxfpreg (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note);
+}
+
+/* Linux dumps the Intel XSAVE extended state in a note named "LINUX"
+ with a note type of NT_X86_XSTATE. Just include the whole note's
+ contents literally. */
+
+static bool
+elfcore_grok_xstatereg (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-xstate", note);
+}
+
+static bool
+elfcore_grok_ppc_vmx (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vmx", note);
+}
+
+static bool
+elfcore_grok_ppc_vsx (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vsx", note);
+}
+
+static bool
+elfcore_grok_ppc_tar (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-tar", note);
+}
+
+static bool
+elfcore_grok_ppc_ppr (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-ppr", note);
+}
+
+static bool
+elfcore_grok_ppc_dscr (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-dscr", note);
+}
+
+static bool
+elfcore_grok_ppc_ebb (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-ebb", note);
+}
+
+static bool
+elfcore_grok_ppc_pmu (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-pmu", note);
+}
+
+static bool
+elfcore_grok_ppc_tm_cgpr (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-tm-cgpr", note);
+}
+
+static bool
+elfcore_grok_ppc_tm_cfpr (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-tm-cfpr", note);
+}
+
+static bool
+elfcore_grok_ppc_tm_cvmx (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-tm-cvmx", note);
+}
+
+static bool
+elfcore_grok_ppc_tm_cvsx (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-tm-cvsx", note);
+}
+
+static bool
+elfcore_grok_ppc_tm_spr (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-tm-spr", note);
+}
+
+static bool
+elfcore_grok_ppc_tm_ctar (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-tm-ctar", note);
+}
+
+static bool
+elfcore_grok_ppc_tm_cppr (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-tm-cppr", note);
+}
+
+static bool
+elfcore_grok_ppc_tm_cdscr (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-tm-cdscr", note);
+}
+
+static bool
+elfcore_grok_s390_high_gprs (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-high-gprs", note);
+}
+
+static bool
+elfcore_grok_s390_timer (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-timer", note);
+}
+
+static bool
+elfcore_grok_s390_todcmp (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-todcmp", note);
+}
+
+static bool
+elfcore_grok_s390_todpreg (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-todpreg", note);
+}
+
+static bool
+elfcore_grok_s390_ctrs (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-ctrs", note);
+}
+
+static bool
+elfcore_grok_s390_prefix (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-prefix", note);
+}
+
+static bool
+elfcore_grok_s390_last_break (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-last-break", note);
+}
+
+static bool
+elfcore_grok_s390_system_call (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-system-call", note);
+}
+
+static bool
+elfcore_grok_s390_tdb (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-tdb", note);
+}
+
+static bool
+elfcore_grok_s390_vxrs_low (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-vxrs-low", note);
+}
+
+static bool
+elfcore_grok_s390_vxrs_high (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-vxrs-high", note);
+}
+
+static bool
+elfcore_grok_s390_gs_cb (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-gs-cb", note);
+}
+
+static bool
+elfcore_grok_s390_gs_bc (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-s390-gs-bc", note);
+}
+
+static bool
+elfcore_grok_arm_vfp (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-arm-vfp", note);
+}
+
+static bool
+elfcore_grok_aarch_tls (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-aarch-tls", note);
+}
+
+static bool
+elfcore_grok_aarch_hw_break (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-aarch-hw-break", note);
+}
+
+static bool
+elfcore_grok_aarch_hw_watch (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-aarch-hw-watch", note);
+}
+
+static bool
+elfcore_grok_aarch_sve (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-aarch-sve", note);
+}
+
+static bool
+elfcore_grok_aarch_pauth (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-aarch-pauth", note);
+}
+
+static bool
+elfcore_grok_aarch_mte (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-aarch-mte",
+ note);
+}
+
+static bool
+elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
+}
+
+/* Convert NOTE into a bfd_section called ".reg-riscv-csr". Return TRUE if
+ successful otherwise, return FALSE. */
+
+static bool
+elfcore_grok_riscv_csr (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-riscv-csr", note);
+}
+
+/* Convert NOTE into a bfd_section called ".gdb-tdesc". Return TRUE if
+ successful otherwise, return FALSE. */
+
+static bool
+elfcore_grok_gdb_tdesc (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".gdb-tdesc", note);
+}
+
+static bool
+elfcore_grok_loongarch_cpucfg (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-loongarch-cpucfg", note);
+}
+
+static bool
+elfcore_grok_loongarch_lbt (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-loongarch-lbt", note);
+}
+
+static bool
+elfcore_grok_loongarch_lsx (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-loongarch-lsx", note);
+}
+
+static bool
+elfcore_grok_loongarch_lasx (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-loongarch-lasx", note);
+}
+
+#if defined (HAVE_PRPSINFO_T)
+typedef prpsinfo_t elfcore_psinfo_t;
+#if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */
+typedef prpsinfo32_t elfcore_psinfo32_t;
+#endif
+#endif
+
+#if defined (HAVE_PSINFO_T)
+typedef psinfo_t elfcore_psinfo_t;
+#if defined (HAVE_PSINFO32_T) /* Sparc64 cross Sparc32 */
+typedef psinfo32_t elfcore_psinfo32_t;
+#endif
+#endif
+
+/* return a malloc'ed copy of a string at START which is at
+ most MAX bytes long, possibly without a terminating '\0'.
+ the copy will always have a terminating '\0'. */
+
+char *
+_bfd_elfcore_strndup (bfd *abfd, char *start, size_t max)
+{
+ char *dups;
+ char *end = (char *) memchr (start, '\0', max);
+ size_t len;
+
+ if (end == NULL)
+ len = max;
+ else
+ len = end - start;
+
+ dups = (char *) bfd_alloc (abfd, len + 1);
+ if (dups == NULL)
+ return NULL;
+
+ memcpy (dups, start, len);
+ dups[len] = '\0';
+
+ return dups;
+}
+
+#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+static bool
+elfcore_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+ if (note->descsz == sizeof (elfcore_psinfo_t))
+ {
+ elfcore_psinfo_t psinfo;
+
+ memcpy (&psinfo, note->descdata, sizeof (psinfo));
+
+#if defined (HAVE_PSINFO_T_PR_PID) || defined (HAVE_PRPSINFO_T_PR_PID)
+ elf_tdata (abfd)->core->pid = psinfo.pr_pid;
+#endif
+ elf_tdata (abfd)->core->program
+ = _bfd_elfcore_strndup (abfd, psinfo.pr_fname,
+ sizeof (psinfo.pr_fname));
+
+ elf_tdata (abfd)->core->command
+ = _bfd_elfcore_strndup (abfd, psinfo.pr_psargs,
+ sizeof (psinfo.pr_psargs));
+ }
+#if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T)
+ else if (note->descsz == sizeof (elfcore_psinfo32_t))
+ {
+ /* 64-bit host, 32-bit corefile */
+ elfcore_psinfo32_t psinfo;
+
+ memcpy (&psinfo, note->descdata, sizeof (psinfo));
+
+#if defined (HAVE_PSINFO32_T_PR_PID) || defined (HAVE_PRPSINFO32_T_PR_PID)
+ elf_tdata (abfd)->core->pid = psinfo.pr_pid;
+#endif
+ elf_tdata (abfd)->core->program
+ = _bfd_elfcore_strndup (abfd, psinfo.pr_fname,
+ sizeof (psinfo.pr_fname));
+
+ elf_tdata (abfd)->core->command
+ = _bfd_elfcore_strndup (abfd, psinfo.pr_psargs,
+ sizeof (psinfo.pr_psargs));
+ }
+#endif
+
+ else
+ {
+ /* Fail - we don't know how to handle any other
+ note size (ie. data object type). */
+ return true;
+ }
+
+ /* Note that for some reason, a spurious space is tacked
+ onto the end of the args in some (at least one anyway)
+ implementations, so strip it off if it exists. */
+
+ {
+ char *command = elf_tdata (abfd)->core->command;
+ int n = strlen (command);
+
+ if (0 < n && command[n - 1] == ' ')
+ command[n - 1] = '\0';
+ }
+
+ return true;
+}
+#endif /* defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) */
+
+#if defined (HAVE_PSTATUS_T)
+static bool
+elfcore_grok_pstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+ if (note->descsz == sizeof (pstatus_t)
+#if defined (HAVE_PXSTATUS_T)
+ || note->descsz == sizeof (pxstatus_t)
+#endif
+ )
+ {
+ pstatus_t pstat;
+
+ memcpy (&pstat, note->descdata, sizeof (pstat));
+
+ elf_tdata (abfd)->core->pid = pstat.pr_pid;
+ }
+#if defined (HAVE_PSTATUS32_T)
+ else if (note->descsz == sizeof (pstatus32_t))
+ {
+ /* 64-bit host, 32-bit corefile */
+ pstatus32_t pstat;
+
+ memcpy (&pstat, note->descdata, sizeof (pstat));
+
+ elf_tdata (abfd)->core->pid = pstat.pr_pid;
+ }
+#endif
+ /* Could grab some more details from the "representative"
+ lwpstatus_t in pstat.pr_lwp, but we'll catch it all in an
+ NT_LWPSTATUS note, presumably. */
+
+ return true;
+}
+#endif /* defined (HAVE_PSTATUS_T) */
+
+#if defined (HAVE_LWPSTATUS_T)
+static bool
+elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+ lwpstatus_t lwpstat;
+ char buf[100];
+ char *name;
+ size_t len;
+ asection *sect;
+
+ if (note->descsz != sizeof (lwpstat)
+#if defined (HAVE_LWPXSTATUS_T)
+ && note->descsz != sizeof (lwpxstatus_t)
+#endif
+ )
+ return true;
+
+ memcpy (&lwpstat, note->descdata, sizeof (lwpstat));
+
+ elf_tdata (abfd)->core->lwpid = lwpstat.pr_lwpid;
+ /* Do not overwrite the core signal if it has already been set by
+ another thread. */
+ if (elf_tdata (abfd)->core->signal == 0)
+ elf_tdata (abfd)->core->signal = lwpstat.pr_cursig;
+
+ /* Make a ".reg/999" section. */
+
+ sprintf (buf, ".reg/%d", elfcore_make_pid (abfd));
+ len = strlen (buf) + 1;
+ name = bfd_alloc (abfd, len);
+ if (name == NULL)
+ return false;
+ memcpy (name, buf, len);
+
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
+ if (sect == NULL)
+ return false;
+
+#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
+ sect->size = sizeof (lwpstat.pr_context.uc_mcontext.gregs);
+ sect->filepos = note->descpos
+ + offsetof (lwpstatus_t, pr_context.uc_mcontext.gregs);
+#endif
+
+#if defined (HAVE_LWPSTATUS_T_PR_REG)
+ sect->size = sizeof (lwpstat.pr_reg);
+ sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg);
+#endif
+
+ sect->alignment_power = 2;
+
+ if (!elfcore_maybe_make_sect (abfd, ".reg", sect))
+ return false;
+
+ /* Make a ".reg2/999" section */
+
+ sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd));
+ len = strlen (buf) + 1;
+ name = bfd_alloc (abfd, len);
+ if (name == NULL)
+ return false;
+ memcpy (name, buf, len);
+
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
+ if (sect == NULL)
+ return false;
+
+#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
+ sect->size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs);
+ sect->filepos = note->descpos
+ + offsetof (lwpstatus_t, pr_context.uc_mcontext.fpregs);
+#endif
+
+#if defined (HAVE_LWPSTATUS_T_PR_FPREG)
+ sect->size = sizeof (lwpstat.pr_fpreg);
+ sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg);
+#endif
+
+ sect->alignment_power = 2;
+
+ return elfcore_maybe_make_sect (abfd, ".reg2", sect);
+}
+#endif /* defined (HAVE_LWPSTATUS_T) */
+
+/* These constants, and the structure offsets used below, are defined by
+ Cygwin's core_dump.h */
+#define NOTE_INFO_PROCESS 1
+#define NOTE_INFO_THREAD 2
+#define NOTE_INFO_MODULE 3
+#define NOTE_INFO_MODULE64 4
+
+static bool
+elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+ char buf[30];
+ char *name;
+ size_t len;
+ unsigned int name_size;
+ asection *sect;
+ unsigned int type;
+ int is_active_thread;
+ bfd_vma base_addr;
+
+ if (note->descsz < 4)
+ return true;
+
+ if (! startswith (note->namedata, "win32"))
+ return true;
+
+ type = bfd_get_32 (abfd, note->descdata);
+
+ struct
+ {
+ const char *type_name;
+ unsigned long min_size;
+ } size_check[] =
+ {
+ { "NOTE_INFO_PROCESS", 12 },
+ { "NOTE_INFO_THREAD", 12 },
+ { "NOTE_INFO_MODULE", 12 },
+ { "NOTE_INFO_MODULE64", 16 },
+ };
+
+ if (type == 0 || type > (sizeof(size_check)/sizeof(size_check[0])))
+ return true;
+
+ if (note->descsz < size_check[type - 1].min_size)
+ {
+ _bfd_error_handler (_("%pB: warning: win32pstatus %s of size %lu bytes"
+ " is too small"),
+ abfd, size_check[type - 1].type_name, note->descsz);
+ return true;
+ }
+
+ switch (type)
+ {
+ case NOTE_INFO_PROCESS:
+ /* FIXME: need to add ->core->command. */
+ elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 4);
+ elf_tdata (abfd)->core->signal = bfd_get_32 (abfd, note->descdata + 8);
+ break;
+
+ case NOTE_INFO_THREAD:
+ /* Make a ".reg/<tid>" section containing the Win32 API thread CONTEXT
+ structure. */
+ /* thread_info.tid */
+ sprintf (buf, ".reg/%ld", (long) bfd_get_32 (abfd, note->descdata + 4));
+
+ len = strlen (buf) + 1;
+ name = (char *) bfd_alloc (abfd, len);
+ if (name == NULL)
+ return false;
+
+ memcpy (name, buf, len);
+
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
+ if (sect == NULL)
+ return false;
+
+ /* sizeof (thread_info.thread_context) */
+ sect->size = note->descsz - 12;
+ /* offsetof (thread_info.thread_context) */
+ sect->filepos = note->descpos + 12;
+ sect->alignment_power = 2;
+
+ /* thread_info.is_active_thread */
+ is_active_thread = bfd_get_32 (abfd, note->descdata + 8);
+
+ if (is_active_thread)
+ if (! elfcore_maybe_make_sect (abfd, ".reg", sect))
+ return false;
+ break;
+
+ case NOTE_INFO_MODULE:
+ case NOTE_INFO_MODULE64:
+ /* Make a ".module/xxxxxxxx" section. */
+ if (type == NOTE_INFO_MODULE)
+ {
+ /* module_info.base_address */
+ base_addr = bfd_get_32 (abfd, note->descdata + 4);
+ sprintf (buf, ".module/%08lx", (unsigned long) base_addr);
+ /* module_info.module_name_size */
+ name_size = bfd_get_32 (abfd, note->descdata + 8);
+ }
+ else /* NOTE_INFO_MODULE64 */
+ {
+ /* module_info.base_address */
+ base_addr = bfd_get_64 (abfd, note->descdata + 4);
+ sprintf (buf, ".module/%016lx", (unsigned long) base_addr);
+ /* module_info.module_name_size */
+ name_size = bfd_get_32 (abfd, note->descdata + 12);
+ }
+
+ len = strlen (buf) + 1;
+ name = (char *) bfd_alloc (abfd, len);
+ if (name == NULL)
+ return false;
+
+ memcpy (name, buf, len);
+
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
+
+ if (sect == NULL)
+ return false;
+
+ if (note->descsz < 12 + name_size)
+ {
+ _bfd_error_handler (_("%pB: win32pstatus NOTE_INFO_MODULE of size %lu"
+ " is too small to contain a name of size %u"),
+ abfd, note->descsz, name_size);
+ return true;
+ }
+
+ sect->size = note->descsz;
+ sect->filepos = note->descpos;
+ sect->alignment_power = 2;
+ break;
+
+ default:
+ return true;
+ }
+
+ return true;
+}
+
+static bool
+elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ switch (note->type)
+ {
+ default:
+ return true;
+
+ case NT_PRSTATUS:
+ if (bed->elf_backend_grok_prstatus)
+ if ((*bed->elf_backend_grok_prstatus) (abfd, note))
+ return true;
+#if defined (HAVE_PRSTATUS_T)
+ return elfcore_grok_prstatus (abfd, note);
+#else
+ return true;
+#endif
+
+#if defined (HAVE_PSTATUS_T)
+ case NT_PSTATUS:
+ return elfcore_grok_pstatus (abfd, note);
+#endif
+
+#if defined (HAVE_LWPSTATUS_T)
+ case NT_LWPSTATUS:
+ return elfcore_grok_lwpstatus (abfd, note);
+#endif
+
+ case NT_FPREGSET: /* FIXME: rename to NT_PRFPREG */
+ return elfcore_grok_prfpreg (abfd, note);
+
+ case NT_WIN32PSTATUS:
+ return elfcore_grok_win32pstatus (abfd, note);
+
+ case NT_PRXFPREG: /* Linux SSE extension */
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_prxfpreg (abfd, note);
+ else
+ return true;
+
+ case NT_X86_XSTATE: /* Linux XSAVE extension */
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_xstatereg (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_VMX:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_vmx (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_VSX:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_vsx (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_TAR:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_tar (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_PPR:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_ppr (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_DSCR:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_dscr (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_EBB:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_ebb (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_PMU:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_pmu (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_TM_CGPR:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_tm_cgpr (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_TM_CFPR:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_tm_cfpr (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_TM_CVMX:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_tm_cvmx (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_TM_CVSX:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_tm_cvsx (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_TM_SPR:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_tm_spr (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_TM_CTAR:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_tm_ctar (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_TM_CPPR:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_tm_cppr (abfd, note);
+ else
+ return true;
+
+ case NT_PPC_TM_CDSCR:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_tm_cdscr (abfd, note);
+ else
+ return true;
+
+ case NT_S390_HIGH_GPRS:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_high_gprs (abfd, note);
+ else
+ return true;
+
+ case NT_S390_TIMER:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_timer (abfd, note);
+ else
+ return true;
+
+ case NT_S390_TODCMP:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_todcmp (abfd, note);
+ else
+ return true;
+
+ case NT_S390_TODPREG:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_todpreg (abfd, note);
+ else
+ return true;
+
+ case NT_S390_CTRS:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_ctrs (abfd, note);
+ else
+ return true;
+
+ case NT_S390_PREFIX:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_prefix (abfd, note);
+ else
+ return true;
+
+ case NT_S390_LAST_BREAK:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_last_break (abfd, note);
+ else
+ return true;
+
+ case NT_S390_SYSTEM_CALL:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_system_call (abfd, note);
+ else
+ return true;
+
+ case NT_S390_TDB:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_tdb (abfd, note);
+ else
+ return true;
+
+ case NT_S390_VXRS_LOW:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_vxrs_low (abfd, note);
+ else
+ return true;
+
+ case NT_S390_VXRS_HIGH:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_vxrs_high (abfd, note);
+ else
+ return true;
+
+ case NT_S390_GS_CB:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_gs_cb (abfd, note);
+ else
+ return true;
+
+ case NT_S390_GS_BC:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_s390_gs_bc (abfd, note);
+ else
+ return true;
+
+ case NT_ARC_V2:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_arc_v2 (abfd, note);
+ else
+ return true;
+
+ case NT_ARM_VFP:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_arm_vfp (abfd, note);
+ else
+ return true;
+
+ case NT_ARM_TLS:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_aarch_tls (abfd, note);
+ else
+ return true;
+
+ case NT_ARM_HW_BREAK:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_aarch_hw_break (abfd, note);
+ else
+ return true;
+
+ case NT_ARM_HW_WATCH:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_aarch_hw_watch (abfd, note);
+ else
+ return true;
+
+ case NT_ARM_SVE:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_aarch_sve (abfd, note);
+ else
+ return true;
+
+ case NT_ARM_PAC_MASK:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_aarch_pauth (abfd, note);
+ else
+ return true;
+
+ case NT_ARM_TAGGED_ADDR_CTRL:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_aarch_mte (abfd, note);
+ else
+ return true;
+
+ case NT_GDB_TDESC:
+ if (note->namesz == 4
+ && strcmp (note->namedata, "GDB") == 0)
+ return elfcore_grok_gdb_tdesc (abfd, note);
+ else
+ return true;
+
+ case NT_RISCV_CSR:
+ if (note->namesz == 4
+ && strcmp (note->namedata, "GDB") == 0)
+ return elfcore_grok_riscv_csr (abfd, note);
+ else
+ return true;
+
+ case NT_LARCH_CPUCFG:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_loongarch_cpucfg (abfd, note);
+ else
+ return true;
+
+ case NT_LARCH_LBT:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_loongarch_lbt (abfd, note);
+ else
+ return true;
+
+ case NT_LARCH_LSX:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_loongarch_lsx (abfd, note);
+ else
+ return true;
+
+ case NT_LARCH_LASX:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_loongarch_lasx (abfd, note);
+ else
+ return true;
+
+ case NT_PRPSINFO:
+ case NT_PSINFO:
+ if (bed->elf_backend_grok_psinfo)
+ if ((*bed->elf_backend_grok_psinfo) (abfd, note))
+ return true;
+#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+ return elfcore_grok_psinfo (abfd, note);
+#else
+ return true;
+#endif
+
+ case NT_AUXV:
+ return elfcore_make_auxv_note_section (abfd, note, 0);
+
+ case NT_FILE:
+ return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.file",
+ note);
+
+ case NT_SIGINFO:
+ return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo",
+ note);
+
+ }
+}
+
+static bool
+elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note)
+{
+ struct bfd_build_id* build_id;
+
+ if (note->descsz == 0)
+ return false;
+
+ build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) - 1 + note->descsz);
+ if (build_id == NULL)
+ return false;
+
+ build_id->size = note->descsz;
+ memcpy (build_id->data, note->descdata, note->descsz);
+ abfd->build_id = build_id;
+
+ return true;
+}
+
+static bool
+elfobj_grok_gnu_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ switch (note->type)
+ {
+ default:
+ return true;
+
+ case NT_GNU_PROPERTY_TYPE_0:
+ return _bfd_elf_parse_gnu_properties (abfd, note);
+
+ case NT_GNU_BUILD_ID:
+ return elfobj_grok_gnu_build_id (abfd, note);
+ }
+}
+
+static bool
+elfobj_grok_stapsdt_note_1 (bfd *abfd, Elf_Internal_Note *note)
+{
+ struct sdt_note *cur =
+ (struct sdt_note *) bfd_alloc (abfd,
+ sizeof (struct sdt_note) + note->descsz);
+
+ cur->next = (struct sdt_note *) (elf_tdata (abfd))->sdt_note_head;
+ cur->size = (bfd_size_type) note->descsz;
+ memcpy (cur->data, note->descdata, note->descsz);
+
+ elf_tdata (abfd)->sdt_note_head = cur;
+
+ return true;
+}
+
+static bool
+elfobj_grok_stapsdt_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ switch (note->type)
+ {
+ case NT_STAPSDT:
+ return elfobj_grok_stapsdt_note_1 (abfd, note);
+
+ default:
+ return true;
+ }
+}
+
+static bool
+elfcore_grok_freebsd_psinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+ size_t offset;
+
+ switch (elf_elfheader (abfd)->e_ident[EI_CLASS])
+ {
+ case ELFCLASS32:
+ if (note->descsz < 108)
+ return false;
+ break;
+
+ case ELFCLASS64:
+ if (note->descsz < 120)
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ /* Check for version 1 in pr_version. */
+ if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1)
+ return false;
+
+ offset = 4;
+
+ /* Skip over pr_psinfosz. */
+ if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS32)
+ offset += 4;
+ else
+ {
+ offset += 4; /* Padding before pr_psinfosz. */
+ offset += 8;
+ }
+
+ /* pr_fname is PRFNAMESZ (16) + 1 bytes in size. */
+ elf_tdata (abfd)->core->program
+ = _bfd_elfcore_strndup (abfd, note->descdata + offset, 17);
+ offset += 17;
+
+ /* pr_psargs is PRARGSZ (80) + 1 bytes in size. */
+ elf_tdata (abfd)->core->command
+ = _bfd_elfcore_strndup (abfd, note->descdata + offset, 81);
+ offset += 81;
+
+ /* Padding before pr_pid. */
+ offset += 2;
+
+ /* The pr_pid field was added in version "1a". */
+ if (note->descsz < offset + 4)
+ return true;
+
+ elf_tdata (abfd)->core->pid
+ = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+
+ return true;
+}
+
+static bool
+elfcore_grok_freebsd_prstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+ size_t offset;
+ size_t size;
+ size_t min_size;
+
+ /* Compute offset of pr_getregsz, skipping over pr_statussz.
+ Also compute minimum size of this note. */
+ switch (elf_elfheader (abfd)->e_ident[EI_CLASS])
+ {
+ case ELFCLASS32:
+ offset = 4 + 4;
+ min_size = offset + (4 * 2) + 4 + 4 + 4;
+ break;
+
+ case ELFCLASS64:
+ offset = 4 + 4 + 8; /* Includes padding before pr_statussz. */
+ min_size = offset + (8 * 2) + 4 + 4 + 4 + 4;
+ break;
+
+ default:
+ return false;
+ }
+
+ if (note->descsz < min_size)
+ return false;
+
+ /* Check for version 1 in pr_version. */
+ if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1)
+ return false;
+
+ /* Extract size of pr_reg from pr_gregsetsz. */
+ /* Skip over pr_gregsetsz and pr_fpregsetsz. */
+ if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS32)
+ {
+ size = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+ offset += 4 * 2;
+ }
+ else
+ {
+ size = bfd_h_get_64 (abfd, (bfd_byte *) note->descdata + offset);
+ offset += 8 * 2;
+ }
+
+ /* Skip over pr_osreldate. */
+ offset += 4;
+
+ /* Read signal from pr_cursig. */
+ if (elf_tdata (abfd)->core->signal == 0)
+ elf_tdata (abfd)->core->signal
+ = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+ offset += 4;
+
+ /* Read TID from pr_pid. */
+ elf_tdata (abfd)->core->lwpid
+ = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+ offset += 4;
+
+ /* Padding before pr_reg. */
+ if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+ offset += 4;
+
+ /* Make sure that there is enough data remaining in the note. */
+ if ((note->descsz - offset) < size)
+ return false;
+
+ /* Make a ".reg/999" section and a ".reg" section. */
+ return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+ size, note->descpos + offset);
+}
+
+static bool
+elfcore_grok_freebsd_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ switch (note->type)
+ {
+ case NT_PRSTATUS:
+ if (bed->elf_backend_grok_freebsd_prstatus)
+ if ((*bed->elf_backend_grok_freebsd_prstatus) (abfd, note))
+ return true;
+ return elfcore_grok_freebsd_prstatus (abfd, note);
+
+ case NT_FPREGSET:
+ return elfcore_grok_prfpreg (abfd, note);
+
+ case NT_PRPSINFO:
+ return elfcore_grok_freebsd_psinfo (abfd, note);
+
+ case NT_FREEBSD_THRMISC:
+ return elfcore_make_note_pseudosection (abfd, ".thrmisc", note);
+
+ case NT_FREEBSD_PROCSTAT_PROC:
+ return elfcore_make_note_pseudosection (abfd, ".note.freebsdcore.proc",
+ note);
+
+ case NT_FREEBSD_PROCSTAT_FILES:
+ return elfcore_make_note_pseudosection (abfd, ".note.freebsdcore.files",
+ note);
+
+ case NT_FREEBSD_PROCSTAT_VMMAP:
+ return elfcore_make_note_pseudosection (abfd, ".note.freebsdcore.vmmap",
+ note);
+
+ case NT_FREEBSD_PROCSTAT_AUXV:
+ return elfcore_make_auxv_note_section (abfd, note, 4);
+
+ case NT_FREEBSD_X86_SEGBASES:
+ return elfcore_make_note_pseudosection (abfd, ".reg-x86-segbases", note);
+
+ case NT_X86_XSTATE:
+ return elfcore_grok_xstatereg (abfd, note);
+
+ case NT_FREEBSD_PTLWPINFO:
+ return elfcore_make_note_pseudosection (abfd, ".note.freebsdcore.lwpinfo",
+ note);
+
+ case NT_ARM_TLS:
+ return elfcore_grok_aarch_tls (abfd, note);
+
+ case NT_ARM_VFP:
+ return elfcore_grok_arm_vfp (abfd, note);
+
+ default:
+ return true;
+ }
+}
+
+static bool
+elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp)
+{
+ char *cp;
+
+ cp = strchr (note->namedata, '@');
+ if (cp != NULL)
+ {
+ *lwpidp = atoi(cp + 1);
+ return true;
+ }
+ return false;
+}
+
+static bool
+elfcore_grok_netbsd_procinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+ if (note->descsz <= 0x7c + 31)
+ return false;
+
+ /* Signal number at offset 0x08. */
+ elf_tdata (abfd)->core->signal
+ = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08);
+
+ /* Process ID at offset 0x50. */
+ elf_tdata (abfd)->core->pid
+ = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x50);
+
+ /* Command name at 0x7c (max 32 bytes, including nul). */
+ elf_tdata (abfd)->core->command
+ = _bfd_elfcore_strndup (abfd, note->descdata + 0x7c, 31);
+
+ return elfcore_make_note_pseudosection (abfd, ".note.netbsdcore.procinfo",
+ note);
+}
+
+static bool
+elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ int lwp;
+
+ if (elfcore_netbsd_get_lwpid (note, &lwp))
+ elf_tdata (abfd)->core->lwpid = lwp;
+
+ switch (note->type)
+ {
+ case NT_NETBSDCORE_PROCINFO:
+ /* NetBSD-specific core "procinfo". Note that we expect to
+ find this note before any of the others, which is fine,
+ since the kernel writes this note out first when it
+ creates a core file. */
+ return elfcore_grok_netbsd_procinfo (abfd, note);
+ case NT_NETBSDCORE_AUXV:
+ /* NetBSD-specific Elf Auxiliary Vector data. */
+ return elfcore_make_auxv_note_section (abfd, note, 4);
+ case NT_NETBSDCORE_LWPSTATUS:
+ return elfcore_make_note_pseudosection (abfd,
+ ".note.netbsdcore.lwpstatus",
+ note);
+ default:
+ break;
+ }
+
+ /* As of March 2020 there are no other machine-independent notes
+ defined for NetBSD core files. If the note type is less
+ than the start of the machine-dependent note types, we don't
+ understand it. */
+
+ if (note->type < NT_NETBSDCORE_FIRSTMACH)
+ return true;
+
+
+ switch (bfd_get_arch (abfd))
+ {
+ /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and
+ PT_GETFPREGS == mach+2. */
+
+ case bfd_arch_aarch64:
+ case bfd_arch_alpha:
+ case bfd_arch_sparc:
+ switch (note->type)
+ {
+ case NT_NETBSDCORE_FIRSTMACH+0:
+ return elfcore_make_note_pseudosection (abfd, ".reg", note);
+
+ case NT_NETBSDCORE_FIRSTMACH+2:
+ return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+
+ default:
+ return true;
+ }
+
+ /* On SuperH, PT_GETREGS == mach+3 and PT_GETFPREGS == mach+5.
+ There's also old PT___GETREGS40 == mach + 1 for old reg
+ structure which lacks GBR. */
+
+ case bfd_arch_sh:
+ switch (note->type)
+ {
+ case NT_NETBSDCORE_FIRSTMACH+3:
+ return elfcore_make_note_pseudosection (abfd, ".reg", note);
+
+ case NT_NETBSDCORE_FIRSTMACH+5:
+ return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+
+ default:
+ return true;
+ }
+
+ /* On all other arch's, PT_GETREGS == mach+1 and
+ PT_GETFPREGS == mach+3. */
+
+ default:
+ switch (note->type)
+ {
+ case NT_NETBSDCORE_FIRSTMACH+1:
+ return elfcore_make_note_pseudosection (abfd, ".reg", note);
+
+ case NT_NETBSDCORE_FIRSTMACH+3:
+ return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+
+ default:
+ return true;
+ }
+ }
+ /* NOTREACHED */
+}
+
+static bool
+elfcore_grok_openbsd_procinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+ if (note->descsz <= 0x48 + 31)
+ return false;
+
+ /* Signal number at offset 0x08. */
+ elf_tdata (abfd)->core->signal
+ = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08);
+
+ /* Process ID at offset 0x20. */
+ elf_tdata (abfd)->core->pid
+ = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x20);
+
+ /* Command name at 0x48 (max 32 bytes, including nul). */
+ elf_tdata (abfd)->core->command
+ = _bfd_elfcore_strndup (abfd, note->descdata + 0x48, 31);
+
+ return true;
+}
+
+/* Processes Solaris's process status note.
+ sig_off ~ offsetof(prstatus_t, pr_cursig)
+ pid_off ~ offsetof(prstatus_t, pr_pid)
+ lwpid_off ~ offsetof(prstatus_t, pr_who)
+ gregset_size ~ sizeof(gregset_t)
+ gregset_offset ~ offsetof(prstatus_t, pr_reg) */
+
+static bool
+elfcore_grok_solaris_prstatus (bfd *abfd, Elf_Internal_Note* note, int sig_off,
+ int pid_off, int lwpid_off, size_t gregset_size,
+ size_t gregset_offset)
+{
+ asection *sect = NULL;
+ elf_tdata (abfd)->core->signal
+ = bfd_get_16 (abfd, note->descdata + sig_off);
+ elf_tdata (abfd)->core->pid
+ = bfd_get_32 (abfd, note->descdata + pid_off);
+ elf_tdata (abfd)->core->lwpid
+ = bfd_get_32 (abfd, note->descdata + lwpid_off);
+
+ sect = bfd_get_section_by_name (abfd, ".reg");
+ if (sect != NULL)
+ sect->size = gregset_size;
+
+ return _bfd_elfcore_make_pseudosection (abfd, ".reg", gregset_size,
+ note->descpos + gregset_offset);
+}
+
+/* Gets program and arguments from a core.
+ prog_off ~ offsetof(prpsinfo | psinfo_t, pr_fname)
+ comm_off ~ offsetof(prpsinfo | psinfo_t, pr_psargs) */
+
+static bool
+elfcore_grok_solaris_info(bfd *abfd, Elf_Internal_Note* note,
+ int prog_off, int comm_off)
+{
+ elf_tdata (abfd)->core->program
+ = _bfd_elfcore_strndup (abfd, note->descdata + prog_off, 16);
+ elf_tdata (abfd)->core->command
+ = _bfd_elfcore_strndup (abfd, note->descdata + comm_off, 80);
+
+ return true;
+}
+
+/* Processes Solaris's LWP status note.
+ gregset_size ~ sizeof(gregset_t)
+ gregset_off ~ offsetof(lwpstatus_t, pr_reg)
+ fpregset_size ~ sizeof(fpregset_t)
+ fpregset_off ~ offsetof(lwpstatus_t, pr_fpreg) */
+
+static bool
+elfcore_grok_solaris_lwpstatus (bfd *abfd, Elf_Internal_Note* note,
+ size_t gregset_size, int gregset_off,
+ size_t fpregset_size, int fpregset_off)
+{
+ asection *sect = NULL;
+ char reg2_section_name[16] = { 0 };
+
+ (void) snprintf (reg2_section_name, 16, "%s/%i", ".reg2",
+ elf_tdata (abfd)->core->lwpid);
+
+ /* offsetof(lwpstatus_t, pr_lwpid) */
+ elf_tdata (abfd)->core->lwpid
+ = bfd_get_32 (abfd, note->descdata + 4);
+ /* offsetof(lwpstatus_t, pr_cursig) */
+ elf_tdata (abfd)->core->signal
+ = bfd_get_16 (abfd, note->descdata + 12);
+
+ sect = bfd_get_section_by_name (abfd, ".reg");
+ if (sect != NULL)
+ sect->size = gregset_size;
+ else if (!_bfd_elfcore_make_pseudosection (abfd, ".reg", gregset_size,
+ note->descpos + gregset_off))
+ return false;
+
+ sect = bfd_get_section_by_name (abfd, reg2_section_name);
+ if (sect != NULL)
+ {
+ sect->size = fpregset_size;
+ sect->filepos = note->descpos + fpregset_off;
+ sect->alignment_power = 2;
+ }
+ else if (!_bfd_elfcore_make_pseudosection (abfd, ".reg2", fpregset_size,
+ note->descpos + fpregset_off))
+ return false;
+
+ return true;
+}
+
+static bool
+elfcore_grok_solaris_note_impl (bfd *abfd, Elf_Internal_Note *note)
+{
+ if (note == NULL)
+ return false;
+
+ /* core files are identified as 32- or 64-bit, SPARC or x86,
+ by the size of the descsz which matches the sizeof()
+ the type appropriate for that note type (e.g., prstatus_t for
+ SOLARIS_NT_PRSTATUS) for the corresponding architecture
+ on Solaris. The core file bitness may differ from the bitness of
+ gdb itself, so fixed values are used instead of sizeof().
+ Appropriate fixed offsets are also used to obtain data from
+ the note. */
+
+ switch ((int) note->type)
+ {
+ case SOLARIS_NT_PRSTATUS:
+ switch (note->descsz)
+ {
+ case 508: /* sizeof(prstatus_t) SPARC 32-bit */
+ return elfcore_grok_solaris_prstatus(abfd, note,
+ 136, 216, 308, 152, 356);
+ case 904: /* sizeof(prstatus_t) SPARC 64-bit */
+ return elfcore_grok_solaris_prstatus(abfd, note,
+ 264, 360, 520, 304, 600);
+ case 432: /* sizeof(prstatus_t) Intel 32-bit */
+ return elfcore_grok_solaris_prstatus(abfd, note,
+ 136, 216, 308, 76, 356);
+ case 824: /* sizeof(prstatus_t) Intel 64-bit */
+ return elfcore_grok_solaris_prstatus(abfd, note,
+ 264, 360, 520, 224, 600);
+ default:
+ return true;
+ }
+
+ case SOLARIS_NT_PSINFO:
+ case SOLARIS_NT_PRPSINFO:
+ switch (note->descsz)
+ {
+ case 260: /* sizeof(prpsinfo_t) SPARC and Intel 32-bit */
+ return elfcore_grok_solaris_info(abfd, note, 84, 100);
+ case 328: /* sizeof(prpsinfo_t) SPARC and Intel 64-bit */
+ return elfcore_grok_solaris_info(abfd, note, 120, 136);
+ case 360: /* sizeof(psinfo_t) SPARC and Intel 32-bit */
+ return elfcore_grok_solaris_info(abfd, note, 88, 104);
+ case 440: /* sizeof(psinfo_t) SPARC and Intel 64-bit */
+ return elfcore_grok_solaris_info(abfd, note, 136, 152);
+ default:
+ return true;
+ }
+
+ case SOLARIS_NT_LWPSTATUS:
+ switch (note->descsz)
+ {
+ case 896: /* sizeof(lwpstatus_t) SPARC 32-bit */
+ return elfcore_grok_solaris_lwpstatus(abfd, note,
+ 152, 344, 400, 496);
+ case 1392: /* sizeof(lwpstatus_t) SPARC 64-bit */
+ return elfcore_grok_solaris_lwpstatus(abfd, note,
+ 304, 544, 544, 848);
+ case 800: /* sizeof(lwpstatus_t) Intel 32-bit */
+ return elfcore_grok_solaris_lwpstatus(abfd, note,
+ 76, 344, 380, 420);
+ case 1296: /* sizeof(lwpstatus_t) Intel 64-bit */
+ return elfcore_grok_solaris_lwpstatus(abfd, note,
+ 224, 544, 528, 768);
+ default:
+ return true;
+ }
+
+ case SOLARIS_NT_LWPSINFO:
+ /* sizeof(lwpsinfo_t) on 32- and 64-bit, respectively */
+ if (note->descsz == 128 || note->descsz == 152)
+ elf_tdata (abfd)->core->lwpid =
+ bfd_get_32 (abfd, note->descdata + 4);
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+/* For name starting with "CORE" this may be either a Solaris
+ core file or a gdb-generated core file. Do Solaris-specific
+ processing on selected note types first with
+ elfcore_grok_solaris_note(), then process the note
+ in elfcore_grok_note(). */
+
+static bool
+elfcore_grok_solaris_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ if (!elfcore_grok_solaris_note_impl (abfd, note))
+ return false;
+
+ return elfcore_grok_note (abfd, note);
+}
+
+static bool
+elfcore_grok_openbsd_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ if (note->type == NT_OPENBSD_PROCINFO)
+ return elfcore_grok_openbsd_procinfo (abfd, note);
+
+ if (note->type == NT_OPENBSD_REGS)
+ return elfcore_make_note_pseudosection (abfd, ".reg", note);
+
+ if (note->type == NT_OPENBSD_FPREGS)
+ return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+
+ if (note->type == NT_OPENBSD_XFPREGS)
+ return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note);
+
+ if (note->type == NT_OPENBSD_AUXV)
+ return elfcore_make_auxv_note_section (abfd, note, 0);
+
+ if (note->type == NT_OPENBSD_WCOOKIE)
+ {
+ asection *sect = bfd_make_section_anyway_with_flags (abfd, ".wcookie",
+ SEC_HAS_CONTENTS);
+
+ if (sect == NULL)
+ return false;
+ sect->size = note->descsz;
+ sect->filepos = note->descpos;
+ sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
+
+ return true;
+ }
+
+ return true;
+}
+
+static bool
+elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid)
+{
+ void *ddata = note->descdata;
+ char buf[100];
+ char *name;
+ asection *sect;
+ short sig;
+ unsigned flags;
+
+ if (note->descsz < 16)
+ return false;
+
+ /* nto_procfs_status 'pid' field is at offset 0. */
+ elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, (bfd_byte *) ddata);
+
+ /* nto_procfs_status 'tid' field is at offset 4. Pass it back. */
+ *tid = bfd_get_32 (abfd, (bfd_byte *) ddata + 4);
+
+ /* nto_procfs_status 'flags' field is at offset 8. */
+ flags = bfd_get_32 (abfd, (bfd_byte *) ddata + 8);
+
+ /* nto_procfs_status 'what' field is at offset 14. */
+ if ((sig = bfd_get_16 (abfd, (bfd_byte *) ddata + 14)) > 0)
+ {
+ elf_tdata (abfd)->core->signal = sig;
+ elf_tdata (abfd)->core->lwpid = *tid;
+ }
+
+ /* _DEBUG_FLAG_CURTID (current thread) is 0x80. Some cores
+ do not come from signals so we make sure we set the current
+ thread just in case. */
+ if (flags & 0x00000080)
+ elf_tdata (abfd)->core->lwpid = *tid;
+
+ /* Make a ".qnx_core_status/%d" section. */
+ sprintf (buf, ".qnx_core_status/%ld", *tid);
+
+ name = (char *) bfd_alloc (abfd, strlen (buf) + 1);
+ if (name == NULL)
+ return false;
+ strcpy (name, buf);
+
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
+ if (sect == NULL)
+ return false;
+
+ sect->size = note->descsz;
+ sect->filepos = note->descpos;
+ sect->alignment_power = 2;
+
+ return (elfcore_maybe_make_sect (abfd, ".qnx_core_status", sect));
+}
+
+static bool
+elfcore_grok_nto_regs (bfd *abfd,
+ Elf_Internal_Note *note,
+ long tid,
+ char *base)
+{
+ char buf[100];
+ char *name;
+ asection *sect;
+
+ /* Make a "(base)/%d" section. */
+ sprintf (buf, "%s/%ld", base, tid);
+
+ name = (char *) bfd_alloc (abfd, strlen (buf) + 1);
+ if (name == NULL)
+ return false;
+ strcpy (name, buf);
+
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
+ if (sect == NULL)
+ return false;
+
+ sect->size = note->descsz;
+ sect->filepos = note->descpos;
+ sect->alignment_power = 2;
+
+ /* This is the current thread. */
+ if (elf_tdata (abfd)->core->lwpid == tid)
+ return elfcore_maybe_make_sect (abfd, base, sect);
+
+ return true;
+}
+
+#define BFD_QNT_CORE_INFO 7
+#define BFD_QNT_CORE_STATUS 8
+#define BFD_QNT_CORE_GREG 9
+#define BFD_QNT_CORE_FPREG 10
+
+static bool
+elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ /* Every GREG section has a STATUS section before it. Store the
+ tid from the previous call to pass down to the next gregs
+ function. */
+ static long tid = 1;
+
+ switch (note->type)
+ {
+ case BFD_QNT_CORE_INFO:
+ return elfcore_make_note_pseudosection (abfd, ".qnx_core_info", note);
+ case BFD_QNT_CORE_STATUS:
+ return elfcore_grok_nto_status (abfd, note, &tid);
+ case BFD_QNT_CORE_GREG:
+ return elfcore_grok_nto_regs (abfd, note, tid, ".reg");
+ case BFD_QNT_CORE_FPREG:
+ return elfcore_grok_nto_regs (abfd, note, tid, ".reg2");
+ default:
+ return true;
+ }
+}
+
+static bool
+elfcore_grok_spu_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ char *name;
+ asection *sect;
+ size_t len;
+
+ /* Use note name as section name. */
+ len = note->namesz;
+ name = (char *) bfd_alloc (abfd, len);
+ if (name == NULL)
+ return false;
+ memcpy (name, note->namedata, len);
+ name[len - 1] = '\0';
+
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
+ if (sect == NULL)
+ return false;
+
+ sect->size = note->descsz;
+ sect->filepos = note->descpos;
+ sect->alignment_power = 1;
+
+ return true;
+}
+
+/* Function: elfcore_write_note
+
+ Inputs:
+ buffer to hold note, and current size of buffer
+ name of note
+ type of note
+ data for note
+ size of data for note
+
+ Writes note to end of buffer. ELF64 notes are written exactly as
+ for ELF32, despite the current (as of 2006) ELF gabi specifying
+ that they ought to have 8-byte namesz and descsz field, and have
+ 8-byte alignment. Other writers, eg. Linux kernel, do the same.
+
+ Return:
+ Pointer to realloc'd buffer, *BUFSIZ updated. */
+
+char *
+elfcore_write_note (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const char *name,
+ int type,
+ const void *input,
+ int size)
+{
+ Elf_External_Note *xnp;
+ size_t namesz;
+ size_t newspace;
+ char *dest;
+
+ namesz = 0;
+ if (name != NULL)
+ namesz = strlen (name) + 1;
+
+ newspace = 12 + ((namesz + 3) & -4) + ((size + 3) & -4);
+
+ buf = (char *) realloc (buf, *bufsiz + newspace);
+ if (buf == NULL)
+ return buf;
+ dest = buf + *bufsiz;
+ *bufsiz += newspace;
+ xnp = (Elf_External_Note *) dest;
+ H_PUT_32 (abfd, namesz, xnp->namesz);
+ H_PUT_32 (abfd, size, xnp->descsz);
+ H_PUT_32 (abfd, type, xnp->type);
+ dest = xnp->name;
+ if (name != NULL)
+ {
+ memcpy (dest, name, namesz);
+ dest += namesz;
+ while (namesz & 3)
+ {
+ *dest++ = '\0';
+ ++namesz;
+ }
+ }
+ memcpy (dest, input, size);
+ dest += size;
+ while (size & 3)
+ {
+ *dest++ = '\0';
+ ++size;
+ }
+ return buf;
+}
+
+/* gcc-8 warns (*) on all the strncpy calls in this function about
+ possible string truncation. The "truncation" is not a bug. We
+ have an external representation of structs with fields that are not
+ necessarily NULL terminated and corresponding internal
+ representation fields that are one larger so that they can always
+ be NULL terminated.
+ gcc versions between 4.2 and 4.6 do not allow pragma control of
+ diagnostics inside functions, giving a hard error if you try to use
+ the finer control available with later versions.
+ gcc prior to 4.2 warns about diagnostic push and pop.
+ gcc-5, gcc-6 and gcc-7 warn that -Wstringop-truncation is unknown,
+ unless you also add #pragma GCC diagnostic ignored "-Wpragma".
+ (*) Depending on your system header files! */
+#if GCC_VERSION >= 8000
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wstringop-truncation"
+#endif
+char *
+elfcore_write_prpsinfo (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const char *fname,
+ const char *psargs)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (bed->elf_backend_write_core_note != NULL)
+ {
+ char *ret;
+ ret = (*bed->elf_backend_write_core_note) (abfd, buf, bufsiz,
+ NT_PRPSINFO, fname, psargs);
+ if (ret != NULL)
+ return ret;
+ }
+
+#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+# if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T)
+ if (bed->s->elfclass == ELFCLASS32)
+ {
+# if defined (HAVE_PSINFO32_T)
+ psinfo32_t data;
+ int note_type = NT_PSINFO;
+# else
+ prpsinfo32_t data;
+ int note_type = NT_PRPSINFO;
+# endif
+
+ memset (&data, 0, sizeof (data));
+ strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+ strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", note_type, &data, sizeof (data));
+ }
+ else
+# endif
+ {
+# if defined (HAVE_PSINFO_T)
+ psinfo_t data;
+ int note_type = NT_PSINFO;
+# else
+ prpsinfo_t data;
+ int note_type = NT_PRPSINFO;
+# endif
+
+ memset (&data, 0, sizeof (data));
+ strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+ strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", note_type, &data, sizeof (data));
+ }
+#endif /* PSINFO_T or PRPSINFO_T */
+
+ free (buf);
+ return NULL;
+}
+#if GCC_VERSION >= 8000
+# pragma GCC diagnostic pop
+#endif
+
+char *
+elfcore_write_linux_prpsinfo32
+ (bfd *abfd, char *buf, int *bufsiz,
+ const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+ if (get_elf_backend_data (abfd)->linux_prpsinfo32_ugid16)
+ {
+ struct elf_external_linux_prpsinfo32_ugid16 data;
+
+ swap_linux_prpsinfo32_ugid16_out (abfd, prpsinfo, &data);
+ return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO,
+ &data, sizeof (data));
+ }
+ else
+ {
+ struct elf_external_linux_prpsinfo32_ugid32 data;
+
+ swap_linux_prpsinfo32_ugid32_out (abfd, prpsinfo, &data);
+ return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO,
+ &data, sizeof (data));
+ }
+}
+
+char *
+elfcore_write_linux_prpsinfo64
+ (bfd *abfd, char *buf, int *bufsiz,
+ const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+ if (get_elf_backend_data (abfd)->linux_prpsinfo64_ugid16)
+ {
+ struct elf_external_linux_prpsinfo64_ugid16 data;
+
+ swap_linux_prpsinfo64_ugid16_out (abfd, prpsinfo, &data);
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", NT_PRPSINFO, &data, sizeof (data));
+ }
+ else
+ {
+ struct elf_external_linux_prpsinfo64_ugid32 data;
+
+ swap_linux_prpsinfo64_ugid32_out (abfd, prpsinfo, &data);
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", NT_PRPSINFO, &data, sizeof (data));
+ }
+}
+
+char *
+elfcore_write_prstatus (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ long pid,
+ int cursig,
+ const void *gregs)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (bed->elf_backend_write_core_note != NULL)
+ {
+ char *ret;
+ ret = (*bed->elf_backend_write_core_note) (abfd, buf, bufsiz,
+ NT_PRSTATUS,
+ pid, cursig, gregs);
+ if (ret != NULL)
+ return ret;
+ }
+
+#if defined (HAVE_PRSTATUS_T)
+#if defined (HAVE_PRSTATUS32_T)
+ if (bed->s->elfclass == ELFCLASS32)
+ {
+ prstatus32_t prstat;
+
+ memset (&prstat, 0, sizeof (prstat));
+ prstat.pr_pid = pid;
+ prstat.pr_cursig = cursig;
+ memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+ return elfcore_write_note (abfd, buf, bufsiz, "CORE",
+ NT_PRSTATUS, &prstat, sizeof (prstat));
+ }
+ else
+#endif
+ {
+ prstatus_t prstat;
+
+ memset (&prstat, 0, sizeof (prstat));
+ prstat.pr_pid = pid;
+ prstat.pr_cursig = cursig;
+ memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+ return elfcore_write_note (abfd, buf, bufsiz, "CORE",
+ NT_PRSTATUS, &prstat, sizeof (prstat));
+ }
+#endif /* HAVE_PRSTATUS_T */
+
+ free (buf);
+ return NULL;
+}
+
+#if defined (HAVE_LWPSTATUS_T)
+char *
+elfcore_write_lwpstatus (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ long pid,
+ int cursig,
+ const void *gregs)
+{
+ lwpstatus_t lwpstat;
+ const char *note_name = "CORE";
+
+ memset (&lwpstat, 0, sizeof (lwpstat));
+ lwpstat.pr_lwpid = pid >> 16;
+ lwpstat.pr_cursig = cursig;
+#if defined (HAVE_LWPSTATUS_T_PR_REG)
+ memcpy (&lwpstat.pr_reg, gregs, sizeof (lwpstat.pr_reg));
+#elif defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
+#if !defined(gregs)
+ memcpy (lwpstat.pr_context.uc_mcontext.gregs,
+ gregs, sizeof (lwpstat.pr_context.uc_mcontext.gregs));
+#else
+ memcpy (lwpstat.pr_context.uc_mcontext.__gregs,
+ gregs, sizeof (lwpstat.pr_context.uc_mcontext.__gregs));
+#endif
+#endif
+ return elfcore_write_note (abfd, buf, bufsiz, note_name,
+ NT_LWPSTATUS, &lwpstat, sizeof (lwpstat));
+}
+#endif /* HAVE_LWPSTATUS_T */
+
+#if defined (HAVE_PSTATUS_T)
+char *
+elfcore_write_pstatus (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ long pid,
+ int cursig ATTRIBUTE_UNUSED,
+ const void *gregs ATTRIBUTE_UNUSED)
+{
+ const char *note_name = "CORE";
+#if defined (HAVE_PSTATUS32_T)
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (bed->s->elfclass == ELFCLASS32)
+ {
+ pstatus32_t pstat;
+
+ memset (&pstat, 0, sizeof (pstat));
+ pstat.pr_pid = pid & 0xffff;
+ buf = elfcore_write_note (abfd, buf, bufsiz, note_name,
+ NT_PSTATUS, &pstat, sizeof (pstat));
+ return buf;
+ }
+ else
+#endif
+ {
+ pstatus_t pstat;
+
+ memset (&pstat, 0, sizeof (pstat));
+ pstat.pr_pid = pid & 0xffff;
+ buf = elfcore_write_note (abfd, buf, bufsiz, note_name,
+ NT_PSTATUS, &pstat, sizeof (pstat));
+ return buf;
+ }
+}
+#endif /* HAVE_PSTATUS_T */
+
+char *
+elfcore_write_prfpreg (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *fpregs,
+ int size)
+{
+ const char *note_name = "CORE";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_FPREGSET, fpregs, size);
+}
+
+char *
+elfcore_write_prxfpreg (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *xfpregs,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PRXFPREG, xfpregs, size);
+}
+
+char *
+elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz,
+ const void *xfpregs, int size)
+{
+ char *note_name;
+ if (get_elf_backend_data (abfd)->elf_osabi == ELFOSABI_FREEBSD)
+ note_name = "FreeBSD";
+ else
+ note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_X86_XSTATE, xfpregs, size);
+}
+
+char *
+elfcore_write_x86_segbases (bfd *abfd, char *buf, int *bufsiz,
+ const void *regs, int size)
+{
+ char *note_name = "FreeBSD";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_FREEBSD_X86_SEGBASES, regs, size);
+}
+
+char *
+elfcore_write_ppc_vmx (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_vmx,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_VMX, ppc_vmx, size);
+}
+
+char *
+elfcore_write_ppc_vsx (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_vsx,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_VSX, ppc_vsx, size);
+}
+
+char *
+elfcore_write_ppc_tar (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_tar,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_TAR, ppc_tar, size);
+}
+
+char *
+elfcore_write_ppc_ppr (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_ppr,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_PPR, ppc_ppr, size);
+}
+
+char *
+elfcore_write_ppc_dscr (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_dscr,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_DSCR, ppc_dscr, size);
+}
+
+char *
+elfcore_write_ppc_ebb (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_ebb,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_EBB, ppc_ebb, size);
+}
+
+char *
+elfcore_write_ppc_pmu (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_pmu,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_PMU, ppc_pmu, size);
+}
+
+char *
+elfcore_write_ppc_tm_cgpr (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_tm_cgpr,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_TM_CGPR, ppc_tm_cgpr, size);
+}
+
+char *
+elfcore_write_ppc_tm_cfpr (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_tm_cfpr,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_TM_CFPR, ppc_tm_cfpr, size);
+}
+
+char *
+elfcore_write_ppc_tm_cvmx (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_tm_cvmx,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_TM_CVMX, ppc_tm_cvmx, size);
+}
+
+char *
+elfcore_write_ppc_tm_cvsx (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_tm_cvsx,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_TM_CVSX, ppc_tm_cvsx, size);
+}
+
+char *
+elfcore_write_ppc_tm_spr (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_tm_spr,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_TM_SPR, ppc_tm_spr, size);
+}
+
+char *
+elfcore_write_ppc_tm_ctar (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_tm_ctar,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_TM_CTAR, ppc_tm_ctar, size);
+}
+
+char *
+elfcore_write_ppc_tm_cppr (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_tm_cppr,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_TM_CPPR, ppc_tm_cppr, size);
+}
+
+char *
+elfcore_write_ppc_tm_cdscr (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_tm_cdscr,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_TM_CDSCR, ppc_tm_cdscr, size);
+}
+
+static char *
+elfcore_write_s390_high_gprs (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_high_gprs,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_HIGH_GPRS,
+ s390_high_gprs, size);
+}
+
+char *
+elfcore_write_s390_timer (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_timer,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_TIMER, s390_timer, size);
+}
+
+char *
+elfcore_write_s390_todcmp (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_todcmp,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_TODCMP, s390_todcmp, size);
+}
+
+char *
+elfcore_write_s390_todpreg (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_todpreg,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_TODPREG, s390_todpreg, size);
+}
+
+char *
+elfcore_write_s390_ctrs (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_ctrs,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_CTRS, s390_ctrs, size);
+}
+
+char *
+elfcore_write_s390_prefix (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_prefix,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_PREFIX, s390_prefix, size);
+}
+
+char *
+elfcore_write_s390_last_break (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_last_break,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_LAST_BREAK,
+ s390_last_break, size);
+}
+
+char *
+elfcore_write_s390_system_call (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_system_call,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_SYSTEM_CALL,
+ s390_system_call, size);
+}
+
+char *
+elfcore_write_s390_tdb (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_tdb,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_TDB, s390_tdb, size);
+}
+
+char *
+elfcore_write_s390_vxrs_low (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_vxrs_low,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_VXRS_LOW, s390_vxrs_low, size);
+}
+
+char *
+elfcore_write_s390_vxrs_high (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_vxrs_high,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_VXRS_HIGH,
+ s390_vxrs_high, size);
+}
+
+char *
+elfcore_write_s390_gs_cb (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_gs_cb,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_GS_CB,
+ s390_gs_cb, size);
+}
+
+char *
+elfcore_write_s390_gs_bc (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *s390_gs_bc,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_S390_GS_BC,
+ s390_gs_bc, size);
+}
+
+char *
+elfcore_write_arm_vfp (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *arm_vfp,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARM_VFP, arm_vfp, size);
+}
+
+char *
+elfcore_write_aarch_tls (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *aarch_tls,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARM_TLS, aarch_tls, size);
+}
+
+char *
+elfcore_write_aarch_hw_break (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *aarch_hw_break,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARM_HW_BREAK, aarch_hw_break, size);
+}
+
+char *
+elfcore_write_aarch_hw_watch (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *aarch_hw_watch,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARM_HW_WATCH, aarch_hw_watch, size);
+}
+
+char *
+elfcore_write_aarch_sve (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *aarch_sve,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARM_SVE, aarch_sve, size);
+}
+
+char *
+elfcore_write_aarch_pauth (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *aarch_pauth,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARM_PAC_MASK, aarch_pauth, size);
+}
+
+char *
+elfcore_write_aarch_mte (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *aarch_mte,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARM_TAGGED_ADDR_CTRL,
+ aarch_mte,
+ size);
+}
+
+char *
+elfcore_write_arc_v2 (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *arc_v2,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARC_V2, arc_v2, size);
+}
+
+char *
+elfcore_write_loongarch_cpucfg (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *loongarch_cpucfg,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_LARCH_CPUCFG,
+ loongarch_cpucfg, size);
+}
+
+char *
+elfcore_write_loongarch_lbt (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *loongarch_lbt,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_LARCH_LBT, loongarch_lbt, size);
+}
+
+char *
+elfcore_write_loongarch_lsx (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *loongarch_lsx,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_LARCH_LSX, loongarch_lsx, size);
+}
+
+char *
+elfcore_write_loongarch_lasx (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *loongarch_lasx,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_LARCH_LASX, loongarch_lasx, size);
+}
+
+/* Write the buffer of csr values in CSRS (length SIZE) into the note
+ buffer BUF and update *BUFSIZ. ABFD is the bfd the note is being
+ written into. Return a pointer to the new start of the note buffer, to
+ replace BUF which may no longer be valid. */
+
+char *
+elfcore_write_riscv_csr (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *csrs,
+ int size)
+{
+ const char *note_name = "GDB";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_RISCV_CSR, csrs, size);
+}
+
+/* Write the target description (a string) pointed to by TDESC, length
+ SIZE, into the note buffer BUF, and update *BUFSIZ. ABFD is the bfd the
+ note is being written into. Return a pointer to the new start of the
+ note buffer, to replace BUF which may no longer be valid. */
+
+char *
+elfcore_write_gdb_tdesc (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *tdesc,
+ int size)
+{
+ const char *note_name = "GDB";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_GDB_TDESC, tdesc, size);
+}
+
+char *
+elfcore_write_register_note (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const char *section,
+ const void *data,
+ int size)
+{
+ if (strcmp (section, ".reg2") == 0)
+ return elfcore_write_prfpreg (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-xfp") == 0)
+ return elfcore_write_prxfpreg (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-xstate") == 0)
+ return elfcore_write_xstatereg (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-x86-segbases") == 0)
+ return elfcore_write_x86_segbases (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-vmx") == 0)
+ return elfcore_write_ppc_vmx (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-vsx") == 0)
+ return elfcore_write_ppc_vsx (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-tar") == 0)
+ return elfcore_write_ppc_tar (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-ppr") == 0)
+ return elfcore_write_ppc_ppr (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-dscr") == 0)
+ return elfcore_write_ppc_dscr (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-ebb") == 0)
+ return elfcore_write_ppc_ebb (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-pmu") == 0)
+ return elfcore_write_ppc_pmu (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-tm-cgpr") == 0)
+ return elfcore_write_ppc_tm_cgpr (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-tm-cfpr") == 0)
+ return elfcore_write_ppc_tm_cfpr (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-tm-cvmx") == 0)
+ return elfcore_write_ppc_tm_cvmx (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-tm-cvsx") == 0)
+ return elfcore_write_ppc_tm_cvsx (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-tm-spr") == 0)
+ return elfcore_write_ppc_tm_spr (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-tm-ctar") == 0)
+ return elfcore_write_ppc_tm_ctar (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-tm-cppr") == 0)
+ return elfcore_write_ppc_tm_cppr (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-tm-cdscr") == 0)
+ return elfcore_write_ppc_tm_cdscr (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-high-gprs") == 0)
+ return elfcore_write_s390_high_gprs (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-timer") == 0)
+ return elfcore_write_s390_timer (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-todcmp") == 0)
+ return elfcore_write_s390_todcmp (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-todpreg") == 0)
+ return elfcore_write_s390_todpreg (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-ctrs") == 0)
+ return elfcore_write_s390_ctrs (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-prefix") == 0)
+ return elfcore_write_s390_prefix (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-last-break") == 0)
+ return elfcore_write_s390_last_break (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-system-call") == 0)
+ return elfcore_write_s390_system_call (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-tdb") == 0)
+ return elfcore_write_s390_tdb (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-vxrs-low") == 0)
+ return elfcore_write_s390_vxrs_low (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-vxrs-high") == 0)
+ return elfcore_write_s390_vxrs_high (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-gs-cb") == 0)
+ return elfcore_write_s390_gs_cb (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-s390-gs-bc") == 0)
+ return elfcore_write_s390_gs_bc (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-arm-vfp") == 0)
+ return elfcore_write_arm_vfp (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-aarch-tls") == 0)
+ return elfcore_write_aarch_tls (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-aarch-hw-break") == 0)
+ return elfcore_write_aarch_hw_break (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-aarch-hw-watch") == 0)
+ return elfcore_write_aarch_hw_watch (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-aarch-sve") == 0)
+ return elfcore_write_aarch_sve (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-aarch-pauth") == 0)
+ return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-aarch-mte") == 0)
+ return elfcore_write_aarch_mte (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-arc-v2") == 0)
+ return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".gdb-tdesc") == 0)
+ return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-riscv-csr") == 0)
+ return elfcore_write_riscv_csr (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-loongarch-cpucfg") == 0)
+ return elfcore_write_loongarch_cpucfg (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-loongarch-lbt") == 0)
+ return elfcore_write_loongarch_lbt (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-loongarch-lsx") == 0)
+ return elfcore_write_loongarch_lsx (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-loongarch-lasx") == 0)
+ return elfcore_write_loongarch_lasx (abfd, buf, bufsiz, data, size);
+ return NULL;
+}
+
+char *
+elfcore_write_file_note (bfd *obfd, char *note_data, int *note_size,
+ const void *buf, int bufsiz)
+{
+ return elfcore_write_note (obfd, note_data, note_size,
+ "CORE", NT_FILE, buf, bufsiz);
+}
+
+static bool
+elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset,
+ size_t align)
+{
+ char *p;
+
+ /* NB: CORE PT_NOTE segments may have p_align values of 0 or 1.
+ gABI specifies that PT_NOTE alignment should be aligned to 4
+ bytes for 32-bit objects and to 8 bytes for 64-bit objects. If
+ align is less than 4, we use 4 byte alignment. */
+ if (align < 4)
+ align = 4;
+ if (align != 4 && align != 8)
+ return false;
+
+ p = buf;
+ while (p < buf + size)
+ {
+ Elf_External_Note *xnp = (Elf_External_Note *) p;
+ Elf_Internal_Note in;
+
+ if (offsetof (Elf_External_Note, name) > buf - p + size)
+ return false;
+
+ in.type = H_GET_32 (abfd, xnp->type);
+
+ in.namesz = H_GET_32 (abfd, xnp->namesz);
+ in.namedata = xnp->name;
+ if (in.namesz > buf - in.namedata + size)
+ return false;
+
+ in.descsz = H_GET_32 (abfd, xnp->descsz);
+ in.descdata = p + ELF_NOTE_DESC_OFFSET (in.namesz, align);
+ in.descpos = offset + (in.descdata - buf);
+ if (in.descsz != 0
+ && (in.descdata >= buf + size
+ || in.descsz > buf - in.descdata + size))
+ return false;
+
+ switch (bfd_get_format (abfd))
+ {
+ default:
+ return true;
+
+ case bfd_core:
+ {
+#define GROKER_ELEMENT(S,F) {S, sizeof (S) - 1, F}
+ struct
+ {
+ const char * string;
+ size_t len;
+ bool (*func) (bfd *, Elf_Internal_Note *);
+ }
+ grokers[] =
+ {
+ GROKER_ELEMENT ("", elfcore_grok_note),
+ GROKER_ELEMENT ("FreeBSD", elfcore_grok_freebsd_note),
+ GROKER_ELEMENT ("NetBSD-CORE", elfcore_grok_netbsd_note),
+ GROKER_ELEMENT ("OpenBSD", elfcore_grok_openbsd_note),
+ GROKER_ELEMENT ("QNX", elfcore_grok_nto_note),
+ GROKER_ELEMENT ("SPU/", elfcore_grok_spu_note),
+ GROKER_ELEMENT ("GNU", elfobj_grok_gnu_note),
+ GROKER_ELEMENT ("CORE", elfcore_grok_solaris_note)
+ };
+#undef GROKER_ELEMENT
+ int i;
+
+ for (i = ARRAY_SIZE (grokers); i--;)
+ {
+ if (in.namesz >= grokers[i].len
+ && strncmp (in.namedata, grokers[i].string,
+ grokers[i].len) == 0)
+ {
+ if (! grokers[i].func (abfd, & in))
+ return false;
+ break;
+ }
+ }
+ break;
+ }
+
+ case bfd_object:
+ if (in.namesz == sizeof "GNU" && strcmp (in.namedata, "GNU") == 0)
+ {
+ if (! elfobj_grok_gnu_note (abfd, &in))
+ return false;
+ }
+ else if (in.namesz == sizeof "stapsdt"
+ && strcmp (in.namedata, "stapsdt") == 0)
+ {
+ if (! elfobj_grok_stapsdt_note (abfd, &in))
+ return false;
+ }
+ break;
+ }
+
+ p += ELF_NOTE_NEXT_OFFSET (in.namesz, in.descsz, align);
+ }
+
+ return true;
+}
+
+bool
+elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size,
+ size_t align)
+{
+ char *buf;
+
+ if (size == 0 || (size + 1) == 0)
+ return true;
+
+ if (bfd_seek (abfd, offset, SEEK_SET) != 0)
+ return false;
+
+ buf = (char *) _bfd_malloc_and_read (abfd, size + 1, size);
+ if (buf == NULL)
+ return false;
+
+ /* PR 17512: file: ec08f814
+ 0-termintate the buffer so that string searches will not overflow. */
+ buf[size] = 0;
+
+ if (!elf_parse_notes (abfd, buf, size, offset, align))
+ {
+ free (buf);
+ return false;
+ }
+
+ free (buf);
+ return true;
+}
+
+/* Providing external access to the ELF program header table. */
+
+/* Return an upper bound on the number of bytes required to store a
+ copy of ABFD's program header table entries. Return -1 if an error
+ occurs; bfd_get_error will return an appropriate code. */
+
+long
+bfd_get_elf_phdr_upper_bound (bfd *abfd)
+{
+ if (abfd->xvec->flavour != bfd_target_elf_flavour)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return -1;
+ }
+
+ return elf_elfheader (abfd)->e_phnum * sizeof (Elf_Internal_Phdr);
+}
+
+/* Copy ABFD's program header table entries to *PHDRS. The entries
+ will be stored as an array of Elf_Internal_Phdr structures, as
+ defined in include/elf/internal.h. To find out how large the
+ buffer needs to be, call bfd_get_elf_phdr_upper_bound.
+
+ Return the number of program header table entries read, or -1 if an
+ error occurs; bfd_get_error will return an appropriate code. */
+
+int
+bfd_get_elf_phdrs (bfd *abfd, void *phdrs)
+{
+ int num_phdrs;
+
+ if (abfd->xvec->flavour != bfd_target_elf_flavour)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return -1;
+ }
+
+ num_phdrs = elf_elfheader (abfd)->e_phnum;
+ if (num_phdrs != 0)
+ memcpy (phdrs, elf_tdata (abfd)->phdr,
+ num_phdrs * sizeof (Elf_Internal_Phdr));
+
+ return num_phdrs;
+}
+
+enum elf_reloc_type_class
+_bfd_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ const asection *rel_sec ATTRIBUTE_UNUSED,
+ const Elf_Internal_Rela *rela ATTRIBUTE_UNUSED)
+{
+ return reloc_class_normal;
+}
+
+/* For RELA architectures, return the relocation value for a
+ relocation against a local symbol. */
+
+bfd_vma
+_bfd_elf_rela_local_sym (bfd *abfd,
+ Elf_Internal_Sym *sym,
+ asection **psec,
+ Elf_Internal_Rela *rel)
+{
+ asection *sec = *psec;
+ bfd_vma relocation;
+
+ relocation = (sec->output_section->vma
+ + sec->output_offset
+ + sym->st_value);
+ if ((sec->flags & SEC_MERGE)
+ && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+ && sec->sec_info_type == SEC_INFO_TYPE_MERGE)
+ {
+ rel->r_addend =
+ _bfd_merged_section_offset (abfd, psec,
+ elf_section_data (sec)->sec_info,
+ sym->st_value + rel->r_addend);
+ if (sec != *psec)
+ {
+ /* If we have changed the section, and our original section is
+ marked with SEC_EXCLUDE, it means that the original
+ SEC_MERGE section has been completely subsumed in some
+ other SEC_MERGE section. In this case, we need to leave
+ some info around for --emit-relocs. */
+ if ((sec->flags & SEC_EXCLUDE) != 0)
+ sec->kept_section = *psec;
+ sec = *psec;
+ }
+ rel->r_addend -= relocation;
+ rel->r_addend += sec->output_section->vma + sec->output_offset;
+ }
+ return relocation;
+}
+
+bfd_vma
+_bfd_elf_rel_local_sym (bfd *abfd,
+ Elf_Internal_Sym *sym,
+ asection **psec,
+ bfd_vma addend)
+{
+ asection *sec = *psec;
+
+ if (sec->sec_info_type != SEC_INFO_TYPE_MERGE)
+ return sym->st_value + addend;
+
+ return _bfd_merged_section_offset (abfd, psec,
+ elf_section_data (sec)->sec_info,
+ sym->st_value + addend);
+}
+
+/* Adjust an address within a section. Given OFFSET within SEC, return
+ the new offset within the section, based upon changes made to the
+ section. Returns -1 if the offset is now invalid.
+ The offset (in abnd out) is in target sized bytes, however big a
+ byte may be. */
+
+bfd_vma
+_bfd_elf_section_offset (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ bfd_vma offset)
+{
+ switch (sec->sec_info_type)
+ {
+ case SEC_INFO_TYPE_STABS:
+ return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info,
+ offset);
+ case SEC_INFO_TYPE_EH_FRAME:
+ return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset);
+
+ default:
+ if ((sec->flags & SEC_ELF_REVERSE_COPY) != 0)
+ {
+ /* Reverse the offset. */
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ bfd_size_type address_size = bed->s->arch_size / 8;
+
+ /* address_size and sec->size are in octets. Convert
+ to bytes before subtracting the original offset. */
+ offset = ((sec->size - address_size)
+ / bfd_octets_per_byte (abfd, sec) - offset);
+ }
+ return offset;
+ }
+}
+
+/* Create a new BFD as if by bfd_openr. Rather than opening a file,
+ reconstruct an ELF file by reading the segments out of remote memory
+ based on the ELF file header at EHDR_VMA and the ELF program headers it
+ points to. If not null, *LOADBASEP is filled in with the difference
+ between the VMAs from which the segments were read, and the VMAs the
+ file headers (and hence BFD's idea of each section's VMA) put them at.
+
+ The function TARGET_READ_MEMORY is called to copy LEN bytes from the
+ remote memory at target address VMA into the local buffer at MYADDR; it
+ should return zero on success or an `errno' code on failure. TEMPL must
+ be a BFD for an ELF target with the word size and byte order found in
+ the remote memory. */
+
+bfd *
+bfd_elf_bfd_from_remote_memory
+ (bfd *templ,
+ bfd_vma ehdr_vma,
+ bfd_size_type size,
+ bfd_vma *loadbasep,
+ int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type))
+{
+ return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory)
+ (templ, ehdr_vma, size, loadbasep, target_read_memory);
+}
+
+long
+_bfd_elf_get_synthetic_symtab (bfd *abfd,
+ long symcount ATTRIBUTE_UNUSED,
+ asymbol **syms ATTRIBUTE_UNUSED,
+ long dynsymcount,
+ asymbol **dynsyms,
+ asymbol **ret)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ asection *relplt;
+ asymbol *s;
+ const char *relplt_name;
+ bool (*slurp_relocs) (bfd *, asection *, asymbol **, bool);
+ arelent *p;
+ long count, i, n;
+ size_t size;
+ Elf_Internal_Shdr *hdr;
+ char *names;
+ asection *plt;
+
+ *ret = NULL;
+
+ if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
+ return 0;
+
+ if (dynsymcount <= 0)
+ return 0;
+
+ if (!bed->plt_sym_val)
+ return 0;
+
+ relplt_name = bed->relplt_name;
+ if (relplt_name == NULL)
+ relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt";
+ relplt = bfd_get_section_by_name (abfd, relplt_name);
+ if (relplt == NULL)
+ return 0;
+
+ hdr = &elf_section_data (relplt)->this_hdr;
+ if (hdr->sh_link != elf_dynsymtab (abfd)
+ || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA))
+ return 0;
+
+ plt = bfd_get_section_by_name (abfd, ".plt");
+ if (plt == NULL)
+ return 0;
+
+ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+ if (! (*slurp_relocs) (abfd, relplt, dynsyms, true))
+ return -1;
+
+ count = relplt->size / hdr->sh_entsize;
+ size = count * sizeof (asymbol);
+ p = relplt->relocation;
+ for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
+ {
+ size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+ if (p->addend != 0)
+ {
+#ifdef BFD64
+ size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64);
+#else
+ size += sizeof ("+0x") - 1 + 8;
+#endif
+ }
+ }
+
+ s = *ret = (asymbol *) bfd_malloc (size);
+ if (s == NULL)
+ return -1;
+
+ names = (char *) (s + count);
+ p = relplt->relocation;
+ n = 0;
+ for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
+ {
+ size_t len;
+ bfd_vma addr;
+
+ addr = bed->plt_sym_val (i, plt, p);
+ if (addr == (bfd_vma) -1)
+ continue;
+
+ *s = **p->sym_ptr_ptr;
+ /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since
+ we are defining a symbol, ensure one of them is set. */
+ if ((s->flags & BSF_LOCAL) == 0)
+ s->flags |= BSF_GLOBAL;
+ s->flags |= BSF_SYNTHETIC;
+ s->section = plt;
+ s->value = addr - plt->vma;
+ s->name = names;
+ s->udata.p = NULL;
+ len = strlen ((*p->sym_ptr_ptr)->name);
+ memcpy (names, (*p->sym_ptr_ptr)->name, len);
+ names += len;
+ if (p->addend != 0)
+ {
+ char buf[30], *a;
+
+ memcpy (names, "+0x", sizeof ("+0x") - 1);
+ names += sizeof ("+0x") - 1;
+ bfd_sprintf_vma (abfd, buf, p->addend);
+ for (a = buf; *a == '0'; ++a)
+ ;
+ len = strlen (a);
+ memcpy (names, a, len);
+ names += len;
+ }
+ memcpy (names, "@plt", sizeof ("@plt"));
+ names += sizeof ("@plt");
+ ++s, ++n;
+ }
+
+ return n;
+}
+
+/* It is only used by x86-64 so far.
+ ??? This repeats *COM* id of zero. sec->id is supposed to be unique,
+ but current usage would allow all of _bfd_std_section to be zero. */
+static const asymbol lcomm_sym
+ = GLOBAL_SYM_INIT ("LARGE_COMMON", &_bfd_elf_large_com_section);
+asection _bfd_elf_large_com_section
+ = BFD_FAKE_SECTION (_bfd_elf_large_com_section, &lcomm_sym,
+ "LARGE_COMMON", 0, SEC_IS_COMMON);
+
+bool
+_bfd_elf_final_write_processing (bfd *abfd)
+{
+ Elf_Internal_Ehdr *i_ehdrp; /* ELF file header, internal form. */
+
+ i_ehdrp = elf_elfheader (abfd);
+
+ if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE)
+ i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
+
+ /* Set the osabi field to ELFOSABI_GNU if the binary contains
+ SHF_GNU_MBIND or SHF_GNU_RETAIN sections or symbols of STT_GNU_IFUNC type
+ or STB_GNU_UNIQUE binding. */
+ if (elf_tdata (abfd)->has_gnu_osabi != 0)
+ {
+ if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE)
+ i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_GNU;
+ else if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_GNU
+ && i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_FREEBSD)
+ {
+ if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_mbind)
+ _bfd_error_handler (_("GNU_MBIND section is supported only by GNU "
+ "and FreeBSD targets"));
+ if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_ifunc)
+ _bfd_error_handler (_("symbol type STT_GNU_IFUNC is supported "
+ "only by GNU and FreeBSD targets"));
+ if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_unique)
+ _bfd_error_handler (_("symbol binding STB_GNU_UNIQUE is supported "
+ "only by GNU and FreeBSD targets"));
+ if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_retain)
+ _bfd_error_handler (_("GNU_RETAIN section is supported "
+ "only by GNU and FreeBSD targets"));
+ bfd_set_error (bfd_error_sorry);
+ return false;
+ }
+ }
+ return true;
+}
+
+
+/* Return TRUE for ELF symbol types that represent functions.
+ This is the default version of this function, which is sufficient for
+ most targets. It returns true if TYPE is STT_FUNC or STT_GNU_IFUNC. */
+
+bool
+_bfd_elf_is_function_type (unsigned int type)
+{
+ return (type == STT_FUNC
+ || type == STT_GNU_IFUNC);
+}
+
+/* If the ELF symbol SYM might be a function in SEC, return the
+ function size and set *CODE_OFF to the function's entry point,
+ otherwise return zero. */
+
+bfd_size_type
+_bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec,
+ bfd_vma *code_off)
+{
+ bfd_size_type size;
+ elf_symbol_type * elf_sym = (elf_symbol_type *) sym;
+
+ if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
+ | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
+ || sym->section != sec)
+ return 0;
+
+ size = (sym->flags & BSF_SYNTHETIC) ? 0 : elf_sym->internal_elf_sym.st_size;
+
+ /* In theory we should check that the symbol's type satisfies
+ _bfd_elf_is_function_type(), but there are some function-like
+ symbols which would fail this test. (eg _start). Instead
+ we check for hidden, local, notype symbols with zero size.
+ This type of symbol is generated by the annobin plugin for gcc
+ and clang, and should not be considered to be a function symbol. */
+ if (size == 0
+ && ((sym->flags & (BSF_SYNTHETIC | BSF_LOCAL)) == BSF_LOCAL)
+ && ELF_ST_TYPE (elf_sym->internal_elf_sym.st_info) == STT_NOTYPE
+ && ELF_ST_VISIBILITY (elf_sym->internal_elf_sym.st_other) == STV_HIDDEN)
+ return 0;
+
+ *code_off = sym->value;
+ /* Do not return 0 for the function's size. */
+ return size ? size : 1;
+}
+
+/* Set to non-zero to enable some debug messages. */
+#define DEBUG_SECONDARY_RELOCS 0
+
+/* An internal-to-the-bfd-library only section type
+ used to indicate a cached secondary reloc section. */
+#define SHT_SECONDARY_RELOC (SHT_LOOS + SHT_RELA)
+
+/* Create a BFD section to hold a secondary reloc section. */
+
+bool
+_bfd_elf_init_secondary_reloc_section (bfd * abfd,
+ Elf_Internal_Shdr *hdr,
+ const char * name,
+ unsigned int shindex)
+{
+ /* We only support RELA secondary relocs. */
+ if (hdr->sh_type != SHT_RELA)
+ return false;
+
+#if DEBUG_SECONDARY_RELOCS
+ fprintf (stderr, "secondary reloc section %s encountered\n", name);
+#endif
+ hdr->sh_type = SHT_SECONDARY_RELOC;
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+}
+
+/* Read in any secondary relocs associated with SEC. */
+
+bool
+_bfd_elf_slurp_secondary_reloc_section (bfd * abfd,
+ asection * sec,
+ asymbol ** symbols,
+ bool dynamic)
+{
+ const struct elf_backend_data * const ebd = get_elf_backend_data (abfd);
+ asection * relsec;
+ bool result = true;
+ bfd_vma (*r_sym) (bfd_vma);
+ ufile_ptr filesize;
+
+#if BFD_DEFAULT_TARGET_SIZE > 32
+ if (bfd_arch_bits_per_address (abfd) != 32)
+ r_sym = elf64_r_sym;
+ else
+#endif
+ r_sym = elf32_r_sym;
+
+ if (!elf_section_data (sec)->has_secondary_relocs)
+ return true;
+
+ /* Discover if there are any secondary reloc sections
+ associated with SEC. */
+ filesize = bfd_get_file_size (abfd);
+ for (relsec = abfd->sections; relsec != NULL; relsec = relsec->next)
+ {
+ Elf_Internal_Shdr * hdr = & elf_section_data (relsec)->this_hdr;
+
+ if (hdr->sh_type == SHT_SECONDARY_RELOC
+ && hdr->sh_info == (unsigned) elf_section_data (sec)->this_idx
+ && (hdr->sh_entsize == ebd->s->sizeof_rel
+ || hdr->sh_entsize == ebd->s->sizeof_rela))
+ {
+ bfd_byte * native_relocs;
+ bfd_byte * native_reloc;
+ arelent * internal_relocs;
+ arelent * internal_reloc;
+ size_t i;
+ unsigned int entsize;
+ unsigned int symcount;
+ bfd_size_type reloc_count;
+ size_t amt;
+
+ if (ebd->elf_info_to_howto == NULL)
+ return false;
+
+#if DEBUG_SECONDARY_RELOCS
+ fprintf (stderr, "read secondary relocs for %s from %s\n",
+ sec->name, relsec->name);
+#endif
+ entsize = hdr->sh_entsize;
+
+ if (filesize != 0
+ && ((ufile_ptr) hdr->sh_offset > filesize
+ || hdr->sh_size > filesize - hdr->sh_offset))
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ result = false;
+ continue;
+ }
+
+ native_relocs = bfd_malloc (hdr->sh_size);
+ if (native_relocs == NULL)
+ {
+ result = false;
+ continue;
+ }
+
+ reloc_count = NUM_SHDR_ENTRIES (hdr);
+ if (_bfd_mul_overflow (reloc_count, sizeof (arelent), & amt))
+ {
+ free (native_relocs);
+ bfd_set_error (bfd_error_file_too_big);
+ result = false;
+ continue;
+ }
+
+ internal_relocs = (arelent *) bfd_alloc (abfd, amt);
+ if (internal_relocs == NULL)
+ {
+ free (native_relocs);
+ result = false;
+ continue;
+ }
+
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
+ || (bfd_bread (native_relocs, hdr->sh_size, abfd)
+ != hdr->sh_size))
+ {
+ free (native_relocs);
+ /* The internal_relocs will be freed when
+ the memory for the bfd is released. */
+ result = false;
+ continue;
+ }
+
+ if (dynamic)
+ symcount = bfd_get_dynamic_symcount (abfd);
+ else
+ symcount = bfd_get_symcount (abfd);
+
+ for (i = 0, internal_reloc = internal_relocs,
+ native_reloc = native_relocs;
+ i < reloc_count;
+ i++, internal_reloc++, native_reloc += entsize)
+ {
+ bool res;
+ Elf_Internal_Rela rela;
+
+ if (entsize == ebd->s->sizeof_rel)
+ ebd->s->swap_reloc_in (abfd, native_reloc, & rela);
+ else /* entsize == ebd->s->sizeof_rela */
+ ebd->s->swap_reloca_in (abfd, native_reloc, & rela);
+
+ /* The address of an ELF reloc is section relative for an object
+ file, and absolute for an executable file or shared library.
+ The address of a normal BFD reloc is always section relative,
+ and the address of a dynamic reloc is absolute.. */
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ internal_reloc->address = rela.r_offset;
+ else
+ internal_reloc->address = rela.r_offset - sec->vma;
+
+ if (r_sym (rela.r_info) == STN_UNDEF)
+ {
+ /* FIXME: This and the error case below mean that we
+ have a symbol on relocs that is not elf_symbol_type. */
+ internal_reloc->sym_ptr_ptr =
+ bfd_abs_section_ptr->symbol_ptr_ptr;
+ }
+ else if (r_sym (rela.r_info) > symcount)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): relocation %zu has invalid symbol index %lu"),
+ abfd, sec, i, (long) r_sym (rela.r_info));
+ bfd_set_error (bfd_error_bad_value);
+ internal_reloc->sym_ptr_ptr =
+ bfd_abs_section_ptr->symbol_ptr_ptr;
+ result = false;
+ }
+ else
+ {
+ asymbol **ps;
+
+ ps = symbols + r_sym (rela.r_info) - 1;
+ internal_reloc->sym_ptr_ptr = ps;
+ /* Make sure that this symbol is not removed by strip. */
+ (*ps)->flags |= BSF_KEEP;
+ }
+
+ internal_reloc->addend = rela.r_addend;
+
+ res = ebd->elf_info_to_howto (abfd, internal_reloc, & rela);
+ if (! res || internal_reloc->howto == NULL)
+ {
+#if DEBUG_SECONDARY_RELOCS
+ fprintf (stderr,
+ "there is no howto associated with reloc %lx\n",
+ rela.r_info);
+#endif
+ result = false;
+ }
+ }
+
+ free (native_relocs);
+ /* Store the internal relocs. */
+ elf_section_data (relsec)->sec_info = internal_relocs;
+ }
+ }
+
+ return result;
+}
+
+/* Set the ELF section header fields of an output secondary reloc section. */
+
+bool
+_bfd_elf_copy_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUSED,
+ bfd *obfd ATTRIBUTE_UNUSED,
+ const Elf_Internal_Shdr *isection,
+ Elf_Internal_Shdr *osection)
+{
+ asection * isec;
+ asection * osec;
+ struct bfd_elf_section_data * esd;
+
+ if (isection == NULL)
+ return false;
+
+ if (isection->sh_type != SHT_SECONDARY_RELOC)
+ return true;
+
+ isec = isection->bfd_section;
+ if (isec == NULL)
+ return false;
+
+ osec = osection->bfd_section;
+ if (osec == NULL)
+ return false;
+
+ esd = elf_section_data (osec);
+ BFD_ASSERT (esd->sec_info == NULL);
+ esd->sec_info = elf_section_data (isec)->sec_info;
+ osection->sh_type = SHT_RELA;
+ osection->sh_link = elf_onesymtab (obfd);
+ if (osection->sh_link == 0)
+ {
+ /* There is no symbol table - we are hosed... */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): link section cannot be set"
+ " because the output file does not have a symbol table"),
+ obfd, osec);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ /* Find the output section that corresponds to the isection's
+ sh_info link. */
+ if (isection->sh_info == 0
+ || isection->sh_info >= elf_numsections (ibfd))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): info section index is invalid"),
+ obfd, osec);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ isection = elf_elfsections (ibfd)[isection->sh_info];
+
+ if (isection == NULL
+ || isection->bfd_section == NULL
+ || isection->bfd_section->output_section == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): info section index cannot be set"
+ " because the section is not in the output"),
+ obfd, osec);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ esd = elf_section_data (isection->bfd_section->output_section);
+ BFD_ASSERT (esd != NULL);
+ osection->sh_info = esd->this_idx;
+ esd->has_secondary_relocs = true;
+#if DEBUG_SECONDARY_RELOCS
+ fprintf (stderr, "update header of %s, sh_link = %u, sh_info = %u\n",
+ osec->name, osection->sh_link, osection->sh_info);
+ fprintf (stderr, "mark section %s as having secondary relocs\n",
+ bfd_section_name (isection->bfd_section->output_section));
+#endif
+
+ return true;
+}
+
+/* Write out a secondary reloc section.
+
+ FIXME: Currently this function can result in a serious performance penalty
+ for files with secondary relocs and lots of sections. The proper way to
+ fix this is for _bfd_elf_copy_special_section_fields() to chain secondary
+ relocs together and then to have this function just walk that chain. */
+
+bool
+_bfd_elf_write_secondary_reloc_section (bfd *abfd, asection *sec)
+{
+ const struct elf_backend_data * const ebd = get_elf_backend_data (abfd);
+ bfd_vma addr_offset;
+ asection * relsec;
+ bfd_vma (*r_info) (bfd_vma, bfd_vma);
+ bool result = true;
+
+ if (sec == NULL)
+ return false;
+
+#if BFD_DEFAULT_TARGET_SIZE > 32
+ if (bfd_arch_bits_per_address (abfd) != 32)
+ r_info = elf64_r_info;
+ else
+#endif
+ r_info = elf32_r_info;
+
+ /* The address of an ELF reloc is section relative for an object
+ file, and absolute for an executable file or shared library.
+ The address of a BFD reloc is always section relative. */
+ addr_offset = 0;
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+ addr_offset = sec->vma;
+
+ /* Discover if there are any secondary reloc sections
+ associated with SEC. */
+ for (relsec = abfd->sections; relsec != NULL; relsec = relsec->next)
+ {
+ const struct bfd_elf_section_data * const esd = elf_section_data (relsec);
+ Elf_Internal_Shdr * const hdr = (Elf_Internal_Shdr *) & esd->this_hdr;
+
+ if (hdr->sh_type == SHT_RELA
+ && hdr->sh_info == (unsigned) elf_section_data (sec)->this_idx)
+ {
+ asymbol * last_sym;
+ int last_sym_idx;
+ size_t reloc_count;
+ size_t idx;
+ bfd_size_type entsize;
+ arelent * src_irel;
+ bfd_byte * dst_rela;
+
+ if (hdr->contents != NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc section processed twice"),
+ abfd, relsec);
+ bfd_set_error (bfd_error_bad_value);
+ result = false;
+ continue;
+ }
+
+ entsize = hdr->sh_entsize;
+ if (entsize == 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc section"
+ " has zero sized entries"),
+ abfd, relsec);
+ bfd_set_error (bfd_error_bad_value);
+ result = false;
+ continue;
+ }
+ else if (entsize != ebd->s->sizeof_rel
+ && entsize != ebd->s->sizeof_rela)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc section"
+ " has non-standard sized entries"),
+ abfd, relsec);
+ bfd_set_error (bfd_error_bad_value);
+ result = false;
+ continue;
+ }
+
+ reloc_count = hdr->sh_size / entsize;
+ hdr->sh_size = entsize * reloc_count;
+ if (reloc_count == 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc section is empty!"),
+ abfd, relsec);
+ bfd_set_error (bfd_error_bad_value);
+ result = false;
+ continue;
+ }
+
+ hdr->contents = bfd_alloc (abfd, hdr->sh_size);
+ if (hdr->contents == NULL)
+ continue;
+
+#if DEBUG_SECONDARY_RELOCS
+ fprintf (stderr, "write %u secondary relocs for %s from %s\n",
+ reloc_count, sec->name, relsec->name);
+#endif
+ last_sym = NULL;
+ last_sym_idx = 0;
+ dst_rela = hdr->contents;
+ src_irel = (arelent *) esd->sec_info;
+ if (src_irel == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: internal relocs missing"
+ " for secondary reloc section"),
+ abfd, relsec);
+ bfd_set_error (bfd_error_bad_value);
+ result = false;
+ continue;
+ }
+
+ for (idx = 0; idx < reloc_count; idx++, dst_rela += entsize)
+ {
+ Elf_Internal_Rela src_rela;
+ arelent *ptr;
+ asymbol *sym;
+ int n;
+
+ ptr = src_irel + idx;
+ if (ptr == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: reloc table entry %zu is empty"),
+ abfd, relsec, idx);
+ bfd_set_error (bfd_error_bad_value);
+ result = false;
+ break;
+ }
+
+ if (ptr->sym_ptr_ptr == NULL)
+ {
+ /* FIXME: Is this an error ? */
+ n = 0;
+ }
+ else
+ {
+ sym = *ptr->sym_ptr_ptr;
+
+ if (sym == last_sym)
+ n = last_sym_idx;
+ else
+ {
+ n = _bfd_elf_symbol_from_bfd_symbol (abfd, & sym);
+ if (n < 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc %zu"
+ " references a missing symbol"),
+ abfd, relsec, idx);
+ bfd_set_error (bfd_error_bad_value);
+ result = false;
+ n = 0;
+ }
+
+ last_sym = sym;
+ last_sym_idx = n;
+ }
+
+ if (sym->the_bfd != NULL
+ && sym->the_bfd->xvec != abfd->xvec
+ && ! _bfd_elf_validate_reloc (abfd, ptr))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc %zu"
+ " references a deleted symbol"),
+ abfd, relsec, idx);
+ bfd_set_error (bfd_error_bad_value);
+ result = false;
+ n = 0;
+ }
+ }
+
+ src_rela.r_offset = ptr->address + addr_offset;
+ if (ptr->howto == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc %zu"
+ " is of an unknown type"),
+ abfd, relsec, idx);
+ bfd_set_error (bfd_error_bad_value);
+ result = false;
+ src_rela.r_info = r_info (0, 0);
+ }
+ else
+ src_rela.r_info = r_info (n, ptr->howto->type);
+ src_rela.r_addend = ptr->addend;
+
+ if (entsize == ebd->s->sizeof_rel)
+ ebd->s->swap_reloc_out (abfd, &src_rela, dst_rela);
+ else /* entsize == ebd->s->sizeof_rela */
+ ebd->s->swap_reloca_out (abfd, &src_rela, dst_rela);
+ }
+ }
+ }
+
+ return result;
+}
Index: GNU/binutils/create-2.40-copy-osabi-patch/create.patch.sh
===================================================================
--- GNU/binutils/create-2.40-copy-osabi-patch/create.patch.sh (nonexistent)
+++ GNU/binutils/create-2.40-copy-osabi-patch/create.patch.sh (revision 33)
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+VERSION=2.40
+
+tar --files-from=file.list -xJvf ../binutils-$VERSION.tar.xz
+mv binutils-$VERSION binutils-$VERSION-orig
+
+cp -rf ./binutils-$VERSION-new ./binutils-$VERSION
+
+diff --unified -Nr binutils-$VERSION-orig binutils-$VERSION > binutils-$VERSION-copy-osabi.patch
+
+mv binutils-$VERSION-copy-osabi.patch ../patches
+
+rm -rf ./binutils-$VERSION
+rm -rf ./binutils-$VERSION-orig
Property changes on: GNU/binutils/create-2.40-copy-osabi-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: GNU/binutils/create-2.40-copy-osabi-patch/file.list
===================================================================
--- GNU/binutils/create-2.40-copy-osabi-patch/file.list (nonexistent)
+++ GNU/binutils/create-2.40-copy-osabi-patch/file.list (revision 33)
@@ -0,0 +1 @@
+binutils-2.40/bfd/elf.c
Index: GNU/binutils/create-2.40-export-demangle-patch/binutils-2.40-new/bfd/Makefile.am
===================================================================
--- GNU/binutils/create-2.40-export-demangle-patch/binutils-2.40-new/bfd/Makefile.am (nonexistent)
+++ GNU/binutils/create-2.40-export-demangle-patch/binutils-2.40-new/bfd/Makefile.am (revision 33)
@@ -0,0 +1,1024 @@
+## Process this file with automake to generate Makefile.in
+#
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+#
+
+AUTOMAKE_OPTIONS = no-dist foreign info-in-builddir no-texinfo.tex
+ACLOCAL_AMFLAGS = -I . -I .. -I ../config
+
+MOSTLYCLEANFILES =
+CLEANFILES =
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
+
+INCDIR = $(srcdir)/../include
+CSEARCH = -I. -I$(srcdir) -I$(INCDIR)
+
+SUBDIRS = po
+
+bfddocdir = doc
+
+libbfd_la_LDFLAGS =
+if INSTALL_LIBBFD
+bfdlibdir = @bfdlibdir@
+bfdincludedir = @bfdincludedir@
+bfdlib_LTLIBRARIES = libbfd.la
+bfdinclude_HEADERS = $(BFD_H) $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h \
+ $(INCDIR)/diagnostics.h $(INCDIR)/bfdlink.h $(INCDIR)/demangle.h
+else !INSTALL_LIBBFD
+# Empty these so that the respective installation directories will not be created.
+bfdlibdir =
+bfdincludedir =
+bfdinclude_HEADERS =
+rpath_bfdlibdir = @bfdlibdir@
+noinst_LTLIBRARIES = libbfd.la
+libbfd_la_LDFLAGS += -rpath $(rpath_bfdlibdir)
+endif
+
+# This is where we get zlib from. zlibdir is -L../zlib and zlibinc is
+# -I../zlib, unless we were configured with --with-system-zlib, in which
+# case both are empty.
+ZLIB = @zlibdir@ -lz
+ZLIBINC = @zlibinc@
+
+WARN_CFLAGS = @WARN_CFLAGS@
+NO_WERROR = @NO_WERROR@
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
+AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' @LARGEFILE_CPPFLAGS@
+if PLUGINS
+bfdinclude_HEADERS += $(INCDIR)/plugin-api.h
+LIBDL = @lt_cv_dlopen_libs@
+endif
+
+# bfd.h goes here, for now
+BFD_H = bfd.h
+
+# Jim Kingdon notes:
+# Writing S-records should be included in all (or at least most)
+# *-*-coff, *-*-aout, etc., configurations, because people will want to
+# be able to use objcopy to create S-records. (S-records are not useful
+# for the debugger, so if you are downloading things as S-records you
+# need two copies of the executable, one to download and one for the
+# debugger).
+BFD32_LIBS = \
+ archive.lo archures.lo bfd.lo bfdio.lo bfdwin.lo cache.lo \
+ coff-bfd.lo compress.lo corefile.lo elf-properties.lo format.lo \
+ hash.lo init.lo libbfd.lo linker.lo merge.lo opncls.lo reloc.lo \
+ section.lo simple.lo stab-syms.lo stabs.lo syms.lo targets.lo \
+ binary.lo ihex.lo srec.lo tekhex.lo verilog.lo
+
+BFD64_LIBS = archive64.lo
+
+BFD32_LIBS_CFILES = \
+ archive.c archures.c bfd.c bfdio.c bfdwin.c cache.c coff-bfd.c \
+ compress.c corefile.c elf-properties.c format.c hash.c \
+ init.c libbfd.c linker.c merge.c opncls.c reloc.c \
+ section.c simple.c stab-syms.c stabs.c syms.c targets.c \
+ binary.c ihex.c srec.c tekhex.c verilog.c
+
+BFD64_LIBS_CFILES = archive64.c
+
+# This list is alphabetized to make it easier to keep in sync
+# with the decls and initializer in archures.c.
+ALL_MACHINES = \
+ cpu-aarch64.lo \
+ cpu-alpha.lo \
+ cpu-amdgcn.lo \
+ cpu-arc.lo \
+ cpu-arm.lo \
+ cpu-avr.lo \
+ cpu-bfin.lo \
+ cpu-bpf.lo \
+ cpu-cr16.lo \
+ cpu-cris.lo \
+ cpu-crx.lo \
+ cpu-csky.lo \
+ cpu-d10v.lo \
+ cpu-d30v.lo \
+ cpu-dlx.lo \
+ cpu-epiphany.lo \
+ cpu-fr30.lo \
+ cpu-frv.lo \
+ cpu-ft32.lo \
+ cpu-h8300.lo \
+ cpu-hppa.lo \
+ cpu-i386.lo \
+ cpu-iamcu.lo \
+ cpu-ia64.lo \
+ cpu-ip2k.lo \
+ cpu-iq2000.lo \
+ cpu-lm32.lo \
+ cpu-loongarch.lo \
+ cpu-m10200.lo \
+ cpu-m10300.lo \
+ cpu-m32c.lo \
+ cpu-m32r.lo \
+ cpu-m68hc11.lo \
+ cpu-m68hc12.lo \
+ cpu-m9s12x.lo \
+ cpu-s12z.lo \
+ cpu-m9s12xg.lo \
+ cpu-m68k.lo \
+ cpu-mcore.lo \
+ cpu-mep.lo \
+ cpu-metag.lo \
+ cpu-microblaze.lo \
+ cpu-mips.lo \
+ cpu-mmix.lo \
+ cpu-moxie.lo \
+ cpu-msp430.lo \
+ cpu-mt.lo \
+ cpu-nds32.lo \
+ cpu-nfp.lo \
+ cpu-nios2.lo \
+ cpu-ns32k.lo \
+ cpu-or1k.lo \
+ cpu-pdp11.lo \
+ cpu-pj.lo \
+ cpu-powerpc.lo \
+ cpu-pru.lo \
+ cpu-rs6000.lo \
+ cpu-riscv.lo \
+ cpu-rl78.lo \
+ cpu-rx.lo \
+ cpu-s390.lo \
+ cpu-score.lo \
+ cpu-sh.lo \
+ cpu-sparc.lo \
+ cpu-spu.lo \
+ cpu-tic30.lo \
+ cpu-tic4x.lo \
+ cpu-tic54x.lo \
+ cpu-tic6x.lo \
+ cpu-tilegx.lo \
+ cpu-tilepro.lo \
+ cpu-v850.lo \
+ cpu-v850_rh850.lo \
+ cpu-vax.lo \
+ cpu-visium.lo \
+ cpu-wasm32.lo \
+ cpu-xgate.lo \
+ cpu-xstormy16.lo \
+ cpu-xtensa.lo \
+ cpu-z80.lo \
+ cpu-z8k.lo
+
+ALL_MACHINES_CFILES = \
+ cpu-aarch64.c \
+ cpu-alpha.c \
+ cpu-amdgcn.c \
+ cpu-arc.c \
+ cpu-arm.c \
+ cpu-avr.c \
+ cpu-bfin.c \
+ cpu-bpf.c \
+ cpu-cr16.c \
+ cpu-cris.c \
+ cpu-crx.c \
+ cpu-csky.c \
+ cpu-d10v.c \
+ cpu-d30v.c \
+ cpu-dlx.c \
+ cpu-epiphany.c \
+ cpu-fr30.c \
+ cpu-frv.c \
+ cpu-ft32.c \
+ cpu-h8300.c \
+ cpu-hppa.c \
+ cpu-i386.c \
+ cpu-iamcu.c \
+ cpu-ia64.c \
+ cpu-ip2k.c \
+ cpu-iq2000.c \
+ cpu-lm32.c \
+ cpu-loongarch.c \
+ cpu-m10200.c \
+ cpu-m10300.c \
+ cpu-m32c.c \
+ cpu-m32r.c \
+ cpu-m68hc11.c \
+ cpu-m68hc12.c \
+ cpu-m9s12x.c \
+ cpu-s12z.c \
+ cpu-m9s12xg.c \
+ cpu-m68k.c \
+ cpu-mcore.c \
+ cpu-mep.c \
+ cpu-metag.c \
+ cpu-microblaze.c \
+ cpu-mips.c \
+ cpu-mmix.c \
+ cpu-moxie.c \
+ cpu-msp430.c \
+ cpu-mt.c \
+ cpu-nds32.c \
+ cpu-nfp.c \
+ cpu-ns32k.c \
+ cpu-nios2.c \
+ cpu-or1k.c \
+ cpu-pdp11.c \
+ cpu-pj.c \
+ cpu-powerpc.c \
+ cpu-pru.c \
+ cpu-rs6000.c \
+ cpu-riscv.c \
+ cpu-rl78.c \
+ cpu-rx.c \
+ cpu-s390.c \
+ cpu-score.c \
+ cpu-sh.c \
+ cpu-sparc.c \
+ cpu-spu.c \
+ cpu-tic30.c \
+ cpu-tic4x.c \
+ cpu-tic54x.c \
+ cpu-tic6x.c \
+ cpu-tilegx.c \
+ cpu-tilepro.c \
+ cpu-v850.c \
+ cpu-v850_rh850.c \
+ cpu-vax.c \
+ cpu-visium.c \
+ cpu-wasm32.c \
+ cpu-xgate.c \
+ cpu-xstormy16.c \
+ cpu-xtensa.c \
+ cpu-z80.c \
+ cpu-z8k.c
+
+# The .o files needed by all of the 32 bit vectors that are configured into
+# target_vector in targets.c if configured with --enable-targets=all.
+BFD32_BACKENDS = \
+ aout-cris.lo \
+ aout-ns32k.lo \
+ aout32.lo \
+ cf-i386lynx.lo \
+ coff-go32.lo \
+ coff-i386.lo \
+ coff-mips.lo \
+ coff-rs6000.lo \
+ coff-sh.lo \
+ coff-stgo32.lo \
+ coff-tic30.lo \
+ coff-tic4x.lo \
+ coff-tic54x.lo \
+ coff-z80.lo \
+ coff-z8k.lo \
+ coffgen.lo \
+ cofflink.lo \
+ dwarf1.lo \
+ dwarf2.lo \
+ ecoff.lo \
+ ecofflink.lo \
+ elf-attrs.lo \
+ elf-eh-frame.lo \
+ elf-sframe.lo \
+ elf-ifunc.lo \
+ elf-m10200.lo \
+ elf-m10300.lo \
+ elf-nacl.lo \
+ elf-strtab.lo \
+ elf-vxworks.lo \
+ elf.lo \
+ elf32-am33lin.lo \
+ elf32-arc.lo \
+ elf32-arm.lo \
+ elf32-avr.lo \
+ elf32-bfin.lo \
+ elf32-cr16.lo \
+ elf32-cris.lo \
+ elf32-crx.lo \
+ elf32-csky.lo \
+ elf32-d10v.lo \
+ elf32-d30v.lo \
+ elf32-dlx.lo \
+ elf32-epiphany.lo \
+ elf32-fr30.lo \
+ elf32-frv.lo \
+ elf32-ft32.lo \
+ elf32-gen.lo \
+ elf32-h8300.lo \
+ elf32-hppa.lo \
+ elf32-i386.lo \
+ elfxx-x86.lo \
+ elf32-ip2k.lo \
+ elf32-iq2000.lo \
+ elf32-lm32.lo \
+ elf32-m32c.lo \
+ elf32-m32r.lo \
+ elf32-m68hc11.lo \
+ elf32-m68hc12.lo \
+ elf32-m68hc1x.lo \
+ elf32-m68k.lo \
+ elf32-s12z.lo \
+ elf32-mcore.lo \
+ elf32-mep.lo \
+ elf32-metag.lo \
+ elf32-microblaze.lo \
+ elf32-moxie.lo \
+ elf32-msp430.lo \
+ elf32-mt.lo \
+ elf32-nds32.lo \
+ elf32-nios2.lo \
+ elf32-or1k.lo \
+ elf32-pj.lo \
+ elf32-ppc.lo \
+ elf32-pru.lo \
+ elf32-rl78.lo \
+ elf32-rx.lo \
+ elf32-s390.lo \
+ elf32-sh.lo \
+ elf32-sparc.lo \
+ elf32-spu.lo \
+ elf32-tic6x.lo \
+ elf32-tilegx.lo \
+ elf32-tilepro.lo \
+ elf32-v850.lo \
+ elf32-vax.lo \
+ elf32-visium.lo \
+ elf32-wasm32.lo \
+ elf32-xgate.lo \
+ elf32-xstormy16.lo \
+ elf32-xtensa.lo \
+ elf32-z80.lo \
+ elf32.lo \
+ elflink.lo \
+ elfxx-sparc.lo \
+ elfxx-tilegx.lo \
+ i386aout.lo \
+ i386bsd.lo \
+ i386lynx.lo \
+ i386msdos.lo \
+ mach-o.lo \
+ mach-o-i386.lo \
+ mach-o-arm.lo \
+ ns32knetbsd.lo \
+ pc532-mach.lo \
+ pdb.lo \
+ pdp11.lo \
+ pe-arm-wince.lo \
+ pe-arm.lo \
+ pe-i386.lo \
+ pe-mcore.lo \
+ pe-sh.lo \
+ pef.lo \
+ pei-arm-wince.lo \
+ pei-arm.lo \
+ pei-i386.lo \
+ pei-mcore.lo \
+ pei-sh.lo \
+ peigen.lo \
+ plugin.lo \
+ ppcboot.lo \
+ reloc16.lo \
+ som.lo \
+ vax1knetbsd.lo \
+ vaxnetbsd.lo \
+ vms-lib.lo \
+ vms-misc.lo \
+ wasm-module.lo \
+ xcofflink.lo \
+ xsym.lo \
+ xtensa-dynconfig.lo \
+ xtensa-isa.lo \
+ xtensa-modules.lo
+
+BFD32_BACKENDS_CFILES = \
+ aout-cris.c \
+ aout-ns32k.c \
+ aout32.c \
+ cf-i386lynx.c \
+ coff-go32.c \
+ coff-i386.c \
+ coff-mips.c \
+ coff-rs6000.c \
+ coff-sh.c \
+ coff-stgo32.c \
+ coff-tic30.c \
+ coff-tic4x.c \
+ coff-tic54x.c \
+ coff-z80.c \
+ coff-z8k.c \
+ coffgen.c \
+ cofflink.c \
+ dwarf1.c \
+ dwarf2.c \
+ ecoff.c \
+ ecofflink.c \
+ elf-attrs.c \
+ elf-eh-frame.c \
+ elf-sframe.c \
+ elf-ifunc.c \
+ elf-m10200.c \
+ elf-m10300.c \
+ elf-nacl.c \
+ elf-strtab.c \
+ elf-vxworks.c \
+ elf.c \
+ elf32-am33lin.c \
+ elf32-arc.c \
+ elf32-arm.c \
+ elf32-avr.c \
+ elf32-bfin.c \
+ elf32-cr16.c \
+ elf32-cris.c \
+ elf32-crx.c \
+ elf32-csky.c \
+ elf32-d10v.c \
+ elf32-d30v.c \
+ elf32-dlx.c \
+ elf32-epiphany.c \
+ elf32-fr30.c \
+ elf32-frv.c \
+ elf32-ft32.c \
+ elf32-gen.c \
+ elf32-h8300.c \
+ elf32-hppa.c \
+ elf32-i386.c \
+ elfxx-x86.c \
+ elf32-ip2k.c \
+ elf32-iq2000.c \
+ elf32-lm32.c \
+ elf32-m32c.c \
+ elf32-m32r.c \
+ elf32-m68hc11.c \
+ elf32-m68hc12.c \
+ elf32-m68hc1x.c \
+ elf32-m68k.c \
+ elf32-s12z.c \
+ elf32-mcore.c \
+ elf32-mep.c \
+ elf32-metag.c \
+ elf32-microblaze.c \
+ elf32-moxie.c \
+ elf32-msp430.c \
+ elf32-mt.c \
+ elf32-nds32.c \
+ elf32-nios2.c \
+ elf32-or1k.c \
+ elf32-pj.c \
+ elf32-ppc.c \
+ elf32-pru.c \
+ elf32-rl78.c \
+ elf32-rx.c \
+ elf32-s390.c \
+ elf32-sh.c \
+ elf32-sparc.c \
+ elf32-spu.c \
+ elf32-tic6x.c \
+ elf32-tilegx.c \
+ elf32-tilepro.c \
+ elf32-v850.c \
+ elf32-vax.c \
+ elf32-visium.c \
+ elf32-wasm32.c \
+ elf32-xgate.c \
+ elf32-xstormy16.c \
+ elf32-xtensa.c \
+ elf32-z80.c \
+ elf32.c \
+ elflink.c \
+ elfxx-sparc.c \
+ elfxx-tilegx.c \
+ i386aout.c \
+ i386bsd.c \
+ i386lynx.c \
+ i386msdos.c \
+ mach-o.c \
+ mach-o-i386.c \
+ mach-o-arm.c \
+ ns32knetbsd.c \
+ pc532-mach.c \
+ pdb.c \
+ pdp11.c \
+ pe-arm-wince.c \
+ pe-arm.c \
+ pe-i386.c \
+ pe-mcore.c \
+ pe-sh.c \
+ pef.c \
+ pei-arm-wince.c \
+ pei-arm.c \
+ pei-i386.c \
+ pei-mcore.c \
+ pei-sh.c \
+ plugin.c \
+ ppcboot.c \
+ reloc16.c \
+ som.c \
+ vax1knetbsd.c \
+ vaxnetbsd.c \
+ vms-lib.c \
+ vms-misc.c \
+ wasm-module.c \
+ xcofflink.c \
+ xsym.c \
+ xtensa-dynconfig.c \
+ xtensa-isa.c \
+ xtensa-modules.c
+
+# The .o files needed by all of the 64 bit vectors that are configured into
+# target_vector in targets.c if configured with --enable-targets=all
+# and --enable-64-bit-bfd.
+# elf32-ia64.c requires a 64-bit bfd_vma, and hence can not be put in
+# BFD32_BACKENDS.
+BFD64_BACKENDS = \
+ elf32-aarch64.lo \
+ elf64-aarch64.lo \
+ elfxx-aarch64.lo \
+ aix5ppc-core.lo \
+ aout64.lo \
+ coff-alpha.lo \
+ coff-x86_64.lo \
+ coff64-rs6000.lo \
+ elf32-ia64.lo \
+ elf32-mips.lo \
+ elf32-score.lo \
+ elf32-score7.lo \
+ elf64-alpha.lo \
+ elf64-amdgcn.lo \
+ elf64-gen.lo \
+ elf64-hppa.lo \
+ elf64-ia64.lo \
+ elf64-ia64-vms.lo \
+ elfxx-ia64.lo \
+ elf32-loongarch.lo \
+ elf64-loongarch.lo \
+ elfxx-loongarch.lo \
+ elfn32-mips.lo \
+ elf64-mips.lo \
+ elfxx-mips.lo \
+ elf64-mmix.lo \
+ elf64-nfp.lo \
+ elf64-ppc.lo \
+ elf32-riscv.lo \
+ elf64-riscv.lo \
+ elfxx-riscv.lo \
+ elf64-s390.lo \
+ elf64-sparc.lo \
+ elf64-tilegx.lo \
+ elf64-x86-64.lo \
+ elfxx-x86.lo \
+ elf64-bpf.lo \
+ elf64.lo \
+ mach-o-aarch64.lo \
+ mach-o-x86-64.lo \
+ mmo.lo \
+ pe-aarch64igen.lo \
+ pe-loongarch64igen.lo \
+ pe-x86_64.lo \
+ pei-aarch64.lo \
+ pe-aarch64.lo \
+ pei-ia64.lo \
+ pei-loongarch64.lo \
+ pei-x86_64.lo \
+ pepigen.lo \
+ pex64igen.lo \
+ vms-alpha.lo
+
+BFD64_BACKENDS_CFILES = \
+ aix5ppc-core.c \
+ aout64.c \
+ coff-alpha.c \
+ coff-x86_64.c \
+ coff64-rs6000.c \
+ elf32-mips.c \
+ elf32-score.c \
+ elf32-score7.c \
+ elf64-alpha.c \
+ elf64-amdgcn.c \
+ elf64-gen.c \
+ elf64-hppa.c \
+ elf64-ia64-vms.c \
+ elf64-mips.c \
+ elf64-mmix.c \
+ elf64-nfp.c \
+ elf64-ppc.c \
+ elf64-s390.c \
+ elf64-sparc.c \
+ elf64-tilegx.c \
+ elf64-x86-64.c \
+ elfxx-x86.c \
+ elf64-bpf.c \
+ elf64.c \
+ elfn32-mips.c \
+ elfxx-aarch64.c \
+ elfxx-ia64.c \
+ elfxx-loongarch.c \
+ elfxx-mips.c \
+ elfxx-riscv.c \
+ mach-o-aarch64.c \
+ mach-o-x86-64.c \
+ mmo.c \
+ pe-aarch64.c \
+ pe-x86_64.c \
+ pei-aarch64.c \
+ pei-ia64.c \
+ pei-loongarch64.c \
+ pei-x86_64.c \
+ vms-alpha.c
+
+OPTIONAL_BACKENDS = \
+ aix386-core.lo \
+ cisco-core.lo \
+ hpux-core.lo \
+ irix-core.lo \
+ lynx-core.lo \
+ netbsd-core.lo \
+ osf-core.lo \
+ rs6000-core.lo \
+ sco5-core.lo \
+ trad-core.lo
+
+OPTIONAL_BACKENDS_CFILES = \
+ aix386-core.c \
+ cisco-core.c \
+ hpux-core.c \
+ irix-core.c \
+ lynx-core.c \
+ netbsd-core.c \
+ osf-core.c \
+ rs6000-core.c \
+ sco5-core.c \
+ trad-core.c
+
+# Reconfigure if config.bfd or configure.host changes.
+# development.sh is used to determine -Werror default.
+CONFIG_STATUS_DEPENDENCIES = \
+ $(srcdir)/config.bfd \
+ $(srcdir)/configure.host \
+ $(srcdir)/development.sh
+
+# These are defined by configure:
+WORDSIZE = @wordsize@
+ALL_BACKENDS = @all_backends@
+BFD_BACKENDS = @bfd_backends@
+BFD_MACHINES = @bfd_machines@
+TDEFAULTS = @tdefaults@
+HAVEVECS = @havevecs@
+
+AM_CPPFLAGS += @HDEFINES@ @COREFLAG@ @TDEFINES@ $(CSEARCH) $(CSWITCHES) \
+ $(HAVEVECS) @INCINTL@
+
+# C source files that correspond to .o's.
+SOURCE_CFILES = \
+ $(BFD32_LIBS_CFILES) \
+ $(BFD64_LIBS_CFILES) \
+ $(ALL_MACHINES_CFILES) \
+ $(BFD32_BACKENDS_CFILES) \
+ $(BFD64_BACKENDS_CFILES) \
+ $(OPTIONAL_BACKENDS_CFILES)
+
+BUILD_CFILES = \
+ elf32-aarch64.c elf64-aarch64.c \
+ elf32-ia64.c elf64-ia64.c \
+ elf32-loongarch.c elf64-loongarch.c \
+ elf32-riscv.c elf64-riscv.c \
+ peigen.c pepigen.c pex64igen.c pe-aarch64igen.c pe-loongarch64igen.c
+
+CFILES = $(SOURCE_CFILES) $(BUILD_CFILES)
+
+## This is a list of all .h files in the source tree minus those that
+## are processed to produce other .h files
+SOURCE_HFILES = \
+ aout-target.h aoutx.h arc-got.h arc-plt.h \
+ coff-arm.h coff-bfd.h coffcode.h coffswap.h \
+ cpu-aarch64.h cpu-arm.h cpu-h8300.h cpu-m68k.h cpu-riscv.h \
+ ecoff-bfd.h ecoffswap.h \
+ elf32-arm.h elf32-avr.h elf32-bfin.h elf32-cr16.h elf32-csky.h \
+ elf32-dlx.h elf32-hppa.h elf32-m68hc1x.h elf32-m68k.h \
+ elf32-metag.h elf32-nds32.h elf32-nios2.h elf32-ppc.h \
+ elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \
+ elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \
+ elf64-hppa.h elf64-ppc.h elf64-tilegx.h \
+ elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \
+ elf-linux-core.h elf-nacl.h elf-s390.h elf-vxworks.h \
+ elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
+ elfxx-sparc.h elfxx-tilegx.h elfxx-x86.h elfxx-loongarch.h \
+ genlink.h go32stub.h \
+ libaout.h libbfd.h libcoff.h libecoff.h libhppa.h \
+ libpei.h libxcoff.h \
+ mach-o.h \
+ netbsd.h ns32k.h \
+ pef.h pef-traceback.h peicode.h plugin.h \
+ som.h sysdep.h \
+ version.h vms.h \
+ wasm-module.h \
+ xcofflink.h xsym.h
+
+## ... and .h files which are in the build tree, minus config.h and bfd.h
+BUILD_HFILES = \
+ bfdver.h elf32-target.h elf64-target.h targmatch.h
+
+# Ensure they are built early:
+BUILT_SOURCES = $(BUILD_HFILES) $(BUILD_CFILES)
+
+HFILES = $(SOURCE_HFILES) $(BUILD_HFILES)
+
+BFD_H_DEPS = $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h $(INCDIR)/diagnostics.h
+LOCAL_H_DEPS = libbfd.h sysdep.h config.h
+$(BFD32_LIBS) \
+ $(BFD64_LIBS) \
+ $(ALL_MACHINES) \
+ $(BFD32_BACKENDS) \
+ $(BFD64_BACKENDS) \
+ $(OPTIONAL_BACKENDS): $(BFD_H) $(BFD_H_DEPS) $(LOCAL_H_DEPS)
+
+SRC_POTFILES = $(SOURCE_CFILES) $(SOURCE_HFILES)
+BLD_POTFILES = $(BUILD_CFILES) $(BUILD_HFILES)
+
+po/SRC-POTFILES.in: @MAINT@ Makefile
+ for file in $(SRC_POTFILES); do echo $$file; done \
+ | LC_ALL=C sort > tmp.src \
+ && mv tmp.src $(srcdir)/po/SRC-POTFILES.in
+
+po/BLD-POTFILES.in: @MAINT@ Makefile
+ for file in $(BLD_POTFILES); do echo $$file; done \
+ | LC_ALL=C sort > tmp.bld \
+ && mv tmp.bld $(srcdir)/po/BLD-POTFILES.in
+
+all diststuff: info
+
+# Various kinds of .o files to put in libbfd.a:
+# BFD_BACKENDS Routines the configured targets need.
+# BFD_MACHINES Architecture-specific routines the configured targets need.
+# COREFILE Core file routines for a native configuration
+# bfd64_libs Routines for 64bit support
+OFILES = $(BFD_BACKENDS) $(BFD_MACHINES) @COREFILE@ @bfd64_libs@
+
+stamp-ofiles: Makefile
+ rm -f tofiles
+ f=""; \
+ for i in $(OFILES) ; do \
+ case " $$f " in \
+ *" $$i "*) ;; \
+ *) f="$$f $$i" ;; \
+ esac ; \
+ done ; \
+ echo $$f > tofiles
+ $(SHELL) $(srcdir)/../move-if-change tofiles ofiles
+ touch stamp-ofiles
+
+ofiles: stamp-ofiles ; @true
+
+# Since BFD64_LIBS is optional and we can't have substitution in
+# libbfd_la_SOURCES, we put BFD64_LIBS in OFILES instead.
+# However, list all sources in EXTRA_libbfd_la_SOURCES so the
+# dependency tracking fragments are picked up in the Makefile.
+libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
+EXTRA_libbfd_la_SOURCES = $(CFILES)
+libbfd_la_DEPENDENCIES = $(OFILES) ofiles ../libsframe/libsframe.la
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS) ../libsframe/libsframe.la
+libbfd_la_LDFLAGS += -release `cat libtool-soversion` @SHARED_LDFLAGS@
+
+# libtool will build .libs/libbfd.a. We create libbfd.a in the build
+# directory so that we don't have to convert all the programs that use
+# libbfd.a simultaneously. This is a hack which should be removed if
+# everything else starts using libtool. FIXME.
+
+noinst_LIBRARIES = libbfd.a
+libbfd_a_SOURCES =
+
+stamp-lib: libbfd.la
+ libtooldir=`$(LIBTOOL) --config | $(SED) -n -e 's/^objdir=//p'`; \
+ if [ -f $$libtooldir/libbfd.a ]; then \
+ cp $$libtooldir/libbfd.a libbfd.tmp; \
+ $(RANLIB) libbfd.tmp; \
+ $(SHELL) $(srcdir)/../move-if-change libbfd.tmp libbfd.a; \
+ else true; fi
+ touch stamp-lib
+
+libbfd.a: stamp-lib ; @true
+
+# This file holds an array associating configuration triplets and
+# vector names. It is built from config.bfd. It is not compiled by
+# itself, but is included by targets.c.
+targmatch.h: config.bfd targmatch.sed
+ $(AM_V_at)rm -f targmatch.new
+ $(AM_V_GEN)$(SED) -f $(srcdir)/targmatch.sed < $(srcdir)/config.bfd > targmatch.new
+ $(AM_V_at)mv -f targmatch.new targmatch.h
+
+# When compiling archures.c and targets.c, supply the default target
+# info from configure.
+
+targets.lo: targets.c Makefile
+if am__fastdepCC
+ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $(TDEFAULTS) $(srcdir)/targets.c
+ $(AM_V_at)mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+else
+if AMDEP
+ source='targets.c' object='$@' libtool=yes @AMDEPBACKSLASH@
+ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+endif
+ $(AM_V_CC)$(LTCOMPILE) -c -o $@ $(TDEFAULTS) $(srcdir)/targets.c
+endif
+
+archures.lo: archures.c Makefile
+if am__fastdepCC
+ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $(TDEFAULTS) $(srcdir)/archures.c
+ $(AM_V_at)mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+else
+if AMDEP
+ source='archures.c' object='$@' libtool=yes @AMDEPBACKSLASH@
+ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+endif
+ $(AM_V_CC)$(LTCOMPILE) -c -o $@ $(TDEFAULTS) $(srcdir)/archures.c
+endif
+
+dwarf2.lo: dwarf2.c Makefile
+if am__fastdepCC
+ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ -DDEBUGDIR=\"$(DEBUGDIR)\" $(srcdir)/dwarf2.c
+ $(AM_V_at)mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+else
+if AMDEP
+ source='dwarf2.c' object='$@' libtool=yes @AMDEPBACKSLASH@
+ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+endif
+ $(AM_V_CC)$(LTCOMPILE) -c -o $@ -DDEBUGDIR=\"$(DEBUGDIR)\" $(srcdir)/dwarf2.c
+endif
+
+elf32-target.h : elfxx-target.h
+ $(AM_V_GEN)$(SED) -e s/NN/32/g < $< > $@
+
+elf64-target.h : elfxx-target.h
+ $(AM_V_GEN)$(SED) -e s/NN/64/g < $< > $@
+
+elf32-aarch64.c : elfnn-aarch64.c
+ $(AM_V_at)echo "#line 1 \"elfnn-aarch64.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/32/g < $< >> $@
+
+elf64-aarch64.c : elfnn-aarch64.c
+ $(AM_V_at)echo "#line 1 \"elfnn-aarch64.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/64/g < $< >> $@
+
+elf32-ia64.c : elfnn-ia64.c
+ $(AM_V_at)echo "#line 1 \"elfnn-ia64.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/32/g < $< >> $@
+
+elf64-ia64.c : elfnn-ia64.c
+ $(AM_V_at)echo "#line 1 \"elfnn-ia64.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/64/g < $< >> $@
+
+elf32-loongarch.c : elfnn-loongarch.c
+ $(AM_V_at)echo "#line 1 \"elfnn-loongarch.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/32/g < $< >> $@
+
+elf64-loongarch.c : elfnn-loongarch.c
+ $(AM_V_at)echo "#line 1 \"elfnn-loongarch.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/64/g < $< >> $@
+
+elf32-riscv.c : elfnn-riscv.c
+ $(AM_V_at)echo "#line 1 \"elfnn-riscv.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/32/g < $< >> $@
+
+elf64-riscv.c : elfnn-riscv.c
+ $(AM_V_at)echo "#line 1 \"elfnn-riscv.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/64/g < $< >> $@
+
+peigen.c : peXXigen.c
+ $(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/XX/pe/g < $< >> $@
+
+pepigen.c : peXXigen.c
+ $(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/XX/pep/g < $< >> $@
+
+pex64igen.c: peXXigen.c
+ $(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/XX/pex64/g < $< >> $@
+
+pe-aarch64igen.c: peXXigen.c
+ $(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/XX/peAArch64/g < $< >> $@
+
+pe-loongarch64igen.c: peXXigen.c
+ $(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/XX/peLoongArch64/g < $< >> $@
+
+host-aout.lo: Makefile
+
+# The following program can be used to generate a simple config file
+# which can be folded into an h-XXX file for a new host, with some editing.
+aout-params.h: gen-aout
+ ./gen-aout host > aout-params.h
+gen-aout: $(srcdir)/gen-aout.c Makefile
+ $(CC) -o gen-aout $(CFLAGS) $(LFLAGS) $(srcdir)/gen-aout.c
+
+$(BFD_H): stmp-bfd-h ; @true
+
+stmp-bfd-h: bfd-in3.h
+ rm -f bfd-tmp.h
+ cp bfd-in3.h bfd-tmp.h
+ $(SHELL) $(srcdir)/../move-if-change bfd-tmp.h $(BFD_H)
+ rm -f bfd-tmp.h
+ touch stmp-bfd-h
+
+BFD_H_FILES = bfd-in.h init.c opncls.c libbfd.c \
+ bfdio.c bfdwin.c section.c archures.c reloc.c \
+ syms.c bfd.c archive.c corefile.c targets.c format.c \
+ linker.c simple.c compress.c
+BFD64_H_FILES = archive64.c
+LIBBFD_H_FILES = libbfd-in.h libbfd.c bfd.c bfdio.c bfdwin.c \
+ cache.c reloc.c section.c targets.c archures.c linker.c
+LIBCOFF_H_FILES = libcoff-in.h coffcode.h
+
+headers: stmp-bin2-h stmp-lbfd-h stmp-lcoff-h
+
+# We only rebuild the header files automatically if we have been
+# configured with --enable-maintainer-mode.
+
+REGEN_HEADER = \
+ ( \
+ set -e; \
+ echo "$$H_FILES" | sed -f $(srcdir)/doc/header.sed; \
+ for file in $$H_FILES; do \
+ file="$(srcdir)/$$file"; \
+ case $$file in \
+ *-in.h) cat $$file;; \
+ *) echo $$file | sed -e 's,.*/,,' -e 's,^,/* Extracted from ,' \
+ -e 's,$$,. */,'; \
+ $(MKDOC) $$CHEW_FLAGS -f $(srcdir)/doc/proto.str < $$file;; \
+ esac; \
+ done; \
+ echo "\#ifdef __cplusplus"; \
+ echo "}"; \
+ echo "\#endif"; \
+ echo "\#endif"; \
+ )
+
+$(srcdir)/bfd-in2.h: @MAINT@ stmp-bin2-h ; @true
+stmp-bin2-h: $(BFD_H_FILES) $(BFD64_H_FILES) $(MKDOC)
+ $(AM_V_GEN)H_FILES="$(BFD_H_FILES)" CHEW_FLAGS= ; $(REGEN_HEADER) > bfd-in2.h-new
+ $(AM_V_at)$(SHELL) $(srcdir)/../move-if-change bfd-in2.h-new $(srcdir)/bfd-in2.h
+ $(AM_V_at)touch stmp-bin2-h
+
+$(srcdir)/libbfd.h: @MAINT@ stmp-lbfd-h ; @true
+stmp-lbfd-h: $(LIBBFD_H_FILES) $(MKDOC)
+ $(AM_V_GEN)H_FILES="$(LIBBFD_H_FILES)" CHEW_FLAGS=-i ; $(REGEN_HEADER) > libbfd.h-new
+ $(AM_V_at)$(SHELL) $(srcdir)/../move-if-change libbfd.h-new $(srcdir)/libbfd.h
+ $(AM_V_at)touch stmp-lbfd-h
+
+$(srcdir)/libcoff.h: @MAINT@ stmp-lcoff-h ; @true
+stmp-lcoff-h: $(LIBCOFF_H_FILES) $(MKDOC)
+ $(AM_V_GEN)H_FILES="$(LIBCOFF_H_FILES)" CHEW_FLAGS=-i ; $(REGEN_HEADER) > libcoff.h-new
+ $(AM_V_at)$(SHELL) $(srcdir)/../move-if-change libcoff.h-new $(srcdir)/libcoff.h
+ $(AM_V_at)touch stmp-lcoff-h
+
+MOSTLYCLEANFILES += ofiles stamp-ofiles
+
+CLEANFILES += bfd.h dep.sed stmp-bfd-h DEP DEPA DEP1 DEP2 libbfd.a stamp-lib \
+ stmp-bin2-h stmp-lbfd-h stmp-lcoff-h
+
+DISTCLEANFILES += $(BUILD_CFILES) $(BUILD_HFILES) libtool-soversion
+
+bfdver.h: $(srcdir)/version.h $(srcdir)/development.sh $(srcdir)/Makefile.in
+ $(AM_V_GEN)\
+ bfd_version=`echo "$(VERSION)" | $(SED) -e 's/\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\).*/\1.00\2.00\3.00\4.00\5/' -e 's/\([^\.]*\)\..*\(..\)\..*\(..\)\..*\(..\)\..*\(..\)$$/\1\2\3\4\5/'` ;\
+ bfd_version_string="\"$(VERSION)\"" ;\
+ bfd_soversion="$(VERSION)" ;\
+ bfd_version_package="\"$(PKGVERSION)\"" ;\
+ report_bugs_to="\"$(REPORT_BUGS_TO)\"" ;\
+ . $(srcdir)/development.sh ;\
+ if test "$$development" = true ; then \
+ bfd_version_date=`$(SED) -n -e 's/.*DATE //p' < $(srcdir)/version.h` ;\
+ bfd_version_string="\"$(VERSION).$${bfd_version_date}\"" ;\
+ bfd_soversion="$(VERSION).$${bfd_version_date}" ;\
+ fi ;\
+ $(SED) -e "s,@bfd_version@,$$bfd_version," \
+ -e "s,@bfd_version_string@,$$bfd_version_string," \
+ -e "s,@bfd_version_package@,$$bfd_version_package," \
+ -e "s,@report_bugs_to@,$$report_bugs_to," \
+ < $(srcdir)/version.h > $@; \
+ echo "$${bfd_soversion}" > libtool-soversion
+
+# Disable -Werror, if it has been enabled, since coffswap.h won't
+# compile with gcc 4.5 and above.
+coff-tic4x.lo: coff-tic4x.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR)
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< $(NO_WERROR)
+
+coff-tic54x.lo: coff-tic54x.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR)
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< $(NO_WERROR)
+
+include doc/local.mk
Index: GNU/binutils/create-2.40-export-demangle-patch/binutils-2.40-new/bfd/Makefile.in
===================================================================
--- GNU/binutils/create-2.40-export-demangle-patch/binutils-2.40-new/bfd/Makefile.in (nonexistent)
+++ GNU/binutils/create-2.40-export-demangle-patch/binutils-2.40-new/bfd/Makefile.in (revision 33)
@@ -0,0 +1,2551 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+#
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@INSTALL_LIBBFD_FALSE@am__append_1 = -rpath $(rpath_bfdlibdir)
+@PLUGINS_TRUE@am__append_2 = $(INCDIR)/plugin-api.h
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
+ $(top_srcdir)/../config/bfd64.m4 \
+ $(top_srcdir)/../config/depstand.m4 \
+ $(top_srcdir)/../config/gettext-sister.m4 \
+ $(top_srcdir)/../config/jobserver.m4 \
+ $(top_srcdir)/../config/largefile.m4 \
+ $(top_srcdir)/../config/lead-dot.m4 \
+ $(top_srcdir)/../config/nls.m4 \
+ $(top_srcdir)/../config/override.m4 \
+ $(top_srcdir)/../config/pkg.m4 \
+ $(top_srcdir)/../config/plugins.m4 \
+ $(top_srcdir)/../config/po.m4 \
+ $(top_srcdir)/../config/progtest.m4 \
+ $(top_srcdir)/../config/zlib.m4 \
+ $(top_srcdir)/../config/zstd.m4 $(top_srcdir)/../libtool.m4 \
+ $(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+ $(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+ $(top_srcdir)/bfd.m4 $(top_srcdir)/warning.m4 \
+ $(top_srcdir)/acinclude.m4 $(top_srcdir)/version.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+ $(am__configure_deps) $(am__bfdinclude_HEADERS_DIST)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = bfd-in3.h po/Makefile.in
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libbfd_a_AR = $(AR) $(ARFLAGS)
+libbfd_a_LIBADD =
+am_libbfd_a_OBJECTS =
+libbfd_a_OBJECTS = $(am_libbfd_a_OBJECTS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(bfdlibdir)" "$(DESTDIR)$(infodir)" \
+ "$(DESTDIR)$(bfdincludedir)"
+LTLIBRARIES = $(bfdlib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+am__objects_1 = archive.lo archures.lo bfd.lo bfdio.lo bfdwin.lo \
+ cache.lo coff-bfd.lo compress.lo corefile.lo elf-properties.lo \
+ format.lo hash.lo init.lo libbfd.lo linker.lo merge.lo \
+ opncls.lo reloc.lo section.lo simple.lo stab-syms.lo stabs.lo \
+ syms.lo targets.lo binary.lo ihex.lo srec.lo tekhex.lo \
+ verilog.lo
+am_libbfd_la_OBJECTS = $(am__objects_1)
+libbfd_la_OBJECTS = $(am_libbfd_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libbfd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libbfd_la_LDFLAGS) $(LDFLAGS) -o $@
+@INSTALL_LIBBFD_FALSE@am_libbfd_la_rpath =
+@INSTALL_LIBBFD_TRUE@am_libbfd_la_rpath = -rpath $(bfdlibdir)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libbfd_a_SOURCES) $(libbfd_la_SOURCES) \
+ $(EXTRA_libbfd_la_SOURCES)
+AM_V_DVIPS = $(am__v_DVIPS_@AM_V@)
+am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@)
+am__v_DVIPS_0 = @echo " DVIPS " $@;
+am__v_DVIPS_1 =
+AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@)
+am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@)
+am__v_MAKEINFO_0 = @echo " MAKEINFO" $@;
+am__v_MAKEINFO_1 =
+AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@)
+am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@)
+am__v_INFOHTML_0 = @echo " INFOHTML" $@;
+am__v_INFOHTML_1 =
+AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@)
+am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@)
+am__v_TEXI2DVI_0 = @echo " TEXI2DVI" $@;
+am__v_TEXI2DVI_1 =
+AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@)
+am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@)
+am__v_TEXI2PDF_0 = @echo " TEXI2PDF" $@;
+am__v_TEXI2PDF_1 =
+AM_V_texinfo = $(am__v_texinfo_@AM_V@)
+am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@)
+am__v_texinfo_0 = -q
+am__v_texinfo_1 =
+AM_V_texidevnull = $(am__v_texidevnull_@AM_V@)
+am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@)
+am__v_texidevnull_0 = > /dev/null
+am__v_texidevnull_1 =
+am__dirstamp = $(am__leading_dot)dirstamp
+INFO_DEPS = doc/bfd.info
+am__TEXINFO_TEX_DIR = $(srcdir)
+DVIS = doc/bfd.dvi
+PDFS = doc/bfd.pdf
+PSS = doc/bfd.ps
+HTMLS = doc/bfd.html
+TEXINFOS = doc/bfd.texi
+TEXI2PDF = $(TEXI2DVI) --pdf --batch
+MAKEINFOHTML = $(MAKEINFO) --html
+AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS)
+DVIPS = dvips
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__bfdinclude_HEADERS_DIST = $(INCDIR)/plugin-api.h bfd.h \
+ $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h \
+ $(INCDIR)/diagnostics.h $(INCDIR)/bfdlink.h $(INCDIR)/demangle.h
+HEADERS = $(bfdinclude_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ cscope
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+ $(LISP)config.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DIST_SUBDIRS = $(SUBDIRS)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+COREFILE = @COREFILE@
+COREFLAG = @COREFLAG@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEBUGDIR = @DEBUGDIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GENCAT = @GENCAT@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+HDEFINES = @HDEFINES@
+INCINTL = @INCINTL@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+LARGEFILE_CPPFLAGS = @LARGEFILE_CPPFLAGS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBINTL = @LIBINTL@
+LIBINTL_DEP = @LIBINTL_DEP@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NO_WERROR = @NO_WERROR@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKGVERSION = @PKGVERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+REPORT_BUGS_TEXI = @REPORT_BUGS_TEXI@
+REPORT_BUGS_TO = @REPORT_BUGS_TO@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHARED_LIBADD = @SHARED_LIBADD@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TDEFINES = @TDEFINES@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+WARN_CFLAGS_FOR_BUILD = @WARN_CFLAGS_FOR_BUILD@
+WARN_WRITE_STRINGS = @WARN_WRITE_STRINGS@
+XGETTEXT = @XGETTEXT@
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+all_backends = @all_backends@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bfd64_libs = @bfd64_libs@
+bfd_backends = @bfd_backends@
+bfd_default_target_size = @bfd_default_target_size@
+bfd_file_ptr = @bfd_file_ptr@
+bfd_machines = @bfd_machines@
+bfd_ufile_ptr = @bfd_ufile_ptr@
+@INSTALL_LIBBFD_FALSE@bfdincludedir =
+@INSTALL_LIBBFD_TRUE@bfdincludedir = @bfdincludedir@
+# Empty these so that the respective installation directories will not be created.
+@INSTALL_LIBBFD_FALSE@bfdlibdir =
+@INSTALL_LIBBFD_TRUE@bfdlibdir = @bfdlibdir@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+havevecs = @havevecs@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_noncanonical = @host_noncanonical@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_cv_dlopen_libs = @lt_cv_dlopen_libs@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+supports_plugins = @supports_plugins@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_noncanonical = @target_noncanonical@
+target_os = @target_os@
+target_vendor = @target_vendor@
+tdefaults = @tdefaults@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+wordsize = @wordsize@
+zlibdir = @zlibdir@
+zlibinc = @zlibinc@
+AUTOMAKE_OPTIONS = no-dist foreign info-in-builddir no-texinfo.tex
+ACLOCAL_AMFLAGS = -I . -I .. -I ../config
+MOSTLYCLEANFILES = ofiles stamp-ofiles $(MKDOC) doc/*.o doc/*.stamp
+CLEANFILES = bfd.h dep.sed stmp-bfd-h DEP DEPA DEP1 DEP2 libbfd.a \
+ stamp-lib stmp-bin2-h stmp-lbfd-h stmp-lcoff-h
+DISTCLEANFILES = $(BUILD_CFILES) $(BUILD_HFILES) libtool-soversion \
+ doc/bfd.?? doc/bfd.??? texput.log
+MAINTAINERCLEANFILES = $(DOCFILES) doc/bfd.info
+INCDIR = $(srcdir)/../include
+CSEARCH = -I. -I$(srcdir) -I$(INCDIR)
+SUBDIRS = po
+bfddocdir = doc
+libbfd_la_LDFLAGS = $(am__append_1) -release `cat libtool-soversion` \
+ @SHARED_LDFLAGS@ $(am__empty)
+@INSTALL_LIBBFD_TRUE@bfdlib_LTLIBRARIES = libbfd.la
+@INSTALL_LIBBFD_FALSE@bfdinclude_HEADERS = $(am__append_2)
+@INSTALL_LIBBFD_TRUE@bfdinclude_HEADERS = $(BFD_H) \
+@INSTALL_LIBBFD_TRUE@ $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h \
+@INSTALL_LIBBFD_TRUE@ $(INCDIR)/diagnostics.h $(INCDIR)/demangle.h \
+@INSTALL_LIBBFD_TRUE@ $(INCDIR)/bfdlink.h $(am__append_2)
+@INSTALL_LIBBFD_FALSE@rpath_bfdlibdir = @bfdlibdir@
+@INSTALL_LIBBFD_FALSE@noinst_LTLIBRARIES = libbfd.la
+
+# This is where we get zlib from. zlibdir is -L../zlib and zlibinc is
+# -I../zlib, unless we were configured with --with-system-zlib, in which
+# case both are empty.
+ZLIB = @zlibdir@ -lz
+ZLIBINC = @zlibinc@
+AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) $(ZSTD_CFLAGS)
+AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' \
+ @LARGEFILE_CPPFLAGS@ @HDEFINES@ @COREFLAG@ @TDEFINES@ \
+ $(CSEARCH) $(CSWITCHES) $(HAVEVECS) @INCINTL@
+@PLUGINS_TRUE@LIBDL = @lt_cv_dlopen_libs@
+
+# bfd.h goes here, for now
+BFD_H = bfd.h
+
+# Jim Kingdon notes:
+# Writing S-records should be included in all (or at least most)
+# *-*-coff, *-*-aout, etc., configurations, because people will want to
+# be able to use objcopy to create S-records. (S-records are not useful
+# for the debugger, so if you are downloading things as S-records you
+# need two copies of the executable, one to download and one for the
+# debugger).
+BFD32_LIBS = \
+ archive.lo archures.lo bfd.lo bfdio.lo bfdwin.lo cache.lo \
+ coff-bfd.lo compress.lo corefile.lo elf-properties.lo format.lo \
+ hash.lo init.lo libbfd.lo linker.lo merge.lo opncls.lo reloc.lo \
+ section.lo simple.lo stab-syms.lo stabs.lo syms.lo targets.lo \
+ binary.lo ihex.lo srec.lo tekhex.lo verilog.lo
+
+BFD64_LIBS = archive64.lo
+BFD32_LIBS_CFILES = \
+ archive.c archures.c bfd.c bfdio.c bfdwin.c cache.c coff-bfd.c \
+ compress.c corefile.c elf-properties.c format.c hash.c \
+ init.c libbfd.c linker.c merge.c opncls.c reloc.c \
+ section.c simple.c stab-syms.c stabs.c syms.c targets.c \
+ binary.c ihex.c srec.c tekhex.c verilog.c
+
+BFD64_LIBS_CFILES = archive64.c
+
+# This list is alphabetized to make it easier to keep in sync
+# with the decls and initializer in archures.c.
+ALL_MACHINES = \
+ cpu-aarch64.lo \
+ cpu-alpha.lo \
+ cpu-amdgcn.lo \
+ cpu-arc.lo \
+ cpu-arm.lo \
+ cpu-avr.lo \
+ cpu-bfin.lo \
+ cpu-bpf.lo \
+ cpu-cr16.lo \
+ cpu-cris.lo \
+ cpu-crx.lo \
+ cpu-csky.lo \
+ cpu-d10v.lo \
+ cpu-d30v.lo \
+ cpu-dlx.lo \
+ cpu-epiphany.lo \
+ cpu-fr30.lo \
+ cpu-frv.lo \
+ cpu-ft32.lo \
+ cpu-h8300.lo \
+ cpu-hppa.lo \
+ cpu-i386.lo \
+ cpu-iamcu.lo \
+ cpu-ia64.lo \
+ cpu-ip2k.lo \
+ cpu-iq2000.lo \
+ cpu-lm32.lo \
+ cpu-loongarch.lo \
+ cpu-m10200.lo \
+ cpu-m10300.lo \
+ cpu-m32c.lo \
+ cpu-m32r.lo \
+ cpu-m68hc11.lo \
+ cpu-m68hc12.lo \
+ cpu-m9s12x.lo \
+ cpu-s12z.lo \
+ cpu-m9s12xg.lo \
+ cpu-m68k.lo \
+ cpu-mcore.lo \
+ cpu-mep.lo \
+ cpu-metag.lo \
+ cpu-microblaze.lo \
+ cpu-mips.lo \
+ cpu-mmix.lo \
+ cpu-moxie.lo \
+ cpu-msp430.lo \
+ cpu-mt.lo \
+ cpu-nds32.lo \
+ cpu-nfp.lo \
+ cpu-nios2.lo \
+ cpu-ns32k.lo \
+ cpu-or1k.lo \
+ cpu-pdp11.lo \
+ cpu-pj.lo \
+ cpu-powerpc.lo \
+ cpu-pru.lo \
+ cpu-rs6000.lo \
+ cpu-riscv.lo \
+ cpu-rl78.lo \
+ cpu-rx.lo \
+ cpu-s390.lo \
+ cpu-score.lo \
+ cpu-sh.lo \
+ cpu-sparc.lo \
+ cpu-spu.lo \
+ cpu-tic30.lo \
+ cpu-tic4x.lo \
+ cpu-tic54x.lo \
+ cpu-tic6x.lo \
+ cpu-tilegx.lo \
+ cpu-tilepro.lo \
+ cpu-v850.lo \
+ cpu-v850_rh850.lo \
+ cpu-vax.lo \
+ cpu-visium.lo \
+ cpu-wasm32.lo \
+ cpu-xgate.lo \
+ cpu-xstormy16.lo \
+ cpu-xtensa.lo \
+ cpu-z80.lo \
+ cpu-z8k.lo
+
+ALL_MACHINES_CFILES = \
+ cpu-aarch64.c \
+ cpu-alpha.c \
+ cpu-amdgcn.c \
+ cpu-arc.c \
+ cpu-arm.c \
+ cpu-avr.c \
+ cpu-bfin.c \
+ cpu-bpf.c \
+ cpu-cr16.c \
+ cpu-cris.c \
+ cpu-crx.c \
+ cpu-csky.c \
+ cpu-d10v.c \
+ cpu-d30v.c \
+ cpu-dlx.c \
+ cpu-epiphany.c \
+ cpu-fr30.c \
+ cpu-frv.c \
+ cpu-ft32.c \
+ cpu-h8300.c \
+ cpu-hppa.c \
+ cpu-i386.c \
+ cpu-iamcu.c \
+ cpu-ia64.c \
+ cpu-ip2k.c \
+ cpu-iq2000.c \
+ cpu-lm32.c \
+ cpu-loongarch.c \
+ cpu-m10200.c \
+ cpu-m10300.c \
+ cpu-m32c.c \
+ cpu-m32r.c \
+ cpu-m68hc11.c \
+ cpu-m68hc12.c \
+ cpu-m9s12x.c \
+ cpu-s12z.c \
+ cpu-m9s12xg.c \
+ cpu-m68k.c \
+ cpu-mcore.c \
+ cpu-mep.c \
+ cpu-metag.c \
+ cpu-microblaze.c \
+ cpu-mips.c \
+ cpu-mmix.c \
+ cpu-moxie.c \
+ cpu-msp430.c \
+ cpu-mt.c \
+ cpu-nds32.c \
+ cpu-nfp.c \
+ cpu-ns32k.c \
+ cpu-nios2.c \
+ cpu-or1k.c \
+ cpu-pdp11.c \
+ cpu-pj.c \
+ cpu-powerpc.c \
+ cpu-pru.c \
+ cpu-rs6000.c \
+ cpu-riscv.c \
+ cpu-rl78.c \
+ cpu-rx.c \
+ cpu-s390.c \
+ cpu-score.c \
+ cpu-sh.c \
+ cpu-sparc.c \
+ cpu-spu.c \
+ cpu-tic30.c \
+ cpu-tic4x.c \
+ cpu-tic54x.c \
+ cpu-tic6x.c \
+ cpu-tilegx.c \
+ cpu-tilepro.c \
+ cpu-v850.c \
+ cpu-v850_rh850.c \
+ cpu-vax.c \
+ cpu-visium.c \
+ cpu-wasm32.c \
+ cpu-xgate.c \
+ cpu-xstormy16.c \
+ cpu-xtensa.c \
+ cpu-z80.c \
+ cpu-z8k.c
+
+
+# The .o files needed by all of the 32 bit vectors that are configured into
+# target_vector in targets.c if configured with --enable-targets=all.
+BFD32_BACKENDS = \
+ aout-cris.lo \
+ aout-ns32k.lo \
+ aout32.lo \
+ cf-i386lynx.lo \
+ coff-go32.lo \
+ coff-i386.lo \
+ coff-mips.lo \
+ coff-rs6000.lo \
+ coff-sh.lo \
+ coff-stgo32.lo \
+ coff-tic30.lo \
+ coff-tic4x.lo \
+ coff-tic54x.lo \
+ coff-z80.lo \
+ coff-z8k.lo \
+ coffgen.lo \
+ cofflink.lo \
+ dwarf1.lo \
+ dwarf2.lo \
+ ecoff.lo \
+ ecofflink.lo \
+ elf-attrs.lo \
+ elf-eh-frame.lo \
+ elf-sframe.lo \
+ elf-ifunc.lo \
+ elf-m10200.lo \
+ elf-m10300.lo \
+ elf-nacl.lo \
+ elf-strtab.lo \
+ elf-vxworks.lo \
+ elf.lo \
+ elf32-am33lin.lo \
+ elf32-arc.lo \
+ elf32-arm.lo \
+ elf32-avr.lo \
+ elf32-bfin.lo \
+ elf32-cr16.lo \
+ elf32-cris.lo \
+ elf32-crx.lo \
+ elf32-csky.lo \
+ elf32-d10v.lo \
+ elf32-d30v.lo \
+ elf32-dlx.lo \
+ elf32-epiphany.lo \
+ elf32-fr30.lo \
+ elf32-frv.lo \
+ elf32-ft32.lo \
+ elf32-gen.lo \
+ elf32-h8300.lo \
+ elf32-hppa.lo \
+ elf32-i386.lo \
+ elfxx-x86.lo \
+ elf32-ip2k.lo \
+ elf32-iq2000.lo \
+ elf32-lm32.lo \
+ elf32-m32c.lo \
+ elf32-m32r.lo \
+ elf32-m68hc11.lo \
+ elf32-m68hc12.lo \
+ elf32-m68hc1x.lo \
+ elf32-m68k.lo \
+ elf32-s12z.lo \
+ elf32-mcore.lo \
+ elf32-mep.lo \
+ elf32-metag.lo \
+ elf32-microblaze.lo \
+ elf32-moxie.lo \
+ elf32-msp430.lo \
+ elf32-mt.lo \
+ elf32-nds32.lo \
+ elf32-nios2.lo \
+ elf32-or1k.lo \
+ elf32-pj.lo \
+ elf32-ppc.lo \
+ elf32-pru.lo \
+ elf32-rl78.lo \
+ elf32-rx.lo \
+ elf32-s390.lo \
+ elf32-sh.lo \
+ elf32-sparc.lo \
+ elf32-spu.lo \
+ elf32-tic6x.lo \
+ elf32-tilegx.lo \
+ elf32-tilepro.lo \
+ elf32-v850.lo \
+ elf32-vax.lo \
+ elf32-visium.lo \
+ elf32-wasm32.lo \
+ elf32-xgate.lo \
+ elf32-xstormy16.lo \
+ elf32-xtensa.lo \
+ elf32-z80.lo \
+ elf32.lo \
+ elflink.lo \
+ elfxx-sparc.lo \
+ elfxx-tilegx.lo \
+ i386aout.lo \
+ i386bsd.lo \
+ i386lynx.lo \
+ i386msdos.lo \
+ mach-o.lo \
+ mach-o-i386.lo \
+ mach-o-arm.lo \
+ ns32knetbsd.lo \
+ pc532-mach.lo \
+ pdb.lo \
+ pdp11.lo \
+ pe-arm-wince.lo \
+ pe-arm.lo \
+ pe-i386.lo \
+ pe-mcore.lo \
+ pe-sh.lo \
+ pef.lo \
+ pei-arm-wince.lo \
+ pei-arm.lo \
+ pei-i386.lo \
+ pei-mcore.lo \
+ pei-sh.lo \
+ peigen.lo \
+ plugin.lo \
+ ppcboot.lo \
+ reloc16.lo \
+ som.lo \
+ vax1knetbsd.lo \
+ vaxnetbsd.lo \
+ vms-lib.lo \
+ vms-misc.lo \
+ wasm-module.lo \
+ xcofflink.lo \
+ xsym.lo \
+ xtensa-dynconfig.lo \
+ xtensa-isa.lo \
+ xtensa-modules.lo
+
+BFD32_BACKENDS_CFILES = \
+ aout-cris.c \
+ aout-ns32k.c \
+ aout32.c \
+ cf-i386lynx.c \
+ coff-go32.c \
+ coff-i386.c \
+ coff-mips.c \
+ coff-rs6000.c \
+ coff-sh.c \
+ coff-stgo32.c \
+ coff-tic30.c \
+ coff-tic4x.c \
+ coff-tic54x.c \
+ coff-z80.c \
+ coff-z8k.c \
+ coffgen.c \
+ cofflink.c \
+ dwarf1.c \
+ dwarf2.c \
+ ecoff.c \
+ ecofflink.c \
+ elf-attrs.c \
+ elf-eh-frame.c \
+ elf-sframe.c \
+ elf-ifunc.c \
+ elf-m10200.c \
+ elf-m10300.c \
+ elf-nacl.c \
+ elf-strtab.c \
+ elf-vxworks.c \
+ elf.c \
+ elf32-am33lin.c \
+ elf32-arc.c \
+ elf32-arm.c \
+ elf32-avr.c \
+ elf32-bfin.c \
+ elf32-cr16.c \
+ elf32-cris.c \
+ elf32-crx.c \
+ elf32-csky.c \
+ elf32-d10v.c \
+ elf32-d30v.c \
+ elf32-dlx.c \
+ elf32-epiphany.c \
+ elf32-fr30.c \
+ elf32-frv.c \
+ elf32-ft32.c \
+ elf32-gen.c \
+ elf32-h8300.c \
+ elf32-hppa.c \
+ elf32-i386.c \
+ elfxx-x86.c \
+ elf32-ip2k.c \
+ elf32-iq2000.c \
+ elf32-lm32.c \
+ elf32-m32c.c \
+ elf32-m32r.c \
+ elf32-m68hc11.c \
+ elf32-m68hc12.c \
+ elf32-m68hc1x.c \
+ elf32-m68k.c \
+ elf32-s12z.c \
+ elf32-mcore.c \
+ elf32-mep.c \
+ elf32-metag.c \
+ elf32-microblaze.c \
+ elf32-moxie.c \
+ elf32-msp430.c \
+ elf32-mt.c \
+ elf32-nds32.c \
+ elf32-nios2.c \
+ elf32-or1k.c \
+ elf32-pj.c \
+ elf32-ppc.c \
+ elf32-pru.c \
+ elf32-rl78.c \
+ elf32-rx.c \
+ elf32-s390.c \
+ elf32-sh.c \
+ elf32-sparc.c \
+ elf32-spu.c \
+ elf32-tic6x.c \
+ elf32-tilegx.c \
+ elf32-tilepro.c \
+ elf32-v850.c \
+ elf32-vax.c \
+ elf32-visium.c \
+ elf32-wasm32.c \
+ elf32-xgate.c \
+ elf32-xstormy16.c \
+ elf32-xtensa.c \
+ elf32-z80.c \
+ elf32.c \
+ elflink.c \
+ elfxx-sparc.c \
+ elfxx-tilegx.c \
+ i386aout.c \
+ i386bsd.c \
+ i386lynx.c \
+ i386msdos.c \
+ mach-o.c \
+ mach-o-i386.c \
+ mach-o-arm.c \
+ ns32knetbsd.c \
+ pc532-mach.c \
+ pdb.c \
+ pdp11.c \
+ pe-arm-wince.c \
+ pe-arm.c \
+ pe-i386.c \
+ pe-mcore.c \
+ pe-sh.c \
+ pef.c \
+ pei-arm-wince.c \
+ pei-arm.c \
+ pei-i386.c \
+ pei-mcore.c \
+ pei-sh.c \
+ plugin.c \
+ ppcboot.c \
+ reloc16.c \
+ som.c \
+ vax1knetbsd.c \
+ vaxnetbsd.c \
+ vms-lib.c \
+ vms-misc.c \
+ wasm-module.c \
+ xcofflink.c \
+ xsym.c \
+ xtensa-dynconfig.c \
+ xtensa-isa.c \
+ xtensa-modules.c
+
+
+# The .o files needed by all of the 64 bit vectors that are configured into
+# target_vector in targets.c if configured with --enable-targets=all
+# and --enable-64-bit-bfd.
+# elf32-ia64.c requires a 64-bit bfd_vma, and hence can not be put in
+# BFD32_BACKENDS.
+BFD64_BACKENDS = \
+ elf32-aarch64.lo \
+ elf64-aarch64.lo \
+ elfxx-aarch64.lo \
+ aix5ppc-core.lo \
+ aout64.lo \
+ coff-alpha.lo \
+ coff-x86_64.lo \
+ coff64-rs6000.lo \
+ elf32-ia64.lo \
+ elf32-mips.lo \
+ elf32-score.lo \
+ elf32-score7.lo \
+ elf64-alpha.lo \
+ elf64-amdgcn.lo \
+ elf64-gen.lo \
+ elf64-hppa.lo \
+ elf64-ia64.lo \
+ elf64-ia64-vms.lo \
+ elfxx-ia64.lo \
+ elf32-loongarch.lo \
+ elf64-loongarch.lo \
+ elfxx-loongarch.lo \
+ elfn32-mips.lo \
+ elf64-mips.lo \
+ elfxx-mips.lo \
+ elf64-mmix.lo \
+ elf64-nfp.lo \
+ elf64-ppc.lo \
+ elf32-riscv.lo \
+ elf64-riscv.lo \
+ elfxx-riscv.lo \
+ elf64-s390.lo \
+ elf64-sparc.lo \
+ elf64-tilegx.lo \
+ elf64-x86-64.lo \
+ elfxx-x86.lo \
+ elf64-bpf.lo \
+ elf64.lo \
+ mach-o-aarch64.lo \
+ mach-o-x86-64.lo \
+ mmo.lo \
+ pe-aarch64igen.lo \
+ pe-loongarch64igen.lo \
+ pe-x86_64.lo \
+ pei-aarch64.lo \
+ pe-aarch64.lo \
+ pei-ia64.lo \
+ pei-loongarch64.lo \
+ pei-x86_64.lo \
+ pepigen.lo \
+ pex64igen.lo \
+ vms-alpha.lo
+
+BFD64_BACKENDS_CFILES = \
+ aix5ppc-core.c \
+ aout64.c \
+ coff-alpha.c \
+ coff-x86_64.c \
+ coff64-rs6000.c \
+ elf32-mips.c \
+ elf32-score.c \
+ elf32-score7.c \
+ elf64-alpha.c \
+ elf64-amdgcn.c \
+ elf64-gen.c \
+ elf64-hppa.c \
+ elf64-ia64-vms.c \
+ elf64-mips.c \
+ elf64-mmix.c \
+ elf64-nfp.c \
+ elf64-ppc.c \
+ elf64-s390.c \
+ elf64-sparc.c \
+ elf64-tilegx.c \
+ elf64-x86-64.c \
+ elfxx-x86.c \
+ elf64-bpf.c \
+ elf64.c \
+ elfn32-mips.c \
+ elfxx-aarch64.c \
+ elfxx-ia64.c \
+ elfxx-loongarch.c \
+ elfxx-mips.c \
+ elfxx-riscv.c \
+ mach-o-aarch64.c \
+ mach-o-x86-64.c \
+ mmo.c \
+ pe-aarch64.c \
+ pe-x86_64.c \
+ pei-aarch64.c \
+ pei-ia64.c \
+ pei-loongarch64.c \
+ pei-x86_64.c \
+ vms-alpha.c
+
+OPTIONAL_BACKENDS = \
+ aix386-core.lo \
+ cisco-core.lo \
+ hpux-core.lo \
+ irix-core.lo \
+ lynx-core.lo \
+ netbsd-core.lo \
+ osf-core.lo \
+ rs6000-core.lo \
+ sco5-core.lo \
+ trad-core.lo
+
+OPTIONAL_BACKENDS_CFILES = \
+ aix386-core.c \
+ cisco-core.c \
+ hpux-core.c \
+ irix-core.c \
+ lynx-core.c \
+ netbsd-core.c \
+ osf-core.c \
+ rs6000-core.c \
+ sco5-core.c \
+ trad-core.c
+
+
+# Reconfigure if config.bfd or configure.host changes.
+# development.sh is used to determine -Werror default.
+CONFIG_STATUS_DEPENDENCIES = \
+ $(srcdir)/config.bfd \
+ $(srcdir)/configure.host \
+ $(srcdir)/development.sh
+
+
+# These are defined by configure:
+WORDSIZE = @wordsize@
+ALL_BACKENDS = @all_backends@
+BFD_BACKENDS = @bfd_backends@
+BFD_MACHINES = @bfd_machines@
+TDEFAULTS = @tdefaults@
+HAVEVECS = @havevecs@
+
+# C source files that correspond to .o's.
+SOURCE_CFILES = \
+ $(BFD32_LIBS_CFILES) \
+ $(BFD64_LIBS_CFILES) \
+ $(ALL_MACHINES_CFILES) \
+ $(BFD32_BACKENDS_CFILES) \
+ $(BFD64_BACKENDS_CFILES) \
+ $(OPTIONAL_BACKENDS_CFILES)
+
+BUILD_CFILES = \
+ elf32-aarch64.c elf64-aarch64.c \
+ elf32-ia64.c elf64-ia64.c \
+ elf32-loongarch.c elf64-loongarch.c \
+ elf32-riscv.c elf64-riscv.c \
+ peigen.c pepigen.c pex64igen.c pe-aarch64igen.c pe-loongarch64igen.c
+
+CFILES = $(SOURCE_CFILES) $(BUILD_CFILES)
+SOURCE_HFILES = \
+ aout-target.h aoutx.h arc-got.h arc-plt.h \
+ coff-arm.h coff-bfd.h coffcode.h coffswap.h \
+ cpu-aarch64.h cpu-arm.h cpu-h8300.h cpu-m68k.h cpu-riscv.h \
+ ecoff-bfd.h ecoffswap.h \
+ elf32-arm.h elf32-avr.h elf32-bfin.h elf32-cr16.h elf32-csky.h \
+ elf32-dlx.h elf32-hppa.h elf32-m68hc1x.h elf32-m68k.h \
+ elf32-metag.h elf32-nds32.h elf32-nios2.h elf32-ppc.h \
+ elf32-rx.h elf32-score.h elf32-sh-relocs.h elf32-spu.h \
+ elf32-tic6x.h elf32-tilegx.h elf32-tilepro.h elf32-v850.h \
+ elf64-hppa.h elf64-ppc.h elf64-tilegx.h \
+ elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \
+ elf-linux-core.h elf-nacl.h elf-s390.h elf-vxworks.h \
+ elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \
+ elfxx-sparc.h elfxx-tilegx.h elfxx-x86.h elfxx-loongarch.h \
+ genlink.h go32stub.h \
+ libaout.h libbfd.h libcoff.h libecoff.h libhppa.h \
+ libpei.h libxcoff.h \
+ mach-o.h \
+ netbsd.h ns32k.h \
+ pef.h pef-traceback.h peicode.h plugin.h \
+ som.h sysdep.h \
+ version.h vms.h \
+ wasm-module.h \
+ xcofflink.h xsym.h
+
+BUILD_HFILES = \
+ bfdver.h elf32-target.h elf64-target.h targmatch.h
+
+
+# Ensure they are built early:
+BUILT_SOURCES = $(BUILD_HFILES) $(BUILD_CFILES)
+HFILES = $(SOURCE_HFILES) $(BUILD_HFILES)
+BFD_H_DEPS = $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h $(INCDIR)/diagnostics.h
+LOCAL_H_DEPS = libbfd.h sysdep.h config.h
+SRC_POTFILES = $(SOURCE_CFILES) $(SOURCE_HFILES)
+BLD_POTFILES = $(BUILD_CFILES) $(BUILD_HFILES)
+
+# Various kinds of .o files to put in libbfd.a:
+# BFD_BACKENDS Routines the configured targets need.
+# BFD_MACHINES Architecture-specific routines the configured targets need.
+# COREFILE Core file routines for a native configuration
+# bfd64_libs Routines for 64bit support
+OFILES = $(BFD_BACKENDS) $(BFD_MACHINES) @COREFILE@ @bfd64_libs@
+
+# Since BFD64_LIBS is optional and we can't have substitution in
+# libbfd_la_SOURCES, we put BFD64_LIBS in OFILES instead.
+# However, list all sources in EXTRA_libbfd_la_SOURCES so the
+# dependency tracking fragments are picked up in the Makefile.
+libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
+EXTRA_libbfd_la_SOURCES = $(CFILES)
+libbfd_la_DEPENDENCIES = $(OFILES) ofiles ../libsframe/libsframe.la
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS) ../libsframe/libsframe.la
+
+# libtool will build .libs/libbfd.a. We create libbfd.a in the build
+# directory so that we don't have to convert all the programs that use
+# libbfd.a simultaneously. This is a hack which should be removed if
+# everything else starts using libtool. FIXME.
+noinst_LIBRARIES = libbfd.a
+libbfd_a_SOURCES =
+BFD_H_FILES = bfd-in.h init.c opncls.c libbfd.c \
+ bfdio.c bfdwin.c section.c archures.c reloc.c \
+ syms.c bfd.c archive.c corefile.c targets.c format.c \
+ linker.c simple.c compress.c
+
+BFD64_H_FILES = archive64.c
+LIBBFD_H_FILES = libbfd-in.h libbfd.c bfd.c bfdio.c bfdwin.c \
+ cache.c reloc.c section.c targets.c archures.c linker.c
+
+LIBCOFF_H_FILES = libcoff-in.h coffcode.h
+
+# We only rebuild the header files automatically if we have been
+# configured with --enable-maintainer-mode.
+REGEN_HEADER = \
+ ( \
+ set -e; \
+ echo "$$H_FILES" | sed -f $(srcdir)/doc/header.sed; \
+ for file in $$H_FILES; do \
+ file="$(srcdir)/$$file"; \
+ case $$file in \
+ *-in.h) cat $$file;; \
+ *) echo $$file | sed -e 's,.*/,,' -e 's,^,/* Extracted from ,' \
+ -e 's,$$,. */,'; \
+ $(MKDOC) $$CHEW_FLAGS -f $(srcdir)/doc/proto.str < $$file;; \
+ esac; \
+ done; \
+ echo "\#ifdef __cplusplus"; \
+ echo "}"; \
+ echo "\#endif"; \
+ echo "\#endif"; \
+ )
+
+DOCFILES = \
+ doc/aoutx.texi \
+ doc/archive.texi \
+ doc/archures.texi \
+ doc/bfdio.texi \
+ doc/bfdt.texi \
+ doc/bfdver.texi \
+ doc/bfdwin.texi \
+ doc/cache.texi \
+ doc/coffcode.texi \
+ doc/corefile.texi \
+ doc/elfcode.texi \
+ doc/elf.texi \
+ doc/format.texi \
+ doc/hash.texi \
+ doc/init.texi \
+ doc/libbfd.texi \
+ doc/linker.texi \
+ doc/mmo.texi \
+ doc/opncls.texi \
+ doc/reloc.texi \
+ doc/section.texi \
+ doc/syms.texi \
+ doc/targets.texi
+
+
+# SRCDOC, SRCPROT, SRCIPROT only used to sidestep Sun Make bug in interaction
+# between VPATH and suffix rules. If you use GNU Make, perhaps other Makes,
+# you don't need these three:
+SRCDOC = \
+ $(srcdir)/aoutx.h $(srcdir)/archive.c \
+ $(srcdir)/archures.c $(srcdir)/bfd.c \
+ $(srcdir)/bfdio.c $(srcdir)/bfdwin.c \
+ $(srcdir)/cache.c $(srcdir)/coffcode.h \
+ $(srcdir)/corefile.c $(srcdir)/elf.c \
+ $(srcdir)/elfcode.h $(srcdir)/format.c \
+ $(srcdir)/libbfd.c $(srcdir)/opncls.c \
+ $(srcdir)/reloc.c $(srcdir)/section.c \
+ $(srcdir)/syms.c $(srcdir)/targets.c \
+ $(srcdir)/hash.c $(srcdir)/linker.c \
+ $(srcdir)/mmo.c
+
+SRCPROT = $(srcdir)/archive.c $(srcdir)/archures.c \
+ $(srcdir)/bfd.c $(srcdir)/coffcode.h $(srcdir)/corefile.c \
+ $(srcdir)/format.c $(srcdir)/libbfd.c \
+ $(srcdir)/bfdio.c $(srcdir)/bfdwin.c \
+ $(srcdir)/opncls.c $(srcdir)/reloc.c \
+ $(srcdir)/section.c $(srcdir)/syms.c \
+ $(srcdir)/targets.c $(srcdir)/init.c
+
+SRCIPROT = $(srcdir)/cache.c $(srcdir)/libbfd.c \
+ $(srcdir)/bfdio.c $(srcdir)/bfdwin.c \
+ $(srcdir)/reloc.c $(srcdir)/cpu-h8300.c \
+ $(srcdir)/cpu-i960.c $(srcdir)/archures.c \
+ $(srcdir)/init.c
+
+TEXIDIR = $(srcdir)/../texinfo/fsf
+info_TEXINFOS = doc/bfd.texi
+doc_bfd_TEXINFOS = $(DOCFILES) doc/bfdsumm.texi
+AM_MAKEINFOFLAGS = --no-split -I "$(srcdir)/doc" -I doc
+TEXI2DVI = texi2dvi -I "$(srcdir)/doc" -I doc
+MKDOC = doc/chew$(EXEEXT_FOR_BUILD)
+
+# We can't replace these rules with an implicit rule, because
+# makes without VPATH support couldn't find the .h files in `..'.
+
+# We do not depend on chew directly so that we can distribute the info
+# files, and permit people to rebuild them, without requiring the makeinfo
+# program. If somebody tries to rebuild info, but none of the .texi files
+# have changed, then nothing will be rebuilt.
+REGEN_TEXI = \
+ ( \
+ set -e; \
+ $(MKDOC) -f $(srcdir)/doc/doc.str < $< > $@.tmp; \
+ texi=$@; \
+ texi=$${texi%.stamp}.texi; \
+ test -e $$texi || test ! -f $(srcdir)/$$texi || $(LN_S) $(srcdir)/$$texi .; \
+ $(SHELL) $(srcdir)/../move-if-change $@.tmp $$texi; \
+ touch $@; \
+ )
+
+noinst_TEXINFOS = doc/bfdint.texi
+all: $(BUILT_SOURCES) config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .dvi .lo .o .obj .ps
+am--refresh: Makefile
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/doc/local.mk $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+$(srcdir)/doc/local.mk $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+bfd-in3.h: $(top_builddir)/config.status $(srcdir)/bfd-in2.h
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+po/Makefile.in: $(top_builddir)/config.status $(top_srcdir)/po/Make-in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+install-bfdlibLTLIBRARIES: $(bfdlib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(bfdlib_LTLIBRARIES)'; test -n "$(bfdlibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bfdlibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bfdlibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(bfdlibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(bfdlibdir)"; \
+ }
+
+uninstall-bfdlibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bfdlib_LTLIBRARIES)'; test -n "$(bfdlibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(bfdlibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(bfdlibdir)/$$f"; \
+ done
+
+clean-bfdlibLTLIBRARIES:
+ -test -z "$(bfdlib_LTLIBRARIES)" || rm -f $(bfdlib_LTLIBRARIES)
+ @list='$(bfdlib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libbfd.la: $(libbfd_la_OBJECTS) $(libbfd_la_DEPENDENCIES) $(EXTRA_libbfd_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libbfd_la_LINK) $(am_libbfd_la_rpath) $(libbfd_la_OBJECTS) $(libbfd_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix386-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix5ppc-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-cris.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout-ns32k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aout64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archures.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bfd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bfdio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bfdwin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cf-i386lynx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cisco-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-alpha.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-bfd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-go32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-i386.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-mips.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-rs6000.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-sh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-stgo32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-tic30.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-tic4x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-tic54x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-x86_64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-z80.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff-z8k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coff64-rs6000.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coffgen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cofflink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compress.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/corefile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-aarch64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-alpha.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-amdgcn.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-arc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-arm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-avr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-bfin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-bpf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-cr16.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-cris.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-crx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-csky.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-d10v.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-d30v.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-dlx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-epiphany.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-fr30.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-frv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-ft32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-h8300.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-hppa.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-i386.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-ia64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-iamcu.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-ip2k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-iq2000.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-lm32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-loongarch.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m10200.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m10300.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m32c.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m32r.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m68hc11.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m68hc12.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m68k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m9s12x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m9s12xg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-mcore.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-mep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-metag.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-microblaze.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-mips.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-mmix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-moxie.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-msp430.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-mt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-nds32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-nfp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-nios2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-ns32k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-or1k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-pdp11.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-pj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-powerpc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-pru.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-riscv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-rl78.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-rs6000.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-rx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-s12z.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-s390.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-score.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-sh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-sparc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-spu.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-tic30.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-tic4x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-tic54x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-tic6x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-tilegx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-tilepro.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-v850.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-v850_rh850.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-vax.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-visium.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-wasm32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-xgate.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-xstormy16.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-xtensa.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-z80.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-z8k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf1.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecoff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecofflink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-attrs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-eh-frame.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-ifunc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-m10200.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-m10300.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-nacl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-properties.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-sframe.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-strtab.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-vxworks.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-aarch64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-am33lin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-arc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-arm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-avr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-bfin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-cr16.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-cris.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-crx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-csky.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-d10v.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-d30v.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-dlx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-epiphany.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-fr30.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-frv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-ft32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-gen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-h8300.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-hppa.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-i386.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-ia64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-ip2k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-iq2000.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-lm32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-loongarch.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m32c.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m32r.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68hc11.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68hc12.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68hc1x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m68k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mcore.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-metag.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-microblaze.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mips.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-moxie.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-msp430.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-mt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-nds32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-nios2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-or1k.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-pj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-ppc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-pru.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-riscv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-rl78.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-rx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-s12z.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-s390.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-score.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-score7.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-sh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-sparc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-spu.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-tic6x.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-tilegx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-tilepro.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-v850.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-vax.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-visium.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-wasm32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-xgate.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-xstormy16.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-xtensa.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-z80.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-aarch64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-alpha.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-amdgcn.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-bpf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-gen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-hppa.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-ia64-vms.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-ia64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-loongarch.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-mips.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-mmix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-nfp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-ppc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-riscv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-s390.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-sparc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-tilegx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-x86-64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elflink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfn32-mips.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-aarch64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-ia64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-loongarch.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-mips.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-riscv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-sparc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-tilegx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-x86.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hpux-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386aout.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386bsd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386lynx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386msdos.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ihex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/init.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irix-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libbfd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linker.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lynx-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mach-o-aarch64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mach-o-arm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mach-o-i386.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mach-o-x86-64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mach-o.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merge.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netbsd-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ns32knetbsd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opncls.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/osf-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pc532-mach.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pdb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pdp11.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pe-aarch64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pe-aarch64igen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pe-arm-wince.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pe-arm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pe-i386.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pe-loongarch64igen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pe-mcore.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pe-sh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pe-x86_64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pef.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pei-aarch64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pei-arm-wince.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pei-arm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pei-i386.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pei-ia64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pei-loongarch64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pei-mcore.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pei-sh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pei-x86_64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peigen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pepigen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pex64igen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppcboot.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reloc16.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rs6000-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sco5-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/section.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/som.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stab-syms.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stabs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syms.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/targets.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tekhex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trad-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vax1knetbsd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vaxnetbsd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verilog.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vms-alpha.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vms-lib.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vms-misc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wasm-module.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xcofflink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xsym.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xtensa-dynconfig.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xtensa-isa.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xtensa-modules.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool config.lt
+doc/$(am__dirstamp):
+ @$(MKDIR_P) doc
+ @: > doc/$(am__dirstamp)
+
+doc/bfd.info: doc/bfd.texi $(doc_bfd_TEXINFOS)
+ @test -f doc/$(am__dirstamp) || $(MAKE) $(AM_MAKEFLAGS) doc/$(am__dirstamp)
+ $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \
+ rm -rf $$backupdir && mkdir $$backupdir && \
+ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \
+ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \
+ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \
+ done; \
+ else :; fi && \
+ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc \
+ -o $@ `test -f 'doc/bfd.texi' || echo '$(srcdir)/'`doc/bfd.texi; \
+ then \
+ rc=0; \
+ else \
+ rc=$$?; \
+ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \
+ fi; \
+ rm -rf $$backupdir; exit $$rc
+
+doc/bfd.dvi: doc/bfd.texi $(doc_bfd_TEXINFOS) doc/$(am__dirstamp)
+ $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc' \
+ $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \
+ `test -f 'doc/bfd.texi' || echo '$(srcdir)/'`doc/bfd.texi
+
+doc/bfd.pdf: doc/bfd.texi $(doc_bfd_TEXINFOS) doc/$(am__dirstamp)
+ $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc' \
+ $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \
+ `test -f 'doc/bfd.texi' || echo '$(srcdir)/'`doc/bfd.texi
+
+doc/bfd.html: doc/bfd.texi $(doc_bfd_TEXINFOS) doc/$(am__dirstamp)
+ $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp)
+ $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc \
+ -o $(@:.html=.htp) `test -f 'doc/bfd.texi' || echo '$(srcdir)/'`doc/bfd.texi; \
+ then \
+ rm -rf $@ && mv $(@:.html=.htp) $@; \
+ else \
+ rm -rf $(@:.html=.htp); exit 1; \
+ fi
+.dvi.ps:
+ $(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+ $(DVIPS) $(AM_V_texinfo) -o $@ $<
+
+uninstall-dvi-am:
+ @$(NORMAL_UNINSTALL)
+ @list='$(DVIS)'; test -n "$(dvidir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \
+ rm -f "$(DESTDIR)$(dvidir)/$$f"; \
+ done
+
+uninstall-html-am:
+ @$(NORMAL_UNINSTALL)
+ @list='$(HTMLS)'; test -n "$(htmldir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \
+ rm -rf "$(DESTDIR)$(htmldir)/$$f"; \
+ done
+
+uninstall-info-am:
+ @$(PRE_UNINSTALL)
+ @if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \
+ list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ relfile=`echo "$$file" | sed 's|^.*/||'`; \
+ echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \
+ if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \
+ then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \
+ done; \
+ else :; fi
+ @$(NORMAL_UNINSTALL)
+ @list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ relfile=`echo "$$file" | sed 's|^.*/||'`; \
+ relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \
+ (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \
+ echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \
+ rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \
+ else :; fi); \
+ done
+
+uninstall-pdf-am:
+ @$(NORMAL_UNINSTALL)
+ @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(pdfdir)/$$f"; \
+ done
+
+uninstall-ps-am:
+ @$(NORMAL_UNINSTALL)
+ @list='$(PSS)'; test -n "$(psdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(psdir)/$$f"; \
+ done
+
+dist-info: $(INFO_DEPS)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ list='$(INFO_DEPS)'; \
+ for base in $$list; do \
+ case $$base in \
+ $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \
+ esac; \
+ if test -f $$base; then d=.; else d=$(srcdir); fi; \
+ base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \
+ for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \
+ if test -f $$file; then \
+ relfile=`expr "$$file" : "$$d/\(.*\)"`; \
+ test -f "$(distdir)/$$relfile" || \
+ cp -p $$file "$(distdir)/$$relfile"; \
+ else :; fi; \
+ done; \
+ done
+
+mostlyclean-aminfo:
+ -rm -rf doc/bfd.t2d doc/bfd.t2p
+
+clean-aminfo:
+ -test -z "doc/bfd.dvi doc/bfd.pdf doc/bfd.ps doc/bfd.html" \
+ || rm -rf doc/bfd.dvi doc/bfd.pdf doc/bfd.ps doc/bfd.html
+
+maintainer-clean-aminfo:
+ @list='$(INFO_DEPS)'; for i in $$list; do \
+ i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \
+ echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \
+ rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \
+ done
+install-bfdincludeHEADERS: $(bfdinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(bfdinclude_HEADERS)'; test -n "$(bfdincludedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bfdincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bfdincludedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(bfdincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(bfdincludedir)" || exit $$?; \
+ done
+
+uninstall-bfdincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bfdinclude_HEADERS)'; test -n "$(bfdincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(bfdincludedir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+ test ! -s cscope.files \
+ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+ -rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+ -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-recursive
+all-am: Makefile $(INFO_DEPS) $(LIBRARIES) $(LTLIBRARIES) $(HEADERS) \
+ config.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(bfdlibdir)" "$(DESTDIR)$(infodir)" "$(DESTDIR)$(bfdincludedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f doc/$(am__dirstamp)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-recursive
+
+clean-am: clean-aminfo clean-bfdlibLTLIBRARIES clean-generic \
+ clean-libtool clean-noinstLIBRARIES clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am: $(DVIS)
+
+html: html-recursive
+
+html-am: $(HTMLS) html-local
+
+info: info-recursive
+
+info-am: $(INFO_DEPS)
+
+install-data-am: install-bfdincludeHEADERS install-bfdlibLTLIBRARIES \
+ install-info-am
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am: $(DVIS)
+ @$(NORMAL_INSTALL)
+ @list='$(DVIS)'; test -n "$(dvidir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dvidir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \
+ done
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am: $(HTMLS)
+ @$(NORMAL_INSTALL)
+ @list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ $(am__strip_dir) \
+ d2=$$d$$p; \
+ if test -d "$$d2"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
+ echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \
+ else \
+ list2="$$list2 $$d2"; \
+ fi; \
+ done; \
+ test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \
+ done; }
+install-info: install-info-recursive
+
+install-info-am: $(INFO_DEPS)
+ @$(NORMAL_INSTALL)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \
+ fi; \
+ for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ esac; \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \
+ for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \
+ $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \
+ if test -f $$ifile; then \
+ echo "$$ifile"; \
+ else : ; fi; \
+ done; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done
+ @$(POST_INSTALL)
+ @if $(am__can_run_installinfo); then \
+ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
+ for file in $$list; do \
+ relfile=`echo "$$file" | sed 's|^.*/||'`; \
+ echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\
+ install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\
+ done; \
+ else : ; fi
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am: $(PDFS)
+ @$(NORMAL_INSTALL)
+ @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done
+install-ps: install-ps-recursive
+
+install-ps-am: $(PSS)
+ @$(NORMAL_INSTALL)
+ @list='$(PSS)'; test -n "$(psdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(psdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-aminfo \
+ maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-aminfo mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am: $(PDFS)
+
+ps: ps-recursive
+
+ps-am: $(PSS)
+
+uninstall-am: uninstall-bfdincludeHEADERS uninstall-bfdlibLTLIBRARIES \
+ uninstall-dvi-am uninstall-html-am uninstall-info-am \
+ uninstall-pdf-am uninstall-ps-am
+
+.MAKE: $(am__recursive_targets) all check install install-am \
+ install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--refresh check check-am clean clean-aminfo \
+ clean-bfdlibLTLIBRARIES clean-cscope clean-generic \
+ clean-libtool clean-noinstLIBRARIES clean-noinstLTLIBRARIES \
+ cscope cscopelist-am ctags ctags-am dist-info distclean \
+ distclean-compile distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags dvi dvi-am html html-am \
+ html-local info info-am install install-am \
+ install-bfdincludeHEADERS install-bfdlibLTLIBRARIES \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs installdirs-am \
+ maintainer-clean maintainer-clean-aminfo \
+ maintainer-clean-generic mostlyclean mostlyclean-aminfo \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-bfdincludeHEADERS uninstall-bfdlibLTLIBRARIES \
+ uninstall-dvi-am uninstall-html-am uninstall-info-am \
+ uninstall-pdf-am uninstall-ps-am
+
+.PRECIOUS: Makefile
+
+$(BFD32_LIBS) \
+ $(BFD64_LIBS) \
+ $(ALL_MACHINES) \
+ $(BFD32_BACKENDS) \
+ $(BFD64_BACKENDS) \
+ $(OPTIONAL_BACKENDS): $(BFD_H) $(BFD_H_DEPS) $(LOCAL_H_DEPS)
+
+po/SRC-POTFILES.in: @MAINT@ Makefile
+ for file in $(SRC_POTFILES); do echo $$file; done \
+ | LC_ALL=C sort > tmp.src \
+ && mv tmp.src $(srcdir)/po/SRC-POTFILES.in
+
+po/BLD-POTFILES.in: @MAINT@ Makefile
+ for file in $(BLD_POTFILES); do echo $$file; done \
+ | LC_ALL=C sort > tmp.bld \
+ && mv tmp.bld $(srcdir)/po/BLD-POTFILES.in
+
+all diststuff: info
+
+stamp-ofiles: Makefile
+ rm -f tofiles
+ f=""; \
+ for i in $(OFILES) ; do \
+ case " $$f " in \
+ *" $$i "*) ;; \
+ *) f="$$f $$i" ;; \
+ esac ; \
+ done ; \
+ echo $$f > tofiles
+ $(SHELL) $(srcdir)/../move-if-change tofiles ofiles
+ touch stamp-ofiles
+
+ofiles: stamp-ofiles ; @true
+
+stamp-lib: libbfd.la
+ libtooldir=`$(LIBTOOL) --config | $(SED) -n -e 's/^objdir=//p'`; \
+ if [ -f $$libtooldir/libbfd.a ]; then \
+ cp $$libtooldir/libbfd.a libbfd.tmp; \
+ $(RANLIB) libbfd.tmp; \
+ $(SHELL) $(srcdir)/../move-if-change libbfd.tmp libbfd.a; \
+ else true; fi
+ touch stamp-lib
+
+libbfd.a: stamp-lib ; @true
+
+# This file holds an array associating configuration triplets and
+# vector names. It is built from config.bfd. It is not compiled by
+# itself, but is included by targets.c.
+targmatch.h: config.bfd targmatch.sed
+ $(AM_V_at)rm -f targmatch.new
+ $(AM_V_GEN)$(SED) -f $(srcdir)/targmatch.sed < $(srcdir)/config.bfd > targmatch.new
+ $(AM_V_at)mv -f targmatch.new targmatch.h
+
+# When compiling archures.c and targets.c, supply the default target
+# info from configure.
+
+targets.lo: targets.c Makefile
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $(TDEFAULTS) $(srcdir)/targets.c
+@am__fastdepCC_TRUE@ $(AM_V_at)mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='targets.c' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC)$(LTCOMPILE) -c -o $@ $(TDEFAULTS) $(srcdir)/targets.c
+
+archures.lo: archures.c Makefile
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $(TDEFAULTS) $(srcdir)/archures.c
+@am__fastdepCC_TRUE@ $(AM_V_at)mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='archures.c' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC)$(LTCOMPILE) -c -o $@ $(TDEFAULTS) $(srcdir)/archures.c
+
+dwarf2.lo: dwarf2.c Makefile
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ -DDEBUGDIR=\"$(DEBUGDIR)\" $(srcdir)/dwarf2.c
+@am__fastdepCC_TRUE@ $(AM_V_at)mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dwarf2.c' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC)$(LTCOMPILE) -c -o $@ -DDEBUGDIR=\"$(DEBUGDIR)\" $(srcdir)/dwarf2.c
+
+elf32-target.h : elfxx-target.h
+ $(AM_V_GEN)$(SED) -e s/NN/32/g < $< > $@
+
+elf64-target.h : elfxx-target.h
+ $(AM_V_GEN)$(SED) -e s/NN/64/g < $< > $@
+
+elf32-aarch64.c : elfnn-aarch64.c
+ $(AM_V_at)echo "#line 1 \"elfnn-aarch64.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/32/g < $< >> $@
+
+elf64-aarch64.c : elfnn-aarch64.c
+ $(AM_V_at)echo "#line 1 \"elfnn-aarch64.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/64/g < $< >> $@
+
+elf32-ia64.c : elfnn-ia64.c
+ $(AM_V_at)echo "#line 1 \"elfnn-ia64.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/32/g < $< >> $@
+
+elf64-ia64.c : elfnn-ia64.c
+ $(AM_V_at)echo "#line 1 \"elfnn-ia64.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/64/g < $< >> $@
+
+elf32-loongarch.c : elfnn-loongarch.c
+ $(AM_V_at)echo "#line 1 \"elfnn-loongarch.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/32/g < $< >> $@
+
+elf64-loongarch.c : elfnn-loongarch.c
+ $(AM_V_at)echo "#line 1 \"elfnn-loongarch.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/64/g < $< >> $@
+
+elf32-riscv.c : elfnn-riscv.c
+ $(AM_V_at)echo "#line 1 \"elfnn-riscv.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/32/g < $< >> $@
+
+elf64-riscv.c : elfnn-riscv.c
+ $(AM_V_at)echo "#line 1 \"elfnn-riscv.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/NN/64/g < $< >> $@
+
+peigen.c : peXXigen.c
+ $(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/XX/pe/g < $< >> $@
+
+pepigen.c : peXXigen.c
+ $(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/XX/pep/g < $< >> $@
+
+pex64igen.c: peXXigen.c
+ $(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/XX/pex64/g < $< >> $@
+
+pe-aarch64igen.c: peXXigen.c
+ $(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/XX/peAArch64/g < $< >> $@
+
+pe-loongarch64igen.c: peXXigen.c
+ $(AM_V_at)echo "#line 1 \"peXXigen.c\"" > $@
+ $(AM_V_GEN)$(SED) -e s/XX/peLoongArch64/g < $< >> $@
+
+host-aout.lo: Makefile
+
+# The following program can be used to generate a simple config file
+# which can be folded into an h-XXX file for a new host, with some editing.
+aout-params.h: gen-aout
+ ./gen-aout host > aout-params.h
+gen-aout: $(srcdir)/gen-aout.c Makefile
+ $(CC) -o gen-aout $(CFLAGS) $(LFLAGS) $(srcdir)/gen-aout.c
+
+$(BFD_H): stmp-bfd-h ; @true
+
+stmp-bfd-h: bfd-in3.h
+ rm -f bfd-tmp.h
+ cp bfd-in3.h bfd-tmp.h
+ $(SHELL) $(srcdir)/../move-if-change bfd-tmp.h $(BFD_H)
+ rm -f bfd-tmp.h
+ touch stmp-bfd-h
+
+headers: stmp-bin2-h stmp-lbfd-h stmp-lcoff-h
+
+$(srcdir)/bfd-in2.h: @MAINT@ stmp-bin2-h ; @true
+stmp-bin2-h: $(BFD_H_FILES) $(BFD64_H_FILES) $(MKDOC)
+ $(AM_V_GEN)H_FILES="$(BFD_H_FILES)" CHEW_FLAGS= ; $(REGEN_HEADER) > bfd-in2.h-new
+ $(AM_V_at)$(SHELL) $(srcdir)/../move-if-change bfd-in2.h-new $(srcdir)/bfd-in2.h
+ $(AM_V_at)touch stmp-bin2-h
+
+$(srcdir)/libbfd.h: @MAINT@ stmp-lbfd-h ; @true
+stmp-lbfd-h: $(LIBBFD_H_FILES) $(MKDOC)
+ $(AM_V_GEN)H_FILES="$(LIBBFD_H_FILES)" CHEW_FLAGS=-i ; $(REGEN_HEADER) > libbfd.h-new
+ $(AM_V_at)$(SHELL) $(srcdir)/../move-if-change libbfd.h-new $(srcdir)/libbfd.h
+ $(AM_V_at)touch stmp-lbfd-h
+
+$(srcdir)/libcoff.h: @MAINT@ stmp-lcoff-h ; @true
+stmp-lcoff-h: $(LIBCOFF_H_FILES) $(MKDOC)
+ $(AM_V_GEN)H_FILES="$(LIBCOFF_H_FILES)" CHEW_FLAGS=-i ; $(REGEN_HEADER) > libcoff.h-new
+ $(AM_V_at)$(SHELL) $(srcdir)/../move-if-change libcoff.h-new $(srcdir)/libcoff.h
+ $(AM_V_at)touch stmp-lcoff-h
+
+bfdver.h: $(srcdir)/version.h $(srcdir)/development.sh $(srcdir)/Makefile.in
+ $(AM_V_GEN)\
+ bfd_version=`echo "$(VERSION)" | $(SED) -e 's/\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\).*/\1.00\2.00\3.00\4.00\5/' -e 's/\([^\.]*\)\..*\(..\)\..*\(..\)\..*\(..\)\..*\(..\)$$/\1\2\3\4\5/'` ;\
+ bfd_version_string="\"$(VERSION)\"" ;\
+ bfd_soversion="$(VERSION)" ;\
+ bfd_version_package="\"$(PKGVERSION)\"" ;\
+ report_bugs_to="\"$(REPORT_BUGS_TO)\"" ;\
+ . $(srcdir)/development.sh ;\
+ if test "$$development" = true ; then \
+ bfd_version_date=`$(SED) -n -e 's/.*DATE //p' < $(srcdir)/version.h` ;\
+ bfd_version_string="\"$(VERSION).$${bfd_version_date}\"" ;\
+ bfd_soversion="$(VERSION).$${bfd_version_date}" ;\
+ fi ;\
+ $(SED) -e "s,@bfd_version@,$$bfd_version," \
+ -e "s,@bfd_version_string@,$$bfd_version_string," \
+ -e "s,@bfd_version_package@,$$bfd_version_package," \
+ -e "s,@report_bugs_to@,$$report_bugs_to," \
+ < $(srcdir)/version.h > $@; \
+ echo "$${bfd_soversion}" > libtool-soversion
+
+# Disable -Werror, if it has been enabled, since coffswap.h won't
+# compile with gcc 4.5 and above.
+coff-tic4x.lo: coff-tic4x.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR)
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< $(NO_WERROR)
+
+coff-tic54x.lo: coff-tic54x.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< $(NO_WERROR)
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< $(NO_WERROR)
+
+$(MKDOC): doc/chew.stamp ; @true
+doc/chew.stamp: $(srcdir)/doc/chew.c doc/$(am__dirstamp)
+ $(AM_V_CCLD)$(CC_FOR_BUILD) -o doc/chw$$$$$(EXEEXT_FOR_BUILD) $(CFLAGS_FOR_BUILD) \
+ $(LDFLAGS_FOR_BUILD) $(H_CFLAGS) \
+ -I. -I$(srcdir) -Idoc -I$(srcdir)/../include -I$(srcdir)/../intl -I../intl \
+ $(srcdir)/doc/chew.c && \
+ $(SHELL) $(srcdir)/../move-if-change \
+ doc/chw$$$$$(EXEEXT_FOR_BUILD) $(MKDOC) && \
+ touch $@
+
+.PRECIOUS: doc/%.stamp
+doc/%.texi: doc/%.stamp ; @true
+doc/%.stamp: $(srcdir)/%.h $(srcdir)/doc/doc.str $(MKDOC) doc/$(am__dirstamp)
+ $(AM_V_GEN)$(REGEN_TEXI)
+doc/%.stamp: $(srcdir)/%.c $(srcdir)/doc/doc.str $(MKDOC) doc/$(am__dirstamp)
+ $(AM_V_GEN)$(REGEN_TEXI)
+
+# Avoid the %.stamp generating a builddir/bfd.texi that overrides the
+# srcdir/ as well as regenerating doc/bfd.info for each make run.
+doc/bfd.stamp: $(srcdir)/doc/bfd.texi ; $(AM_V_at)touch $@
+
+# We use bfdt.texi, rather than bfd.texi, to avoid conflicting with
+# bfd.texi on an 8.3 filesystem.
+doc/bfdt.stamp: $(srcdir)/bfd.c $(srcdir)/doc/doc.str $(MKDOC) doc/$(am__dirstamp)
+ $(AM_V_GEN)$(REGEN_TEXI)
+
+doc/bfdver.texi: $(srcdir)/Makefile.in
+ $(AM_V_GEN)\
+ $(MKDIR_P) $(@D); \
+ echo "@set VERSION $(VERSION)" > $@; \
+ if test -n "$(PKGVERSION)"; then \
+ echo "@set VERSION_PACKAGE $(PKGVERSION)" >> $@; \
+ fi; \
+ echo "@set UPDATED `date '+%B %Y'`" >> $@; \
+ if test -n "$(REPORT_BUGS_TEXI)"; then \
+ echo "@set BUGURL $(REPORT_BUGS_TEXI)" >> $@; \
+ fi
+
+html-local: doc/bfd/index.html
+doc/bfd/index.html: doc/bfd.texi $(bfd_TEXINFOS) doc/$(am__dirstamp)
+ $(AM_V_at)$(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) \
+ --split=node -o doc/bfd $(srcdir)/doc/bfd.texi
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: GNU/binutils/create-2.40-export-demangle-patch/create.patch.sh
===================================================================
--- GNU/binutils/create-2.40-export-demangle-patch/create.patch.sh (nonexistent)
+++ GNU/binutils/create-2.40-export-demangle-patch/create.patch.sh (revision 33)
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+VERSION=2.40
+
+tar --files-from=file.list -xJvf ../binutils-$VERSION.tar.xz
+mv binutils-$VERSION binutils-$VERSION-orig
+
+cp -rf ./binutils-$VERSION-new ./binutils-$VERSION
+
+diff --unified -Nr binutils-$VERSION-orig binutils-$VERSION > binutils-$VERSION-export-demangle.patch
+
+mv binutils-$VERSION-export-demangle.patch ../patches
+
+rm -rf ./binutils-$VERSION
+rm -rf ./binutils-$VERSION-orig
Property changes on: GNU/binutils/create-2.40-export-demangle-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: GNU/binutils/create-2.40-export-demangle-patch/file.list
===================================================================
--- GNU/binutils/create-2.40-export-demangle-patch/file.list (nonexistent)
+++ GNU/binutils/create-2.40-export-demangle-patch/file.list (revision 33)
@@ -0,0 +1,2 @@
+binutils-2.40/bfd/Makefile.am
+binutils-2.40/bfd/Makefile.in
Index: GNU/binutils/create-2.40-fname-in-error-messages-patch/binutils-2.40-new/binutils/readelf.c
===================================================================
--- GNU/binutils/create-2.40-fname-in-error-messages-patch/binutils-2.40-new/binutils/readelf.c (nonexistent)
+++ GNU/binutils/create-2.40-fname-in-error-messages-patch/binutils-2.40-new/binutils/readelf.c (revision 33)
@@ -0,0 +1,23019 @@
+/* readelf.c -- display contents of an ELF format file
+ Copyright (C) 1998-2023 Free Software Foundation, Inc.
+
+ Originally developed by Eric Youngdale <eric@andante.jic.com>
+ Modifications by Nick Clifton <nickc@redhat.com>
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* The difference between readelf and objdump:
+
+ Both programs are capable of displaying the contents of ELF format files,
+ so why does the binutils project have two file dumpers ?
+
+ The reason is that objdump sees an ELF file through a BFD filter of the
+ world; if BFD has a bug where, say, it disagrees about a machine constant
+ in e_flags, then the odds are good that it will remain internally
+ consistent. The linker sees it the BFD way, objdump sees it the BFD way,
+ GAS sees it the BFD way. There was need for a tool to go find out what
+ the file actually says.
+
+ This is why the readelf program does not link against the BFD library - it
+ exists as an independent program to help verify the correct working of BFD.
+
+ There is also the case that readelf can provide more information about an
+ ELF file than is provided by objdump. In particular it can display DWARF
+ debugging information which (at the moment) objdump cannot. */
+
+#include "sysdep.h"
+#include <assert.h>
+#include <time.h>
+#include <zlib.h>
+#ifdef HAVE_ZSTD
+#include <zstd.h>
+#endif
+#include <wchar.h>
+
+#if defined HAVE_MSGPACK
+#include <msgpack.h>
+#endif
+
+/* Define BFD64 here, even if our default architecture is 32 bit ELF
+ as this will allow us to read in and parse 64bit and 32bit ELF files. */
+#define BFD64
+
+#include "bfd.h"
+#include "bucomm.h"
+#include "elfcomm.h"
+#include "demanguse.h"
+#include "dwarf.h"
+#include "ctf-api.h"
+#include "sframe-api.h"
+#include "demangle.h"
+
+#include "elf/common.h"
+#include "elf/external.h"
+#include "elf/internal.h"
+
+
+/* Included here, before RELOC_MACROS_GEN_FUNC is defined, so that
+ we can obtain the H8 reloc numbers. We need these for the
+ get_reloc_size() function. We include h8.h again after defining
+ RELOC_MACROS_GEN_FUNC so that we get the naming function as well. */
+
+#include "elf/h8.h"
+#undef _ELF_H8_H
+
+/* Undo the effects of #including reloc-macros.h. */
+
+#undef START_RELOC_NUMBERS
+#undef RELOC_NUMBER
+#undef FAKE_RELOC
+#undef EMPTY_RELOC
+#undef END_RELOC_NUMBERS
+#undef _RELOC_MACROS_H
+
+/* The following headers use the elf/reloc-macros.h file to
+ automatically generate relocation recognition functions
+ such as elf_mips_reloc_type() */
+
+#define RELOC_MACROS_GEN_FUNC
+
+#include "elf/aarch64.h"
+#include "elf/alpha.h"
+#include "elf/amdgpu.h"
+#include "elf/arc.h"
+#include "elf/arm.h"
+#include "elf/avr.h"
+#include "elf/bfin.h"
+#include "elf/cr16.h"
+#include "elf/cris.h"
+#include "elf/crx.h"
+#include "elf/csky.h"
+#include "elf/d10v.h"
+#include "elf/d30v.h"
+#include "elf/dlx.h"
+#include "elf/bpf.h"
+#include "elf/epiphany.h"
+#include "elf/fr30.h"
+#include "elf/frv.h"
+#include "elf/ft32.h"
+#include "elf/h8.h"
+#include "elf/hppa.h"
+#include "elf/i386.h"
+#include "elf/i370.h"
+#include "elf/i860.h"
+#include "elf/i960.h"
+#include "elf/ia64.h"
+#include "elf/ip2k.h"
+#include "elf/lm32.h"
+#include "elf/iq2000.h"
+#include "elf/m32c.h"
+#include "elf/m32r.h"
+#include "elf/m68k.h"
+#include "elf/m68hc11.h"
+#include "elf/s12z.h"
+#include "elf/mcore.h"
+#include "elf/mep.h"
+#include "elf/metag.h"
+#include "elf/microblaze.h"
+#include "elf/mips.h"
+#include "elf/mmix.h"
+#include "elf/mn10200.h"
+#include "elf/mn10300.h"
+#include "elf/moxie.h"
+#include "elf/mt.h"
+#include "elf/msp430.h"
+#include "elf/nds32.h"
+#include "elf/nfp.h"
+#include "elf/nios2.h"
+#include "elf/or1k.h"
+#include "elf/pj.h"
+#include "elf/ppc.h"
+#include "elf/ppc64.h"
+#include "elf/pru.h"
+#include "elf/riscv.h"
+#include "elf/rl78.h"
+#include "elf/rx.h"
+#include "elf/s390.h"
+#include "elf/score.h"
+#include "elf/sh.h"
+#include "elf/sparc.h"
+#include "elf/spu.h"
+#include "elf/tic6x.h"
+#include "elf/tilegx.h"
+#include "elf/tilepro.h"
+#include "elf/v850.h"
+#include "elf/vax.h"
+#include "elf/visium.h"
+#include "elf/wasm32.h"
+#include "elf/x86-64.h"
+#include "elf/xgate.h"
+#include "elf/xstormy16.h"
+#include "elf/xtensa.h"
+#include "elf/z80.h"
+#include "elf/loongarch.h"
+
+#include "getopt.h"
+#include "libiberty.h"
+#include "safe-ctype.h"
+#include "filenames.h"
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &(((TYPE *) 0)->MEMBER))
+#endif
+
+typedef struct elf_section_list
+{
+ Elf_Internal_Shdr * hdr;
+ struct elf_section_list * next;
+} elf_section_list;
+
+/* Flag bits indicating particular types of dump. */
+#define HEX_DUMP (1 << 0) /* The -x command line switch. */
+#define DISASS_DUMP (1 << 1) /* The -i command line switch. */
+#define DEBUG_DUMP (1 << 2) /* The -w command line switch. */
+#define STRING_DUMP (1 << 3) /* The -p command line switch. */
+#define RELOC_DUMP (1 << 4) /* The -R command line switch. */
+#define CTF_DUMP (1 << 5) /* The --ctf command line switch. */
+#define SFRAME_DUMP (1 << 6) /* The --sframe command line switch. */
+
+typedef unsigned char dump_type;
+
+/* A linked list of the section names for which dumps were requested. */
+struct dump_list_entry
+{
+ char * name;
+ dump_type type;
+ struct dump_list_entry * next;
+};
+
+/* A dynamic array of flags indicating for which sections a dump
+ has been requested via command line switches. */
+struct dump_data
+{
+ dump_type * dump_sects;
+ unsigned int num_dump_sects;
+};
+
+static struct dump_data cmdline;
+
+static struct dump_list_entry * dump_sects_byname;
+
+char * program_name = "readelf";
+
+static bool show_name = false;
+static bool do_dynamic = false;
+static bool do_syms = false;
+static bool do_dyn_syms = false;
+static bool do_lto_syms = false;
+static bool do_reloc = false;
+static bool do_sections = false;
+static bool do_section_groups = false;
+static bool do_section_details = false;
+static bool do_segments = false;
+static bool do_unwind = false;
+static bool do_using_dynamic = false;
+static bool do_header = false;
+static bool do_dump = false;
+static bool do_version = false;
+static bool do_histogram = false;
+static bool do_debugging = false;
+static bool do_ctf = false;
+static bool do_sframe = false;
+static bool do_arch = false;
+static bool do_notes = false;
+static bool do_archive_index = false;
+static bool check_all = false;
+static bool is_32bit_elf = false;
+static bool decompress_dumps = false;
+static bool do_not_show_symbol_truncation = false;
+static bool do_demangle = false; /* Pretty print C++ symbol names. */
+static bool process_links = false;
+static bool dump_any_debugging = false;
+static int demangle_flags = DMGL_ANSI | DMGL_PARAMS;
+static int sym_base = 0;
+
+static char *dump_ctf_parent_name;
+static char *dump_ctf_symtab_name;
+static char *dump_ctf_strtab_name;
+
+struct group_list
+{
+ struct group_list * next;
+ unsigned int section_index;
+};
+
+struct group
+{
+ struct group_list * root;
+ unsigned int group_index;
+};
+
+typedef struct filedata
+{
+ const char * file_name;
+ bool is_separate;
+ FILE * handle;
+ uint64_t file_size;
+ Elf_Internal_Ehdr file_header;
+ uint64_t archive_file_offset;
+ uint64_t archive_file_size;
+ /* Everything below this point is cleared out by free_filedata. */
+ Elf_Internal_Shdr * section_headers;
+ Elf_Internal_Phdr * program_headers;
+ char * string_table;
+ uint64_t string_table_length;
+ uint64_t dynamic_addr;
+ uint64_t dynamic_size;
+ uint64_t dynamic_nent;
+ Elf_Internal_Dyn * dynamic_section;
+ Elf_Internal_Shdr * dynamic_strtab_section;
+ char * dynamic_strings;
+ uint64_t dynamic_strings_length;
+ Elf_Internal_Shdr * dynamic_symtab_section;
+ uint64_t num_dynamic_syms;
+ Elf_Internal_Sym * dynamic_symbols;
+ uint64_t version_info[16];
+ unsigned int dynamic_syminfo_nent;
+ Elf_Internal_Syminfo * dynamic_syminfo;
+ uint64_t dynamic_syminfo_offset;
+ uint64_t nbuckets;
+ uint64_t nchains;
+ uint64_t * buckets;
+ uint64_t * chains;
+ uint64_t ngnubuckets;
+ uint64_t ngnuchains;
+ uint64_t * gnubuckets;
+ uint64_t * gnuchains;
+ uint64_t * mipsxlat;
+ uint64_t gnusymidx;
+ char * program_interpreter;
+ uint64_t dynamic_info[DT_ENCODING];
+ uint64_t dynamic_info_DT_GNU_HASH;
+ uint64_t dynamic_info_DT_MIPS_XHASH;
+ elf_section_list * symtab_shndx_list;
+ size_t group_count;
+ struct group * section_groups;
+ struct group ** section_headers_groups;
+ /* A dynamic array of flags indicating for which sections a dump of
+ some kind has been requested. It is reset on a per-object file
+ basis and then initialised from the cmdline_dump_sects array,
+ the results of interpreting the -w switch, and the
+ dump_sects_byname list. */
+ struct dump_data dump;
+} Filedata;
+
+/* How to print a vma value. */
+typedef enum print_mode
+{
+ HEX,
+ HEX_5,
+ DEC,
+ DEC_5,
+ UNSIGNED,
+ UNSIGNED_5,
+ PREFIX_HEX,
+ PREFIX_HEX_5,
+ FULL_HEX,
+ LONG_HEX,
+ OCTAL,
+ OCTAL_5
+}
+print_mode;
+
+typedef enum unicode_display_type
+{
+ unicode_default = 0,
+ unicode_locale,
+ unicode_escape,
+ unicode_hex,
+ unicode_highlight,
+ unicode_invalid
+} unicode_display_type;
+
+static unicode_display_type unicode_display = unicode_default;
+
+typedef enum
+{
+ reltype_unknown,
+ reltype_rel,
+ reltype_rela,
+ reltype_relr
+} relocation_type;
+
+/* Versioned symbol info. */
+enum versioned_symbol_info
+{
+ symbol_undefined,
+ symbol_hidden,
+ symbol_public
+};
+
+static int
+fseek64 (FILE *stream, int64_t offset, int whence)
+{
+#if defined (HAVE_FSEEKO64)
+ off64_t o = offset;
+ if (o != offset)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ return fseeko64 (stream, o, whence);
+#elif defined (HAVE_FSEEKO)
+ off_t o = offset;
+ if (o != offset)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ return fseeko (stream, o, whence);
+#else
+ long o = offset;
+ if (o != offset)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ return fseek (stream, o, whence);
+#endif
+}
+
+static const char * get_symbol_version_string
+ (Filedata *, bool, const char *, size_t, unsigned,
+ Elf_Internal_Sym *, enum versioned_symbol_info *, unsigned short *);
+
+#define UNKNOWN -1
+
+static inline const char *
+section_name (const Filedata *filedata, const Elf_Internal_Shdr *hdr)
+{
+ return filedata->string_table + hdr->sh_name;
+}
+
+static inline bool
+section_name_valid (const Filedata *filedata, const Elf_Internal_Shdr *hdr)
+{
+ return (hdr != NULL
+ && filedata->string_table != NULL
+ && hdr->sh_name < filedata->string_table_length);
+}
+
+static inline const char *
+section_name_print (const Filedata *filedata, const Elf_Internal_Shdr *hdr)
+{
+ if (hdr == NULL)
+ return _("<none>");
+ if (filedata->string_table == NULL)
+ return _("<no-strings>");
+ if (hdr->sh_name >= filedata->string_table_length)
+ return _("<corrupt>");
+ return section_name (filedata, hdr);
+}
+
+#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+
+static inline bool
+valid_symbol_name (const char *strtab, size_t strtab_size, uint64_t offset)
+{
+ return strtab != NULL && offset < strtab_size;
+}
+
+static inline bool
+valid_dynamic_name (const Filedata *filedata, uint64_t offset)
+{
+ return valid_symbol_name (filedata->dynamic_strings,
+ filedata->dynamic_strings_length, offset);
+}
+
+/* GET_DYNAMIC_NAME asssumes that VALID_DYNAMIC_NAME has
+ already been called and verified that the string exists. */
+static inline const char *
+get_dynamic_name (const Filedata *filedata, size_t offset)
+{
+ return filedata->dynamic_strings + offset;
+}
+
+#define REMOVE_ARCH_BITS(ADDR) \
+ do \
+ { \
+ if (filedata->file_header.e_machine == EM_ARM) \
+ (ADDR) &= ~1; \
+ } \
+ while (0)
+
+/* Get the correct GNU hash section name. */
+#define GNU_HASH_SECTION_NAME(filedata) \
+ filedata->dynamic_info_DT_MIPS_XHASH ? ".MIPS.xhash" : ".gnu.hash"
+
+/* Retrieve NMEMB structures, each SIZE bytes long from FILEDATA starting at
+ OFFSET + the offset of the current archive member, if we are examining an
+ archive. Put the retrieved data into VAR, if it is not NULL. Otherwise
+ allocate a buffer using malloc and fill that. In either case return the
+ pointer to the start of the retrieved data or NULL if something went wrong.
+ If something does go wrong and REASON is not NULL then emit an error
+ message using REASON as part of the context. */
+
+static void *
+get_data (void *var,
+ Filedata *filedata,
+ uint64_t offset,
+ uint64_t size,
+ uint64_t nmemb,
+ const char *reason)
+{
+ void * mvar;
+ uint64_t amt = size * nmemb;
+
+ if (size == 0 || nmemb == 0)
+ return NULL;
+
+ /* If size_t is smaller than uint64_t, eg because you are building
+ on a 32-bit host, then make sure that when the sizes are cast to
+ size_t no information is lost. */
+ if ((size_t) size != size
+ || (size_t) nmemb != nmemb
+ || (size_t) amt != amt
+ || amt / size != nmemb
+ || (size_t) amt + 1 == 0)
+ {
+ if (reason)
+ error (_("Size overflow prevents reading %" PRIu64
+ " elements of size %" PRIu64 " for %s\n"),
+ nmemb, size, reason);
+ return NULL;
+ }
+
+ /* Be kind to memory checkers (eg valgrind, address sanitizer) by not
+ attempting to allocate memory when the read is bound to fail. */
+ if (filedata->archive_file_offset > filedata->file_size
+ || offset > filedata->file_size - filedata->archive_file_offset
+ || amt > filedata->file_size - filedata->archive_file_offset - offset)
+ {
+ if (reason)
+ error (_("Reading %" PRIu64 " bytes extends past end of file for %s\n"),
+ amt, reason);
+ return NULL;
+ }
+
+ if (fseek64 (filedata->handle, filedata->archive_file_offset + offset,
+ SEEK_SET))
+ {
+ if (reason)
+ error (_("Unable to seek to %#" PRIx64 " for %s\n"),
+ filedata->archive_file_offset + offset, reason);
+ return NULL;
+ }
+
+ mvar = var;
+ if (mvar == NULL)
+ {
+ /* + 1 so that we can '\0' terminate invalid string table sections. */
+ mvar = malloc ((size_t) amt + 1);
+
+ if (mvar == NULL)
+ {
+ if (reason)
+ error (_("Out of memory allocating %" PRIu64 " bytes for %s\n"),
+ amt, reason);
+ return NULL;
+ }
+
+ ((char *) mvar)[amt] = '\0';
+ }
+
+ if (fread (mvar, (size_t) size, (size_t) nmemb, filedata->handle) != nmemb)
+ {
+ if (reason)
+ error (_("Unable to read in %" PRIu64 " bytes of %s\n"),
+ amt, reason);
+ if (mvar != var)
+ free (mvar);
+ return NULL;
+ }
+
+ return mvar;
+}
+
+/* Print a VMA value in the MODE specified.
+ Returns the number of characters displayed. */
+
+static unsigned int
+print_vma (uint64_t vma, print_mode mode)
+{
+ unsigned int nc = 0;
+
+ switch (mode)
+ {
+ case FULL_HEX:
+ nc = printf ("0x");
+ /* Fall through. */
+ case LONG_HEX:
+ if (!is_32bit_elf)
+ return nc + printf ("%16.16" PRIx64, vma);
+ return nc + printf ("%8.8" PRIx64, vma);
+
+ case DEC_5:
+ if (vma <= 99999)
+ return printf ("%5" PRId64, vma);
+ /* Fall through. */
+ case PREFIX_HEX:
+ nc = printf ("0x");
+ /* Fall through. */
+ case HEX:
+ return nc + printf ("%" PRIx64, vma);
+
+ case PREFIX_HEX_5:
+ nc = printf ("0x");
+ /* Fall through. */
+ case HEX_5:
+ return nc + printf ("%05" PRIx64, vma);
+
+ case DEC:
+ return printf ("%" PRId64, vma);
+
+ case UNSIGNED:
+ return printf ("%" PRIu64, vma);
+
+ case UNSIGNED_5:
+ return printf ("%5" PRIu64, vma);
+
+ case OCTAL:
+ return printf ("%" PRIo64, vma);
+
+ case OCTAL_5:
+ return printf ("%5" PRIo64, vma);
+
+ default:
+ /* FIXME: Report unrecognised mode ? */
+ return 0;
+ }
+}
+
+
+/* Display a symbol on stdout. Handles the display of control characters and
+ multibye characters (assuming the host environment supports them).
+
+ Display at most abs(WIDTH) characters, truncating as necessary, unless do_wide is true.
+
+ If truncation will happen and do_not_show_symbol_truncation is FALSE then display
+ abs(WIDTH) - 5 characters followed by "[...]".
+
+ If WIDTH is negative then ensure that the output is at least (- WIDTH) characters,
+ padding as necessary.
+
+ Returns the number of emitted characters. */
+
+static unsigned int
+print_symbol (signed int width, const char * symbol)
+{
+ bool extra_padding = false;
+ bool do_dots = false;
+ signed int num_printed = 0;
+#ifdef HAVE_MBSTATE_T
+ mbstate_t state;
+#endif
+ unsigned int width_remaining;
+ const void * alloced_symbol = NULL;
+
+ if (width < 0)
+ {
+ /* Keep the width positive. This helps the code below. */
+ width = - width;
+ extra_padding = true;
+ }
+ else if (width == 0)
+ return 0;
+
+ if (do_wide)
+ /* Set the remaining width to a very large value.
+ This simplifies the code below. */
+ width_remaining = INT_MAX;
+ else
+ {
+ width_remaining = width;
+ if (! do_not_show_symbol_truncation
+ && (int) strlen (symbol) > width)
+ {
+ width_remaining -= 5;
+ if ((int) width_remaining < 0)
+ width_remaining = 0;
+ do_dots = true;
+ }
+ }
+
+#ifdef HAVE_MBSTATE_T
+ /* Initialise the multibyte conversion state. */
+ memset (& state, 0, sizeof (state));
+#endif
+
+ if (do_demangle && *symbol)
+ {
+ const char * res = cplus_demangle (symbol, demangle_flags);
+
+ if (res != NULL)
+ alloced_symbol = symbol = res;
+ }
+
+ while (width_remaining)
+ {
+ size_t n;
+ const char c = *symbol++;
+
+ if (c == 0)
+ break;
+
+ if (ISPRINT (c))
+ {
+ putchar (c);
+ width_remaining --;
+ num_printed ++;
+ }
+ else if (ISCNTRL (c))
+ {
+ /* Do not print control characters directly as they can affect terminal
+ settings. Such characters usually appear in the names generated
+ by the assembler for local labels. */
+
+ if (width_remaining < 2)
+ break;
+
+ printf ("^%c", c + 0x40);
+ width_remaining -= 2;
+ num_printed += 2;
+ }
+ else if (c == 0x7f)
+ {
+ if (width_remaining < 5)
+ break;
+ printf ("<DEL>");
+ width_remaining -= 5;
+ num_printed += 5;
+ }
+ else if (unicode_display != unicode_locale
+ && unicode_display != unicode_default)
+ {
+ /* Display unicode characters as something else. */
+ unsigned char bytes[4];
+ bool is_utf8;
+ unsigned int nbytes;
+
+ bytes[0] = c;
+
+ if (bytes[0] < 0xc0)
+ {
+ nbytes = 1;
+ is_utf8 = false;
+ }
+ else
+ {
+ bytes[1] = *symbol++;
+
+ if ((bytes[1] & 0xc0) != 0x80)
+ {
+ is_utf8 = false;
+ /* Do not consume this character. It may only
+ be the first byte in the sequence that was
+ corrupt. */
+ --symbol;
+ nbytes = 1;
+ }
+ else if ((bytes[0] & 0x20) == 0)
+ {
+ is_utf8 = true;
+ nbytes = 2;
+ }
+ else
+ {
+ bytes[2] = *symbol++;
+
+ if ((bytes[2] & 0xc0) != 0x80)
+ {
+ is_utf8 = false;
+ symbol -= 2;
+ nbytes = 1;
+ }
+ else if ((bytes[0] & 0x10) == 0)
+ {
+ is_utf8 = true;
+ nbytes = 3;
+ }
+ else
+ {
+ bytes[3] = *symbol++;
+
+ nbytes = 4;
+
+ if ((bytes[3] & 0xc0) != 0x80)
+ {
+ is_utf8 = false;
+ symbol -= 3;
+ nbytes = 1;
+ }
+ else
+ is_utf8 = true;
+ }
+ }
+ }
+
+ if (unicode_display == unicode_invalid)
+ is_utf8 = false;
+
+ if (unicode_display == unicode_hex || ! is_utf8)
+ {
+ unsigned int i;
+
+ if (width_remaining < (nbytes * 2) + 2)
+ break;
+
+ putchar (is_utf8 ? '<' : '{');
+ printf ("0x");
+ for (i = 0; i < nbytes; i++)
+ printf ("%02x", bytes[i]);
+ putchar (is_utf8 ? '>' : '}');
+ }
+ else
+ {
+ if (unicode_display == unicode_highlight && isatty (1))
+ printf ("\x1B[31;47m"); /* Red. */
+
+ switch (nbytes)
+ {
+ case 2:
+ if (width_remaining < 6)
+ break;
+ printf ("\\u%02x%02x",
+ (bytes[0] & 0x1c) >> 2,
+ ((bytes[0] & 0x03) << 6) | (bytes[1] & 0x3f));
+ break;
+ case 3:
+ if (width_remaining < 6)
+ break;
+ printf ("\\u%02x%02x",
+ ((bytes[0] & 0x0f) << 4) | ((bytes[1] & 0x3c) >> 2),
+ ((bytes[1] & 0x03) << 6) | (bytes[2] & 0x3f));
+ break;
+ case 4:
+ if (width_remaining < 8)
+ break;
+ printf ("\\u%02x%02x%02x",
+ ((bytes[0] & 0x07) << 6) | ((bytes[1] & 0x3c) >> 2),
+ ((bytes[1] & 0x03) << 6) | ((bytes[2] & 0x3c) >> 2),
+ ((bytes[2] & 0x03) << 6) | (bytes[3] & 0x3f));
+
+ break;
+ default:
+ /* URG. */
+ break;
+ }
+
+ if (unicode_display == unicode_highlight && isatty (1))
+ printf ("\033[0m"); /* Default colour. */
+ }
+
+ if (bytes[nbytes - 1] == 0)
+ break;
+ }
+ else
+ {
+#ifdef HAVE_MBSTATE_T
+ wchar_t w;
+#endif
+ /* Let printf do the hard work of displaying multibyte characters. */
+ printf ("%.1s", symbol - 1);
+ width_remaining --;
+ num_printed ++;
+
+#ifdef HAVE_MBSTATE_T
+ /* Try to find out how many bytes made up the character that was
+ just printed. Advance the symbol pointer past the bytes that
+ were displayed. */
+ n = mbrtowc (& w, symbol - 1, MB_CUR_MAX, & state);
+#else
+ n = 1;
+#endif
+ if (n != (size_t) -1 && n != (size_t) -2 && n > 0)
+ symbol += (n - 1);
+ }
+ }
+
+ if (do_dots)
+ num_printed += printf ("[...]");
+
+ if (extra_padding && num_printed < width)
+ {
+ /* Fill in the remaining spaces. */
+ printf ("%-*s", width - num_printed, " ");
+ num_printed = width;
+ }
+
+ free ((void *) alloced_symbol);
+ return num_printed;
+}
+
+/* Returns a pointer to a static buffer containing a printable version of
+ the given section's name. Like print_symbol, except that it does not try
+ to print multibyte characters, it just interprets them as hex values. */
+
+static const char *
+printable_section_name (Filedata * filedata, const Elf_Internal_Shdr * sec)
+{
+#define MAX_PRINT_SEC_NAME_LEN 256
+ static char sec_name_buf [MAX_PRINT_SEC_NAME_LEN + 1];
+ const char * name = section_name_print (filedata, sec);
+ char * buf = sec_name_buf;
+ char c;
+ unsigned int remaining = MAX_PRINT_SEC_NAME_LEN;
+
+ while ((c = * name ++) != 0)
+ {
+ if (ISCNTRL (c))
+ {
+ if (remaining < 2)
+ break;
+
+ * buf ++ = '^';
+ * buf ++ = c + 0x40;
+ remaining -= 2;
+ }
+ else if (ISPRINT (c))
+ {
+ * buf ++ = c;
+ remaining -= 1;
+ }
+ else
+ {
+ static char hex[17] = "0123456789ABCDEF";
+
+ if (remaining < 4)
+ break;
+ * buf ++ = '<';
+ * buf ++ = hex[(c & 0xf0) >> 4];
+ * buf ++ = hex[c & 0x0f];
+ * buf ++ = '>';
+ remaining -= 4;
+ }
+
+ if (remaining == 0)
+ break;
+ }
+
+ * buf = 0;
+ return sec_name_buf;
+}
+
+static const char *
+printable_section_name_from_index (Filedata *filedata, size_t ndx)
+{
+ if (ndx >= filedata->file_header.e_shnum)
+ return _("<corrupt>");
+
+ return printable_section_name (filedata, filedata->section_headers + ndx);
+}
+
+/* Return a pointer to section NAME, or NULL if no such section exists. */
+
+static Elf_Internal_Shdr *
+find_section (Filedata * filedata, const char * name)
+{
+ unsigned int i;
+
+ if (filedata->section_headers == NULL)
+ return NULL;
+
+ for (i = 0; i < filedata->file_header.e_shnum; i++)
+ if (section_name_valid (filedata, filedata->section_headers + i)
+ && streq (section_name (filedata, filedata->section_headers + i),
+ name))
+ return filedata->section_headers + i;
+
+ return NULL;
+}
+
+/* Return a pointer to a section containing ADDR, or NULL if no such
+ section exists. */
+
+static Elf_Internal_Shdr *
+find_section_by_address (Filedata * filedata, uint64_t addr)
+{
+ unsigned int i;
+
+ if (filedata->section_headers == NULL)
+ return NULL;
+
+ for (i = 0; i < filedata->file_header.e_shnum; i++)
+ {
+ Elf_Internal_Shdr *sec = filedata->section_headers + i;
+
+ if (addr >= sec->sh_addr && addr < sec->sh_addr + sec->sh_size)
+ return sec;
+ }
+
+ return NULL;
+}
+
+static Elf_Internal_Shdr *
+find_section_by_type (Filedata * filedata, unsigned int type)
+{
+ unsigned int i;
+
+ if (filedata->section_headers == NULL)
+ return NULL;
+
+ for (i = 0; i < filedata->file_header.e_shnum; i++)
+ {
+ Elf_Internal_Shdr *sec = filedata->section_headers + i;
+
+ if (sec->sh_type == type)
+ return sec;
+ }
+
+ return NULL;
+}
+
+/* Return a pointer to section NAME, or NULL if no such section exists,
+ restricted to the list of sections given in SET. */
+
+static Elf_Internal_Shdr *
+find_section_in_set (Filedata * filedata, const char * name, unsigned int * set)
+{
+ unsigned int i;
+
+ if (filedata->section_headers == NULL)
+ return NULL;
+
+ if (set != NULL)
+ {
+ while ((i = *set++) > 0)
+ {
+ /* See PR 21156 for a reproducer. */
+ if (i >= filedata->file_header.e_shnum)
+ continue; /* FIXME: Should we issue an error message ? */
+
+ if (section_name_valid (filedata, filedata->section_headers + i)
+ && streq (section_name (filedata, filedata->section_headers + i),
+ name))
+ return filedata->section_headers + i;
+ }
+ }
+
+ return find_section (filedata, name);
+}
+
+/* Return TRUE if the current file is for IA-64 machine and OpenVMS ABI.
+ This OS has so many departures from the ELF standard that we test it at
+ many places. */
+
+static inline bool
+is_ia64_vms (Filedata * filedata)
+{
+ return filedata->file_header.e_machine == EM_IA_64
+ && filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_OPENVMS;
+}
+
+/* Guess the relocation size commonly used by the specific machines. */
+
+static bool
+guess_is_rela (unsigned int e_machine)
+{
+ switch (e_machine)
+ {
+ /* Targets that use REL relocations. */
+ case EM_386:
+ case EM_IAMCU:
+ case EM_960:
+ case EM_ARM:
+ case EM_D10V:
+ case EM_CYGNUS_D10V:
+ case EM_DLX:
+ case EM_MIPS:
+ case EM_MIPS_RS3_LE:
+ case EM_CYGNUS_M32R:
+ case EM_SCORE:
+ case EM_XGATE:
+ case EM_NFP:
+ case EM_BPF:
+ return false;
+
+ /* Targets that use RELA relocations. */
+ case EM_68K:
+ case EM_860:
+ case EM_AARCH64:
+ case EM_ADAPTEVA_EPIPHANY:
+ case EM_ALPHA:
+ case EM_ALTERA_NIOS2:
+ case EM_ARC:
+ case EM_ARC_COMPACT:
+ case EM_ARC_COMPACT2:
+ case EM_AVR:
+ case EM_AVR_OLD:
+ case EM_BLACKFIN:
+ case EM_CR16:
+ case EM_CRIS:
+ case EM_CRX:
+ case EM_CSKY:
+ case EM_D30V:
+ case EM_CYGNUS_D30V:
+ case EM_FR30:
+ case EM_FT32:
+ case EM_CYGNUS_FR30:
+ case EM_CYGNUS_FRV:
+ case EM_H8S:
+ case EM_H8_300:
+ case EM_H8_300H:
+ case EM_IA_64:
+ case EM_IP2K:
+ case EM_IP2K_OLD:
+ case EM_IQ2000:
+ case EM_LATTICEMICO32:
+ case EM_M32C_OLD:
+ case EM_M32C:
+ case EM_M32R:
+ case EM_MCORE:
+ case EM_CYGNUS_MEP:
+ case EM_METAG:
+ case EM_MMIX:
+ case EM_MN10200:
+ case EM_CYGNUS_MN10200:
+ case EM_MN10300:
+ case EM_CYGNUS_MN10300:
+ case EM_MOXIE:
+ case EM_MSP430:
+ case EM_MSP430_OLD:
+ case EM_MT:
+ case EM_NDS32:
+ case EM_NIOS32:
+ case EM_OR1K:
+ case EM_PPC64:
+ case EM_PPC:
+ case EM_TI_PRU:
+ case EM_RISCV:
+ case EM_RL78:
+ case EM_RX:
+ case EM_S390:
+ case EM_S390_OLD:
+ case EM_SH:
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ case EM_SPU:
+ case EM_TI_C6000:
+ case EM_TILEGX:
+ case EM_TILEPRO:
+ case EM_V800:
+ case EM_V850:
+ case EM_CYGNUS_V850:
+ case EM_VAX:
+ case EM_VISIUM:
+ case EM_X86_64:
+ case EM_L1OM:
+ case EM_K1OM:
+ case EM_XSTORMY16:
+ case EM_XTENSA:
+ case EM_XTENSA_OLD:
+ case EM_MICROBLAZE:
+ case EM_MICROBLAZE_OLD:
+ case EM_WEBASSEMBLY:
+ return true;
+
+ case EM_68HC05:
+ case EM_68HC08:
+ case EM_68HC11:
+ case EM_68HC16:
+ case EM_FX66:
+ case EM_ME16:
+ case EM_MMA:
+ case EM_NCPU:
+ case EM_NDR1:
+ case EM_PCP:
+ case EM_ST100:
+ case EM_ST19:
+ case EM_ST7:
+ case EM_ST9PLUS:
+ case EM_STARCORE:
+ case EM_SVX:
+ case EM_TINYJ:
+ default:
+ warn (_("Don't know about relocations on this machine architecture\n"));
+ return false;
+ }
+}
+
+/* Load RELA type relocations from FILEDATA at REL_OFFSET extending for REL_SIZE bytes.
+ Returns TRUE upon success, FALSE otherwise. If successful then a
+ pointer to a malloc'ed buffer containing the relocs is placed in *RELASP,
+ and the number of relocs loaded is placed in *NRELASP. It is the caller's
+ responsibility to free the allocated buffer. */
+
+static bool
+slurp_rela_relocs (Filedata *filedata,
+ uint64_t rel_offset,
+ uint64_t rel_size,
+ Elf_Internal_Rela **relasp,
+ uint64_t *nrelasp)
+{
+ Elf_Internal_Rela * relas;
+ uint64_t nrelas;
+ unsigned int i;
+
+ if (is_32bit_elf)
+ {
+ Elf32_External_Rela * erelas;
+
+ erelas = (Elf32_External_Rela *) get_data (NULL, filedata, rel_offset, 1,
+ rel_size, _("32-bit relocation data"));
+ if (!erelas)
+ return false;
+
+ nrelas = rel_size / sizeof (Elf32_External_Rela);
+
+ relas = (Elf_Internal_Rela *) cmalloc (nrelas,
+ sizeof (Elf_Internal_Rela));
+
+ if (relas == NULL)
+ {
+ free (erelas);
+ error (_("out of memory parsing relocs\n"));
+ return false;
+ }
+
+ for (i = 0; i < nrelas; i++)
+ {
+ relas[i].r_offset = BYTE_GET (erelas[i].r_offset);
+ relas[i].r_info = BYTE_GET (erelas[i].r_info);
+ relas[i].r_addend = BYTE_GET_SIGNED (erelas[i].r_addend);
+ }
+
+ free (erelas);
+ }
+ else
+ {
+ Elf64_External_Rela * erelas;
+
+ erelas = (Elf64_External_Rela *) get_data (NULL, filedata, rel_offset, 1,
+ rel_size, _("64-bit relocation data"));
+ if (!erelas)
+ return false;
+
+ nrelas = rel_size / sizeof (Elf64_External_Rela);
+
+ relas = (Elf_Internal_Rela *) cmalloc (nrelas,
+ sizeof (Elf_Internal_Rela));
+
+ if (relas == NULL)
+ {
+ free (erelas);
+ error (_("out of memory parsing relocs\n"));
+ return false;
+ }
+
+ for (i = 0; i < nrelas; i++)
+ {
+ relas[i].r_offset = BYTE_GET (erelas[i].r_offset);
+ relas[i].r_info = BYTE_GET (erelas[i].r_info);
+ relas[i].r_addend = BYTE_GET_SIGNED (erelas[i].r_addend);
+
+ if (filedata->file_header.e_machine == EM_MIPS
+ && filedata->file_header.e_ident[EI_DATA] != ELFDATA2MSB)
+ {
+ /* In little-endian objects, r_info isn't really a
+ 64-bit little-endian value: it has a 32-bit
+ little-endian symbol index followed by four
+ individual byte fields. Reorder INFO
+ accordingly. */
+ uint64_t inf = relas[i].r_info;
+ inf = (((inf & 0xffffffff) << 32)
+ | ((inf >> 56) & 0xff)
+ | ((inf >> 40) & 0xff00)
+ | ((inf >> 24) & 0xff0000)
+ | ((inf >> 8) & 0xff000000));
+ relas[i].r_info = inf;
+ }
+ }
+
+ free (erelas);
+ }
+
+ *relasp = relas;
+ *nrelasp = nrelas;
+ return true;
+}
+
+/* Load REL type relocations from FILEDATA at REL_OFFSET extending for REL_SIZE bytes.
+ Returns TRUE upon success, FALSE otherwise. If successful then a
+ pointer to a malloc'ed buffer containing the relocs is placed in *RELSP,
+ and the number of relocs loaded is placed in *NRELSP. It is the caller's
+ responsibility to free the allocated buffer. */
+
+static bool
+slurp_rel_relocs (Filedata *filedata,
+ uint64_t rel_offset,
+ uint64_t rel_size,
+ Elf_Internal_Rela **relsp,
+ uint64_t *nrelsp)
+{
+ Elf_Internal_Rela * rels;
+ uint64_t nrels;
+ unsigned int i;
+
+ if (is_32bit_elf)
+ {
+ Elf32_External_Rel * erels;
+
+ erels = (Elf32_External_Rel *) get_data (NULL, filedata, rel_offset, 1,
+ rel_size, _("32-bit relocation data"));
+ if (!erels)
+ return false;
+
+ nrels = rel_size / sizeof (Elf32_External_Rel);
+
+ rels = (Elf_Internal_Rela *) cmalloc (nrels, sizeof (Elf_Internal_Rela));
+
+ if (rels == NULL)
+ {
+ free (erels);
+ error (_("out of memory parsing relocs\n"));
+ return false;
+ }
+
+ for (i = 0; i < nrels; i++)
+ {
+ rels[i].r_offset = BYTE_GET (erels[i].r_offset);
+ rels[i].r_info = BYTE_GET (erels[i].r_info);
+ rels[i].r_addend = 0;
+ }
+
+ free (erels);
+ }
+ else
+ {
+ Elf64_External_Rel * erels;
+
+ erels = (Elf64_External_Rel *) get_data (NULL, filedata, rel_offset, 1,
+ rel_size, _("64-bit relocation data"));
+ if (!erels)
+ return false;
+
+ nrels = rel_size / sizeof (Elf64_External_Rel);
+
+ rels = (Elf_Internal_Rela *) cmalloc (nrels, sizeof (Elf_Internal_Rela));
+
+ if (rels == NULL)
+ {
+ free (erels);
+ error (_("out of memory parsing relocs\n"));
+ return false;
+ }
+
+ for (i = 0; i < nrels; i++)
+ {
+ rels[i].r_offset = BYTE_GET (erels[i].r_offset);
+ rels[i].r_info = BYTE_GET (erels[i].r_info);
+ rels[i].r_addend = 0;
+
+ if (filedata->file_header.e_machine == EM_MIPS
+ && filedata->file_header.e_ident[EI_DATA] != ELFDATA2MSB)
+ {
+ /* In little-endian objects, r_info isn't really a
+ 64-bit little-endian value: it has a 32-bit
+ little-endian symbol index followed by four
+ individual byte fields. Reorder INFO
+ accordingly. */
+ uint64_t inf = rels[i].r_info;
+ inf = (((inf & 0xffffffff) << 32)
+ | ((inf >> 56) & 0xff)
+ | ((inf >> 40) & 0xff00)
+ | ((inf >> 24) & 0xff0000)
+ | ((inf >> 8) & 0xff000000));
+ rels[i].r_info = inf;
+ }
+ }
+
+ free (erels);
+ }
+
+ *relsp = rels;
+ *nrelsp = nrels;
+ return true;
+}
+
+static bool
+slurp_relr_relocs (Filedata *filedata,
+ uint64_t relr_offset,
+ uint64_t relr_size,
+ uint64_t **relrsp,
+ uint64_t *nrelrsp)
+{
+ void *relrs;
+ size_t size = 0, nentries, i;
+ uint64_t base = 0, addr, entry;
+
+ relrs = get_data (NULL, filedata, relr_offset, 1, relr_size,
+ _("RELR relocation data"));
+ if (!relrs)
+ return false;
+
+ if (is_32bit_elf)
+ nentries = relr_size / sizeof (Elf32_External_Relr);
+ else
+ nentries = relr_size / sizeof (Elf64_External_Relr);
+ for (i = 0; i < nentries; i++)
+ {
+ if (is_32bit_elf)
+ entry = BYTE_GET (((Elf32_External_Relr *)relrs)[i].r_data);
+ else
+ entry = BYTE_GET (((Elf64_External_Relr *)relrs)[i].r_data);
+ if ((entry & 1) == 0)
+ size++;
+ else
+ while ((entry >>= 1) != 0)
+ if ((entry & 1) == 1)
+ size++;
+ }
+
+ *relrsp = malloc (size * sizeof (**relrsp));
+ if (*relrsp == NULL)
+ {
+ free (relrs);
+ error (_("out of memory parsing relocs\n"));
+ return false;
+ }
+
+ size = 0;
+ for (i = 0; i < nentries; i++)
+ {
+ const uint64_t entry_bytes = is_32bit_elf ? 4 : 8;
+
+ if (is_32bit_elf)
+ entry = BYTE_GET (((Elf32_External_Relr *)relrs)[i].r_data);
+ else
+ entry = BYTE_GET (((Elf64_External_Relr *)relrs)[i].r_data);
+ if ((entry & 1) == 0)
+ {
+ (*relrsp)[size++] = entry;
+ base = entry + entry_bytes;
+ }
+ else
+ {
+ for (addr = base; (entry >>= 1) != 0; addr += entry_bytes)
+ if ((entry & 1) != 0)
+ (*relrsp)[size++] = addr;
+ base += entry_bytes * (entry_bytes * CHAR_BIT - 1);
+ }
+ }
+
+ *nrelrsp = size;
+ free (relrs);
+ return true;
+}
+
+/* Returns the reloc type extracted from the reloc info field. */
+
+static unsigned int
+get_reloc_type (Filedata * filedata, uint64_t reloc_info)
+{
+ if (is_32bit_elf)
+ return ELF32_R_TYPE (reloc_info);
+
+ switch (filedata->file_header.e_machine)
+ {
+ case EM_MIPS:
+ /* Note: We assume that reloc_info has already been adjusted for us. */
+ return ELF64_MIPS_R_TYPE (reloc_info);
+
+ case EM_SPARCV9:
+ return ELF64_R_TYPE_ID (reloc_info);
+
+ default:
+ return ELF64_R_TYPE (reloc_info);
+ }
+}
+
+/* Return the symbol index extracted from the reloc info field. */
+
+static uint64_t
+get_reloc_symindex (uint64_t reloc_info)
+{
+ return is_32bit_elf ? ELF32_R_SYM (reloc_info) : ELF64_R_SYM (reloc_info);
+}
+
+static inline bool
+uses_msp430x_relocs (Filedata * filedata)
+{
+ return
+ filedata->file_header.e_machine == EM_MSP430 /* Paranoia. */
+ /* GCC uses osabi == ELFOSBI_STANDALONE. */
+ && (((filedata->file_header.e_flags & EF_MSP430_MACH) == E_MSP430_MACH_MSP430X)
+ /* TI compiler uses ELFOSABI_NONE. */
+ || (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_NONE));
+}
+
+/* Display the contents of the relocation data found at the specified
+ offset. */
+
+static bool
+dump_relocations (Filedata *filedata,
+ uint64_t rel_offset,
+ uint64_t rel_size,
+ Elf_Internal_Sym *symtab,
+ uint64_t nsyms,
+ char *strtab,
+ uint64_t strtablen,
+ relocation_type rel_type,
+ bool is_dynsym)
+{
+ size_t i;
+ Elf_Internal_Rela * rels;
+ bool res = true;
+
+ if (rel_type == reltype_unknown)
+ rel_type = guess_is_rela (filedata->file_header.e_machine) ? reltype_rela : reltype_rel;
+
+ if (rel_type == reltype_rela)
+ {
+ if (!slurp_rela_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
+ return false;
+ }
+ else if (rel_type == reltype_rel)
+ {
+ if (!slurp_rel_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
+ return false;
+ }
+ else if (rel_type == reltype_relr)
+ {
+ uint64_t * relrs;
+ const char *format
+ = is_32bit_elf ? "%08" PRIx64 "\n" : "%016" PRIx64 "\n";
+
+ if (!slurp_relr_relocs (filedata, rel_offset, rel_size, &relrs,
+ &rel_size))
+ return false;
+
+ printf (ngettext (" %" PRIu64 " offset\n",
+ " %" PRIu64 " offsets\n", rel_size),
+ rel_size);
+ for (i = 0; i < rel_size; i++)
+ printf (format, relrs[i]);
+ free (relrs);
+ return true;
+ }
+
+ if (is_32bit_elf)
+ {
+ if (rel_type == reltype_rela)
+ {
+ if (do_wide)
+ printf (_(" Offset Info Type Sym. Value Symbol's Name + Addend\n"));
+ else
+ printf (_(" Offset Info Type Sym.Value Sym. Name + Addend\n"));
+ }
+ else
+ {
+ if (do_wide)
+ printf (_(" Offset Info Type Sym. Value Symbol's Name\n"));
+ else
+ printf (_(" Offset Info Type Sym.Value Sym. Name\n"));
+ }
+ }
+ else
+ {
+ if (rel_type == reltype_rela)
+ {
+ if (do_wide)
+ printf (_(" Offset Info Type Symbol's Value Symbol's Name + Addend\n"));
+ else
+ printf (_(" Offset Info Type Sym. Value Sym. Name + Addend\n"));
+ }
+ else
+ {
+ if (do_wide)
+ printf (_(" Offset Info Type Symbol's Value Symbol's Name\n"));
+ else
+ printf (_(" Offset Info Type Sym. Value Sym. Name\n"));
+ }
+ }
+
+ for (i = 0; i < rel_size; i++)
+ {
+ const char * rtype;
+ uint64_t offset;
+ uint64_t inf;
+ uint64_t symtab_index;
+ uint64_t type;
+
+ offset = rels[i].r_offset;
+ inf = rels[i].r_info;
+
+ type = get_reloc_type (filedata, inf);
+ symtab_index = get_reloc_symindex (inf);
+
+ if (is_32bit_elf)
+ {
+ printf ("%8.8lx %8.8lx ",
+ (unsigned long) offset & 0xffffffff,
+ (unsigned long) inf & 0xffffffff);
+ }
+ else
+ {
+ printf (do_wide
+ ? "%16.16" PRIx64 " %16.16" PRIx64 " "
+ : "%12.12" PRIx64 " %12.12" PRIx64 " ",
+ offset, inf);
+ }
+
+ switch (filedata->file_header.e_machine)
+ {
+ default:
+ rtype = NULL;
+ break;
+
+ case EM_AARCH64:
+ rtype = elf_aarch64_reloc_type (type);
+ break;
+
+ case EM_M32R:
+ case EM_CYGNUS_M32R:
+ rtype = elf_m32r_reloc_type (type);
+ break;
+
+ case EM_386:
+ case EM_IAMCU:
+ rtype = elf_i386_reloc_type (type);
+ break;
+
+ case EM_68HC11:
+ case EM_68HC12:
+ rtype = elf_m68hc11_reloc_type (type);
+ break;
+
+ case EM_S12Z:
+ rtype = elf_s12z_reloc_type (type);
+ break;
+
+ case EM_68K:
+ rtype = elf_m68k_reloc_type (type);
+ break;
+
+ case EM_960:
+ rtype = elf_i960_reloc_type (type);
+ break;
+
+ case EM_AVR:
+ case EM_AVR_OLD:
+ rtype = elf_avr_reloc_type (type);
+ break;
+
+ case EM_OLD_SPARCV9:
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ case EM_SPARC:
+ rtype = elf_sparc_reloc_type (type);
+ break;
+
+ case EM_SPU:
+ rtype = elf_spu_reloc_type (type);
+ break;
+
+ case EM_V800:
+ rtype = v800_reloc_type (type);
+ break;
+ case EM_V850:
+ case EM_CYGNUS_V850:
+ rtype = v850_reloc_type (type);
+ break;
+
+ case EM_D10V:
+ case EM_CYGNUS_D10V:
+ rtype = elf_d10v_reloc_type (type);
+ break;
+
+ case EM_D30V:
+ case EM_CYGNUS_D30V:
+ rtype = elf_d30v_reloc_type (type);
+ break;
+
+ case EM_DLX:
+ rtype = elf_dlx_reloc_type (type);
+ break;
+
+ case EM_SH:
+ rtype = elf_sh_reloc_type (type);
+ break;
+
+ case EM_MN10300:
+ case EM_CYGNUS_MN10300:
+ rtype = elf_mn10300_reloc_type (type);
+ break;
+
+ case EM_MN10200:
+ case EM_CYGNUS_MN10200:
+ rtype = elf_mn10200_reloc_type (type);
+ break;
+
+ case EM_FR30:
+ case EM_CYGNUS_FR30:
+ rtype = elf_fr30_reloc_type (type);
+ break;
+
+ case EM_CYGNUS_FRV:
+ rtype = elf_frv_reloc_type (type);
+ break;
+
+ case EM_CSKY:
+ rtype = elf_csky_reloc_type (type);
+ break;
+
+ case EM_FT32:
+ rtype = elf_ft32_reloc_type (type);
+ break;
+
+ case EM_MCORE:
+ rtype = elf_mcore_reloc_type (type);
+ break;
+
+ case EM_MMIX:
+ rtype = elf_mmix_reloc_type (type);
+ break;
+
+ case EM_MOXIE:
+ rtype = elf_moxie_reloc_type (type);
+ break;
+
+ case EM_MSP430:
+ if (uses_msp430x_relocs (filedata))
+ {
+ rtype = elf_msp430x_reloc_type (type);
+ break;
+ }
+ /* Fall through. */
+ case EM_MSP430_OLD:
+ rtype = elf_msp430_reloc_type (type);
+ break;
+
+ case EM_NDS32:
+ rtype = elf_nds32_reloc_type (type);
+ break;
+
+ case EM_PPC:
+ rtype = elf_ppc_reloc_type (type);
+ break;
+
+ case EM_PPC64:
+ rtype = elf_ppc64_reloc_type (type);
+ break;
+
+ case EM_MIPS:
+ case EM_MIPS_RS3_LE:
+ rtype = elf_mips_reloc_type (type);
+ break;
+
+ case EM_RISCV:
+ rtype = elf_riscv_reloc_type (type);
+ break;
+
+ case EM_ALPHA:
+ rtype = elf_alpha_reloc_type (type);
+ break;
+
+ case EM_ARM:
+ rtype = elf_arm_reloc_type (type);
+ break;
+
+ case EM_ARC:
+ case EM_ARC_COMPACT:
+ case EM_ARC_COMPACT2:
+ rtype = elf_arc_reloc_type (type);
+ break;
+
+ case EM_PARISC:
+ rtype = elf_hppa_reloc_type (type);
+ break;
+
+ case EM_H8_300:
+ case EM_H8_300H:
+ case EM_H8S:
+ rtype = elf_h8_reloc_type (type);
+ break;
+
+ case EM_OR1K:
+ rtype = elf_or1k_reloc_type (type);
+ break;
+
+ case EM_PJ:
+ case EM_PJ_OLD:
+ rtype = elf_pj_reloc_type (type);
+ break;
+ case EM_IA_64:
+ rtype = elf_ia64_reloc_type (type);
+ break;
+
+ case EM_CRIS:
+ rtype = elf_cris_reloc_type (type);
+ break;
+
+ case EM_860:
+ rtype = elf_i860_reloc_type (type);
+ break;
+
+ case EM_X86_64:
+ case EM_L1OM:
+ case EM_K1OM:
+ rtype = elf_x86_64_reloc_type (type);
+ break;
+
+ case EM_S370:
+ rtype = i370_reloc_type (type);
+ break;
+
+ case EM_S390_OLD:
+ case EM_S390:
+ rtype = elf_s390_reloc_type (type);
+ break;
+
+ case EM_SCORE:
+ rtype = elf_score_reloc_type (type);
+ break;
+
+ case EM_XSTORMY16:
+ rtype = elf_xstormy16_reloc_type (type);
+ break;
+
+ case EM_CRX:
+ rtype = elf_crx_reloc_type (type);
+ break;
+
+ case EM_VAX:
+ rtype = elf_vax_reloc_type (type);
+ break;
+
+ case EM_VISIUM:
+ rtype = elf_visium_reloc_type (type);
+ break;
+
+ case EM_BPF:
+ rtype = elf_bpf_reloc_type (type);
+ break;
+
+ case EM_ADAPTEVA_EPIPHANY:
+ rtype = elf_epiphany_reloc_type (type);
+ break;
+
+ case EM_IP2K:
+ case EM_IP2K_OLD:
+ rtype = elf_ip2k_reloc_type (type);
+ break;
+
+ case EM_IQ2000:
+ rtype = elf_iq2000_reloc_type (type);
+ break;
+
+ case EM_XTENSA_OLD:
+ case EM_XTENSA:
+ rtype = elf_xtensa_reloc_type (type);
+ break;
+
+ case EM_LATTICEMICO32:
+ rtype = elf_lm32_reloc_type (type);
+ break;
+
+ case EM_M32C_OLD:
+ case EM_M32C:
+ rtype = elf_m32c_reloc_type (type);
+ break;
+
+ case EM_MT:
+ rtype = elf_mt_reloc_type (type);
+ break;
+
+ case EM_BLACKFIN:
+ rtype = elf_bfin_reloc_type (type);
+ break;
+
+ case EM_CYGNUS_MEP:
+ rtype = elf_mep_reloc_type (type);
+ break;
+
+ case EM_CR16:
+ rtype = elf_cr16_reloc_type (type);
+ break;
+
+ case EM_MICROBLAZE:
+ case EM_MICROBLAZE_OLD:
+ rtype = elf_microblaze_reloc_type (type);
+ break;
+
+ case EM_RL78:
+ rtype = elf_rl78_reloc_type (type);
+ break;
+
+ case EM_RX:
+ rtype = elf_rx_reloc_type (type);
+ break;
+
+ case EM_METAG:
+ rtype = elf_metag_reloc_type (type);
+ break;
+
+ case EM_TI_C6000:
+ rtype = elf_tic6x_reloc_type (type);
+ break;
+
+ case EM_TILEGX:
+ rtype = elf_tilegx_reloc_type (type);
+ break;
+
+ case EM_TILEPRO:
+ rtype = elf_tilepro_reloc_type (type);
+ break;
+
+ case EM_WEBASSEMBLY:
+ rtype = elf_wasm32_reloc_type (type);
+ break;
+
+ case EM_XGATE:
+ rtype = elf_xgate_reloc_type (type);
+ break;
+
+ case EM_ALTERA_NIOS2:
+ rtype = elf_nios2_reloc_type (type);
+ break;
+
+ case EM_TI_PRU:
+ rtype = elf_pru_reloc_type (type);
+ break;
+
+ case EM_NFP:
+ if (EF_NFP_MACH (filedata->file_header.e_flags) == E_NFP_MACH_3200)
+ rtype = elf_nfp3200_reloc_type (type);
+ else
+ rtype = elf_nfp_reloc_type (type);
+ break;
+
+ case EM_Z80:
+ rtype = elf_z80_reloc_type (type);
+ break;
+
+ case EM_LOONGARCH:
+ rtype = elf_loongarch_reloc_type (type);
+ break;
+
+ case EM_AMDGPU:
+ rtype = elf_amdgpu_reloc_type (type);
+ break;
+ }
+
+ if (rtype == NULL)
+ printf (_("unrecognized: %-7lx"), (unsigned long) type & 0xffffffff);
+ else
+ printf (do_wide ? "%-22s" : "%-17.17s", rtype);
+
+ if (filedata->file_header.e_machine == EM_ALPHA
+ && rtype != NULL
+ && streq (rtype, "R_ALPHA_LITUSE")
+ && rel_type == reltype_rela)
+ {
+ switch (rels[i].r_addend)
+ {
+ case LITUSE_ALPHA_ADDR: rtype = "ADDR"; break;
+ case LITUSE_ALPHA_BASE: rtype = "BASE"; break;
+ case LITUSE_ALPHA_BYTOFF: rtype = "BYTOFF"; break;
+ case LITUSE_ALPHA_JSR: rtype = "JSR"; break;
+ case LITUSE_ALPHA_TLSGD: rtype = "TLSGD"; break;
+ case LITUSE_ALPHA_TLSLDM: rtype = "TLSLDM"; break;
+ case LITUSE_ALPHA_JSRDIRECT: rtype = "JSRDIRECT"; break;
+ default: rtype = NULL;
+ }
+
+ if (rtype)
+ printf (" (%s)", rtype);
+ else
+ {
+ putchar (' ');
+ printf (_("<unknown addend: %" PRIx64 ">"),
+ rels[i].r_addend);
+ res = false;
+ }
+ }
+ else if (symtab_index)
+ {
+ if (symtab == NULL || symtab_index >= nsyms)
+ {
+ error (_(" bad symbol index: %08lx in reloc\n"),
+ (unsigned long) symtab_index);
+ res = false;
+ }
+ else
+ {
+ Elf_Internal_Sym * psym;
+ const char * version_string;
+ enum versioned_symbol_info sym_info;
+ unsigned short vna_other;
+
+ psym = symtab + symtab_index;
+
+ version_string
+ = get_symbol_version_string (filedata, is_dynsym,
+ strtab, strtablen,
+ symtab_index,
+ psym,
+ &sym_info,
+ &vna_other);
+
+ printf (" ");
+
+ if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC)
+ {
+ const char * name;
+ unsigned int len;
+ unsigned int width = is_32bit_elf ? 8 : 14;
+
+ /* Relocations against GNU_IFUNC symbols do not use the value
+ of the symbol as the address to relocate against. Instead
+ they invoke the function named by the symbol and use its
+ result as the address for relocation.
+
+ To indicate this to the user, do not display the value of
+ the symbol in the "Symbols's Value" field. Instead show
+ its name followed by () as a hint that the symbol is
+ invoked. */
+
+ if (strtab == NULL
+ || psym->st_name == 0
+ || psym->st_name >= strtablen)
+ name = "??";
+ else
+ name = strtab + psym->st_name;
+
+ len = print_symbol (width, name);
+ if (version_string)
+ printf (sym_info == symbol_public ? "@@%s" : "@%s",
+ version_string);
+ printf ("()%-*s", len <= width ? (width + 1) - len : 1, " ");
+ }
+ else
+ {
+ print_vma (psym->st_value, LONG_HEX);
+
+ printf (is_32bit_elf ? " " : " ");
+ }
+
+ if (psym->st_name == 0)
+ {
+ const char * sec_name = "<null>";
+ char name_buf[40];
+
+ if (ELF_ST_TYPE (psym->st_info) == STT_SECTION)
+ {
+ if (psym->st_shndx < filedata->file_header.e_shnum
+ && filedata->section_headers != NULL)
+ sec_name = section_name_print (filedata,
+ filedata->section_headers
+ + psym->st_shndx);
+ else if (psym->st_shndx == SHN_ABS)
+ sec_name = "ABS";
+ else if (psym->st_shndx == SHN_COMMON)
+ sec_name = "COMMON";
+ else if ((filedata->file_header.e_machine == EM_MIPS
+ && psym->st_shndx == SHN_MIPS_SCOMMON)
+ || (filedata->file_header.e_machine == EM_TI_C6000
+ && psym->st_shndx == SHN_TIC6X_SCOMMON))
+ sec_name = "SCOMMON";
+ else if (filedata->file_header.e_machine == EM_MIPS
+ && psym->st_shndx == SHN_MIPS_SUNDEFINED)
+ sec_name = "SUNDEF";
+ else if ((filedata->file_header.e_machine == EM_X86_64
+ || filedata->file_header.e_machine == EM_L1OM
+ || filedata->file_header.e_machine == EM_K1OM)
+ && psym->st_shndx == SHN_X86_64_LCOMMON)
+ sec_name = "LARGE_COMMON";
+ else if (filedata->file_header.e_machine == EM_IA_64
+ && filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_HPUX
+ && psym->st_shndx == SHN_IA_64_ANSI_COMMON)
+ sec_name = "ANSI_COM";
+ else if (is_ia64_vms (filedata)
+ && psym->st_shndx == SHN_IA_64_VMS_SYMVEC)
+ sec_name = "VMS_SYMVEC";
+ else
+ {
+ sprintf (name_buf, "<section 0x%x>",
+ (unsigned int) psym->st_shndx);
+ sec_name = name_buf;
+ }
+ }
+ print_symbol (22, sec_name);
+ }
+ else if (strtab == NULL)
+ printf (_("<string table index: %3ld>"), psym->st_name);
+ else if (psym->st_name >= strtablen)
+ {
+ error (_("<corrupt string table index: %3ld>\n"),
+ psym->st_name);
+ res = false;
+ }
+ else
+ {
+ print_symbol (22, strtab + psym->st_name);
+ if (version_string)
+ printf (sym_info == symbol_public ? "@@%s" : "@%s",
+ version_string);
+ }
+
+ if (rel_type == reltype_rela)
+ {
+ uint64_t off = rels[i].r_addend;
+
+ if ((int64_t) off < 0)
+ printf (" - %" PRIx64, -off);
+ else
+ printf (" + %" PRIx64, off);
+ }
+ }
+ }
+ else if (rel_type == reltype_rela)
+ {
+ uint64_t off = rels[i].r_addend;
+
+ printf ("%*c", is_32bit_elf ? 12 : 20, ' ');
+ if ((int64_t) off < 0)
+ printf ("-%" PRIx64, -off);
+ else
+ printf ("%" PRIx64, off);
+ }
+
+ if (filedata->file_header.e_machine == EM_SPARCV9
+ && rtype != NULL
+ && streq (rtype, "R_SPARC_OLO10"))
+ printf (" + %" PRIx64, ELF64_R_TYPE_DATA (inf));
+
+ putchar ('\n');
+
+ if (! is_32bit_elf && filedata->file_header.e_machine == EM_MIPS)
+ {
+ uint64_t type2 = ELF64_MIPS_R_TYPE2 (inf);
+ uint64_t type3 = ELF64_MIPS_R_TYPE3 (inf);
+ const char * rtype2 = elf_mips_reloc_type (type2);
+ const char * rtype3 = elf_mips_reloc_type (type3);
+
+ printf (" Type2: ");
+
+ if (rtype2 == NULL)
+ printf (_("unrecognized: %-7lx"),
+ (unsigned long) type2 & 0xffffffff);
+ else
+ printf ("%-17.17s", rtype2);
+
+ printf ("\n Type3: ");
+
+ if (rtype3 == NULL)
+ printf (_("unrecognized: %-7lx"),
+ (unsigned long) type3 & 0xffffffff);
+ else
+ printf ("%-17.17s", rtype3);
+
+ putchar ('\n');
+ }
+ }
+
+ free (rels);
+
+ return res;
+}
+
+static const char *
+get_aarch64_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_AARCH64_BTI_PLT: return "AARCH64_BTI_PLT";
+ case DT_AARCH64_PAC_PLT: return "AARCH64_PAC_PLT";
+ case DT_AARCH64_VARIANT_PCS: return "AARCH64_VARIANT_PCS";
+ default:
+ return NULL;
+ }
+}
+
+static const char *
+get_mips_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_MIPS_RLD_VERSION: return "MIPS_RLD_VERSION";
+ case DT_MIPS_TIME_STAMP: return "MIPS_TIME_STAMP";
+ case DT_MIPS_ICHECKSUM: return "MIPS_ICHECKSUM";
+ case DT_MIPS_IVERSION: return "MIPS_IVERSION";
+ case DT_MIPS_FLAGS: return "MIPS_FLAGS";
+ case DT_MIPS_BASE_ADDRESS: return "MIPS_BASE_ADDRESS";
+ case DT_MIPS_MSYM: return "MIPS_MSYM";
+ case DT_MIPS_CONFLICT: return "MIPS_CONFLICT";
+ case DT_MIPS_LIBLIST: return "MIPS_LIBLIST";
+ case DT_MIPS_LOCAL_GOTNO: return "MIPS_LOCAL_GOTNO";
+ case DT_MIPS_CONFLICTNO: return "MIPS_CONFLICTNO";
+ case DT_MIPS_LIBLISTNO: return "MIPS_LIBLISTNO";
+ case DT_MIPS_SYMTABNO: return "MIPS_SYMTABNO";
+ case DT_MIPS_UNREFEXTNO: return "MIPS_UNREFEXTNO";
+ case DT_MIPS_GOTSYM: return "MIPS_GOTSYM";
+ case DT_MIPS_HIPAGENO: return "MIPS_HIPAGENO";
+ case DT_MIPS_RLD_MAP: return "MIPS_RLD_MAP";
+ case DT_MIPS_RLD_MAP_REL: return "MIPS_RLD_MAP_REL";
+ case DT_MIPS_DELTA_CLASS: return "MIPS_DELTA_CLASS";
+ case DT_MIPS_DELTA_CLASS_NO: return "MIPS_DELTA_CLASS_NO";
+ case DT_MIPS_DELTA_INSTANCE: return "MIPS_DELTA_INSTANCE";
+ case DT_MIPS_DELTA_INSTANCE_NO: return "MIPS_DELTA_INSTANCE_NO";
+ case DT_MIPS_DELTA_RELOC: return "MIPS_DELTA_RELOC";
+ case DT_MIPS_DELTA_RELOC_NO: return "MIPS_DELTA_RELOC_NO";
+ case DT_MIPS_DELTA_SYM: return "MIPS_DELTA_SYM";
+ case DT_MIPS_DELTA_SYM_NO: return "MIPS_DELTA_SYM_NO";
+ case DT_MIPS_DELTA_CLASSSYM: return "MIPS_DELTA_CLASSSYM";
+ case DT_MIPS_DELTA_CLASSSYM_NO: return "MIPS_DELTA_CLASSSYM_NO";
+ case DT_MIPS_CXX_FLAGS: return "MIPS_CXX_FLAGS";
+ case DT_MIPS_PIXIE_INIT: return "MIPS_PIXIE_INIT";
+ case DT_MIPS_SYMBOL_LIB: return "MIPS_SYMBOL_LIB";
+ case DT_MIPS_LOCALPAGE_GOTIDX: return "MIPS_LOCALPAGE_GOTIDX";
+ case DT_MIPS_LOCAL_GOTIDX: return "MIPS_LOCAL_GOTIDX";
+ case DT_MIPS_HIDDEN_GOTIDX: return "MIPS_HIDDEN_GOTIDX";
+ case DT_MIPS_PROTECTED_GOTIDX: return "MIPS_PROTECTED_GOTIDX";
+ case DT_MIPS_OPTIONS: return "MIPS_OPTIONS";
+ case DT_MIPS_INTERFACE: return "MIPS_INTERFACE";
+ case DT_MIPS_DYNSTR_ALIGN: return "MIPS_DYNSTR_ALIGN";
+ case DT_MIPS_INTERFACE_SIZE: return "MIPS_INTERFACE_SIZE";
+ case DT_MIPS_RLD_TEXT_RESOLVE_ADDR: return "MIPS_RLD_TEXT_RESOLVE_ADDR";
+ case DT_MIPS_PERF_SUFFIX: return "MIPS_PERF_SUFFIX";
+ case DT_MIPS_COMPACT_SIZE: return "MIPS_COMPACT_SIZE";
+ case DT_MIPS_GP_VALUE: return "MIPS_GP_VALUE";
+ case DT_MIPS_AUX_DYNAMIC: return "MIPS_AUX_DYNAMIC";
+ case DT_MIPS_PLTGOT: return "MIPS_PLTGOT";
+ case DT_MIPS_RWPLT: return "MIPS_RWPLT";
+ case DT_MIPS_XHASH: return "MIPS_XHASH";
+ default:
+ return NULL;
+ }
+}
+
+static const char *
+get_sparc64_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_SPARC_REGISTER: return "SPARC_REGISTER";
+ default:
+ return NULL;
+ }
+}
+
+static const char *
+get_ppc_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_PPC_GOT: return "PPC_GOT";
+ case DT_PPC_OPT: return "PPC_OPT";
+ default:
+ return NULL;
+ }
+}
+
+static const char *
+get_ppc64_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_PPC64_GLINK: return "PPC64_GLINK";
+ case DT_PPC64_OPD: return "PPC64_OPD";
+ case DT_PPC64_OPDSZ: return "PPC64_OPDSZ";
+ case DT_PPC64_OPT: return "PPC64_OPT";
+ default:
+ return NULL;
+ }
+}
+
+static const char *
+get_parisc_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_HP_LOAD_MAP: return "HP_LOAD_MAP";
+ case DT_HP_DLD_FLAGS: return "HP_DLD_FLAGS";
+ case DT_HP_DLD_HOOK: return "HP_DLD_HOOK";
+ case DT_HP_UX10_INIT: return "HP_UX10_INIT";
+ case DT_HP_UX10_INITSZ: return "HP_UX10_INITSZ";
+ case DT_HP_PREINIT: return "HP_PREINIT";
+ case DT_HP_PREINITSZ: return "HP_PREINITSZ";
+ case DT_HP_NEEDED: return "HP_NEEDED";
+ case DT_HP_TIME_STAMP: return "HP_TIME_STAMP";
+ case DT_HP_CHECKSUM: return "HP_CHECKSUM";
+ case DT_HP_GST_SIZE: return "HP_GST_SIZE";
+ case DT_HP_GST_VERSION: return "HP_GST_VERSION";
+ case DT_HP_GST_HASHVAL: return "HP_GST_HASHVAL";
+ case DT_HP_EPLTREL: return "HP_GST_EPLTREL";
+ case DT_HP_EPLTRELSZ: return "HP_GST_EPLTRELSZ";
+ case DT_HP_FILTERED: return "HP_FILTERED";
+ case DT_HP_FILTER_TLS: return "HP_FILTER_TLS";
+ case DT_HP_COMPAT_FILTERED: return "HP_COMPAT_FILTERED";
+ case DT_HP_LAZYLOAD: return "HP_LAZYLOAD";
+ case DT_HP_BIND_NOW_COUNT: return "HP_BIND_NOW_COUNT";
+ case DT_PLT: return "PLT";
+ case DT_PLT_SIZE: return "PLT_SIZE";
+ case DT_DLT: return "DLT";
+ case DT_DLT_SIZE: return "DLT_SIZE";
+ default:
+ return NULL;
+ }
+}
+
+static const char *
+get_ia64_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_IA_64_PLT_RESERVE: return "IA_64_PLT_RESERVE";
+ case DT_IA_64_VMS_SUBTYPE: return "VMS_SUBTYPE";
+ case DT_IA_64_VMS_IMGIOCNT: return "VMS_IMGIOCNT";
+ case DT_IA_64_VMS_LNKFLAGS: return "VMS_LNKFLAGS";
+ case DT_IA_64_VMS_VIR_MEM_BLK_SIZ: return "VMS_VIR_MEM_BLK_SIZ";
+ case DT_IA_64_VMS_IDENT: return "VMS_IDENT";
+ case DT_IA_64_VMS_NEEDED_IDENT: return "VMS_NEEDED_IDENT";
+ case DT_IA_64_VMS_IMG_RELA_CNT: return "VMS_IMG_RELA_CNT";
+ case DT_IA_64_VMS_SEG_RELA_CNT: return "VMS_SEG_RELA_CNT";
+ case DT_IA_64_VMS_FIXUP_RELA_CNT: return "VMS_FIXUP_RELA_CNT";
+ case DT_IA_64_VMS_FIXUP_NEEDED: return "VMS_FIXUP_NEEDED";
+ case DT_IA_64_VMS_SYMVEC_CNT: return "VMS_SYMVEC_CNT";
+ case DT_IA_64_VMS_XLATED: return "VMS_XLATED";
+ case DT_IA_64_VMS_STACKSIZE: return "VMS_STACKSIZE";
+ case DT_IA_64_VMS_UNWINDSZ: return "VMS_UNWINDSZ";
+ case DT_IA_64_VMS_UNWIND_CODSEG: return "VMS_UNWIND_CODSEG";
+ case DT_IA_64_VMS_UNWIND_INFOSEG: return "VMS_UNWIND_INFOSEG";
+ case DT_IA_64_VMS_LINKTIME: return "VMS_LINKTIME";
+ case DT_IA_64_VMS_SEG_NO: return "VMS_SEG_NO";
+ case DT_IA_64_VMS_SYMVEC_OFFSET: return "VMS_SYMVEC_OFFSET";
+ case DT_IA_64_VMS_SYMVEC_SEG: return "VMS_SYMVEC_SEG";
+ case DT_IA_64_VMS_UNWIND_OFFSET: return "VMS_UNWIND_OFFSET";
+ case DT_IA_64_VMS_UNWIND_SEG: return "VMS_UNWIND_SEG";
+ case DT_IA_64_VMS_STRTAB_OFFSET: return "VMS_STRTAB_OFFSET";
+ case DT_IA_64_VMS_SYSVER_OFFSET: return "VMS_SYSVER_OFFSET";
+ case DT_IA_64_VMS_IMG_RELA_OFF: return "VMS_IMG_RELA_OFF";
+ case DT_IA_64_VMS_SEG_RELA_OFF: return "VMS_SEG_RELA_OFF";
+ case DT_IA_64_VMS_FIXUP_RELA_OFF: return "VMS_FIXUP_RELA_OFF";
+ case DT_IA_64_VMS_PLTGOT_OFFSET: return "VMS_PLTGOT_OFFSET";
+ case DT_IA_64_VMS_PLTGOT_SEG: return "VMS_PLTGOT_SEG";
+ case DT_IA_64_VMS_FPMODE: return "VMS_FPMODE";
+ default:
+ return NULL;
+ }
+}
+
+static const char *
+get_solaris_section_type (unsigned long type)
+{
+ switch (type)
+ {
+ case 0x6fffffee: return "SUNW_ancillary";
+ case 0x6fffffef: return "SUNW_capchain";
+ case 0x6ffffff0: return "SUNW_capinfo";
+ case 0x6ffffff1: return "SUNW_symsort";
+ case 0x6ffffff2: return "SUNW_tlssort";
+ case 0x6ffffff3: return "SUNW_LDYNSYM";
+ case 0x6ffffff4: return "SUNW_dof";
+ case 0x6ffffff5: return "SUNW_cap";
+ case 0x6ffffff6: return "SUNW_SIGNATURE";
+ case 0x6ffffff7: return "SUNW_ANNOTATE";
+ case 0x6ffffff8: return "SUNW_DEBUGSTR";
+ case 0x6ffffff9: return "SUNW_DEBUG";
+ case 0x6ffffffa: return "SUNW_move";
+ case 0x6ffffffb: return "SUNW_COMDAT";
+ case 0x6ffffffc: return "SUNW_syminfo";
+ case 0x6ffffffd: return "SUNW_verdef";
+ case 0x6ffffffe: return "SUNW_verneed";
+ case 0x6fffffff: return "SUNW_versym";
+ case 0x70000000: return "SPARC_GOTDATA";
+ default: return NULL;
+ }
+}
+
+static const char *
+get_alpha_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_ALPHA_PLTRO: return "ALPHA_PLTRO";
+ default: return NULL;
+ }
+}
+
+static const char *
+get_score_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_SCORE_BASE_ADDRESS: return "SCORE_BASE_ADDRESS";
+ case DT_SCORE_LOCAL_GOTNO: return "SCORE_LOCAL_GOTNO";
+ case DT_SCORE_SYMTABNO: return "SCORE_SYMTABNO";
+ case DT_SCORE_GOTSYM: return "SCORE_GOTSYM";
+ case DT_SCORE_UNREFEXTNO: return "SCORE_UNREFEXTNO";
+ case DT_SCORE_HIPAGENO: return "SCORE_HIPAGENO";
+ default: return NULL;
+ }
+}
+
+static const char *
+get_tic6x_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_C6000_GSYM_OFFSET: return "C6000_GSYM_OFFSET";
+ case DT_C6000_GSTR_OFFSET: return "C6000_GSTR_OFFSET";
+ case DT_C6000_DSBT_BASE: return "C6000_DSBT_BASE";
+ case DT_C6000_DSBT_SIZE: return "C6000_DSBT_SIZE";
+ case DT_C6000_PREEMPTMAP: return "C6000_PREEMPTMAP";
+ case DT_C6000_DSBT_INDEX: return "C6000_DSBT_INDEX";
+ default: return NULL;
+ }
+}
+
+static const char *
+get_nios2_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_NIOS2_GP: return "NIOS2_GP";
+ default: return NULL;
+ }
+}
+
+static const char *
+get_solaris_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case 0x6000000d: return "SUNW_AUXILIARY";
+ case 0x6000000e: return "SUNW_RTLDINF";
+ case 0x6000000f: return "SUNW_FILTER";
+ case 0x60000010: return "SUNW_CAP";
+ case 0x60000011: return "SUNW_SYMTAB";
+ case 0x60000012: return "SUNW_SYMSZ";
+ case 0x60000013: return "SUNW_SORTENT";
+ case 0x60000014: return "SUNW_SYMSORT";
+ case 0x60000015: return "SUNW_SYMSORTSZ";
+ case 0x60000016: return "SUNW_TLSSORT";
+ case 0x60000017: return "SUNW_TLSSORTSZ";
+ case 0x60000018: return "SUNW_CAPINFO";
+ case 0x60000019: return "SUNW_STRPAD";
+ case 0x6000001a: return "SUNW_CAPCHAIN";
+ case 0x6000001b: return "SUNW_LDMACH";
+ case 0x6000001d: return "SUNW_CAPCHAINENT";
+ case 0x6000001f: return "SUNW_CAPCHAINSZ";
+ case 0x60000021: return "SUNW_PARENT";
+ case 0x60000023: return "SUNW_ASLR";
+ case 0x60000025: return "SUNW_RELAX";
+ case 0x60000029: return "SUNW_NXHEAP";
+ case 0x6000002b: return "SUNW_NXSTACK";
+
+ case 0x70000001: return "SPARC_REGISTER";
+ case 0x7ffffffd: return "AUXILIARY";
+ case 0x7ffffffe: return "USED";
+ case 0x7fffffff: return "FILTER";
+
+ default: return NULL;
+ }
+}
+
+static const char *
+get_riscv_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_RISCV_VARIANT_CC: return "RISCV_VARIANT_CC";
+ default:
+ return NULL;
+ }
+}
+
+static const char *
+get_dynamic_type (Filedata * filedata, unsigned long type)
+{
+ static char buff[64];
+
+ switch (type)
+ {
+ case DT_NULL: return "NULL";
+ case DT_NEEDED: return "NEEDED";
+ case DT_PLTRELSZ: return "PLTRELSZ";
+ case DT_PLTGOT: return "PLTGOT";
+ case DT_HASH: return "HASH";
+ case DT_STRTAB: return "STRTAB";
+ case DT_SYMTAB: return "SYMTAB";
+ case DT_RELA: return "RELA";
+ case DT_RELASZ: return "RELASZ";
+ case DT_RELAENT: return "RELAENT";
+ case DT_STRSZ: return "STRSZ";
+ case DT_SYMENT: return "SYMENT";
+ case DT_INIT: return "INIT";
+ case DT_FINI: return "FINI";
+ case DT_SONAME: return "SONAME";
+ case DT_RPATH: return "RPATH";
+ case DT_SYMBOLIC: return "SYMBOLIC";
+ case DT_REL: return "REL";
+ case DT_RELSZ: return "RELSZ";
+ case DT_RELENT: return "RELENT";
+ case DT_RELR: return "RELR";
+ case DT_RELRSZ: return "RELRSZ";
+ case DT_RELRENT: return "RELRENT";
+ case DT_PLTREL: return "PLTREL";
+ case DT_DEBUG: return "DEBUG";
+ case DT_TEXTREL: return "TEXTREL";
+ case DT_JMPREL: return "JMPREL";
+ case DT_BIND_NOW: return "BIND_NOW";
+ case DT_INIT_ARRAY: return "INIT_ARRAY";
+ case DT_FINI_ARRAY: return "FINI_ARRAY";
+ case DT_INIT_ARRAYSZ: return "INIT_ARRAYSZ";
+ case DT_FINI_ARRAYSZ: return "FINI_ARRAYSZ";
+ case DT_RUNPATH: return "RUNPATH";
+ case DT_FLAGS: return "FLAGS";
+
+ case DT_PREINIT_ARRAY: return "PREINIT_ARRAY";
+ case DT_PREINIT_ARRAYSZ: return "PREINIT_ARRAYSZ";
+ case DT_SYMTAB_SHNDX: return "SYMTAB_SHNDX";
+
+ case DT_CHECKSUM: return "CHECKSUM";
+ case DT_PLTPADSZ: return "PLTPADSZ";
+ case DT_MOVEENT: return "MOVEENT";
+ case DT_MOVESZ: return "MOVESZ";
+ case DT_FEATURE: return "FEATURE";
+ case DT_POSFLAG_1: return "POSFLAG_1";
+ case DT_SYMINSZ: return "SYMINSZ";
+ case DT_SYMINENT: return "SYMINENT"; /* aka VALRNGHI */
+
+ case DT_ADDRRNGLO: return "ADDRRNGLO";
+ case DT_CONFIG: return "CONFIG";
+ case DT_DEPAUDIT: return "DEPAUDIT";
+ case DT_AUDIT: return "AUDIT";
+ case DT_PLTPAD: return "PLTPAD";
+ case DT_MOVETAB: return "MOVETAB";
+ case DT_SYMINFO: return "SYMINFO"; /* aka ADDRRNGHI */
+
+ case DT_VERSYM: return "VERSYM";
+
+ case DT_TLSDESC_GOT: return "TLSDESC_GOT";
+ case DT_TLSDESC_PLT: return "TLSDESC_PLT";
+ case DT_RELACOUNT: return "RELACOUNT";
+ case DT_RELCOUNT: return "RELCOUNT";
+ case DT_FLAGS_1: return "FLAGS_1";
+ case DT_VERDEF: return "VERDEF";
+ case DT_VERDEFNUM: return "VERDEFNUM";
+ case DT_VERNEED: return "VERNEED";
+ case DT_VERNEEDNUM: return "VERNEEDNUM";
+
+ case DT_AUXILIARY: return "AUXILIARY";
+ case DT_USED: return "USED";
+ case DT_FILTER: return "FILTER";
+
+ case DT_GNU_PRELINKED: return "GNU_PRELINKED";
+ case DT_GNU_CONFLICT: return "GNU_CONFLICT";
+ case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ";
+ case DT_GNU_LIBLIST: return "GNU_LIBLIST";
+ case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ";
+ case DT_GNU_HASH: return "GNU_HASH";
+ case DT_GNU_FLAGS_1: return "GNU_FLAGS_1";
+
+ default:
+ if ((type >= DT_LOPROC) && (type <= DT_HIPROC))
+ {
+ const char * result;
+
+ switch (filedata->file_header.e_machine)
+ {
+ case EM_AARCH64:
+ result = get_aarch64_dynamic_type (type);
+ break;
+ case EM_MIPS:
+ case EM_MIPS_RS3_LE:
+ result = get_mips_dynamic_type (type);
+ break;
+ case EM_SPARCV9:
+ result = get_sparc64_dynamic_type (type);
+ break;
+ case EM_PPC:
+ result = get_ppc_dynamic_type (type);
+ break;
+ case EM_PPC64:
+ result = get_ppc64_dynamic_type (type);
+ break;
+ case EM_IA_64:
+ result = get_ia64_dynamic_type (type);
+ break;
+ case EM_ALPHA:
+ result = get_alpha_dynamic_type (type);
+ break;
+ case EM_SCORE:
+ result = get_score_dynamic_type (type);
+ break;
+ case EM_TI_C6000:
+ result = get_tic6x_dynamic_type (type);
+ break;
+ case EM_ALTERA_NIOS2:
+ result = get_nios2_dynamic_type (type);
+ break;
+ case EM_RISCV:
+ result = get_riscv_dynamic_type (type);
+ break;
+ default:
+ if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
+ result = get_solaris_dynamic_type (type);
+ else
+ result = NULL;
+ break;
+ }
+
+ if (result != NULL)
+ return result;
+
+ snprintf (buff, sizeof (buff), _("Processor Specific: %lx"), type);
+ }
+ else if (((type >= DT_LOOS) && (type <= DT_HIOS))
+ || (filedata->file_header.e_machine == EM_PARISC
+ && (type >= OLD_DT_LOOS) && (type <= OLD_DT_HIOS)))
+ {
+ const char * result;
+
+ switch (filedata->file_header.e_machine)
+ {
+ case EM_PARISC:
+ result = get_parisc_dynamic_type (type);
+ break;
+ case EM_IA_64:
+ result = get_ia64_dynamic_type (type);
+ break;
+ default:
+ if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
+ result = get_solaris_dynamic_type (type);
+ else
+ result = NULL;
+ break;
+ }
+
+ if (result != NULL)
+ return result;
+
+ snprintf (buff, sizeof (buff), _("Operating System specific: %lx"),
+ type);
+ }
+ else
+ snprintf (buff, sizeof (buff), _("<unknown>: %lx"), type);
+
+ return buff;
+ }
+}
+
+static bool get_program_headers (Filedata *);
+static bool get_dynamic_section (Filedata *);
+
+static void
+locate_dynamic_section (Filedata *filedata)
+{
+ uint64_t dynamic_addr = 0;
+ uint64_t dynamic_size = 0;
+
+ if (filedata->file_header.e_phnum != 0
+ && get_program_headers (filedata))
+ {
+ Elf_Internal_Phdr *segment;
+ unsigned int i;
+
+ for (i = 0, segment = filedata->program_headers;
+ i < filedata->file_header.e_phnum;
+ i++, segment++)
+ {
+ if (segment->p_type == PT_DYNAMIC)
+ {
+ dynamic_addr = segment->p_offset;
+ dynamic_size = segment->p_filesz;
+
+ if (filedata->section_headers != NULL)
+ {
+ Elf_Internal_Shdr *sec;
+
+ sec = find_section (filedata, ".dynamic");
+ if (sec != NULL)
+ {
+ if (sec->sh_size == 0
+ || sec->sh_type == SHT_NOBITS)
+ {
+ dynamic_addr = 0;
+ dynamic_size = 0;
+ }
+ else
+ {
+ dynamic_addr = sec->sh_offset;
+ dynamic_size = sec->sh_size;
+ }
+ }
+ }
+
+ if (dynamic_addr > filedata->file_size
+ || (dynamic_size > filedata->file_size - dynamic_addr))
+ {
+ dynamic_addr = 0;
+ dynamic_size = 0;
+ }
+ break;
+ }
+ }
+ }
+ filedata->dynamic_addr = dynamic_addr;
+ filedata->dynamic_size = dynamic_size ? dynamic_size : 1;
+}
+
+static bool
+is_pie (Filedata *filedata)
+{
+ Elf_Internal_Dyn *entry;
+
+ if (filedata->dynamic_size == 0)
+ locate_dynamic_section (filedata);
+ if (filedata->dynamic_size <= 1)
+ return false;
+
+ if (!get_dynamic_section (filedata))
+ return false;
+
+ for (entry = filedata->dynamic_section;
+ entry < filedata->dynamic_section + filedata->dynamic_nent;
+ entry++)
+ {
+ if (entry->d_tag == DT_FLAGS_1)
+ {
+ if ((entry->d_un.d_val & DF_1_PIE) != 0)
+ return true;
+ break;
+ }
+ }
+ return false;
+}
+
+static char *
+get_file_type (Filedata *filedata)
+{
+ unsigned e_type = filedata->file_header.e_type;
+ static char buff[64];
+
+ switch (e_type)
+ {
+ case ET_NONE: return _("NONE (None)");
+ case ET_REL: return _("REL (Relocatable file)");
+ case ET_EXEC: return _("EXEC (Executable file)");
+ case ET_DYN:
+ if (is_pie (filedata))
+ return _("DYN (Position-Independent Executable file)");
+ else
+ return _("DYN (Shared object file)");
+ case ET_CORE: return _("CORE (Core file)");
+
+ default:
+ if ((e_type >= ET_LOPROC) && (e_type <= ET_HIPROC))
+ snprintf (buff, sizeof (buff), _("Processor Specific: (%x)"), e_type);
+ else if ((e_type >= ET_LOOS) && (e_type <= ET_HIOS))
+ snprintf (buff, sizeof (buff), _("OS Specific: (%x)"), e_type);
+ else
+ snprintf (buff, sizeof (buff), _("<unknown>: %x"), e_type);
+ return buff;
+ }
+}
+
+static char *
+get_machine_name (unsigned e_machine)
+{
+ static char buff[64]; /* XXX */
+
+ switch (e_machine)
+ {
+ /* Please keep this switch table sorted by increasing EM_ value. */
+ /* 0 */
+ case EM_NONE: return _("None");
+ case EM_M32: return "WE32100";
+ case EM_SPARC: return "Sparc";
+ case EM_386: return "Intel 80386";
+ case EM_68K: return "MC68000";
+ case EM_88K: return "MC88000";
+ case EM_IAMCU: return "Intel MCU";
+ case EM_860: return "Intel 80860";
+ case EM_MIPS: return "MIPS R3000";
+ case EM_S370: return "IBM System/370";
+ /* 10 */
+ case EM_MIPS_RS3_LE: return "MIPS R4000 big-endian";
+ case EM_OLD_SPARCV9: return "Sparc v9 (old)";
+ case EM_PARISC: return "HPPA";
+ case EM_VPP550: return "Fujitsu VPP500";
+ case EM_SPARC32PLUS: return "Sparc v8+" ;
+ case EM_960: return "Intel 80960";
+ case EM_PPC: return "PowerPC";
+ /* 20 */
+ case EM_PPC64: return "PowerPC64";
+ case EM_S390_OLD:
+ case EM_S390: return "IBM S/390";
+ case EM_SPU: return "SPU";
+ /* 30 */
+ case EM_V800: return "Renesas V850 (using RH850 ABI)";
+ case EM_FR20: return "Fujitsu FR20";
+ case EM_RH32: return "TRW RH32";
+ case EM_MCORE: return "MCORE";
+ /* 40 */
+ case EM_ARM: return "ARM";
+ case EM_OLD_ALPHA: return "Digital Alpha (old)";
+ case EM_SH: return "Renesas / SuperH SH";
+ case EM_SPARCV9: return "Sparc v9";
+ case EM_TRICORE: return "Siemens Tricore";
+ case EM_ARC: return "ARC";
+ case EM_H8_300: return "Renesas H8/300";
+ case EM_H8_300H: return "Renesas H8/300H";
+ case EM_H8S: return "Renesas H8S";
+ case EM_H8_500: return "Renesas H8/500";
+ /* 50 */
+ case EM_IA_64: return "Intel IA-64";
+ case EM_MIPS_X: return "Stanford MIPS-X";
+ case EM_COLDFIRE: return "Motorola Coldfire";
+ case EM_68HC12: return "Motorola MC68HC12 Microcontroller";
+ case EM_MMA: return "Fujitsu Multimedia Accelerator";
+ case EM_PCP: return "Siemens PCP";
+ case EM_NCPU: return "Sony nCPU embedded RISC processor";
+ case EM_NDR1: return "Denso NDR1 microprocesspr";
+ case EM_STARCORE: return "Motorola Star*Core processor";
+ case EM_ME16: return "Toyota ME16 processor";
+ /* 60 */
+ case EM_ST100: return "STMicroelectronics ST100 processor";
+ case EM_TINYJ: return "Advanced Logic Corp. TinyJ embedded processor";
+ case EM_X86_64: return "Advanced Micro Devices X86-64";
+ case EM_PDSP: return "Sony DSP processor";
+ case EM_PDP10: return "Digital Equipment Corp. PDP-10";
+ case EM_PDP11: return "Digital Equipment Corp. PDP-11";
+ case EM_FX66: return "Siemens FX66 microcontroller";
+ case EM_ST9PLUS: return "STMicroelectronics ST9+ 8/16 bit microcontroller";
+ case EM_ST7: return "STMicroelectronics ST7 8-bit microcontroller";
+ case EM_68HC16: return "Motorola MC68HC16 Microcontroller";
+ /* 70 */
+ case EM_68HC11: return "Motorola MC68HC11 Microcontroller";
+ case EM_68HC08: return "Motorola MC68HC08 Microcontroller";
+ case EM_68HC05: return "Motorola MC68HC05 Microcontroller";
+ case EM_SVX: return "Silicon Graphics SVx";
+ case EM_ST19: return "STMicroelectronics ST19 8-bit microcontroller";
+ case EM_VAX: return "Digital VAX";
+ case EM_CRIS: return "Axis Communications 32-bit embedded processor";
+ case EM_JAVELIN: return "Infineon Technologies 32-bit embedded cpu";
+ case EM_FIREPATH: return "Element 14 64-bit DSP processor";
+ case EM_ZSP: return "LSI Logic's 16-bit DSP processor";
+ /* 80 */
+ case EM_MMIX: return "Donald Knuth's educational 64-bit processor";
+ case EM_HUANY: return "Harvard Universitys's machine-independent object format";
+ case EM_PRISM: return "Vitesse Prism";
+ case EM_AVR_OLD:
+ case EM_AVR: return "Atmel AVR 8-bit microcontroller";
+ case EM_CYGNUS_FR30:
+ case EM_FR30: return "Fujitsu FR30";
+ case EM_CYGNUS_D10V:
+ case EM_D10V: return "d10v";
+ case EM_CYGNUS_D30V:
+ case EM_D30V: return "d30v";
+ case EM_CYGNUS_V850:
+ case EM_V850: return "Renesas V850";
+ case EM_CYGNUS_M32R:
+ case EM_M32R: return "Renesas M32R (formerly Mitsubishi M32r)";
+ case EM_CYGNUS_MN10300:
+ case EM_MN10300: return "mn10300";
+ /* 90