📄 elf32-i386.c
字号:
/* Intel 80386/80486-specific support for 32-bit ELF Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.This file is part of BFD, the Binary File Descriptor library.This program is free software; you can redistribute it and/or 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 "bfdlink.h"#include "libbfd.h"#include "elf-bfd.h"static reloc_howto_type *elf_i386_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type));static void elf_i386_info_to_howto PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));static void elf_i386_info_to_howto_rel PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));static boolean elf_i386_is_local_label_name PARAMS ((bfd *, const char *));static struct bfd_hash_entry *elf_i386_link_hash_newfunc PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));static struct bfd_link_hash_table *elf_i386_link_hash_table_create PARAMS ((bfd *));static boolean elf_i386_check_relocs PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *));static boolean elf_i386_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));static boolean elf_i386_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));static boolean elf_i386_relocate_section PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));static boolean elf_i386_finish_dynamic_symbol PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, Elf_Internal_Sym *));static boolean elf_i386_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));#define USE_REL 1 /* 386 uses REL relocations instead of RELA */#include "elf/i386.h"static reloc_howto_type elf_howto_table[]={ HOWTO(R_386_NONE, 0, 0, 0, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_NONE", true, 0x00000000, 0x00000000, false), HOWTO(R_386_32, 0, 2, 32, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_32", true, 0xffffffff, 0xffffffff, false), HOWTO(R_386_PC32, 0, 2, 32, true, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_PC32", true, 0xffffffff, 0xffffffff, true), HOWTO(R_386_GOT32, 0, 2, 32, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_GOT32", true, 0xffffffff, 0xffffffff, false), HOWTO(R_386_PLT32, 0, 2, 32, true, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_PLT32", true, 0xffffffff, 0xffffffff, true), HOWTO(R_386_COPY, 0, 2, 32, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_COPY", true, 0xffffffff, 0xffffffff, false), HOWTO(R_386_GLOB_DAT, 0, 2, 32, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_GLOB_DAT", true, 0xffffffff, 0xffffffff, false), HOWTO(R_386_JUMP_SLOT, 0, 2, 32, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_JUMP_SLOT", true, 0xffffffff, 0xffffffff, false), HOWTO(R_386_RELATIVE, 0, 2, 32, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_RELATIVE", true, 0xffffffff, 0xffffffff, false), HOWTO(R_386_GOTOFF, 0, 2, 32, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_GOTOFF", true, 0xffffffff, 0xffffffff, false), HOWTO(R_386_GOTPC, 0, 2, 32, true, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_GOTPC", true, 0xffffffff, 0xffffffff, true), /* We have a gap in the reloc numbers here. R_386_standard counts the number up to this point, and R_386_ext_offset is the value to subtract from a reloc type of R_386_16 thru R_386_PC8 to form an index into this table. */#define R_386_standard ((unsigned int) R_386_GOTPC + 1)#define R_386_ext_offset ((unsigned int) R_386_16 - R_386_standard) /* The remaining relocs are a GNU extension. */ HOWTO(R_386_16, 0, 1, 16, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_16", true, 0xffff, 0xffff, false), HOWTO(R_386_PC16, 0, 1, 16, true, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_PC16", true, 0xffff, 0xffff, true), HOWTO(R_386_8, 0, 0, 8, false, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_8", true, 0xff, 0xff, false), HOWTO(R_386_PC8, 0, 0, 8, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_386_PC8", true, 0xff, 0xff, true), /* Another gap. */#define R_386_ext ((unsigned int) R_386_PC8 + 1 - R_386_ext_offset)#define R_386_vt_offset ((unsigned int) R_386_GNU_VTINHERIT - R_386_ext)/* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_386_GNU_VTINHERIT, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ NULL, /* special_function */ "R_386_GNU_VTINHERIT", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false),/* GNU extension to record C++ vtable member usage. */ HOWTO (R_386_GNU_VTENTRY, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ _bfd_elf_rel_vtable_reloc_fn, /* special_function */ "R_386_GNU_VTENTRY", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false)#define R_386_vt ((unsigned int) R_386_GNU_VTENTRY + 1 - R_386_vt_offset)};#ifdef DEBUG_GEN_RELOC#define TRACE(str) fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str)#else#define TRACE(str)#endifstatic reloc_howto_type *elf_i386_reloc_type_lookup (abfd, code) bfd *abfd ATTRIBUTE_UNUSED; bfd_reloc_code_real_type code;{ switch (code) { case BFD_RELOC_NONE: TRACE ("BFD_RELOC_NONE"); return &elf_howto_table[(unsigned int) R_386_NONE ]; case BFD_RELOC_32: TRACE ("BFD_RELOC_32"); return &elf_howto_table[(unsigned int) R_386_32 ]; case BFD_RELOC_CTOR: TRACE ("BFD_RELOC_CTOR"); return &elf_howto_table[(unsigned int) R_386_32 ]; case BFD_RELOC_32_PCREL: TRACE ("BFD_RELOC_PC32"); return &elf_howto_table[(unsigned int) R_386_PC32 ]; case BFD_RELOC_386_GOT32: TRACE ("BFD_RELOC_386_GOT32"); return &elf_howto_table[(unsigned int) R_386_GOT32 ]; case BFD_RELOC_386_PLT32: TRACE ("BFD_RELOC_386_PLT32"); return &elf_howto_table[(unsigned int) R_386_PLT32 ]; case BFD_RELOC_386_COPY: TRACE ("BFD_RELOC_386_COPY"); return &elf_howto_table[(unsigned int) R_386_COPY ]; case BFD_RELOC_386_GLOB_DAT: TRACE ("BFD_RELOC_386_GLOB_DAT"); return &elf_howto_table[(unsigned int) R_386_GLOB_DAT ]; case BFD_RELOC_386_JUMP_SLOT: TRACE ("BFD_RELOC_386_JUMP_SLOT"); return &elf_howto_table[(unsigned int) R_386_JUMP_SLOT ]; case BFD_RELOC_386_RELATIVE: TRACE ("BFD_RELOC_386_RELATIVE"); return &elf_howto_table[(unsigned int) R_386_RELATIVE ]; case BFD_RELOC_386_GOTOFF: TRACE ("BFD_RELOC_386_GOTOFF"); return &elf_howto_table[(unsigned int) R_386_GOTOFF ]; case BFD_RELOC_386_GOTPC: TRACE ("BFD_RELOC_386_GOTPC"); return &elf_howto_table[(unsigned int) R_386_GOTPC ]; /* The remaining relocs are a GNU extension. */ case BFD_RELOC_16: TRACE ("BFD_RELOC_16"); return &elf_howto_table[(unsigned int) R_386_16 - R_386_ext_offset]; case BFD_RELOC_16_PCREL: TRACE ("BFD_RELOC_16_PCREL"); return &elf_howto_table[(unsigned int) R_386_PC16 - R_386_ext_offset]; case BFD_RELOC_8: TRACE ("BFD_RELOC_8"); return &elf_howto_table[(unsigned int) R_386_8 - R_386_ext_offset]; case BFD_RELOC_8_PCREL: TRACE ("BFD_RELOC_8_PCREL"); return &elf_howto_table[(unsigned int) R_386_PC8 - R_386_ext_offset]; case BFD_RELOC_VTABLE_INHERIT: TRACE ("BFD_RELOC_VTABLE_INHERIT"); return &elf_howto_table[(unsigned int) R_386_GNU_VTINHERIT - R_386_vt_offset]; case BFD_RELOC_VTABLE_ENTRY: TRACE ("BFD_RELOC_VTABLE_ENTRY"); return &elf_howto_table[(unsigned int) R_386_GNU_VTENTRY - R_386_vt_offset]; default: break; } TRACE ("Unknown"); return 0;}static voidelf_i386_info_to_howto (abfd, cache_ptr, dst) bfd *abfd ATTRIBUTE_UNUSED; arelent *cache_ptr ATTRIBUTE_UNUSED; Elf32_Internal_Rela *dst ATTRIBUTE_UNUSED;{ abort ();}static voidelf_i386_info_to_howto_rel (abfd, cache_ptr, dst) bfd *abfd ATTRIBUTE_UNUSED; arelent *cache_ptr; Elf32_Internal_Rel *dst;{ unsigned int r_type = ELF32_R_TYPE (dst->r_info); unsigned int indx; if ((indx = r_type) >= R_386_standard && ((indx = r_type - R_386_ext_offset) - R_386_standard >= R_386_ext - R_386_standard) && ((indx = r_type - R_386_vt_offset) - R_386_ext >= R_386_vt - R_386_ext)) { (*_bfd_error_handler) (_("%s: invalid relocation type %d"), bfd_get_filename (abfd), (int) r_type); indx = (unsigned int) R_386_NONE; } cache_ptr->howto = &elf_howto_table[indx];}/* Return whether a symbol name implies a local label. The UnixWare 2.1 cc generates temporary symbols that start with .X, so we recognize them here. FIXME: do other SVR4 compilers also use .X?. If so, we should move the .X recognition into _bfd_elf_is_local_label_name. */static booleanelf_i386_is_local_label_name (abfd, name) bfd *abfd; const char *name;{ if (name[0] == '.' && name[1] == 'X') return true; return _bfd_elf_is_local_label_name (abfd, name);}/* Functions for the i386 ELF linker. *//* The name of the dynamic interpreter. This is put in the .interp section. */#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1"/* The size in bytes of an entry in the procedure linkage table. */#define PLT_ENTRY_SIZE 16/* The first entry in an absolute procedure linkage table looks like this. See the SVR4 ABI i386 supplement to see how this works. */static const bfd_byte elf_i386_plt0_entry[PLT_ENTRY_SIZE] ={ 0xff, 0x35, /* pushl contents of address */ 0, 0, 0, 0, /* replaced with address of .got + 4. */ 0xff, 0x25, /* jmp indirect */ 0, 0, 0, 0, /* replaced with address of .got + 8. */ 0, 0, 0, 0 /* pad out to 16 bytes. */};/* Subsequent entries in an absolute procedure linkage table look like this. */static const bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] ={ 0xff, 0x25, /* jmp indirect */ 0, 0, 0, 0, /* replaced with address of this symbol in .got. */ 0x68, /* pushl immediate */ 0, 0, 0, 0, /* replaced with offset into relocation table. */ 0xe9, /* jmp relative */ 0, 0, 0, 0 /* replaced with offset to start of .plt. */};/* The first entry in a PIC procedure linkage table look like this. */static const bfd_byte elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] ={ 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ 0, 0, 0, 0 /* pad out to 16 bytes. */};/* Subsequent entries in a PIC procedure linkage table look like this. */static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] ={ 0xff, 0xa3, /* jmp *offset(%ebx) */ 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ 0x68, /* pushl immediate */ 0, 0, 0, 0, /* replaced with offset into relocation table. */ 0xe9, /* jmp relative */ 0, 0, 0, 0 /* replaced with offset to start of .plt. */};/* The i386 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 elf_i386_pcrel_relocs_copied{ /* Next section. */ struct elf_i386_pcrel_relocs_copied *next; /* A section in dynobj. */ asection *section; /* Number of relocs copied in this section. */ bfd_size_type count;};/* i386 ELF linker hash entry. */struct elf_i386_link_hash_entry{ struct elf_link_hash_entry root; /* Number of PC relative relocs copied for this symbol. */ struct elf_i386_pcrel_relocs_copied *pcrel_relocs_copied;};/* i386 ELF linker hash table. */struct elf_i386_link_hash_table{ struct elf_link_hash_table root;};/* Declare this now that the above structures are defined. */static boolean elf_i386_discard_copies PARAMS ((struct elf_i386_link_hash_entry *, PTR));/* Traverse an i386 ELF linker hash table. */#define elf_i386_link_hash_traverse(table, func, info) \ (elf_link_hash_traverse \ (&(table)->root, \ (boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \ (info)))/* Get the i386 ELF linker hash table from a link_info structure. */#define elf_i386_hash_table(p) \ ((struct elf_i386_link_hash_table *) ((p)->hash))/* Create an entry in an i386 ELF linker hash table. */static struct bfd_hash_entry *elf_i386_link_hash_newfunc (entry, table, string) struct bfd_hash_entry *entry; struct bfd_hash_table *table; const char *string;{ struct elf_i386_link_hash_entry *ret = (struct elf_i386_link_hash_entry *) entry; /* Allocate the structure if it has not already been allocated by a subclass. */ if (ret == (struct elf_i386_link_hash_entry *) NULL) ret = ((struct elf_i386_link_hash_entry *) bfd_hash_allocate (table, sizeof (struct elf_i386_link_hash_entry))); if (ret == (struct elf_i386_link_hash_entry *) NULL) return (struct bfd_hash_entry *) ret; /* Call the allocation method of the superclass. */ ret = ((struct elf_i386_link_hash_entry *) _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -