cofflink.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,243 行 · 第 1/5 页

C
2,243
字号
/* COFF specific linker code.   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001   Free Software Foundation, Inc.   Written by Ian Lance Taylor, Cygnus Support.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.  *//* This file contains the COFF backend linker code.  */#include "bfd.h"#include "sysdep.h"#include "bfdlink.h"#include "libbfd.h"#include "coff/internal.h"#include "libcoff.h"static boolean coff_link_add_object_symbols  PARAMS ((bfd *, struct bfd_link_info *));static boolean coff_link_check_archive_element  PARAMS ((bfd *, struct bfd_link_info *, boolean *));static boolean coff_link_check_ar_symbols  PARAMS ((bfd *, struct bfd_link_info *, boolean *));static boolean coff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));static char *dores_com PARAMS ((char *, bfd *, int));static char *get_name PARAMS ((char *, char **));static int process_embedded_commands  PARAMS ((bfd *, struct bfd_link_info *, bfd *));static void mark_relocs PARAMS ((struct coff_final_link_info *, bfd *));/* Return true if SYM is a weak, external symbol.  */#define IS_WEAK_EXTERNAL(abfd, sym)			\  ((sym).n_sclass == C_WEAKEXT				\   || (obj_pe (abfd) && (sym).n_sclass == C_NT_WEAK))/* Return true if SYM is an external symbol.  */#define IS_EXTERNAL(abfd, sym)				\  ((sym).n_sclass == C_EXT || IS_WEAK_EXTERNAL (abfd, sym))/* Define macros so that the ISFCN, et. al., macros work correctly.   These macros are defined in include/coff/internal.h in terms of   N_TMASK, etc.  These definitions require a user to define local   variables with the appropriate names, and with values from the   coff_data (abfd) structure.  */#define N_TMASK n_tmask#define N_BTSHFT n_btshft#define N_BTMASK n_btmask/* Create an entry in a COFF linker hash table.  */struct bfd_hash_entry *_bfd_coff_link_hash_newfunc (entry, table, string)     struct bfd_hash_entry *entry;     struct bfd_hash_table *table;     const char *string;{  struct coff_link_hash_entry *ret = (struct coff_link_hash_entry *) entry;  /* Allocate the structure if it has not already been allocated by a     subclass.  */  if (ret == (struct coff_link_hash_entry *) NULL)    ret = ((struct coff_link_hash_entry *)	   bfd_hash_allocate (table, sizeof (struct coff_link_hash_entry)));  if (ret == (struct coff_link_hash_entry *) NULL)    return (struct bfd_hash_entry *) ret;  /* Call the allocation method of the superclass.  */  ret = ((struct coff_link_hash_entry *)	 _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,				 table, string));  if (ret != (struct coff_link_hash_entry *) NULL)    {      /* Set local fields.  */      ret->indx = -1;      ret->type = T_NULL;      ret->class = C_NULL;      ret->numaux = 0;      ret->auxbfd = NULL;      ret->aux = NULL;    }  return (struct bfd_hash_entry *) ret;}/* Initialize a COFF linker hash table.  */boolean_bfd_coff_link_hash_table_init (table, abfd, newfunc)     struct coff_link_hash_table *table;     bfd *abfd;     struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,						struct bfd_hash_table *,						const char *));{  table->stab_info = NULL;  return _bfd_link_hash_table_init (&table->root, abfd, newfunc);}/* Create a COFF linker hash table.  */struct bfd_link_hash_table *_bfd_coff_link_hash_table_create (abfd)     bfd *abfd;{  struct coff_link_hash_table *ret;  ret = ((struct coff_link_hash_table *)	 bfd_alloc (abfd, sizeof (struct coff_link_hash_table)));  if (ret == NULL)    return NULL;  if (! _bfd_coff_link_hash_table_init (ret, abfd,					_bfd_coff_link_hash_newfunc))    {      bfd_release (abfd, ret);      return (struct bfd_link_hash_table *) NULL;    }  return &ret->root;}/* Create an entry in a COFF debug merge hash table.  */struct bfd_hash_entry *_bfd_coff_debug_merge_hash_newfunc (entry, table, string)     struct bfd_hash_entry *entry;     struct bfd_hash_table *table;     const char *string;{  struct coff_debug_merge_hash_entry *ret =    (struct coff_debug_merge_hash_entry *) entry;  /* Allocate the structure if it has not already been allocated by a     subclass.  */  if (ret == (struct coff_debug_merge_hash_entry *) NULL)    ret = ((struct coff_debug_merge_hash_entry *)	   bfd_hash_allocate (table,			      sizeof (struct coff_debug_merge_hash_entry)));  if (ret == (struct coff_debug_merge_hash_entry *) NULL)    return (struct bfd_hash_entry *) ret;  /* Call the allocation method of the superclass.  */  ret = ((struct coff_debug_merge_hash_entry *)	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));  if (ret != (struct coff_debug_merge_hash_entry *) NULL)    {      /* Set local fields.  */      ret->types = NULL;    }  return (struct bfd_hash_entry *) ret;}/* Given a COFF BFD, add symbols to the global hash table as   appropriate.  */boolean_bfd_coff_link_add_symbols (abfd, info)     bfd *abfd;     struct bfd_link_info *info;{  switch (bfd_get_format (abfd))    {    case bfd_object:      return coff_link_add_object_symbols (abfd, info);    case bfd_archive:      return (_bfd_generic_link_add_archive_symbols	      (abfd, info, coff_link_check_archive_element));    default:      bfd_set_error (bfd_error_wrong_format);      return false;    }}/* Add symbols from a COFF object file.  */static booleancoff_link_add_object_symbols (abfd, info)     bfd *abfd;     struct bfd_link_info *info;{  if (! _bfd_coff_get_external_symbols (abfd))    return false;  if (! coff_link_add_symbols (abfd, info))    return false;  if (! info->keep_memory)    {      if (! _bfd_coff_free_symbols (abfd))	return false;    }  return true;}/* Check a single archive element to see if we need to include it in   the link.  *PNEEDED is set according to whether this element is   needed in the link or not.  This is called via   _bfd_generic_link_add_archive_symbols.  */static booleancoff_link_check_archive_element (abfd, info, pneeded)     bfd *abfd;     struct bfd_link_info *info;     boolean *pneeded;{  if (! _bfd_coff_get_external_symbols (abfd))    return false;  if (! coff_link_check_ar_symbols (abfd, info, pneeded))    return false;  if (*pneeded)    {      if (! coff_link_add_symbols (abfd, info))	return false;    }  if (! info->keep_memory || ! *pneeded)    {      if (! _bfd_coff_free_symbols (abfd))	return false;    }  return true;}/* Look through the symbols to see if this object file should be   included in the link.  */static booleancoff_link_check_ar_symbols (abfd, info, pneeded)     bfd *abfd;     struct bfd_link_info *info;     boolean *pneeded;{  bfd_size_type symesz;  bfd_byte *esym;  bfd_byte *esym_end;  *pneeded = false;  symesz = bfd_coff_symesz (abfd);  esym = (bfd_byte *) obj_coff_external_syms (abfd);  esym_end = esym + obj_raw_syment_count (abfd) * symesz;  while (esym < esym_end)    {      struct internal_syment sym;      enum coff_symbol_classification classification;      bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);      classification = bfd_coff_classify_symbol (abfd, &sym);      if (classification == COFF_SYMBOL_GLOBAL	  || classification == COFF_SYMBOL_COMMON)	{	  const char *name;	  char buf[SYMNMLEN + 1];	  struct bfd_link_hash_entry *h;	  /* This symbol is externally visible, and is defined by this             object file.  */	  name = _bfd_coff_internal_syment_name (abfd, &sym, buf);	  if (name == NULL)	    return false;	  h = bfd_link_hash_lookup (info->hash, name, false, false, true);	  /* We are only interested in symbols that are currently	     undefined.  If a symbol is currently known to be common,	     COFF linkers do not bring in an object file which defines	     it.  */	  if (h != (struct bfd_link_hash_entry *) NULL	      && h->type == bfd_link_hash_undefined)	    {	      if (! (*info->callbacks->add_archive_element) (info, abfd, name))		return false;	      *pneeded = true;	      return true;	    }	}      esym += (sym.n_numaux + 1) * symesz;    }  /* We do not need this object file.  */  return true;}/* Add all the symbols from an object file to the hash table.  */static booleancoff_link_add_symbols (abfd, info)     bfd *abfd;     struct bfd_link_info *info;{  unsigned int n_tmask = coff_data (abfd)->local_n_tmask;  unsigned int n_btshft = coff_data (abfd)->local_n_btshft;  unsigned int n_btmask = coff_data (abfd)->local_n_btmask;  boolean keep_syms;  boolean default_copy;  bfd_size_type symcount;  struct coff_link_hash_entry **sym_hash;  bfd_size_type symesz;  bfd_byte *esym;  bfd_byte *esym_end;  /* Keep the symbols during this function, in case the linker needs     to read the generic symbols in order to report an error message.  */  keep_syms = obj_coff_keep_syms (abfd);  obj_coff_keep_syms (abfd) = true;  if (info->keep_memory)    default_copy = false;  else    default_copy = true;  symcount = obj_raw_syment_count (abfd);  /* We keep a list of the linker hash table entries that correspond     to particular symbols.  */  sym_hash = ((struct coff_link_hash_entry **)	      bfd_alloc (abfd,			 ((size_t) symcount			  * sizeof (struct coff_link_hash_entry *))));  if (sym_hash == NULL && symcount != 0)    goto error_return;  obj_coff_sym_hashes (abfd) = sym_hash;  memset (sym_hash, 0,	  (size_t) symcount * sizeof (struct coff_link_hash_entry *));  symesz = bfd_coff_symesz (abfd);  BFD_ASSERT (symesz == bfd_coff_auxesz (abfd));  esym = (bfd_byte *) obj_coff_external_syms (abfd);  esym_end = esym + symcount * symesz;  while (esym < esym_end)    {      struct internal_syment sym;      enum coff_symbol_classification classification;      boolean copy;      bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);      classification = bfd_coff_classify_symbol (abfd, &sym);      if (classification != COFF_SYMBOL_LOCAL)	{	  const char *name;	  char buf[SYMNMLEN + 1];	  flagword flags;	  asection *section;	  bfd_vma value;	  boolean addit;	  /* This symbol is externally visible.  */	  name = _bfd_coff_internal_syment_name (abfd, &sym, buf);	  if (name == NULL)	    goto error_return;	  /* We must copy the name into memory if we got it from the             syment itself, rather than the string table.  */	  copy = default_copy;	  if (sym._n._n_n._n_zeroes != 0	      || sym._n._n_n._n_offset == 0)	    copy = true;	  value = sym.n_value;	  switch (classification)	    {	    default:	      abort ();	    case COFF_SYMBOL_GLOBAL:	      flags = BSF_EXPORT | BSF_GLOBAL;	      section = coff_section_from_bfd_index (abfd, sym.n_scnum);	      if (! obj_pe (abfd))		value -= section->vma;	      break;	    case COFF_SYMBOL_UNDEFINED:	      flags = 0;	      section = bfd_und_section_ptr;	      break;	    case COFF_SYMBOL_COMMON:	      flags = BSF_GLOBAL;	      section = bfd_com_section_ptr;	      break;	    case COFF_SYMBOL_PE_SECTION:	      flags = BSF_SECTION_SYM | BSF_GLOBAL;	      section = coff_section_from_bfd_index (abfd, sym.n_scnum);	      break;	    }	  if (IS_WEAK_EXTERNAL (abfd, sym))	    flags = BSF_WEAK;	  addit = true;	  /* In the PE format, section symbols actually refer to the             start of the output section.  We handle them specially             here.  */	  if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0)	    {	      *sym_hash = coff_link_hash_lookup (coff_hash_table (info),						 name, false, copy, false);	      if (*sym_hash != NULL)		{		  if (((*sym_hash)->coff_link_hash_flags		       & COFF_LINK_HASH_PE_SECTION_SYMBOL) == 0		      && (*sym_hash)->root.type != bfd_link_hash_undefined		      && (*sym_hash)->root.type != bfd_link_hash_undefweak)		    (*_bfd_error_handler)		      ("Warning: symbol `%s' is both section and non-section",		       name);		  addit = false;		}	    }	  /* The Microsoft Visual C compiler does string pooling by	     hashing the constants to an internal symbol name, and	     relying on the the linker comdat support to discard	     duplicate names.  However, if one string is a literal and	     one is a data initializer, one will end up in the .data	     section and one will end up in the .rdata section.  The	     Microsoft linker will combine them into the .data	     section, which seems to be wrong since it might cause the	     literal to change.	     As long as there are no external references to the	     symbols, which there shouldn't be, we can treat the .data	     and .rdata instances as separate symbols.  The comdat	     code in the linker will do the appropriate merging.  Here	     we avoid getting a multiple definition error for one of	     these special symbols.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?