| /* AArch64-specific support for NN-bit ELF. |
| Copyright (C) 2009-2024 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_late_size_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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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 */ |
| 0, /* 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" |
| |
| /* Stub name for a BTI landing stub. */ |
| #define BTI_STUB_ENTRY_NAME "__%s_bti_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_bti_direct_branch_stub[] = |
| { |
| 0xd503245f, /* bti c */ |
| 0x14000000, /* b <label> */ |
| }; |
| |
| 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_bti_direct_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; |
| |
| /* The target is also a stub. */ |
| bool double_stub; |
| |
| /* 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; |
| |
| /* True when two stubs are added where one targets the other, happens |
| when BTI stubs are inserted and then the stub layout must not change |
| during elfNN_aarch64_build_stubs. */ |
| bool has_double_stub; |
| |
| /* 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; |
| |
| /* Array of relative relocs to be emitted in DT_RELR format. */ |
| bfd_size_type relr_alloc; |
| bfd_size_type relr_count; |
| struct relr_entry |
| { |
| asection *sec; |
| bfd_vma off; |
| } *relr; |
| /* Sorted output addresses of above relative relocs. */ |
| bfd_vma *relr_sorted; |
| /* Layout recomputation count. */ |
| bfd_size_type relr_layout_iter; |
| }; |
| |
| /* 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; |
| memset (&eh->stub_sec, 0, |
| (sizeof (struct elf_aarch64_stub_hash_entry) |
| - offsetof (struct elf_aarch64_stub_hash_entry, stub_sec))); |
| } |
| |
| 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; |
| } |
| |
| /* 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. */ |
| |