Wolfgang Thallergcc16 merge934c3885 months agoHistory
3253 lines · 87.5 KB · C
RawDownload
/* write.c - emit .o file   Copyright (C) 1986-2026 Free Software Foundation, Inc.    This file is part of GAS, the GNU Assembler.    GAS 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, or (at your option)   any later version.    GAS 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 GAS; see the file COPYING.  If not, write to the Free   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA   02110-1301, USA.  */ /* This thing should be set up to do byte ordering correctly.  But...  */ #include "as.h"#include "subsegs.h"#include "obstack.h"#include "output-file.h"#include "dwarf2dbg.h"#include "compress-debug.h"#include "codeview.h" #ifndef FINALIZE_SECTION_RELOCS#define FINALIZE_SECTION_RELOCS(sec, relocs, n)	\  bfd_finalize_section_relocs (stdoutput, sec, n ? relocs : NULL, n)#endif #ifndef TC_FORCE_RELOCATION#define TC_FORCE_RELOCATION(FIX)		\  (generic_force_reloc (FIX))#endif #ifndef TC_FORCE_RELOCATION_ABS#define TC_FORCE_RELOCATION_ABS(FIX)		\  (TC_FORCE_RELOCATION (FIX))#endif #define GENERIC_FORCE_RELOCATION_LOCAL(FIX)	\  (!(FIX)->fx_pcrel				\   || TC_FORCE_RELOCATION (FIX))#ifndef TC_FORCE_RELOCATION_LOCAL#define TC_FORCE_RELOCATION_LOCAL GENERIC_FORCE_RELOCATION_LOCAL#endif #define GENERIC_FORCE_RELOCATION_SUB_SAME(FIX, SEG)	\  (!SEG_NORMAL (SEG))#ifndef TC_FORCE_RELOCATION_SUB_SAME#define TC_FORCE_RELOCATION_SUB_SAME GENERIC_FORCE_RELOCATION_SUB_SAME#endif #ifndef md_register_arithmetic# define md_register_arithmetic 1#endif #ifndef TC_FORCE_RELOCATION_SUB_ABS#define TC_FORCE_RELOCATION_SUB_ABS(FIX, SEG)	\  (!md_register_arithmetic && (SEG) == reg_section)#endif #ifndef TC_FORCE_RELOCATION_SUB_LOCAL#ifdef DIFF_EXPR_OK#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG)	\  (!md_register_arithmetic && (SEG) == reg_section)#else#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG)	1#endif#endif #ifndef TC_VALIDATE_FIX_SUB#define TC_VALIDATE_FIX_SUB(FIX, SEG) 0#endif #ifndef TC_LINKRELAX_FIXUP#define TC_LINKRELAX_FIXUP(SEG) 1#endif #ifndef MD_APPLY_SYM_VALUE#define MD_APPLY_SYM_VALUE(FIX) 1#endif #ifndef TC_FINALIZE_SYMS_BEFORE_SIZE_SEG#define TC_FINALIZE_SYMS_BEFORE_SIZE_SEG 1#endif #ifndef	MD_PCREL_FROM_SECTION#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from (FIX)#endif #ifndef TC_FAKE_LABEL#define TC_FAKE_LABEL(NAME) (strcmp ((NAME), FAKE_LABEL_NAME) == 0)#endif /* Positive values of TC_FX_SIZE_SLACK allow a target to define   fixups that far past the end of a frag.  Having such fixups   is of course most most likely a bug in setting fx_size correctly.   A negative value disables the fixup check entirely, which is   appropriate for something like the Renesas / SuperH SH_COUNT   reloc.  */#ifndef TC_FX_SIZE_SLACK#define TC_FX_SIZE_SLACK(FIX) 0#endif /* Used to control final evaluation of expressions.  */int finalize_syms = 0; int symbol_table_frozen; symbolS *abs_section_sym; /* Relocs generated by ".reloc" pseudo.  */struct reloc_list* reloc_list; void print_fixup (fixS *); /* We generally attach relocs to frag chains.  However, after we have   chained these all together into a segment, any relocs we add after   that must be attached to a segment.  This will include relocs added   in md_estimate_size_before_relax, for example.  */static bool frags_chained = false; static unsigned int n_fixups; #define RELOC_ENUM enum bfd_reloc_code_real /* Create a fixS in obstack 'notes'.  */ static fixS *fix_new_internal (fragS *frag,		/* Which frag?  */		  unsigned long where,	/* Where in that frag?  */		  unsigned long size,	/* 1, 2, or 4 usually.  */		  symbolS *add_symbol,	/* X_add_symbol.  */		  symbolS *sub_symbol,	/* X_op_symbol.  */		  offsetT offset,	/* X_add_number.  */		  int pcrel,		/* TRUE if PC-relative relocation.  */		  RELOC_ENUM r_type	/* Relocation type.  */,		  int at_beginning)	/* Add to the start of the list?  */{  fixS *fixP;   n_fixups++;   fixP = obstack_alloc (&notes, sizeof (fixS));   fixP->fx_frag = frag;  fixP->fx_where = where;  fixP->fx_size = size;  /* We've made fx_size a narrow field; check that it's wide enough.  */  if (fixP->fx_size != size)    {      as_bad (_("field fx_size too small to hold %lu"), size);      abort ();    }  fixP->fx_addsy = add_symbol;  fixP->fx_subsy = sub_symbol;  fixP->fx_offset = offset;  fixP->fx_dot_frag = symbol_get_frag_and_value (&dot_symbol,						 &fixP->fx_dot_value);  fixP->fx_pcrel = pcrel;  fixP->fx_r_type = r_type;  fixP->fx_pcrel_adjust = 0;  fixP->fx_addnumber = 0;  fixP->fx_tcbit = 0;  fixP->fx_tcbit2 = 0;  fixP->fx_tcbit3 = 0;  fixP->fx_done = 0;  fixP->fx_no_overflow = 0;  fixP->fx_signed = 0; #ifdef USING_CGEN  fixP->fx_cgen.insn = NULL;  fixP->fx_cgen.opinfo = 0;#endif #ifdef TC_FIX_TYPE  TC_INIT_FIX_DATA (fixP);#endif   fixP->fx_file = as_where (&fixP->fx_line);   {     fixS **seg_fix_rootP = (frags_chained			    ? &seg_info (now_seg)->fix_root			    : &frchain_now->fix_root);    fixS **seg_fix_tailP = (frags_chained			    ? &seg_info (now_seg)->fix_tail			    : &frchain_now->fix_tail);     if (at_beginning)      {	fixP->fx_next = *seg_fix_rootP;	*seg_fix_rootP = fixP;	if (fixP->fx_next == NULL)	  *seg_fix_tailP = fixP;      }    else      {	fixP->fx_next = NULL;	if (*seg_fix_tailP)	  (*seg_fix_tailP)->fx_next = fixP;	else	  *seg_fix_rootP = fixP;	*seg_fix_tailP = fixP;      }  }   return fixP;} /* Create a fixup relative to a symbol (plus a constant).  */ fixS *fix_new (fragS *frag,			/* Which frag?  */	 unsigned long where,		/* Where in that frag?  */	 unsigned long size,		/* 1, 2, or 4 usually.  */	 symbolS *add_symbol,		/* X_add_symbol.  */	 offsetT offset,		/* X_add_number.  */	 int pcrel,			/* TRUE if PC-relative relocation.  */	 RELOC_ENUM r_type		/* Relocation type.  */){  return fix_new_internal (frag, where, size, add_symbol,			   NULL, offset, pcrel, r_type, false);} /* Create a fixup for an expression.  Currently we only support fixups   for difference expressions.  That is itself more than most object   file formats support anyhow.  */ fixS *fix_new_exp (fragS *frag,		/* Which frag?  */	     unsigned long where,	/* Where in that frag?  */	     unsigned long size,	/* 1, 2, or 4 usually.  */	     const expressionS *exp,	/* Expression.  */	     int pcrel,			/* TRUE if PC-relative relocation.  */	     RELOC_ENUM r_type		/* Relocation type.  */){  symbolS *add = NULL;  symbolS *sub = NULL;  offsetT off = 0;   switch (exp->X_op)    {    case O_absent:      break;     case O_register:      as_bad (_("register value used as expression"));      break;     case O_symbol_rva:      add = exp->X_add_symbol;      off = exp->X_add_number;      r_type = BFD_RELOC_RVA;      break;     case O_uminus:      sub = exp->X_add_symbol;      off = exp->X_add_number;      break;     case O_subtract:      sub = exp->X_op_symbol;      /* Fall through.  */    case O_symbol:      add = exp->X_add_symbol;      /* Fall through.  */    case O_constant:      off = exp->X_add_number;      break;     case O_add: /* This comes up when _GLOBAL_OFFSET_TABLE_+(.-L0) is read, if		   the difference expression cannot immediately be reduced.  */    default:      add = make_expr_symbol (exp);      break;    }   return fix_new_internal (frag, where, size, add, sub, off, pcrel,			   r_type, false);} /* Create a fixup at the beginning of FRAG.  The arguments are the same   as for fix_new, except that WHERE is implicitly 0.  */ fixS *fix_at_start (fragS *frag, unsigned long size, symbolS *add_symbol,	      offsetT offset, int pcrel, RELOC_ENUM r_type){  return fix_new_internal (frag, 0, size, add_symbol,			   NULL, offset, pcrel, r_type, true);} /* Generic function to determine whether a fixup requires a relocation.  */intgeneric_force_reloc (fixS *fix){  if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT      || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY)    return 1;   if (fix->fx_addsy == NULL)    return 0;   return S_FORCE_RELOC (fix->fx_addsy, fix->fx_subsy == NULL);} /* Append a string onto another string, bumping the pointer along.  */voidappend (char **charPP, char *fromP, unsigned long length){  /* Don't trust memcpy() of 0 chars.  */  if (length == 0)    return;   memcpy (*charPP, fromP, length);  *charPP += length;} /* This routine records the largest alignment seen for each segment.   If the beginning of the segment is aligned on the worst-case   boundary, all of the other alignments within it will work.  At   least one object format really uses this info.  */ voidrecord_alignment (/* Segment to which alignment pertains.  */		  segT seg,		  /* Alignment, as a power of 2 (e.g., 1 => 2-byte		     boundary, 2 => 4-byte boundary, etc.)  */		  unsigned int align){  if (seg == absolute_section)    return;   if (align > bfd_section_alignment (seg))    bfd_set_section_alignment (seg, align);} intget_recorded_alignment (segT seg){  if (seg == absolute_section)    return 0;   return bfd_section_alignment (seg);} /* Reset the section indices after removing the gas created sections.  */ static voidrenumber_sections (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *countparg){  int *countp = countparg;   sec->index = *countp;  ++*countp;} static fragS *chain_frchains_together_1 (segT section, struct frchain *frchp){  fragS dummy, *prev_frag = &dummy;  fixS fix_dummy, *prev_fix = &fix_dummy;   do    {      prev_frag->fr_next = frchp->frch_root;      prev_frag = frchp->frch_last;      gas_assert (prev_frag->fr_type != 0);      if (frchp->fix_root != NULL)	{	  if (seg_info (section)->fix_root == NULL)	    seg_info (section)->fix_root = frchp->fix_root;	  prev_fix->fx_next = frchp->fix_root;	  seg_info (section)->fix_tail = frchp->fix_tail;	  prev_fix = frchp->fix_tail;	}      frchp = frchp->frch_next;    } while (frchp);  gas_assert (prev_frag != &dummy	      && prev_frag->fr_type != 0);  prev_frag->fr_next = 0;  return prev_frag;} static voidchain_frchains_together (bfd *abfd ATTRIBUTE_UNUSED,			 segT section,			 void *xxx ATTRIBUTE_UNUSED){  segment_info_type *info;   /* BFD may have introduced its own sections without using     subseg_new, so it is possible that seg_info is NULL.  */  info = seg_info (section);  if (info != NULL)    info->frchainP->frch_last      = chain_frchains_together_1 (section, info->frchainP);   /* Now that we've chained the frags together, we must add new fixups     to the segment, not to the frag chain.  */  frags_chained = true;} static voidcvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP){  switch (fragP->fr_type)    {    case rs_space_nop:      goto skip_align;    case rs_align:    case rs_align_code:    case rs_align_test:    case rs_org:    case rs_space:#ifdef HANDLE_ALIGN      HANDLE_ALIGN (sec, fragP);#endif    skip_align:      know (fragP->fr_next != NULL);      fragP->fr_offset = (fragP->fr_next->fr_address			  - fragP->fr_address			  - fragP->fr_fix) / fragP->fr_var;      if (fragP->fr_offset < 0)	{	  as_bad_where (fragP->fr_file, fragP->fr_line,			_("attempt to .org/.space/.nops backwards? (%ld)"),			(long) fragP->fr_offset);	  fragP->fr_offset = 0;	}      if (fragP->fr_type == rs_space_nop)	fragP->fr_type = rs_fill_nop;      else	fragP->fr_type = rs_fill;      break;     case rs_fill:    case rs_fill_nop:      break;     case rs_leb128:      {	valueT value = S_GET_VALUE (fragP->fr_symbol);	int size; 	if (!S_IS_DEFINED (fragP->fr_symbol))	  {	    as_bad_where (fragP->fr_file, fragP->fr_line,			  _("leb128 operand is an undefined symbol: %s"),			  S_GET_NAME (fragP->fr_symbol));	  } 	size = output_leb128 (fragP->fr_literal + fragP->fr_fix, value,			      fragP->fr_subtype); 	fragP->fr_fix += size;	fragP->fr_type = rs_fill;	fragP->fr_var = 0;	fragP->fr_offset = 0;	fragP->fr_symbol = NULL;      }      break;     case rs_cfa:      eh_frame_convert_frag (fragP);      break;     case rs_dwarf2dbg:      dwarf2dbg_convert_frag (fragP);      break;     case rs_sframe:      sframe_convert_frag (fragP);      break;     case rs_machine_dependent:      md_convert_frag (stdoutput, sec, fragP);       gas_assert (fragP->fr_next == NULL		  || (fragP->fr_next->fr_address - fragP->fr_address		      == fragP->fr_fix));       /* After md_convert_frag, we make the frag into a ".space 0".	 md_convert_frag() should set up any fixSs and constants	 required.  */      frag_wane (fragP);      break; #ifndef WORKING_DOT_WORD    case rs_broken_word:      {	struct broken_word *lie;

Lines 1–500 of 3253.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t