📄 elf.c
字号:
/* ELF executable support for BFD. 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. *//*SECTION ELF backends BFD support for ELF formats is being worked on. Currently, the best supported back ends are for sparc and i386 (running svr4 or Solaris 2). Documentation of the internals of the support code still needs to be written. The code is changing quickly enough that we haven't bothered yet. *//* For sparc64-cross-sparc32. */#define _SYSCALL32#include "bfd.h"#include "sysdep.h"#include "bfdlink.h"#include "libbfd.h"#define ARCH_SIZE 0#include "elf-bfd.h"static INLINE struct elf_segment_map *make_mapping PARAMS ((bfd *, asection **, unsigned int, unsigned int, boolean));static boolean map_sections_to_segments PARAMS ((bfd *));static int elf_sort_sections PARAMS ((const PTR, const PTR));static boolean assign_file_positions_for_segments PARAMS ((bfd *));static boolean assign_file_positions_except_relocs PARAMS ((bfd *));static boolean prep_headers PARAMS ((bfd *));static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **, int));static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));static char *elf_read PARAMS ((bfd *, long, unsigned int));static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));static boolean assign_section_numbers PARAMS ((bfd *));static INLINE int sym_is_global PARAMS ((bfd *, asymbol *));static boolean elf_map_symbols PARAMS ((bfd *));static bfd_size_type get_program_header_size PARAMS ((bfd *));static boolean elfcore_read_notes PARAMS ((bfd *, bfd_vma, bfd_vma));static boolean elf_find_function PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, const char **));/* Swap version information in and out. The version information is currently size independent. If that ever changes, this code will need to move into elfcode.h. *//* Swap in a Verdef structure. */void_bfd_elf_swap_verdef_in (abfd, src, dst) bfd *abfd; const Elf_External_Verdef *src; Elf_Internal_Verdef *dst;{ dst->vd_version = bfd_h_get_16 (abfd, src->vd_version); dst->vd_flags = bfd_h_get_16 (abfd, src->vd_flags); dst->vd_ndx = bfd_h_get_16 (abfd, src->vd_ndx); dst->vd_cnt = bfd_h_get_16 (abfd, src->vd_cnt); dst->vd_hash = bfd_h_get_32 (abfd, src->vd_hash); dst->vd_aux = bfd_h_get_32 (abfd, src->vd_aux); dst->vd_next = bfd_h_get_32 (abfd, src->vd_next);}/* Swap out a Verdef structure. */void_bfd_elf_swap_verdef_out (abfd, src, dst) bfd *abfd; const Elf_Internal_Verdef *src; Elf_External_Verdef *dst;{ bfd_h_put_16 (abfd, src->vd_version, dst->vd_version); bfd_h_put_16 (abfd, src->vd_flags, dst->vd_flags); bfd_h_put_16 (abfd, src->vd_ndx, dst->vd_ndx); bfd_h_put_16 (abfd, src->vd_cnt, dst->vd_cnt); bfd_h_put_32 (abfd, src->vd_hash, dst->vd_hash); bfd_h_put_32 (abfd, src->vd_aux, dst->vd_aux); bfd_h_put_32 (abfd, src->vd_next, dst->vd_next);}/* Swap in a Verdaux structure. */void_bfd_elf_swap_verdaux_in (abfd, src, dst) bfd *abfd; const Elf_External_Verdaux *src; Elf_Internal_Verdaux *dst;{ dst->vda_name = bfd_h_get_32 (abfd, src->vda_name); dst->vda_next = bfd_h_get_32 (abfd, src->vda_next);}/* Swap out a Verdaux structure. */void_bfd_elf_swap_verdaux_out (abfd, src, dst) bfd *abfd; const Elf_Internal_Verdaux *src; Elf_External_Verdaux *dst;{ bfd_h_put_32 (abfd, src->vda_name, dst->vda_name); bfd_h_put_32 (abfd, src->vda_next, dst->vda_next);}/* Swap in a Verneed structure. */void_bfd_elf_swap_verneed_in (abfd, src, dst) bfd *abfd; const Elf_External_Verneed *src; Elf_Internal_Verneed *dst;{ dst->vn_version = bfd_h_get_16 (abfd, src->vn_version); dst->vn_cnt = bfd_h_get_16 (abfd, src->vn_cnt); dst->vn_file = bfd_h_get_32 (abfd, src->vn_file); dst->vn_aux = bfd_h_get_32 (abfd, src->vn_aux); dst->vn_next = bfd_h_get_32 (abfd, src->vn_next);}/* Swap out a Verneed structure. */void_bfd_elf_swap_verneed_out (abfd, src, dst) bfd *abfd; const Elf_Internal_Verneed *src; Elf_External_Verneed *dst;{ bfd_h_put_16 (abfd, src->vn_version, dst->vn_version); bfd_h_put_16 (abfd, src->vn_cnt, dst->vn_cnt); bfd_h_put_32 (abfd, src->vn_file, dst->vn_file); bfd_h_put_32 (abfd, src->vn_aux, dst->vn_aux); bfd_h_put_32 (abfd, src->vn_next, dst->vn_next);}/* Swap in a Vernaux structure. */void_bfd_elf_swap_vernaux_in (abfd, src, dst) bfd *abfd; const Elf_External_Vernaux *src; Elf_Internal_Vernaux *dst;{ dst->vna_hash = bfd_h_get_32 (abfd, src->vna_hash); dst->vna_flags = bfd_h_get_16 (abfd, src->vna_flags); dst->vna_other = bfd_h_get_16 (abfd, src->vna_other); dst->vna_name = bfd_h_get_32 (abfd, src->vna_name); dst->vna_next = bfd_h_get_32 (abfd, src->vna_next);}/* Swap out a Vernaux structure. */void_bfd_elf_swap_vernaux_out (abfd, src, dst) bfd *abfd; const Elf_Internal_Vernaux *src; Elf_External_Vernaux *dst;{ bfd_h_put_32 (abfd, src->vna_hash, dst->vna_hash); bfd_h_put_16 (abfd, src->vna_flags, dst->vna_flags); bfd_h_put_16 (abfd, src->vna_other, dst->vna_other); bfd_h_put_32 (abfd, src->vna_name, dst->vna_name); bfd_h_put_32 (abfd, src->vna_next, dst->vna_next);}/* Swap in a Versym structure. */void_bfd_elf_swap_versym_in (abfd, src, dst) bfd *abfd; const Elf_External_Versym *src; Elf_Internal_Versym *dst;{ dst->vs_vers = bfd_h_get_16 (abfd, src->vs_vers);}/* Swap out a Versym structure. */void_bfd_elf_swap_versym_out (abfd, src, dst) bfd *abfd; const Elf_Internal_Versym *src; Elf_External_Versym *dst;{ bfd_h_put_16 (abfd, src->vs_vers, dst->vs_vers);}/* Standard ELF hash function. Do not change this function; you will cause invalid hash tables to be generated. */unsigned longbfd_elf_hash (namearg) const char *namearg;{ const unsigned char *name = (const unsigned char *) namearg; unsigned long h = 0; unsigned long g; int ch; while ((ch = *name++) != '\0') { h = (h << 4) + ch; if ((g = (h & 0xf0000000)) != 0) { h ^= g >> 24; /* The ELF ABI says `h &= ~g', but this is equivalent in this case and on some machines one insn instead of two. */ h ^= g; } } return h;}/* Read a specified number of bytes at a specified offset in an ELF file, into a newly allocated buffer, and return a pointer to the buffer. */static char *elf_read (abfd, offset, size) bfd *abfd; long offset; unsigned int size;{ char *buf; if ((buf = bfd_alloc (abfd, size)) == NULL) return NULL; if (bfd_seek (abfd, offset, SEEK_SET) == -1) return NULL; if (bfd_read ((PTR) buf, size, 1, abfd) != size) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_file_truncated); return NULL; } return buf;}booleanbfd_elf_mkobject (abfd) bfd *abfd;{ /* This just does initialization. */ /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */ elf_tdata (abfd) = (struct elf_obj_tdata *) bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); if (elf_tdata (abfd) == 0) return false; /* Since everything is done at close time, do we need any initialization? */ return true;}booleanbfd_elf_mkcorefile (abfd) bfd *abfd;{ /* I think this can be done just like an object file. */ return bfd_elf_mkobject (abfd);}char *bfd_elf_get_str_section (abfd, shindex) bfd *abfd; unsigned int shindex;{ Elf_Internal_Shdr **i_shdrp; char *shstrtab = NULL; unsigned int offset; unsigned int shstrtabsize; i_shdrp = elf_elfsections (abfd); if (i_shdrp == 0 || i_shdrp[shindex] == 0) return 0; shstrtab = (char *) i_shdrp[shindex]->contents; if (shstrtab == NULL) { /* No cached one, attempt to read, and cache what we read. */ offset = i_shdrp[shindex]->sh_offset; shstrtabsize = i_shdrp[shindex]->sh_size; shstrtab = elf_read (abfd, offset, shstrtabsize); i_shdrp[shindex]->contents = (PTR) shstrtab; } return shstrtab;}char *bfd_elf_string_from_elf_section (abfd, shindex, strindex) bfd *abfd; unsigned int shindex; unsigned int strindex;{ Elf_Internal_Shdr *hdr; if (strindex == 0) return ""; hdr = elf_elfsections (abfd)[shindex]; if (hdr->contents == NULL && bfd_elf_get_str_section (abfd, shindex) == NULL) return NULL; if (strindex >= hdr->sh_size) { (*_bfd_error_handler) (_("%s: invalid string offset %u >= %lu for section `%s'"), bfd_get_filename (abfd), strindex, (unsigned long) hdr->sh_size, ((shindex == elf_elfheader(abfd)->e_shstrndx && strindex == hdr->sh_name) ? ".shstrtab" : elf_string_from_elf_strtab (abfd, hdr->sh_name))); return ""; } return ((char *) hdr->contents) + strindex;}/* Make a BFD section from an ELF section. We store a pointer to the BFD section in the bfd_section field of the header. */boolean_bfd_elf_make_section_from_shdr (abfd, hdr, name) bfd *abfd; Elf_Internal_Shdr *hdr; const char *name;{ asection *newsect; flagword flags; struct elf_backend_data *bed; if (hdr->bfd_section != NULL) { BFD_ASSERT (strcmp (name, bfd_get_section_name (abfd, hdr->bfd_section)) == 0); return true; } newsect = bfd_make_section_anyway (abfd, name); if (newsect == NULL) return false; newsect->filepos = hdr->sh_offset; if (! bfd_set_section_vma (abfd, newsect, hdr->sh_addr) || ! bfd_set_section_size (abfd, newsect, hdr->sh_size) || ! bfd_set_section_alignment (abfd, newsect, bfd_log2 (hdr->sh_addralign))) return false; flags = SEC_NO_FLAGS; if (hdr->sh_type != SHT_NOBITS) flags |= SEC_HAS_CONTENTS; if ((hdr->sh_flags & SHF_ALLOC) != 0) { flags |= SEC_ALLOC; if (hdr->sh_type != SHT_NOBITS) flags |= SEC_LOAD; } if ((hdr->sh_flags & SHF_WRITE) == 0) flags |= SEC_READONLY; if ((hdr->sh_flags & SHF_EXECINSTR) != 0) flags |= SEC_CODE; else if ((flags & SEC_LOAD) != 0) flags |= SEC_DATA; /* The debugging sections appear to be recognized only by name, not any sort of flag. */ { static const char *debug_sec_names [] = { ".debug", ".gnu.linkonce.wi.", ".line", ".stab" }; int i; for (i = sizeof (debug_sec_names) / sizeof (debug_sec_names[0]); i--;) if (strncmp (name, debug_sec_names[i], strlen (debug_sec_names[i])) == 0) break; if (i >= 0) flags |= SEC_DEBUGGING; } /* As a GNU extension, if the name begins with .gnu.linkonce, we only link a single copy of the section. This is used to support g++. g++ will emit each template expansion in its own section. The symbols will be defined as weak, so that multiple definitions are permitted. The GNU linker extension is to actually discard all but one of the sections. */ if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0) flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; bed = get_elf_backend_data (abfd); if (bed->elf_backend_section_flags) if (! bed->elf_backend_section_flags (&flags, hdr)) return false; if (! bfd_set_section_flags (abfd, newsect, flags)) return false; if ((flags & SEC_ALLOC) != 0) { Elf_Internal_Phdr *phdr; unsigned int i; /* Look through the phdrs to see if we need to adjust the lma. If all the p_paddr fields are zero, we ignore them, since some ELF linkers produce such output. */ phdr = elf_tdata (abfd)->phdr; for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) { if (phdr->p_paddr != 0) break; } if (i < elf_elfheader (abfd)->e_phnum) { phdr = elf_tdata (abfd)->phdr; for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) { if (phdr->p_type == PT_LOAD && phdr->p_vaddr != phdr->p_paddr && phdr->p_vaddr <= hdr->sh_addr && (phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size) && ((flags & SEC_LOAD) == 0 || (phdr->p_offset <= (bfd_vma) hdr->sh_offset && (phdr->p_offset + phdr->p_filesz >= hdr->sh_offset + hdr->sh_size))))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -