📄 elf64-x86-64.c
字号:
/* X86-64 specific support for 64-bit ELF Copyright 2000, 2001 Free Software Foundation, Inc. Contributed by Jan Hubicka <jh@suse.cz>.This file is part of BFD, the Binary File Descriptor library.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "bfd.h"#include "sysdep.h"#include "libbfd.h"#include "elf-bfd.h"#include "elf/x86-64.h"/* We use only the RELA entries. */#define USE_RELA/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */#define MINUS_ONE (~ (bfd_vma) 0)/* The relocation "howto" table. Order of fields: type, size, bitsize, pc_relative, complain_on_overflow, special_function, name, partial_inplace, src_mask, dst_pack, pcrel_offset. */static reloc_howto_type x86_64_elf_howto_table[] ={ HOWTO(R_X86_64_NONE, 0, 0, 0, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_X86_64_NONE", false, 0x00000000, 0x00000000, false), HOWTO(R_X86_64_64, 0, 4, 64, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_64", false, MINUS_ONE, MINUS_ONE, false), HOWTO(R_X86_64_PC32, 0, 4, 32, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_PC32", false, 0xffffffff, 0xffffffff, true), HOWTO(R_X86_64_GOT32, 0, 4, 32, false, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_GOT32", false, 0xffffffff, 0xffffffff, false), HOWTO(R_X86_64_PLT32, 0, 4, 32, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_PLT32", false, 0xffffffff, 0xffffffff, true), HOWTO(R_X86_64_COPY, 0, 4, 32, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_COPY", false, 0xffffffff, 0xffffffff, false), HOWTO(R_X86_64_GLOB_DAT, 0, 4, 64, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_GLOB_DAT", false, MINUS_ONE, MINUS_ONE, false), HOWTO(R_X86_64_JUMP_SLOT, 0, 4, 64, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_JUMP_SLOT", false, MINUS_ONE, MINUS_ONE, false), HOWTO(R_X86_64_RELATIVE, 0, 4, 64, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_RELATIVE", false, MINUS_ONE, MINUS_ONE, false), HOWTO(R_X86_64_GOTPCREL, 0, 4, 32, true,0 , complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_GOTPCREL", false, 0xffffffff, 0xffffffff, true), HOWTO(R_X86_64_32, 0, 4, 32, false, 0, complain_overflow_unsigned, bfd_elf_generic_reloc, "R_X86_64_32", false, 0xffffffff, 0xffffffff, false), HOWTO(R_X86_64_32S, 0, 4, 32, false, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_32S", false, 0xffffffff, 0xffffffff, false), HOWTO(R_X86_64_16, 0, 1, 16, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_16", false, 0xffff, 0xffff, false), HOWTO(R_X86_64_PC16,0, 1, 16, true, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_X86_64_PC16", false, 0xffff, 0xffff, true), HOWTO(R_X86_64_8, 0, 0, 8, false, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_8", false, 0xff, 0xff, false), HOWTO(R_X86_64_PC8, 0, 0, 8, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_PC8", false, 0xff, 0xff, true)};/* Map BFD relocs to the x86_64 elf relocs. */struct elf_reloc_map{ bfd_reloc_code_real_type bfd_reloc_val; unsigned char elf_reloc_val;};static CONST struct elf_reloc_map x86_64_reloc_map[] ={ { BFD_RELOC_NONE, R_X86_64_NONE, }, { BFD_RELOC_64, R_X86_64_64, }, { BFD_RELOC_32_PCREL, R_X86_64_PC32, }, { BFD_RELOC_X86_64_GOT32, R_X86_64_GOT32,}, { BFD_RELOC_X86_64_PLT32, R_X86_64_PLT32,}, { BFD_RELOC_X86_64_COPY, R_X86_64_COPY, }, { BFD_RELOC_X86_64_GLOB_DAT, R_X86_64_GLOB_DAT, }, { BFD_RELOC_X86_64_JUMP_SLOT, R_X86_64_JUMP_SLOT, }, { BFD_RELOC_X86_64_RELATIVE, R_X86_64_RELATIVE, }, { BFD_RELOC_X86_64_GOTPCREL, R_X86_64_GOTPCREL, }, { BFD_RELOC_32, R_X86_64_32, }, { BFD_RELOC_X86_64_32S, R_X86_64_32S, }, { BFD_RELOC_16, R_X86_64_16, }, { BFD_RELOC_16_PCREL, R_X86_64_PC16, }, { BFD_RELOC_8, R_X86_64_8, }, { BFD_RELOC_8_PCREL, R_X86_64_PC8, },};static reloc_howto_type *elf64_x86_64_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type));static void elf64_x86_64_info_to_howto PARAMS ((bfd *, arelent *, Elf64_Internal_Rela *));static struct bfd_link_hash_table *elf64_x86_64_link_hash_table_create PARAMS ((bfd *));static struct bfd_hash_entry *elf64_x86_64_link_hash_newfunc PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));static boolean elf64_x86_64_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));static boolean elf64_x86_64_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));static boolean elf64_x86_64_relocate_section PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));static boolean elf64_x86_64_finish_dynamic_symbol PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, Elf_Internal_Sym *sym));static boolean elf64_x86_64_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));/* Given a BFD reloc type, return a HOWTO structure. */static reloc_howto_type *elf64_x86_64_reloc_type_lookup (abfd, code) bfd *abfd ATTRIBUTE_UNUSED; bfd_reloc_code_real_type code;{ unsigned int i; for (i = 0; i < sizeof (x86_64_reloc_map) / sizeof (struct elf_reloc_map); i++) { if (x86_64_reloc_map[i].bfd_reloc_val == code) return &x86_64_elf_howto_table[(int) x86_64_reloc_map[i].elf_reloc_val]; } return 0;}/* Given an x86_64 ELF reloc type, fill in an arelent structure. */static voidelf64_x86_64_info_to_howto (abfd, cache_ptr, dst) bfd *abfd ATTRIBUTE_UNUSED; arelent *cache_ptr; Elf64_Internal_Rela *dst;{ unsigned r_type; r_type = ELF64_R_TYPE (dst->r_info); BFD_ASSERT (r_type < (unsigned int) R_X86_64_max); cache_ptr->howto = &x86_64_elf_howto_table[r_type]; BFD_ASSERT (r_type == cache_ptr->howto->type);}/* Functions for the x86-64 ELF linker. *//* The name of the dynamic interpreter. This is put in the .interp section. */#define ELF_DYNAMIC_INTERPRETER "/lib/ld64.so.1"/* The size in bytes of an entry in the global offset table. */#define GOT_ENTRY_SIZE 8/* The size in bytes of an entry in the procedure linkage table. */#define PLT_ENTRY_SIZE 16/* The first entry in a procedure linkage table looks like this. See the SVR4 ABI i386 supplement and the x86-64 ABI to see how this works. */static const bfd_byte elf64_x86_64_plt0_entry[PLT_ENTRY_SIZE] ={ 0xff, 0x35, 8, 0, 0, 0, /* pushq GOT+8(%rip) */ 0xff, 0x25, 16, 0, 0, 0, /* jmpq *GOT+16(%rip) */ 0x90, 0x90, 0x90, 0x90 /* pad out to 16 bytes with nops. */};/* Subsequent entries in a procedure linkage table look like this. */static const bfd_byte elf64_x86_64_plt_entry[PLT_ENTRY_SIZE] ={ 0xff, 0x25, /* jmpq *name@GOTPC(%rip) */ 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ 0x68, /* pushq immediate */ 0, 0, 0, 0, /* replaced with index into relocation table. */ 0xe9, /* jmp relative */ 0, 0, 0, 0 /* replaced with offset to start of .plt0. */};/* The x86-64 linker needs to keep track of the number of relocs that it decides to copy in check_relocs for each symbol. This is so that it can discard PC relative relocs if it doesn't need them when linking with -Bsymbolic. We store the information in a field extending the regular ELF linker hash table. *//* This structure keeps track of the number of PC relative relocs we have copied for a given symbol. */struct elf64_x86_64_pcrel_relocs_copied{ /* Next section. */ struct elf64_x86_64_pcrel_relocs_copied *next; /* A section in dynobj. */ asection *section; /* Number of relocs copied in this section. */ bfd_size_type count;};/* x86-64 ELF linker hash entry. */struct elf64_x86_64_link_hash_entry{ struct elf_link_hash_entry root; /* Number of PC relative relocs copied for this symbol. */ struct elf64_x86_64_pcrel_relocs_copied *pcrel_relocs_copied;};/* x86-64 ELF linker hash table. */struct elf64_x86_64_link_hash_table{ struct elf_link_hash_table root;};/* Declare this now that the above structures are defined. */static boolean elf64_x86_64_discard_copies PARAMS ((struct elf64_x86_64_link_hash_entry *, PTR));/* Traverse an x86-64 ELF linker hash table. */#define elf64_x86_64_link_hash_traverse(table, func, info) \ (elf_link_hash_traverse \ (&(table)->root, \ (boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \ (info)))/* Get the x86-64 ELF linker hash table from a link_info structure. */#define elf64_x86_64_hash_table(p) \ ((struct elf64_x86_64_link_hash_table *) ((p)->hash))/* Create an entry in an x86-64 ELF linker hash table. */static struct bfd_hash_entry *elf64_x86_64_link_hash_newfunc (entry, table, string) struct bfd_hash_entry *entry; struct bfd_hash_table *table; const char *string;{ struct elf64_x86_64_link_hash_entry *ret = (struct elf64_x86_64_link_hash_entry *) entry; /* Allocate the structure if it has not already been allocated by a subclass. */ if (ret == (struct elf64_x86_64_link_hash_entry *) NULL) ret = ((struct elf64_x86_64_link_hash_entry *) bfd_hash_allocate (table, sizeof (struct elf64_x86_64_link_hash_entry))); if (ret == (struct elf64_x86_64_link_hash_entry *) NULL) return (struct bfd_hash_entry *) ret; /* Call the allocation method of the superclass. */ ret = ((struct elf64_x86_64_link_hash_entry *) _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); if (ret != (struct elf64_x86_64_link_hash_entry *) NULL) { ret->pcrel_relocs_copied = NULL; } return (struct bfd_hash_entry *) ret;}/* Create an X86-64 ELF linker hash table. */static struct bfd_link_hash_table *elf64_x86_64_link_hash_table_create (abfd) bfd *abfd;{ struct elf64_x86_64_link_hash_table *ret; ret = ((struct elf64_x86_64_link_hash_table *) bfd_alloc (abfd, sizeof (struct elf64_x86_64_link_hash_table))); if (ret == (struct elf64_x86_64_link_hash_table *) NULL) return NULL; if (! _bfd_elf_link_hash_table_init (&ret->root, abfd, elf64_x86_64_link_hash_newfunc)) { bfd_release (abfd, ret); return NULL; } return &ret->root.root;}booleanelf64_x86_64_elf_object_p (abfd) bfd *abfd;{ /* Set the right machine number for an x86-64 elf64 file. */ bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x86_64); return true;}/* Look through the relocs for a section during the first phase, and allocate space in the global offset table or procedure linkage table. */static booleanelf64_x86_64_check_relocs (abfd, info, sec, relocs) bfd *abfd; struct bfd_link_info *info; asection *sec; const Elf_Internal_Rela *relocs;{ bfd *dynobj; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; bfd_signed_vma *local_got_refcounts; const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; asection *sgot; asection *srelgot; asection *sreloc; if (info->relocateable) return true; dynobj = elf_hash_table (info)->dynobj; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); local_got_refcounts = elf_local_got_refcounts (abfd); sgot = srelgot = sreloc = NULL; rel_end = relocs + sec->reloc_count; for (rel = relocs; rel < rel_end; rel++) { unsigned long r_symndx; struct elf_link_hash_entry *h; r_symndx = ELF64_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) h = NULL; else h = sym_hashes[r_symndx - symtab_hdr->sh_info]; /* Some relocs require a global offset table. */ if (dynobj == NULL) { switch (ELF64_R_TYPE (rel->r_info)) { case R_X86_64_GOT32: case R_X86_64_GOTPCREL: elf_hash_table (info)->dynobj = dynobj = abfd; if (! _bfd_elf_create_got_section (dynobj, info)) return false; break; } } switch (ELF64_R_TYPE (rel->r_info)) { case R_X86_64_GOTPCREL: case R_X86_64_GOT32: /* This symbol requires a global offset table entry. */ if (sgot == NULL) { sgot = bfd_get_section_by_name (dynobj, ".got"); BFD_ASSERT (sgot != NULL); } if (srelgot == NULL && (h != NULL || info->shared)) { srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); if (srelgot == NULL) { srelgot = bfd_make_section (dynobj, ".rela.got"); if (srelgot == NULL || ! bfd_set_section_flags (dynobj, srelgot, (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED | SEC_READONLY)) || ! bfd_set_section_alignment (dynobj, srelgot, 3)) return false; } } if (h != NULL) { if (h->got.refcount == -1) { h->got.refcount = 1; /* Make sure this symbol is output as a dynamic symbol. */ if (h->dynindx == -1) { if (! bfd_elf64_link_record_dynamic_symbol (info, h)) return false; } sgot->_raw_size += GOT_ENTRY_SIZE; srelgot->_raw_size += sizeof (Elf64_External_Rela); } else h->got.refcount += 1; } else { /* This is a global offset table entry for a local symbol. */ if (local_got_refcounts == NULL) { size_t size; size = symtab_hdr->sh_info * sizeof (bfd_signed_vma); local_got_refcounts = ((bfd_signed_vma *) bfd_alloc (abfd, size)); if (local_got_refcounts == NULL) return false; elf_local_got_refcounts (abfd) = local_got_refcounts; memset (local_got_refcounts, -1, size); } if (local_got_refcounts[r_symndx] == -1) { local_got_refcounts[r_symndx] = 1; sgot->_raw_size += GOT_ENTRY_SIZE; if (info->shared) { /* If we are generating a shared object, we need to output a R_X86_64_RELATIVE reloc so that the dynamic linker can adjust this GOT entry. */ srelgot->_raw_size += sizeof (Elf64_External_Rela); } } else local_got_refcounts[r_symndx] += 1; } break; case R_X86_64_PLT32: /* This symbol requires a procedure linkage table entry. We actually build the entry in adjust_dynamic_symbol, because this might be a case of linking PIC code which is never referenced by a dynamic object, in which case we don't need to generate a procedure linkage table entry after all. */ /* If this is a local symbol, we resolve it directly without creating a procedure linkage table entry. */ if (h == NULL) continue; h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; if (h->plt.refcount == -1) h->plt.refcount = 1; else h->plt.refcount += 1; break; case R_X86_64_8: case R_X86_64_16: case R_X86_64_32:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -