| /* write.c - emit .o file | 
 |    Copyright (C) 1986-2025 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 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 = (fixS *) obstack_alloc (¬es, 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, | 
 | 			   (symbolS *) 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, | 
 | 			   (symbolS *) NULL, offset, pcrel, r_type, true); | 
 | } | 
 |  | 
 | /* Generic function to determine whether a fixup requires a relocation.  */ | 
 | int | 
 | generic_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.  */ | 
 | void | 
 | append (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.  */ | 
 |  | 
 | void | 
 | record_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); | 
 | } | 
 |  | 
 | int | 
 | get_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 void | 
 | renumber_sections (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *countparg) | 
 | { | 
 |   int *countp = (int *) 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 != (fixS *) NULL) | 
 | 	{ | 
 | 	  if (seg_info (section)->fix_root == (fixS *) 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 void | 
 | chain_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 != (segment_info_type *) 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 void | 
 | cvt_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; | 
 |  | 
 | 	if (fragP->fr_subtype) | 
 | 	  { | 
 | 	    fragP->fr_fix += md_short_jump_size; | 
 | 	    for (lie = (struct broken_word *) (fragP->fr_symbol); | 
 | 		 lie && lie->dispfrag == fragP; | 
 | 		 lie = lie->next_broken_word) | 
 | 	      if (lie->added == 1) | 
 | 		fragP->fr_fix += md_long_jump_size; | 
 | 	  } | 
 | 	frag_wane (fragP); | 
 |       } | 
 |       break; | 
 | #endif | 
 |  | 
 | #if defined (TE_PE) && defined (O_secrel) | 
 |     case rs_cv_comp: | 
 |       { | 
 | 	offsetT 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, | 
 | 			  _(".cv_%ccomp operand is an undefined symbol: %s"), | 
 | 			  fragP->fr_subtype ? 's' : 'u', | 
 | 			  S_GET_NAME (fragP->fr_symbol)); | 
 | 	  } | 
 |  | 
 | 	size = output_cv_comp (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; | 
 | #endif | 
 |  | 
 |     default: | 
 |       BAD_CASE (fragP->fr_type); | 
 |       break; | 
 |     } | 
 | #ifdef md_frag_check | 
 |   md_frag_check (fragP); | 
 | #endif | 
 | } | 
 |  | 
 | struct relax_seg_info | 
 | { | 
 |   int pass; | 
 |   int changed; | 
 | }; | 
 |  | 
 | static void | 
 | relax_seg (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *xxx) | 
 | { | 
 |   segment_info_type *seginfo = seg_info (sec); | 
 |   struct relax_seg_info *info = (struct relax_seg_info *) xxx; | 
 |  | 
 |   if (seginfo && seginfo->frchainP | 
 |       && relax_segment (seginfo->frchainP->frch_root, sec, info->pass)) | 
 |     info->changed = 1; | 
 | } | 
 |  | 
 | static void | 
 | size_seg (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *xxx ATTRIBUTE_UNUSED) | 
 | { | 
 |   flagword flags; | 
 |   fragS *fragp; | 
 |   segment_info_type *seginfo; | 
 |   int x; | 
 |   valueT size, newsize; | 
 |  | 
 |   subseg_change (sec, 0); | 
 |  | 
 |   seginfo = seg_info (sec); | 
 |   if (seginfo && seginfo->frchainP) | 
 |     { | 
 |       for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next) | 
 | 	cvt_frag_to_fill (sec, fragp); | 
 |       for (fragp = seginfo->frchainP->frch_root; | 
 | 	   fragp->fr_next; | 
 | 	   fragp = fragp->fr_next) | 
 | 	/* Walk to last elt.  */ | 
 | 	; | 
 |       size = fragp->fr_address + fragp->fr_fix; | 
 |     } | 
 |   else | 
 |     size = 0; | 
 |  | 
 |   flags = bfd_section_flags (sec); | 
 |   if (size == 0 && bfd_section_size (sec) != 0 && | 
 |     (flags & SEC_HAS_CONTENTS) != 0) | 
 |     return; | 
 |  | 
 |   if (size > 0 && ! seginfo->bss) | 
 |     flags |= SEC_HAS_CONTENTS; | 
 |  | 
 |   x = bfd_set_section_flags (sec, flags); | 
 |   gas_assert (x); | 
 |  | 
 |   /* If permitted, allow the backend to pad out the section | 
 |      to some alignment boundary.  */ | 
 |   if (do_not_pad_sections_to_alignment) | 
 |     newsize = size; | 
 |   else | 
 |     newsize = md_section_align (sec, size); | 
 |   x = bfd_set_section_size (sec, newsize); | 
 |   gas_assert (x); | 
 |  | 
 |   /* If the size had to be rounded up, add some padding in the last | 
 |      non-empty frag.  */ | 
 |   gas_assert (newsize >= size); | 
 |   if (size != newsize) | 
 |     { | 
 |       fragS *last = seginfo->frchainP->frch_last; | 
 |       fragp = seginfo->frchainP->frch_root; | 
 |       while (fragp->fr_next != last) | 
 | 	fragp = fragp->fr_next; | 
 |       last->fr_address = size; | 
 |       if ((newsize - size) % fragp->fr_var == 0) | 
 | 	fragp->fr_offset += (newsize - size) / fragp->fr_var; | 
 |       else | 
 | 	/* If we hit this abort, it's likely due to subsegs_finish not | 
 | 	   providing sufficient alignment on the last frag, and the | 
 | 	   machine dependent code using alignment frags with fr_var | 
 | 	   greater than 1.  */ | 
 | 	abort (); | 
 |     } | 
 |  | 
 | #ifdef tc_frob_section | 
 |   tc_frob_section (sec); | 
 | #endif | 
 | #ifdef obj_frob_section | 
 |   obj_frob_section (sec); | 
 | #endif | 
 | } | 
 |  | 
 | #ifdef DEBUG2 | 
 | static void | 
 | dump_section_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, FILE *stream) | 
 | { | 
 |   segment_info_type *seginfo = seg_info (sec); | 
 |   fixS *fixp = seginfo->fix_root; | 
 |  | 
 |   if (!fixp) | 
 |     return; | 
 |  | 
 |   fprintf (stream, "sec %s relocs:\n", sec->name); | 
 |   while (fixp) | 
 |     { | 
 |       symbolS *s = fixp->fx_addsy; | 
 |  | 
 |       fprintf (stream, "  %08lx: type %d ", (unsigned long) fixp, | 
 | 	       (int) fixp->fx_r_type); | 
 |       if (s == NULL) | 
 | 	fprintf (stream, "no sym\n"); | 
 |       else | 
 | 	{ | 
 | 	  print_symbol_value_1 (stream, s); | 
 | 	  fprintf (stream, "\n"); | 
 | 	} | 
 |       fixp = fixp->fx_next; | 
 |     } | 
 | } | 
 | #else | 
 | #define dump_section_relocs(ABFD,SEC,STREAM)	((void) 0) | 
 | #endif | 
 |  | 
 | #ifndef EMIT_SECTION_SYMBOLS | 
 | #define EMIT_SECTION_SYMBOLS 1 | 
 | #endif | 
 |  | 
 | /* Resolve U.A.OFFSET_SYM and U.A.SYM fields of RELOC_LIST entries, | 
 |    and check for validity.  Convert RELOC_LIST from using U.A fields | 
 |    to U.B fields.  */ | 
 | static void | 
 | resolve_reloc_expr_symbols (void) | 
 | { | 
 |   bfd_vma addr_mask = 1; | 
 |   struct reloc_list *r; | 
 |  | 
 |   /* Avoid a shift by the width of type.  */ | 
 |   addr_mask <<= bfd_arch_bits_per_address (stdoutput) - 1; | 
 |   addr_mask <<= 1; | 
 |   addr_mask -= 1; | 
 |  | 
 |   for (r = reloc_list; r; r = r->next) | 
 |     { | 
 |       reloc_howto_type *howto = r->u.a.howto; | 
 |       expressionS *symval; | 
 |       symbolS *sym; | 
 |       bfd_vma offset, addend; | 
 |       asection *sec; | 
 |  | 
 |       resolve_symbol_value (r->u.a.offset_sym); | 
 |       symval = symbol_get_value_expression (r->u.a.offset_sym); | 
 |  | 
 |       offset = 0; | 
 |       sym = NULL; | 
 |       if (symval->X_op == O_constant) | 
 | 	sym = r->u.a.offset_sym; | 
 |       else if (symval->X_op == O_symbol) | 
 | 	{ | 
 | 	  sym = symval->X_add_symbol; | 
 | 	  offset = symval->X_add_number; | 
 | 	  symval = symbol_get_value_expression (symval->X_add_symbol); | 
 | 	} | 
 |       if (sym == NULL | 
 | 	  || symval->X_op != O_constant | 
 | 	  || (sec = S_GET_SEGMENT (sym)) == NULL | 
 | 	  || !SEG_NORMAL (sec)) | 
 | 	{ | 
 | 	  as_bad_where (r->file, r->line, _("invalid offset expression")); | 
 | 	  sec = NULL; | 
 | 	} | 
 |       else | 
 | 	offset += S_GET_VALUE (sym); | 
 |  | 
 |       sym = NULL; | 
 |       addend = r->u.a.addend; | 
 |       if (r->u.a.sym != NULL) | 
 | 	{ | 
 | 	  resolve_symbol_value (r->u.a.sym); | 
 | 	  symval = symbol_get_value_expression (r->u.a.sym); | 
 | 	  if (symval->X_op == O_constant) | 
 | 	    sym = r->u.a.sym; | 
 | 	  else if (symval->X_op == O_symbol) | 
 | 	    { | 
 | 	      sym = symval->X_add_symbol; | 
 | 	      addend += symval->X_add_number; | 
 | 	      symval = symbol_get_value_expression (symval->X_add_symbol); | 
 | 	    } | 
 | 	  if (symval->X_op != O_constant) | 
 | 	    { | 
 | 	      as_bad_where (r->file, r->line, _("invalid reloc expression")); | 
 | 	      sec = NULL; | 
 | 	    } | 
 | 	  else if (sym != NULL && sec != NULL) | 
 | 	    { | 
 | 	      /* Convert relocs against local symbols to refer to the | 
 | 		 corresponding section symbol plus offset instead.  Keep | 
 | 		 PC-relative relocs of the REL variety intact though to | 
 | 		 prevent the offset from overflowing the relocated field, | 
 | 		 unless it has enough bits to cover the whole address | 
 | 		 space.  */ | 
 | 	      if (S_IS_LOCAL (sym) | 
 | 		  && S_IS_DEFINED (sym) | 
 | 		  && !symbol_section_p (sym) | 
 | 		  && (sec->use_rela_p | 
 | 		      || (howto->partial_inplace | 
 | 			  && (!howto->pc_relative | 
 | 			      || howto->src_mask == addr_mask)))) | 
 | 		{ | 
 | 		  asection *symsec = S_GET_SEGMENT (sym); | 
 | 		  if (!(((symsec->flags & SEC_MERGE) != 0 | 
 | 			 && addend != 0) | 
 | 			|| (symsec->flags & SEC_THREAD_LOCAL) != 0)) | 
 | 		    { | 
 | 		      addend += S_GET_VALUE (sym); | 
 | 		      sym = section_symbol (symsec); | 
 | 		    } | 
 | 		} | 
 | 	      symbol_mark_used_in_reloc (sym); | 
 | 	    } | 
 | 	} | 
 |       if (sym == NULL) | 
 | 	{ | 
 | 	  if (abs_section_sym == NULL) | 
 | 	    abs_section_sym = section_symbol (absolute_section); | 
 | 	  sym = abs_section_sym; | 
 | 	} | 
 |  | 
 |       r->u.b.sec = sec; | 
 |       r->u.b.s = symbol_get_bfdsym (sym); | 
 |       r->u.b.r.sym_ptr_ptr = &r->u.b.s; | 
 |       r->u.b.r.address = offset; | 
 |       r->u.b.r.addend = addend; | 
 |       r->u.b.r.howto = howto; | 
 |     } | 
 | } | 
 |  | 
 | /* This pass over fixups decides whether symbols can be replaced with | 
 |    section symbols.  */ | 
 |  | 
 | static void | 
 | adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED, | 
 | 		   asection *sec, | 
 | 		   void *xxx ATTRIBUTE_UNUSED) | 
 | { | 
 |   segment_info_type *seginfo = seg_info (sec); | 
 |   fixS *fixp; | 
 |   valueT val; | 
 |  | 
 |   if (seginfo == NULL) | 
 |     return; | 
 |  | 
 |   dump_section_relocs (abfd, sec, stderr); | 
 |  | 
 |   for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) | 
 |     if (fixp->fx_done) | 
 |       /* Ignore it.  */ | 
 |       ; | 
 |     else if (fixp->fx_addsy) | 
 |       { | 
 | 	symbolS *sym; | 
 | 	asection *symsec; | 
 |  | 
 | #ifdef DEBUG5 | 
 | 	fprintf (stderr, "\n\nadjusting fixup:\n"); | 
 | 	print_fixup (fixp); | 
 | #endif | 
 |  | 
 | 	sym = fixp->fx_addsy; | 
 |  | 
 | 	/* All symbols should have already been resolved at this | 
 | 	   point.  It is possible to see unresolved expression | 
 | 	   symbols, though, since they are not in the regular symbol | 
 | 	   table.  */ | 
 | 	resolve_symbol_value (sym); | 
 |  | 
 | 	if (fixp->fx_subsy != NULL) | 
 | 	  resolve_symbol_value (fixp->fx_subsy); | 
 |  | 
 | 	/* If this symbol is equated to an undefined or common symbol, | 
 | 	   convert the fixup to being against that symbol.  */ | 
 | 	while (symbol_equated_reloc_p (sym) | 
 | 	       || S_IS_WEAKREFR (sym)) | 
 | 	  { | 
 | 	    symbolS *newsym = symbol_get_value_expression (sym)->X_add_symbol; | 
 | 	    if (sym == newsym) | 
 | 	      break; | 
 | 	    fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number; | 
 | 	    fixp->fx_addsy = newsym; | 
 | 	    sym = newsym; | 
 | 	  } | 
 |  | 
 | 	if (symbol_mri_common_p (sym)) | 
 | 	  { | 
 | 	    fixp->fx_offset += S_GET_VALUE (sym); | 
 | 	    fixp->fx_addsy = symbol_get_value_expression (sym)->X_add_symbol; | 
 | 	    continue; | 
 | 	  } | 
 |  | 
 | 	/* If the symbol is undefined, common, weak, or global (ELF | 
 | 	   shared libs), we can't replace it with the section symbol.  */ | 
 | 	if (S_FORCE_RELOC (fixp->fx_addsy, 1)) | 
 | 	  continue; | 
 |  | 
 | 	/* Is there some other (target cpu dependent) reason we can't adjust | 
 | 	   this one?  (E.g. relocations involving function addresses on | 
 | 	   the PA.  */ | 
 | #ifdef tc_fix_adjustable | 
 | 	if (! tc_fix_adjustable (fixp)) | 
 | 	  continue; | 
 | #endif | 
 |  | 
 | 	/* Since we're reducing to section symbols, don't attempt to reduce | 
 | 	   anything that's already using one.  */ | 
 | 	if (symbol_section_p (sym)) | 
 | 	  { | 
 | 	    /* Mark the section symbol used in relocation so that it will | 
 | 	       be included in the symbol table.  */ | 
 | 	    symbol_mark_used_in_reloc (sym); | 
 | 	    continue; | 
 | 	  } | 
 |  | 
 | 	symsec = S_GET_SEGMENT (sym); | 
 | 	if (symsec == NULL) | 
 | 	  abort (); | 
 |  | 
 | 	if (bfd_is_abs_section (symsec) | 
 | 	    || symsec == reg_section) | 
 | 	  { | 
 | 	    /* The fixup_segment routine normally will not use this | 
 | 	       symbol in a relocation.  */ | 
 | 	    continue; | 
 | 	  } | 
 |  | 
 | 	/* Don't try to reduce relocs which refer to non-local symbols | 
 | 	   in .linkonce sections.  It can lead to confusion when a | 
 | 	   debugging section refers to a .linkonce section.  I hope | 
 | 	   this will always be correct.  */ | 
 | 	if (symsec != sec && ! S_IS_LOCAL (sym)) | 
 | 	  { | 
 | 	    if ((symsec->flags & SEC_LINK_ONCE) != 0 | 
 | 		|| (IS_ELF | 
 | 		    /* The GNU toolchain uses an extension for ELF: a | 
 | 		       section beginning with the magic string | 
 | 		       .gnu.linkonce is a linkonce section.  */ | 
 | 		    && startswith (segment_name (symsec), ".gnu.linkonce"))) | 
 | 	      continue; | 
 | 	  } | 
 |  | 
 | 	/* Never adjust a reloc against local symbol in a merge section | 
 | 	   with non-zero addend.  */ | 
 | 	if ((symsec->flags & SEC_MERGE) != 0 | 
 | 	    && (fixp->fx_offset != 0 || fixp->fx_subsy != NULL)) | 
 | 	  continue; | 
 |  | 
 | 	/* Never adjust a reloc against TLS local symbol.  */ | 
 | 	if ((symsec->flags & SEC_THREAD_LOCAL) != 0) | 
 | 	  continue; | 
 |  | 
 | 	val = S_GET_VALUE (sym); | 
 |  | 
 | #if defined(TC_AARCH64) && defined(OBJ_COFF) | 
 | 	/* coff aarch64 relocation offsets need to be limited to 21bits. | 
 | 	   This is because addend may need to be stored in an ADRP instruction. | 
 | 	   In this case the addend cannot be stored down shifted otherwise rounding errors occur. */ | 
 | 	if ((val + 0x100000) > 0x1fffff) | 
 | 	  continue; | 
 | #endif | 
 |  | 
 | 	/* We refetch the segment when calling section_symbol, rather | 
 | 	   than using symsec, because S_GET_VALUE may wind up changing | 
 | 	   the section when it calls resolve_symbol_value.  */ | 
 | 	fixp->fx_offset += val; | 
 | 	fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym)); | 
 | #ifdef DEBUG5 | 
 | 	fprintf (stderr, "\nadjusted fixup:\n"); | 
 | 	print_fixup (fixp); | 
 | #endif | 
 |       } | 
 |  | 
 |   dump_section_relocs (abfd, sec, stderr); | 
 | } | 
 |  | 
 | void | 
 | as_bad_subtract (fixS *fixp) | 
 | { | 
 |   as_bad_where (fixp->fx_file, fixp->fx_line, | 
 | 		_("can't resolve %s - %s"), | 
 | 		fixp->fx_addsy ? S_GET_NAME (fixp->fx_addsy) : "0", | 
 | 		S_GET_NAME (fixp->fx_subsy)); | 
 | } | 
 |  | 
 | /* fixup_segment() | 
 |  | 
 |    Go through all the fixS's in a segment and see which ones can be | 
 |    handled now.  (These consist of fixS where we have since discovered | 
 |    the value of a symbol, or the address of the frag involved.) | 
 |    For each one, call md_apply_fix to put the fix into the frag data. | 
 |    Ones that we couldn't completely handle here will be output later | 
 |    by emit_relocations.  */ | 
 |  | 
 | static void | 
 | fixup_segment (fixS *fixP, segT this_segment) | 
 | { | 
 |   valueT add_number; | 
 |   fragS *fragP; | 
 |  | 
 |   if (fixP != NULL && abs_section_sym == NULL) | 
 |     abs_section_sym = section_symbol (absolute_section); | 
 |  | 
 |   /* If the linker is doing the relaxing, we must not do any fixups. | 
 |  | 
 |      Well, strictly speaking that's not true -- we could do any that | 
 |      are PC-relative and don't cross regions that could change size.  */ | 
 |   if (linkrelax && TC_LINKRELAX_FIXUP (this_segment)) | 
 |     { | 
 |       for (; fixP; fixP = fixP->fx_next) | 
 | 	if (!fixP->fx_done) | 
 | 	  { | 
 | 	    if (fixP->fx_addsy == NULL) | 
 | 	      { | 
 | 		/* There was no symbol required by this relocation. | 
 | 		   However, BFD doesn't really handle relocations | 
 | 		   without symbols well. So fake up a local symbol in | 
 | 		   the absolute section.  */ | 
 | 		fixP->fx_addsy = abs_section_sym; | 
 | 	      } | 
 | 	    symbol_mark_used_in_reloc (fixP->fx_addsy); | 
 | 	    if (fixP->fx_subsy != NULL) | 
 | 	      symbol_mark_used_in_reloc (fixP->fx_subsy); | 
 | 	  } | 
 |       return; | 
 |     } | 
 |  | 
 |   for (; fixP; fixP = fixP->fx_next) | 
 |     { | 
 |       segT add_symbol_segment = absolute_section; | 
 |  | 
 | #ifdef DEBUG5 | 
 |       fprintf (stderr, "\nprocessing fixup:\n"); | 
 |       print_fixup (fixP); | 
 | #endif | 
 |  | 
 |       fragP = fixP->fx_frag; | 
 |       know (fragP); | 
 | #ifdef TC_VALIDATE_FIX | 
 |       TC_VALIDATE_FIX (fixP, this_segment, skip); | 
 | #endif | 
 |       add_number = fixP->fx_offset; | 
 |  | 
 |       if (fixP->fx_addsy != NULL) | 
 | 	add_symbol_segment = S_GET_SEGMENT (fixP->fx_addsy); | 
 |  | 
 |       if (fixP->fx_subsy != NULL) | 
 | 	{ | 
 | 	  segT sub_symbol_segment; | 
 |  | 
 | 	  resolve_symbol_value (fixP->fx_subsy); | 
 | 	  sub_symbol_segment = S_GET_SEGMENT (fixP->fx_subsy); | 
 |  | 
 | 	  if (fixP->fx_addsy != NULL | 
 | 	      && sub_symbol_segment == add_symbol_segment | 
 | 	      && !S_FORCE_RELOC (fixP->fx_addsy, 0) | 
 | 	      && !S_FORCE_RELOC (fixP->fx_subsy, 0) | 
 | 	      && !TC_FORCE_RELOCATION_SUB_SAME (fixP, add_symbol_segment)) | 
 | 	    { | 
 | 	      add_number += S_GET_VALUE_WHERE (fixP->fx_addsy, fixP->fx_file, fixP->fx_line); | 
 | 	      add_number -= S_GET_VALUE_WHERE (fixP->fx_subsy, fixP->fx_file, fixP->fx_line); | 
 | 	      fixP->fx_offset = add_number; | 
 | 	      fixP->fx_addsy = NULL; | 
 | 	      fixP->fx_subsy = NULL; | 
 | #ifdef TC_M68K | 
 | 	      /* See the comment below about 68k weirdness.  */ | 
 | 	      fixP->fx_pcrel = 0; | 
 | #endif | 
 | 	    } | 
 | 	  else if (sub_symbol_segment == absolute_section | 
 | 		   && !S_FORCE_RELOC (fixP->fx_subsy, 0) | 
 | 		   && !TC_FORCE_RELOCATION_SUB_ABS (fixP, add_symbol_segment)) | 
 | 	    { | 
 | 	      add_number -= S_GET_VALUE_WHERE (fixP->fx_subsy, fixP->fx_file, fixP->fx_line); | 
 | 	      fixP->fx_offset = add_number; | 
 | 	      fixP->fx_subsy = NULL; | 
 | 	    } | 
 | 	  else if (sub_symbol_segment == this_segment | 
 | 		   && !S_FORCE_RELOC (fixP->fx_subsy, 0) | 
 | 		   && !TC_FORCE_RELOCATION_SUB_LOCAL (fixP, add_symbol_segment)) | 
 | 	    { | 
 | 	      add_number -= S_GET_VALUE_WHERE (fixP->fx_subsy, fixP->fx_file, fixP->fx_line); | 
 | 	      fixP->fx_offset = (add_number + fixP->fx_dot_value | 
 | 				 + fixP->fx_dot_frag->fr_address); | 
 |  | 
 | 	      /* Make it pc-relative.  If the back-end code has not | 
 | 		 selected a pc-relative reloc, cancel the adjustment | 
 | 		 we do later on all pc-relative relocs.  */ | 
 | 	      if (0 | 
 | #ifdef TC_M68K | 
 | 		  /* Do this for m68k even if it's already described | 
 | 		     as pc-relative.  On the m68k, an operand of | 
 | 		     "pc@(foo-.-2)" should address "foo" in a | 
 | 		     pc-relative mode.  */ | 
 | 		  || 1 | 
 | #endif | 
 | 		  || !fixP->fx_pcrel) | 
 | 		add_number += MD_PCREL_FROM_SECTION (fixP, this_segment); | 
 | 	      fixP->fx_subsy = NULL; | 
 | 	      fixP->fx_pcrel = 1; | 
 | 	    } | 
 | 	  else if (!TC_VALIDATE_FIX_SUB (fixP, add_symbol_segment)) | 
 | 	    { | 
 | 	      if (!md_register_arithmetic | 
 | 		  && (add_symbol_segment == reg_section | 
 | 		      || sub_symbol_segment == reg_section)) | 
 | 		as_bad_where (fixP->fx_file, fixP->fx_line, | 
 | 			      _("register value used as expression")); | 
 | 	      else | 
 | 		as_bad_subtract (fixP); | 
 | 	    } | 
 | 	  else if (sub_symbol_segment != undefined_section | 
 | 		   && ! bfd_is_com_section (sub_symbol_segment) | 
 | 		   && MD_APPLY_SYM_VALUE (fixP)) | 
 | 	    add_number -= S_GET_VALUE_WHERE (fixP->fx_subsy, fixP->fx_file, fixP->fx_line); | 
 | 	} | 
 |  | 
 |       if (fixP->fx_addsy) | 
 | 	{ | 
 | 	  if (add_symbol_segment == this_segment | 
 | 	      && !S_FORCE_RELOC (fixP->fx_addsy, 0) | 
 | 	      && !TC_FORCE_RELOCATION_LOCAL (fixP)) | 
 | 	    { | 
 | 	      /* This fixup was made when the symbol's segment was | 
 | 		 SEG_UNKNOWN, but it is now in the local segment. | 
 | 		 So we know how to do the address without relocation.  */ | 
 | 	      add_number += S_GET_VALUE_WHERE (fixP->fx_addsy, fixP->fx_file, fixP->fx_line); | 
 | 	      fixP->fx_offset = add_number; | 
 | 	      if (fixP->fx_pcrel) | 
 | 		add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment); | 
 | 	      fixP->fx_addsy = NULL; | 
 | 	      fixP->fx_pcrel = 0; | 
 | 	    } | 
 | 	  else if (add_symbol_segment == absolute_section | 
 | 		   && !S_FORCE_RELOC (fixP->fx_addsy, 0) | 
 | 		   && !TC_FORCE_RELOCATION_ABS (fixP)) | 
 | 	    { | 
 | 	      add_number += S_GET_VALUE_WHERE (fixP->fx_addsy, fixP->fx_file, fixP->fx_line); | 
 | 	      fixP->fx_offset = add_number; | 
 | 	      fixP->fx_addsy = NULL; | 
 | 	    } | 
 | 	  else if (add_symbol_segment != undefined_section | 
 | 		   && ! bfd_is_com_section (add_symbol_segment) | 
 | 		   && MD_APPLY_SYM_VALUE (fixP)) | 
 | 	    add_number += S_GET_VALUE_WHERE (fixP->fx_addsy, fixP->fx_file, fixP->fx_line); | 
 | 	} | 
 |  | 
 |       if (fixP->fx_pcrel) | 
 | 	{ | 
 | 	  add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment); | 
 | 	  if (!fixP->fx_done && fixP->fx_addsy == NULL) | 
 | 	    { | 
 | 	      /* There was no symbol required by this relocation. | 
 | 		 However, BFD doesn't really handle relocations | 
 | 		 without symbols well. So fake up a local symbol in | 
 | 		 the absolute section.  */ | 
 | 	      fixP->fx_addsy = abs_section_sym; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       if (!fixP->fx_done) | 
 | 	md_apply_fix (fixP, &add_number, this_segment); | 
 |  | 
 |       if (!fixP->fx_done) | 
 | 	{ | 
 | 	  if (fixP->fx_addsy == NULL) | 
 | 	    fixP->fx_addsy = abs_section_sym; | 
 | 	  symbol_mark_used_in_reloc (fixP->fx_addsy); | 
 | 	  if (fixP->fx_subsy != NULL) | 
 | 	    symbol_mark_used_in_reloc (fixP->fx_subsy); | 
 | 	} | 
 |  | 
 |       if (!fixP->fx_no_overflow && fixP->fx_size != 0) | 
 | 	{ | 
 | 	  if (fixP->fx_size < sizeof (valueT)) | 
 | 	    { | 
 | 	      valueT mask; | 
 |  | 
 | 	      mask = 0; | 
 | 	      mask--;		/* Set all bits to one.  */ | 
 | 	      mask <<= fixP->fx_size * 8 - (fixP->fx_signed ? 1 : 0); | 
 | 	      if ((add_number & mask) != 0 | 
 | 		  && (fixP->fx_signed | 
 | 		      ? (add_number & mask) != mask | 
 | 		      : (-add_number & mask) != 0)) | 
 | 		{ | 
 | 		  char buf[50], buf2[50]; | 
 | 		  bfd_sprintf_vma (stdoutput, buf, fragP->fr_address + fixP->fx_where); | 
 | 		  if (add_number > 1000) | 
 | 		    bfd_sprintf_vma (stdoutput, buf2, add_number); | 
 | 		  else | 
 | 		    sprintf (buf2, "%ld", (long) add_number); | 
 | 		  as_bad_where (fixP->fx_file, fixP->fx_line, | 
 | 				ngettext ("value of %s too large for field " | 
 | 					  "of %d byte at %s", | 
 | 					  "value of %s too large for field " | 
 | 					  "of %d bytes at %s", | 
 | 					  fixP->fx_size), | 
 | 				buf2, fixP->fx_size, buf); | 
 | 		} /* Generic error checking.  */ | 
 | 	    } | 
 | #ifdef WARN_SIGNED_OVERFLOW_WORD | 
 | 	  /* Warn if a .word value is too large when treated as a signed | 
 | 	     number.  We already know it is not too negative.  This is to | 
 | 	     catch over-large switches generated by gcc on the 68k.  */ | 
 | 	  if (!flag_signed_overflow_ok | 
 | 	      && fixP->fx_size == 2 | 
 | 	      && add_number > 0x7fff) | 
 | 	    as_bad_where (fixP->fx_file, fixP->fx_line, | 
 | 			  _("signed .word overflow; switch may be too large; %ld at 0x%lx"), | 
 | 			  (long) add_number, | 
 | 			  (long) (fragP->fr_address + fixP->fx_where)); | 
 | #endif | 
 | 	} | 
 |  | 
 | #ifdef TC_VALIDATE_FIX | 
 |     skip:  ATTRIBUTE_UNUSED_LABEL | 
 |       ; | 
 | #endif | 
 | #ifdef DEBUG5 | 
 |       fprintf (stderr, "result:\n"); | 
 |       print_fixup (fixP); | 
 | #endif | 
 |     }				/* For each fixS in this segment.  */ | 
 | } | 
 |  | 
 | static void | 
 | fix_segment (bfd *abfd ATTRIBUTE_UNUSED, | 
 | 	     asection *sec, | 
 | 	     void *xxx ATTRIBUTE_UNUSED) | 
 | { | 
 |   segment_info_type *seginfo = seg_info (sec); | 
 |  | 
 |   fixup_segment (seginfo->fix_root, sec); | 
 | } | 
 |  | 
 | static void | 
 | install_reloc (asection *sec, arelent *reloc, fragS *fragp, | 
 | 	       const char *file, unsigned int line) | 
 | { | 
 |   char *err; | 
 |   bfd_reloc_status_type s; | 
 |   asymbol *sym; | 
 |  | 
 |   if (reloc->sym_ptr_ptr != NULL | 
 |       && (sym = *reloc->sym_ptr_ptr) != NULL | 
 |       && (sym->flags & BSF_KEEP) == 0 | 
 |       && ((sym->flags & BSF_SECTION_SYM) == 0 | 
 | 	  || (EMIT_SECTION_SYMBOLS | 
 | 	      && !bfd_is_abs_section (sym->section)))) | 
 |     as_bad_where (file, line, _("redefined symbol cannot be used on reloc")); | 
 |  | 
 |   s = bfd_install_relocation (stdoutput, reloc, | 
 | 			      fragp->fr_literal, fragp->fr_address, | 
 | 			      sec, &err); | 
 |   switch (s) | 
 |     { | 
 |     case bfd_reloc_ok: | 
 |       break; | 
 |     case bfd_reloc_overflow: | 
 |       as_bad_where (file, line, _("relocation overflow")); | 
 |       break; | 
 |     case bfd_reloc_outofrange: | 
 |       as_bad_where (file, line, _("relocation out of range")); | 
 |       break; | 
 |     default: | 
 |       as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"), | 
 | 		file, line, s); | 
 |     } | 
 | } | 
 |  | 
 | static fragS * | 
 | get_frag_for_reloc (fragS *last_frag, | 
 | 		    const segment_info_type *seginfo, | 
 | 		    const struct reloc_list *r) | 
 | { | 
 |   fragS *f; | 
 |  | 
 |   for (f = last_frag; f != NULL; f = f->fr_next) | 
 |     if (f->fr_address <= r->u.b.r.address | 
 | 	&& r->u.b.r.address < f->fr_address + f->fr_fix) | 
 |       return f; | 
 |  | 
 |   for (f = seginfo->frchainP->frch_root; f != NULL; f = f->fr_next) | 
 |     if (f->fr_address <= r->u.b.r.address | 
 | 	&& r->u.b.r.address < f->fr_address + f->fr_fix) | 
 |       return f; | 
 |  | 
 |   for (f = seginfo->frchainP->frch_root; f != NULL; f = f->fr_next) | 
 |     if (f->fr_address <= r->u.b.r.address | 
 | 	&& r->u.b.r.address <= f->fr_address + f->fr_fix) | 
 |       return f; | 
 |  | 
 |   as_bad_where (r->file, r->line, | 
 | 		_("reloc not within (fixed part of) section")); | 
 |   return NULL; | 
 | } | 
 |  | 
 | static void | 
 | write_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, | 
 | 	      void *xxx ATTRIBUTE_UNUSED) | 
 | { | 
 |   segment_info_type *seginfo = seg_info (sec); | 
 |   unsigned int n; | 
 |   struct reloc_list *my_reloc_list, **rp, *r; | 
 |   arelent **relocs; | 
 |   fixS *fixp; | 
 |   fragS *last_frag; | 
 |  | 
 |   /* If seginfo is NULL, we did not create this section; don't do | 
 |      anything with it.  */ | 
 |   if (seginfo == NULL) | 
 |     return; | 
 |  | 
 |   n = 0; | 
 |   for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) | 
 |     if (!fixp->fx_done) | 
 |       n++; | 
 |  | 
 | #ifdef RELOC_EXPANSION_POSSIBLE | 
 |   n *= MAX_RELOC_EXPANSION; | 
 | #endif | 
 |  | 
 |   /* Extract relocs for this section from reloc_list.  */ | 
 |   rp = &reloc_list; | 
 |  | 
 |   my_reloc_list = NULL; | 
 |   while ((r = *rp) != NULL) | 
 |     { | 
 |       if (r->u.b.sec == sec) | 
 | 	{ | 
 | 	  *rp = r->next; | 
 | 	  r->next = my_reloc_list; | 
 | 	  my_reloc_list = r; | 
 | 	  n++; | 
 | 	} | 
 |       else | 
 | 	rp = &r->next; | 
 |     } | 
 |  | 
 |   relocs = notes_alloc (n * sizeof (arelent *)); | 
 |  | 
 |   n = 0; | 
 |   r = my_reloc_list; | 
 |   last_frag = NULL; | 
 |   for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next) | 
 |     { | 
 |       int fx_size, slack; | 
 |       valueT loc; | 
 |       arelent **reloc; | 
 | #ifndef RELOC_EXPANSION_POSSIBLE | 
 |       arelent *rel; | 
 |  | 
 |       reloc = &rel; | 
 | #endif | 
 |  | 
 |       if (fixp->fx_done) | 
 | 	continue; | 
 |  | 
 |       fx_size = fixp->fx_size; | 
 |       slack = TC_FX_SIZE_SLACK (fixp); | 
 |       if (slack > 0) | 
 | 	fx_size = fx_size > slack ? fx_size - slack : 0; | 
 |       loc = fixp->fx_where + fx_size; | 
 |       if (slack >= 0 && loc > fixp->fx_frag->fr_fix) | 
 | 	as_bad_where (fixp->fx_file, fixp->fx_line, | 
 | 		      _("internal error: fixup not contained within frag")); | 
 |  | 
 | #ifdef obj_fixup_removed_symbol | 
 |       if (fixp->fx_addsy && symbol_removed_p (fixp->fx_addsy)) | 
 | 	obj_fixup_removed_symbol (&fixp->fx_addsy); | 
 |       if (fixp->fx_subsy && symbol_removed_p (fixp->fx_subsy)) | 
 | 	obj_fixup_removed_symbol (&fixp->fx_subsy); | 
 | #endif | 
 |  | 
 | #ifndef RELOC_EXPANSION_POSSIBLE | 
 |       *reloc = tc_gen_reloc (sec, fixp); | 
 | #else | 
 |       reloc = tc_gen_reloc (sec, fixp); | 
 | #endif | 
 |  | 
 |       while (*reloc) | 
 | 	{ | 
 | 	  while (r != NULL && r->u.b.r.address < (*reloc)->address) | 
 | 	    { | 
 | 	      fragS *f = get_frag_for_reloc (last_frag, seginfo, r); | 
 | 	      if (f != NULL) | 
 | 		{ | 
 | 		  last_frag = f; | 
 | 		  relocs[n++] = &r->u.b.r; | 
 | 		  install_reloc (sec, &r->u.b.r, f, r->file, r->line); | 
 | 		} | 
 | 	      r = r->next; | 
 | 	    } | 
 | #ifdef GAS_SORT_RELOCS | 
 | 	  if (n != 0 && (*reloc)->address < relocs[n - 1]->address) | 
 | 	    { | 
 | 	      size_t lo = 0; | 
 | 	      size_t hi = n - 1; | 
 | 	      bfd_vma look = (*reloc)->address; | 
 | 	      while (lo < hi) | 
 | 		{ | 
 | 		  size_t mid = (lo + hi) / 2; | 
 | 		  if (relocs[mid]->address > look) | 
 | 		    hi = mid; | 
 | 		  else | 
 | 		    { | 
 | 		      lo = mid + 1; | 
 | 		      if (relocs[mid]->address == look) | 
 | 			break; | 
 | 		    } | 
 | 		} | 
 | 	      while (lo < hi && relocs[lo]->address == look) | 
 | 		lo++; | 
 | 	      memmove (relocs + lo + 1, relocs + lo, | 
 | 		       (n - lo) * sizeof (*relocs)); | 
 | 	      n++; | 
 | 	      relocs[lo] = *reloc; | 
 | 	    } | 
 | 	  else | 
 | #endif | 
 | 	    relocs[n++] = *reloc; | 
 | 	  install_reloc (sec, *reloc, fixp->fx_frag, | 
 | 			 fixp->fx_file, fixp->fx_line); | 
 | #ifndef RELOC_EXPANSION_POSSIBLE | 
 | 	  break; | 
 | #else | 
 | 	  reloc++; | 
 | #endif | 
 | 	} | 
 |     } | 
 |  | 
 |   while (r != NULL) | 
 |     { | 
 |       fragS *f = get_frag_for_reloc (last_frag, seginfo, r); | 
 |       if (f != NULL) | 
 | 	{ | 
 | 	  last_frag = f; | 
 | 	  relocs[n++] = &r->u.b.r; | 
 | 	  install_reloc (sec, &r->u.b.r, f, r->file, r->line); | 
 | 	} | 
 |       r = r->next; | 
 |     } | 
 |  | 
 | #ifdef DEBUG4 | 
 |   { | 
 |     unsigned int k, j, nsyms; | 
 |     asymbol **sympp; | 
 |     sympp = bfd_get_outsymbols (stdoutput); | 
 |     nsyms = bfd_get_symcount (stdoutput); | 
 |     for (k = 0; k < n; k++) | 
 |       if (((*relocs[k]->sym_ptr_ptr)->flags & BSF_SECTION_SYM) == 0) | 
 | 	{ | 
 | 	  for (j = 0; j < nsyms; j++) | 
 | 	    if (sympp[j] == *relocs[k]->sym_ptr_ptr) | 
 | 	      break; | 
 | 	  if (j == nsyms) | 
 | 	    abort (); | 
 | 	} | 
 |   } | 
 | #endif | 
 |  | 
 |   bfd_set_reloc (stdoutput, sec, n ? relocs : NULL, n); | 
 |  | 
 | #ifdef SET_SECTION_RELOCS | 
 |   SET_SECTION_RELOCS (sec, relocs, n); | 
 | #endif | 
 |  | 
 | #ifdef DEBUG3 | 
 |   { | 
 |     unsigned int k; | 
 |  | 
 |     fprintf (stderr, "relocs for sec %s\n", sec->name); | 
 |     for (k = 0; k < n; k++) | 
 |       { | 
 | 	arelent *rel = relocs[k]; | 
 | 	asymbol *s = *rel->sym_ptr_ptr; | 
 | 	fprintf (stderr, "  reloc %2d @%p off %4lx : sym %-10s addend %lx\n", | 
 | 		 k, rel, (unsigned long)rel->address, s->name, | 
 | 		 (unsigned long)rel->addend); | 
 |       } | 
 |   } | 
 | #endif | 
 | } | 
 |  | 
 | static int | 
 | compress_frag (bool use_zstd, void *ctx, const char *contents, int in_size, | 
 | 	       fragS **last_newf, struct obstack *ob) | 
 | { | 
 |   int out_size; | 
 |   int total_out_size = 0; | 
 |   fragS *f = *last_newf; | 
 |   char *next_out; | 
 |   int avail_out; | 
 |  | 
 |   /* Call the compression routine repeatedly until it has finished | 
 |      processing the frag.  */ | 
 |   while (in_size > 0) | 
 |     { | 
 |       /* Reserve all the space available in the current chunk. | 
 | 	 If none is available, start a new frag.  */ | 
 |       avail_out = obstack_room (ob); | 
 |       if (avail_out <= 0) | 
 | 	{ | 
 | 	  obstack_finish (ob); | 
 | 	  f = frag_alloc (ob, 0); | 
 | 	  f->fr_type = rs_fill; | 
 | 	  (*last_newf)->fr_next = f; | 
 | 	  *last_newf = f; | 
 | 	  avail_out = obstack_room (ob); | 
 | 	} | 
 |       if (avail_out <= 0) | 
 | 	as_fatal (_("can't extend frag")); | 
 |       next_out = obstack_next_free (ob); | 
 |       obstack_blank_fast (ob, avail_out); | 
 |       out_size = compress_data (use_zstd, ctx, &contents, &in_size, &next_out, | 
 | 				&avail_out); | 
 |       if (out_size < 0) | 
 | 	return -1; | 
 |  | 
 |       f->fr_fix += out_size; | 
 |       total_out_size += out_size; | 
 |  | 
 |       /* Return unused space.  */ | 
 |       if (avail_out > 0) | 
 | 	obstack_blank_fast (ob, -avail_out); | 
 |     } | 
 |  | 
 |   return total_out_size; | 
 | } | 
 |  | 
 | static void | 
 | compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED) | 
 | { | 
 |   segment_info_type *seginfo = seg_info (sec); | 
 |   bfd_size_type uncompressed_size = sec->size; | 
 |   flagword flags = bfd_section_flags (sec); | 
 |  | 
 |   if (seginfo == NULL | 
 |       || uncompressed_size < 32 | 
 |       || (flags & SEC_HAS_CONTENTS) == 0) | 
 |     return; | 
 |  | 
 |   const char *section_name = bfd_section_name (sec); | 
 |   if (!startswith (section_name, ".debug_") | 
 |       && !startswith (section_name, ".gnu.debuglto_.debug_") | 
 |       && !startswith (section_name, ".gnu.linkonce.wi.")) | 
 |     return; | 
 |  | 
 |   bool use_zstd = abfd->flags & BFD_COMPRESS_ZSTD; | 
 |   void *ctx = compress_init (use_zstd); | 
 |   if (ctx == NULL) | 
 |     return; | 
 |  | 
 |   unsigned int header_size; | 
 |   if ((abfd->flags & BFD_COMPRESS_GABI) == 0) | 
 |     header_size = 12; | 
 |   else | 
 |     header_size = bfd_get_compression_header_size (stdoutput, NULL); | 
 |  | 
 |   /* Create a new frag to contain the compression header.  */ | 
 |   struct obstack *ob = &seginfo->frchainP->frch_obstack; | 
 |   fragS *first_newf = frag_alloc (ob, header_size); | 
 |   fragS *last_newf = first_newf; | 
 |   last_newf->fr_type = rs_fill; | 
 |   last_newf->fr_fix = header_size; | 
 |   char *header = last_newf->fr_literal; | 
 |   bfd_size_type compressed_size = header_size; | 
 |  | 
 |   /* Stream the frags through the compression engine, adding new frags | 
 |      as necessary to accommodate the compressed output.  */ | 
 |   for (fragS *f = seginfo->frchainP->frch_root; | 
 |        f; | 
 |        f = f->fr_next) | 
 |     { | 
 |       offsetT fill_size; | 
 |       char *fill_literal; | 
 |       offsetT count; | 
 |       int out_size; | 
 |  | 
 |       gas_assert (f->fr_type == rs_fill); | 
 |       if (f->fr_fix) | 
 | 	{ | 
 | 	  out_size = compress_frag (use_zstd, ctx, f->fr_literal, f->fr_fix, | 
 | 				    &last_newf, ob); | 
 | 	  if (out_size < 0) | 
 | 	    return; | 
 | 	  compressed_size += out_size; | 
 | 	} | 
 |       fill_literal = f->fr_literal + f->fr_fix; | 
 |       fill_size = f->fr_var; | 
 |       count = f->fr_offset; | 
 |       gas_assert (count >= 0); | 
 |       if (fill_size && count) | 
 | 	{ | 
 | 	  while (count--) | 
 | 	    { | 
 | 	      out_size = compress_frag (use_zstd, ctx, fill_literal, | 
 | 					(int)fill_size, &last_newf, ob); | 
 | 	      if (out_size < 0) | 
 | 		return; | 
 | 	      compressed_size += out_size; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Flush the compression state.  */ | 
 |   for (;;) | 
 |     { | 
 |       int avail_out; | 
 |       char *next_out; | 
 |       int out_size; | 
 |  | 
 |       /* Reserve all the space available in the current chunk. | 
 | 	 If none is available, start a new frag.  */ | 
 |       avail_out = obstack_room (ob); | 
 |       if (avail_out <= 0) | 
 | 	{ | 
 | 	  fragS *newf; | 
 |  | 
 | 	  obstack_finish (ob); | 
 | 	  newf = frag_alloc (ob, 0); | 
 | 	  newf->fr_type = rs_fill; | 
 | 	  last_newf->fr_next = newf; | 
 | 	  last_newf = newf; | 
 | 	  avail_out = obstack_room (ob); | 
 | 	} | 
 |       if (avail_out <= 0) | 
 | 	as_fatal (_("can't extend frag")); | 
 |       next_out = obstack_next_free (ob); | 
 |       obstack_blank_fast (ob, avail_out); | 
 |       int x = compress_finish (use_zstd, ctx, &next_out, &avail_out, &out_size); | 
 |       if (x < 0) | 
 | 	return; | 
 |  | 
 |       last_newf->fr_fix += out_size; | 
 |       compressed_size += out_size; | 
 |  | 
 |       /* Return unused space.  */ | 
 |       if (avail_out > 0) | 
 | 	obstack_blank_fast (ob, -avail_out); | 
 |  | 
 |       if (x == 0) | 
 | 	break; | 
 |     } | 
 |  | 
 |   /* PR binutils/18087: If compression didn't make the section smaller, | 
 |      just keep it uncompressed.  */ | 
 |   if (compressed_size >= uncompressed_size) | 
 |     return; | 
 |  | 
 |   /* Replace the uncompressed frag list with the compressed frag list.  */ | 
 |   seginfo->frchainP->frch_root = first_newf; | 
 |   seginfo->frchainP->frch_last = last_newf; | 
 |  | 
 |   /* Update the section size and its name.  */ | 
 |   bfd_update_compression_header (abfd, (bfd_byte *) header, sec); | 
 |   bool x = bfd_set_section_size (sec, compressed_size); | 
 |   gas_assert (x); | 
 |   if ((abfd->flags & BFD_COMPRESS_GABI) == 0 | 
 |       && section_name[1] == 'd') | 
 |     { | 
 |       char *compressed_name = bfd_debug_name_to_zdebug (abfd, section_name); | 
 |       bfd_rename_section (sec, compressed_name); | 
 |     } | 
 | } | 
 |  | 
 | #ifndef md_generate_nops | 
 | /* Genenerate COUNT bytes of no-op instructions to WHERE.  A target | 
 |    backend must override this with proper no-op instructions.   */ | 
 |  | 
 | static void | 
 | md_generate_nops (fragS *f ATTRIBUTE_UNUSED, | 
 | 		  char *where ATTRIBUTE_UNUSED, | 
 | 		  offsetT count ATTRIBUTE_UNUSED, | 
 | 		  int control ATTRIBUTE_UNUSED) | 
 | { | 
 |   as_bad (_("unimplemented .nops directive")); | 
 | } | 
 | #endif | 
 |  | 
 | static void | 
 | write_contents (bfd *abfd ATTRIBUTE_UNUSED, | 
 | 		asection *sec, | 
 | 		void *xxx ATTRIBUTE_UNUSED) | 
 | { | 
 |   segment_info_type *seginfo = seg_info (sec); | 
 |   addressT offset = 0; | 
 |   fragS *f; | 
 |  | 
 |   /* Write out the frags.  */ | 
 |   if (seginfo == NULL | 
 |       || !(bfd_section_flags (sec) & SEC_HAS_CONTENTS)) | 
 |     return; | 
 |  | 
 |   for (f = seginfo->frchainP->frch_root; | 
 |        f; | 
 |        f = f->fr_next) | 
 |     { | 
 |       int x; | 
 |       addressT fill_size; | 
 |       char *fill_literal; | 
 |       offsetT count; | 
 |  | 
 |       gas_assert (f->fr_type == rs_fill || f->fr_type == rs_fill_nop); | 
 |       if (f->fr_fix) | 
 | 	{ | 
 | 	  x = bfd_set_section_contents (stdoutput, sec, | 
 | 					f->fr_literal, (file_ptr) offset, | 
 | 					(bfd_size_type) f->fr_fix); | 
 | 	  if (!x) | 
 | 	    as_fatal (ngettext ("can't write %ld byte " | 
 | 				"to section %s of %s: '%s'", | 
 | 				"can't write %ld bytes " | 
 | 				"to section %s of %s: '%s'", | 
 | 				(long) f->fr_fix), | 
 | 		      (long) f->fr_fix, | 
 | 		      bfd_section_name (sec), bfd_get_filename (stdoutput), | 
 | 		      bfd_errmsg (bfd_get_error ())); | 
 | 	  offset += f->fr_fix; | 
 | 	} | 
 |  | 
 |       fill_size = f->fr_var; | 
 |       count = f->fr_offset; | 
 |       fill_literal = f->fr_literal + f->fr_fix; | 
 |  | 
 |       if (f->fr_type == rs_fill_nop) | 
 | 	{ | 
 | 	  gas_assert (count >= 0 && fill_size == 1); | 
 | 	  if (count > 0) | 
 | 	    { | 
 | 	      char *buf = xmalloc (count); | 
 | 	      md_generate_nops (f, buf, count, *fill_literal); | 
 | 	      x = bfd_set_section_contents | 
 | 		(stdoutput, sec, buf, (file_ptr) offset, | 
 | 		 (bfd_size_type) count); | 
 | 	      if (!x) | 
 | 		as_fatal (ngettext ("can't fill %ld byte " | 
 | 				    "in section %s of %s: '%s'", | 
 | 				    "can't fill %ld bytes " | 
 | 				    "in section %s of %s: '%s'", | 
 | 				    (long) count), | 
 | 			  (long) count, | 
 | 			  bfd_section_name (sec), | 
 | 			  bfd_get_filename (stdoutput), | 
 | 			  bfd_errmsg (bfd_get_error ())); | 
 | 	      offset += count; | 
 | #ifndef NO_LISTING | 
 | 	      if (listing & LISTING_LISTING) | 
 | 		f->fr_opcode = buf; | 
 | 	      else | 
 | #endif | 
 | 		free (buf); | 
 | 	    } | 
 | 	  continue; | 
 | 	} | 
 |  | 
 |       gas_assert (count >= 0); | 
 |       if (fill_size && count) | 
 | 	{ | 
 | 	  char buf[256]; | 
 | 	  if (fill_size > sizeof (buf)) | 
 | 	    { | 
 | 	      /* Do it the old way. Can this ever happen?  */ | 
 | 	      while (count--) | 
 | 		{ | 
 | 		  x = bfd_set_section_contents (stdoutput, sec, | 
 | 						fill_literal, | 
 | 						(file_ptr) offset, | 
 | 						(bfd_size_type) fill_size); | 
 | 		  if (!x) | 
 | 		    as_fatal (ngettext ("can't fill %ld byte " | 
 | 					"in section %s of %s: '%s'", | 
 | 					"can't fill %ld bytes " | 
 | 					"in section %s of %s: '%s'", | 
 | 					(long) fill_size), | 
 | 			      (long) fill_size, | 
 | 			      bfd_section_name (sec), | 
 | 			      bfd_get_filename (stdoutput), | 
 | 			      bfd_errmsg (bfd_get_error ())); | 
 | 		  offset += fill_size; | 
 | 		} | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      /* Build a buffer full of fill objects and output it as | 
 | 		 often as necessary. This saves on the overhead of | 
 | 		 potentially lots of bfd_set_section_contents calls.  */ | 
 | 	      int n_per_buf, i; | 
 | 	      if (fill_size == 1) | 
 | 		{ | 
 | 		  n_per_buf = sizeof (buf); | 
 | 		  memset (buf, *fill_literal, n_per_buf); | 
 | 		} | 
 | 	      else | 
 | 		{ | 
 | 		  char *bufp; | 
 | 		  n_per_buf = sizeof (buf) / fill_size; | 
 | 		  for (i = n_per_buf, bufp = buf; i; i--, bufp += fill_size) | 
 | 		    memcpy (bufp, fill_literal, fill_size); | 
 | 		} | 
 | 	      for (; count > 0; count -= n_per_buf) | 
 | 		{ | 
 | 		  n_per_buf = n_per_buf > count ? count : n_per_buf; | 
 | 		  x = bfd_set_section_contents | 
 | 		    (stdoutput, sec, buf, (file_ptr) offset, | 
 | 		     (bfd_size_type) n_per_buf * fill_size); | 
 | 		  if (!x) | 
 | 		    as_fatal (ngettext ("can't fill %ld byte " | 
 | 					"in section %s of %s: '%s'", | 
 | 					"can't fill %ld bytes " | 
 | 					"in section %s of %s: '%s'", | 
 | 					(long) (n_per_buf * fill_size)), | 
 | 			      (long) (n_per_buf * fill_size), | 
 | 			      bfd_section_name (sec), | 
 | 			      bfd_get_filename (stdoutput), | 
 | 			      bfd_errmsg (bfd_get_error ())); | 
 | 		  offset += n_per_buf * fill_size; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | merge_data_into_text (void) | 
 | { | 
 |   seg_info (text_section)->frchainP->frch_last->fr_next = | 
 |     seg_info (data_section)->frchainP->frch_root; | 
 |   seg_info (text_section)->frchainP->frch_last = | 
 |     seg_info (data_section)->frchainP->frch_last; | 
 |   seg_info (data_section)->frchainP = 0; | 
 | } | 
 |  | 
 | static void | 
 | set_symtab (void) | 
 | { | 
 |   int nsyms; | 
 |   asymbol **asympp; | 
 |   symbolS *symp; | 
 |   bool result; | 
 |  | 
 |   /* Count symbols.  We can't rely on a count made by the loop in | 
 |      write_object_file, because *_frob_file may add a new symbol or | 
 |      two.  Generate unused section symbols only if needed.  */ | 
 |   nsyms = 0; | 
 |   for (symp = symbol_rootP; symp; symp = symbol_next (symp)) | 
 |     if (!symbol_removed_p (symp) | 
 | 	&& (bfd_keep_unused_section_symbols (stdoutput) | 
 | 	    || !symbol_section_p (symp) | 
 | 	    || symbol_used_in_reloc_p (symp))) | 
 |       nsyms++; | 
 |  | 
 |   if (nsyms) | 
 |     { | 
 |       int i; | 
 |  | 
 |       asympp = notes_alloc (nsyms * sizeof (asymbol *)); | 
 |       symp = symbol_rootP; | 
 |       for (i = 0; i < nsyms; symp = symbol_next (symp)) | 
 | 	if (!symbol_removed_p (symp) | 
 | 	    && (bfd_keep_unused_section_symbols (stdoutput) | 
 | 		|| !symbol_section_p (symp) | 
 | 		|| symbol_used_in_reloc_p (symp))) | 
 | 	  { | 
 | 	    asympp[i] = symbol_get_bfdsym (symp); | 
 | 	    if (asympp[i]->flags != BSF_SECTION_SYM | 
 | 		|| !(bfd_is_const_section (asympp[i]->section) | 
 | 		     && asympp[i]->section->symbol == asympp[i])) | 
 | 	      asympp[i]->flags |= BSF_KEEP; | 
 | 	    symbol_mark_written (symp); | 
 | 	    /* Include this section symbol in the symbol table.  */ | 
 | 	    if (symbol_section_p (symp)) | 
 | 	      asympp[i]->flags |= BSF_SECTION_SYM_USED; | 
 | 	    i++; | 
 | 	  } | 
 |     } | 
 |   else | 
 |     asympp = 0; | 
 |   result = bfd_set_symtab (stdoutput, asympp, nsyms); | 
 |   gas_assert (result); | 
 |   symbol_table_frozen = 1; | 
 | } | 
 |  | 
 | /* Finish the subsegments.  After every sub-segment, we fake an | 
 |    ".align ...".  This conforms to BSD4.2 brain-damage.  We then fake | 
 |    ".fill 0" because that is the kind of frag that requires least | 
 |    thought.  ".align" frags like to have a following frag since that | 
 |    makes calculating their intended length trivial.  */ | 
 |  | 
 | #ifndef SUB_SEGMENT_ALIGN | 
 | #ifdef HANDLE_ALIGN | 
 | /* The last subsegment gets an alignment corresponding to the alignment | 
 |    of the section.  This allows proper nop-filling at the end of | 
 |    code-bearing sections.  */ | 
 | #define SUB_SEGMENT_ALIGN(SEG, FRCHAIN)					\ | 
 |   (!(FRCHAIN)->frch_next && subseg_text_p (SEG)				\ | 
 |    && !do_not_pad_sections_to_alignment					\ | 
 |    ? get_recorded_alignment (SEG)					\ | 
 |    : 0) | 
 | #else | 
 | #define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0 | 
 | #endif | 
 | #endif | 
 |  | 
 | static void | 
 | subsegs_finish_section (asection *s) | 
 | { | 
 |   struct frchain *frchainP; | 
 |   segment_info_type *seginfo = seg_info (s); | 
 |   if (!seginfo) | 
 |     return; | 
 |  | 
 |   /* This now gets called even if we had errors.  In that case, any alignment | 
 |      is meaningless, and, moreover, will look weird if we are generating a | 
 |      listing.  */ | 
 |   if (had_errors ()) | 
 |     do_not_pad_sections_to_alignment = 1; | 
 |  | 
 |   for (frchainP = seginfo->frchainP; | 
 |        frchainP != NULL; | 
 |        frchainP = frchainP->frch_next) | 
 |     { | 
 |       int alignment; | 
 |  | 
 |       subseg_set (s, frchainP->frch_subseg); | 
 |  | 
 |       alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP); | 
 |       if ((bfd_section_flags (now_seg) & (SEC_MERGE | SEC_STRINGS)) | 
 | 	  && now_seg->entsize) | 
 | 	{ | 
 | 	  unsigned int entsize = now_seg->entsize; | 
 | 	  int entalign = 0; | 
 |  | 
 | 	  while ((entsize & 1) == 0) | 
 | 	    { | 
 | 	      ++entalign; | 
 | 	      entsize >>= 1; | 
 | 	    } | 
 |  | 
 | 	  if (entalign > alignment) | 
 | 	    alignment = entalign; | 
 | 	} | 
 |  | 
 |       if (subseg_text_p (now_seg)) | 
 | 	frag_align_code (alignment, 0); | 
 |       else | 
 | 	frag_align (alignment, 0, 0); | 
 |  | 
 |       /* frag_align will have left a new frag. | 
 | 	 Use this last frag for an empty ".fill". | 
 |  | 
 | 	 For this segment ... | 
 | 	 Create a last frag. Do not leave a "being filled in frag".  */ | 
 |       frag_wane (frag_now); | 
 |       frag_now->fr_fix = 0; | 
 |       know (frag_now->fr_next == NULL); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | subsegs_finish (void) | 
 | { | 
 |   asection *s; | 
 |  | 
 |   for (s = stdoutput->sections; s; s = s->next) | 
 |     subsegs_finish_section (s); | 
 | } | 
 |  | 
 | #ifdef OBJ_ELF | 
 |  | 
 | static void | 
 | create_obj_attrs_section (void) | 
 | { | 
 |   offsetT size = bfd_elf_obj_attr_size (stdoutput); | 
 |   if (size == 0) | 
 |     return; | 
 |  | 
 |   const char *name = get_elf_backend_data (stdoutput)->obj_attrs_section; | 
 |   if (name == NULL) | 
 |     /* Note: .gnu.attributes is different from GNU_BUILD_ATTRS_SECTION_NAME | 
 |        (a.k.a .gnu.build.attributes). The first one seems to be used by some | 
 |        backends like PowerPC to store the build attributes. The second one is | 
 |        used to store build notes.  */ | 
 |     name = ".gnu.attributes"; | 
 |   segT s = subseg_new (name, 0); | 
 |   elf_section_type (s) | 
 |     = get_elf_backend_data (stdoutput)->obj_attrs_section_type; | 
 |   bfd_set_section_flags (s, SEC_READONLY | SEC_DATA); | 
 |   frag_now_fix (); | 
 |   char *p = frag_more (size); | 
 |   bfd_elf_set_obj_attr_contents (stdoutput, (bfd_byte *)p, size); | 
 |  | 
 |   subsegs_finish_section (s); | 
 |   relax_segment (seg_info (s)->frchainP->frch_root, s, 0); | 
 |   size_seg (stdoutput, s, NULL); | 
 | } | 
 |  | 
 | /* Create a relocation against an entry in a GNU Build attribute section.  */ | 
 |  | 
 | static void | 
 | create_note_reloc (segT           sec, | 
 | 		   symbolS *      sym, | 
 | 		   bfd_size_type  note_offset, | 
 | 		   bfd_size_type  desc2_offset, | 
 | 		   offsetT        desc2_size, | 
 | 		   int            reloc_type, | 
 | 		   bfd_vma        addend, | 
 | 		   char *         note) | 
 | { | 
 |   struct reloc_list * reloc; | 
 |  | 
 |   reloc = notes_alloc (sizeof (*reloc)); | 
 |  | 
 |   /* We create a .b type reloc as resolve_reloc_expr_symbols() has already been called.  */ | 
 |   reloc->u.b.sec           = sec; | 
 |   reloc->u.b.s             = symbol_get_bfdsym (sym); | 
 |   reloc->u.b.r.sym_ptr_ptr = & reloc->u.b.s; | 
 |   reloc->u.b.r.address     = note_offset + desc2_offset; | 
 |   reloc->u.b.r.addend      = addend; | 
 |   reloc->u.b.r.howto       = bfd_reloc_type_lookup (stdoutput, reloc_type); | 
 |  | 
 |   if (reloc->u.b.r.howto == NULL) | 
 |     { | 
 |       as_bad (_("unable to create reloc for build note")); | 
 |       return; | 
 |     } | 
 |  | 
 |   reloc->file = N_("<gnu build note>"); | 
 |   reloc->line = 0; | 
 |  | 
 |   reloc->next = reloc_list; | 
 |   reloc_list = reloc; | 
 |  | 
 |   /* For REL relocs, store the addend in the section.  */ | 
 |   if (! sec->use_rela_p | 
 |       /* The SH target is a special case that uses RELA relocs | 
 | 	 but still stores the addend in the word being relocated.  */ | 
 |       || strstr (bfd_get_target (stdoutput), "-sh") != NULL) | 
 |     { | 
 |       offsetT i; | 
 |  | 
 |       /* Zero out the addend, since it is now stored in the note.  */ | 
 |       reloc->u.b.r.addend = 0; | 
 |  | 
 |       if (target_big_endian) | 
 | 	{ | 
 | 	  for (i = desc2_size; addend != 0 && i > 0; addend >>= 8, i--) | 
 | 	    note[desc2_offset + i - 1] = (addend & 0xff); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  for (i = 0; addend != 0 && i < desc2_size; addend >>= 8, i++) | 
 | 	    note[desc2_offset + i] = (addend & 0xff); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | maybe_generate_build_notes (void) | 
 | { | 
 |   segT      sec; | 
 |   char *    note; | 
 |   offsetT   note_size; | 
 |   offsetT   total_size; | 
 |   offsetT   desc_size; | 
 |   offsetT   desc2_offset; | 
 |   int       desc_reloc; | 
 |   symbolS * sym; | 
 |   asymbol * bsym; | 
 |  | 
 |   if (! flag_generate_build_notes | 
 |       || bfd_get_section_by_name (stdoutput, | 
 | 				  GNU_BUILD_ATTRS_SECTION_NAME) != NULL) | 
 |     return; | 
 |  | 
 |   /* Create a GNU Build Attribute section.  */ | 
 |   sec = subseg_new (GNU_BUILD_ATTRS_SECTION_NAME, false); | 
 |   elf_section_type (sec) = SHT_NOTE; | 
 |   bfd_set_section_flags (sec, (SEC_READONLY | SEC_HAS_CONTENTS | SEC_DATA | 
 | 			       | SEC_OCTETS)); | 
 |   bfd_set_section_alignment (sec, 2); | 
 |  | 
 |   /* Work out the size of the notes that we will create, | 
 |      and the relocation we should use.  */ | 
 |   if (bfd_arch_bits_per_address (stdoutput) <= 32) | 
 |     { | 
 |       note_size = 28; | 
 |       desc_size = 8; /* Two 4-byte offsets.  */ | 
 |       desc2_offset = 24; | 
 |  | 
 |       /* FIXME: The BFD backend for the CRX target does not support the | 
 | 	 BFD_RELOC_32, even though it really should.  Likewise for the | 
 | 	 CR16 target.  So we have special case code here...  */ | 
 |       if (strstr (bfd_get_target (stdoutput), "-crx") != NULL) | 
 | 	desc_reloc = BFD_RELOC_CRX_NUM32; | 
 |       else if (strstr (bfd_get_target (stdoutput), "-cr16") != NULL) | 
 | 	desc_reloc = BFD_RELOC_CR16_NUM32; | 
 |       else | 
 | 	desc_reloc = BFD_RELOC_32; | 
 |     } | 
 |   else | 
 |     { | 
 |       note_size = 36; | 
 |       desc_size = 16; /* Two  8-byte offsets.  */ | 
 |       desc2_offset = 28; | 
 |       /* FIXME: The BFD backend for the IA64 target does not support the | 
 | 	 BFD_RELOC_64, even though it really should.  The HPPA backend | 
 | 	 has a similar issue, although it does not support BFD_RELOCs at | 
 | 	 all!  So we have special case code to handle these targets.  */ | 
 |       if (strstr (bfd_get_target (stdoutput), "-ia64") != NULL) | 
 | 	desc_reloc = target_big_endian ? BFD_RELOC_IA64_DIR32MSB : BFD_RELOC_IA64_DIR32LSB; | 
 |       else if (strstr (bfd_get_target (stdoutput), "-hppa") != NULL) | 
 | 	desc_reloc = 80; /* R_PARISC_DIR64.  */ | 
 |       else | 
 | 	desc_reloc = BFD_RELOC_64; | 
 |     } | 
 |    | 
 |   /* We have to create a note for *each* code section. | 
 |      Linker garbage collection might discard some.  */ | 
 |   total_size = 0; | 
 |   note = NULL; | 
 |  | 
 |   for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) | 
 |     if ((bsym = symbol_get_bfdsym (sym)) != NULL | 
 | 	&& bsym->flags & BSF_SECTION_SYM | 
 | 	&& bsym->section != NULL | 
 | 	/* Skip linkonce sections - we cannot use these section symbols as they may disappear.  */ | 
 | 	&& (bsym->section->flags & (SEC_CODE | SEC_LINK_ONCE)) == SEC_CODE | 
 | 	/* Not all linkonce sections are flagged...  */ | 
 | 	&& !startswith (S_GET_NAME (sym), ".gnu.linkonce")) | 
 |       { | 
 | 	/* Create a version note.  */ | 
 | 	frag_now_fix (); | 
 | 	note = frag_more (note_size); | 
 | 	memset (note, 0, note_size); | 
 |  | 
 | 	if (target_big_endian) | 
 | 	  { | 
 | 	    note[3] = 8; /* strlen (name) + 1.  */ | 
 | 	    note[7] = desc_size; /* Two N-byte offsets.  */ | 
 | 	    note[10] = NT_GNU_BUILD_ATTRIBUTE_OPEN >> 8; | 
 | 	    note[11] = NT_GNU_BUILD_ATTRIBUTE_OPEN & 0xff; | 
 | 	  } | 
 | 	else | 
 | 	  { | 
 | 	    note[0] = 8; /* strlen (name) + 1.  */ | 
 | 	    note[4] = desc_size; /* Two N-byte offsets.  */ | 
 | 	    note[8] = NT_GNU_BUILD_ATTRIBUTE_OPEN & 0xff; | 
 | 	    note[9] = NT_GNU_BUILD_ATTRIBUTE_OPEN >> 8; | 
 | 	  } | 
 |  | 
 | 	/* The a1 version number indicates that this note was | 
 | 	   generated by the assembler and not the gcc annobin plugin.  */ | 
 | 	memcpy (note + 12, "GA$3a1", 8); | 
 |  | 
 | 	/* Create a relocation to install the start address of the note...  */ | 
 | 	create_note_reloc (sec, sym, total_size, 20, desc_size / 2, desc_reloc, 0, note); | 
 |  | 
 | 	/* ...and another one to install the end address.  */ | 
 | 	create_note_reloc (sec, sym, total_size, desc2_offset, | 
 | 			   desc_size / 2, | 
 | 			   desc_reloc, | 
 | 			   bfd_section_size (bsym->section), | 
 | 			   note); | 
 |  | 
 | 	/* Mark the section symbol used in relocation so that it will be | 
 | 	   included in the symbol table.  */ | 
 | 	symbol_mark_used_in_reloc (sym); | 
 |  | 
 | 	total_size += note_size; | 
 | 	/* FIXME: Maybe add a note recording the assembler command line and version ?  */ | 
 |       } | 
 |  | 
 |   /* Install the note(s) into the section.  */ | 
 |   if (total_size) | 
 |     bfd_set_section_contents (stdoutput, sec, (bfd_byte *) note, 0, total_size); | 
 |   subsegs_finish_section (sec); | 
 |   relax_segment (seg_info (sec)->frchainP->frch_root, sec, 0); | 
 |   size_seg (stdoutput, sec, NULL); | 
 | } | 
 | #endif /* OBJ_ELF */ | 
 |  | 
 | /* Write the object file.  */ | 
 |  | 
 | void | 
 | write_object_file (void) | 
 | { | 
 |   struct relax_seg_info rsi; | 
 | #ifndef WORKING_DOT_WORD | 
 |   fragS *fragP;			/* Track along all frags.  */ | 
 | #endif | 
 |  | 
 |   subsegs_finish (); | 
 |  | 
 | #ifdef md_pre_output_hook | 
 |   md_pre_output_hook; | 
 | #endif | 
 |  | 
 | #ifdef md_pre_relax_hook | 
 |   md_pre_relax_hook; | 
 | #endif | 
 |  | 
 |   /* From now on, we don't care about sub-segments.  Build one frag chain | 
 |      for each segment. Linked through fr_next.  */ | 
 |  | 
 |   /* Remove the sections created by gas for its own purposes.  */ | 
 |   { | 
 |     int i; | 
 |  | 
 |     bfd_section_list_remove (stdoutput, reg_section); | 
 |     bfd_section_list_remove (stdoutput, expr_section); | 
 |     stdoutput->section_count -= 2; | 
 |     i = 0; | 
 |     bfd_map_over_sections (stdoutput, renumber_sections, &i); | 
 |   } | 
 |  | 
 |   bfd_map_over_sections (stdoutput, chain_frchains_together, (char *) 0); | 
 |  | 
 |   /* We have two segments. If user gave -R flag, then we must put the | 
 |      data frags into the text segment. Do this before relaxing so | 
 |      we know to take advantage of -R and make shorter addresses.  */ | 
 |   if (flag_readonly_data_in_text) | 
 |     { | 
 |       merge_data_into_text (); | 
 |     } | 
 |  | 
 |   rsi.pass = 0; | 
 |   while (1) | 
 |     { | 
 | #ifndef WORKING_DOT_WORD | 
 |       /* We need to reset the markers in the broken word list and | 
 | 	 associated frags between calls to relax_segment (via | 
 | 	 relax_seg).  Since the broken word list is global, we do it | 
 | 	 once per round, rather than locally in relax_segment for each | 
 | 	 segment.  */ | 
 |       struct broken_word *brokp; | 
 |  | 
 |       for (brokp = broken_words; | 
 | 	   brokp != (struct broken_word *) NULL; | 
 | 	   brokp = brokp->next_broken_word) | 
 | 	{ | 
 | 	  brokp->added = 0; | 
 |  | 
 | 	  if (brokp->dispfrag != (fragS *) NULL | 
 | 	      && brokp->dispfrag->fr_type == rs_broken_word) | 
 | 	    brokp->dispfrag->fr_subtype = 0; | 
 | 	} | 
 | #endif | 
 |  | 
 |       rsi.changed = 0; | 
 |       bfd_map_over_sections (stdoutput, relax_seg, &rsi); | 
 |       rsi.pass++; | 
 |       if (!rsi.changed) | 
 | 	break; | 
 |     } | 
 |  | 
 |   /* Note - Most ports will use the default value of | 
 |      TC_FINALIZE_SYMS_BEFORE_SIZE_SEG, which 1.  This will force | 
 |      local symbols to be resolved, removing their frag information. | 
 |      Some ports however, will not have finished relaxing all of | 
 |      their frags and will still need the local symbol frag | 
 |      information.  These ports can set | 
 |      TC_FINALIZE_SYMS_BEFORE_SIZE_SEG to 0.  */ | 
 |   finalize_syms = TC_FINALIZE_SYMS_BEFORE_SIZE_SEG; | 
 |  | 
 |   bfd_map_over_sections (stdoutput, size_seg, (char *) 0); | 
 |  | 
 |   /* Relaxation has completed.  Freeze all syms.  */ | 
 |   finalize_syms = 1; | 
 |  | 
 |   dwarf2dbg_final_check (); | 
 |  | 
 | #ifdef md_post_relax_hook | 
 |   md_post_relax_hook; | 
 | #endif | 
 |  | 
 | #ifdef OBJ_ELF | 
 |   if (IS_ELF) | 
 |     create_obj_attrs_section (); | 
 | #endif | 
 |  | 
 | #ifndef WORKING_DOT_WORD | 
 |   { | 
 |     struct broken_word *lie; | 
 |     struct broken_word **prevP; | 
 |  | 
 |     prevP = &broken_words; | 
 |     for (lie = broken_words; lie; lie = lie->next_broken_word) | 
 |       if (!lie->added) | 
 | 	{ | 
 | 	  expressionS exp; | 
 |  | 
 | 	  subseg_change (lie->seg, lie->subseg); | 
 | 	  exp.X_op = O_subtract; | 
 | 	  exp.X_add_symbol = lie->add; | 
 | 	  exp.X_op_symbol = lie->sub; | 
 | 	  exp.X_add_number = lie->addnum; | 
 | #ifdef TC_CONS_FIX_NEW | 
 | 	  TC_CONS_FIX_NEW (lie->frag, | 
 | 			   lie->word_goes_here - lie->frag->fr_literal, | 
 | 			   2, &exp, TC_PARSE_CONS_RETURN_NONE); | 
 | #else | 
 | 	  fix_new_exp (lie->frag, | 
 | 		       lie->word_goes_here - lie->frag->fr_literal, | 
 | 		       2, &exp, 0, BFD_RELOC_16); | 
 | #endif | 
 | 	  *prevP = lie->next_broken_word; | 
 | 	} | 
 |       else | 
 | 	prevP = &(lie->next_broken_word); | 
 |  | 
 |     for (lie = broken_words; lie;) | 
 |       { | 
 | 	struct broken_word *untruth; | 
 | 	char *table_ptr; | 
 | 	addressT table_addr; | 
 | 	addressT from_addr, to_addr; | 
 | 	int n, m; | 
 |  | 
 | 	subseg_change (lie->seg, lie->subseg); | 
 | 	fragP = lie->dispfrag; | 
 |  | 
 | 	/* Find out how many broken_words go here.  */ | 
 | 	n = 0; | 
 | 	for (untruth = lie; | 
 | 	     untruth && untruth->dispfrag == fragP; | 
 | 	     untruth = untruth->next_broken_word) | 
 | 	  if (untruth->added == 1) | 
 | 	    n++; | 
 |  | 
 | 	table_ptr = lie->dispfrag->fr_opcode; | 
 | 	table_addr = (lie->dispfrag->fr_address | 
 | 		      + (table_ptr - lie->dispfrag->fr_literal)); | 
 | 	/* Create the jump around the long jumps.  This is a short | 
 | 	   jump from table_ptr+0 to table_ptr+n*long_jump_size.  */ | 
 | 	from_addr = table_addr; | 
 | 	to_addr = table_addr + md_short_jump_size + n * md_long_jump_size; | 
 | 	md_create_short_jump (table_ptr, from_addr, to_addr, lie->dispfrag, | 
 | 			      lie->add); | 
 | 	table_ptr += md_short_jump_size; | 
 | 	table_addr += md_short_jump_size; | 
 |  | 
 | 	for (m = 0; | 
 | 	     lie && lie->dispfrag == fragP; | 
 | 	     m++, lie = lie->next_broken_word) | 
 | 	  { | 
 | 	    if (lie->added == 2) | 
 | 	      continue; | 
 | 	    /* Patch the jump table.  */ | 
 | 	    for (untruth = (struct broken_word *) (fragP->fr_symbol); | 
 | 		 untruth && untruth->dispfrag == fragP; | 
 | 		 untruth = untruth->next_broken_word) | 
 | 	      { | 
 | 		if (untruth->use_jump == lie) | 
 | 		  { | 
 | 		    /* This is the offset from ??? to table_ptr+0. | 
 | 		       The target is the same for all users of this | 
 | 		       md_long_jump, but the "sub" bases (and hence the | 
 | 		       offsets) may be different.  */ | 
 | 		    addressT to_word = table_addr - S_GET_VALUE (untruth->sub); | 
 | #ifdef TC_CHECK_ADJUSTED_BROKEN_DOT_WORD | 
 | 		    TC_CHECK_ADJUSTED_BROKEN_DOT_WORD (to_word, untruth); | 
 | #endif | 
 | 		    md_number_to_chars (untruth->word_goes_here, to_word, 2); | 
 | 		  } | 
 | 	      } | 
 |  | 
 | 	    /* Install the long jump.  */ | 
 | 	    /* This is a long jump from table_ptr+0 to the final target.  */ | 
 | 	    from_addr = table_addr; | 
 | 	    to_addr = S_GET_VALUE (lie->add) + lie->addnum; | 
 | 	    md_create_long_jump (table_ptr, from_addr, to_addr, lie->dispfrag, | 
 | 				 lie->add); | 
 | 	    table_ptr += md_long_jump_size; | 
 | 	    table_addr += md_long_jump_size; | 
 | 	  } | 
 |       } | 
 |   } | 
 | #endif /* not WORKING_DOT_WORD  */ | 
 |  | 
 |   /* Resolve symbol values.  This needs to be done before processing | 
 |      the relocations.  */ | 
 |   if (symbol_rootP) | 
 |     { | 
 |       symbolS *symp; | 
 |  | 
 |       for (symp = symbol_rootP; symp; symp = symbol_next (symp)) | 
 | 	resolve_symbol_value (symp); | 
 |     } | 
 |   resolve_local_symbol_values (); | 
 |   resolve_reloc_expr_symbols (); | 
 |  | 
 | #ifdef OBJ_ELF | 
 |   if (IS_ELF) | 
 |     maybe_generate_build_notes (); | 
 | #endif | 
 |  | 
 | #ifdef tc_frob_file_before_adjust | 
 |   tc_frob_file_before_adjust (); | 
 | #endif | 
 | #ifdef obj_frob_file_before_adjust | 
 |   obj_frob_file_before_adjust (); | 
 | #endif | 
 |  | 
 |   bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *) 0); | 
 |  | 
 | #ifdef tc_frob_file_before_fix | 
 |   tc_frob_file_before_fix (); | 
 | #endif | 
 | #ifdef obj_frob_file_before_fix | 
 |   obj_frob_file_before_fix (); | 
 | #endif | 
 |  | 
 |   bfd_map_over_sections (stdoutput, fix_segment, (char *) 0); | 
 |  | 
 |   /* Set up symbol table, and write it out.  */ | 
 |   if (symbol_rootP) | 
 |     { | 
 |       symbolS *symp; | 
 |       bool skip_next_symbol = false; | 
 |  | 
 |       for (symp = symbol_rootP; symp; symp = symbol_next (symp)) | 
 | 	{ | 
 | 	  int punt = 0; | 
 | 	  const char *name; | 
 |  | 
 | 	  if (skip_next_symbol) | 
 | 	    { | 
 | 	      /* Don't do anything besides moving the value of the | 
 | 		 symbol from the GAS value-field to the BFD value-field.  */ | 
 | 	      symbol_get_bfdsym (symp)->value = S_GET_VALUE (symp); | 
 | 	      skip_next_symbol = false; | 
 | 	      continue; | 
 | 	    } | 
 |  | 
 | 	  if (symbol_mri_common_p (symp)) | 
 | 	    { | 
 | 	      if (S_IS_EXTERNAL (symp)) | 
 | 		as_bad (_("%s: global symbols not supported in common sections"), | 
 | 			S_GET_NAME (symp)); | 
 | 	      symbol_remove (symp, &symbol_rootP, &symbol_lastP); | 
 | 	      continue; | 
 | 	    } | 
 |  | 
 | 	  name = S_GET_NAME (symp); | 
 | 	  if (name) | 
 | 	    { | 
 | 	      const char *name2 = | 
 | 		decode_local_label_name ((char *) S_GET_NAME (symp)); | 
 | 	      /* They only differ if `name' is a fb or dollar local | 
 | 		 label name.  */ | 
 | 	      if (name2 != name && ! S_IS_DEFINED (symp)) | 
 | 		as_bad (_("local label `%s' is not defined"), name2); | 
 | 	    } | 
 |  | 
 | 	  /* Do it again, because adjust_reloc_syms might introduce | 
 | 	     more symbols.  They'll probably only be section symbols, | 
 | 	     but they'll still need to have the values computed.  */ | 
 | 	  resolve_symbol_value (symp); | 
 |  | 
 | 	  /* Skip symbols which were equated to undefined or common | 
 | 	     symbols.  */ | 
 | 	  if (symbol_equated_reloc_p (symp) | 
 | 	      || S_IS_WEAKREFR (symp)) | 
 | 	    { | 
 | 	      const char *sname = S_GET_NAME (symp); | 
 |  | 
 | 	      if (S_IS_COMMON (symp) | 
 | 		  && !TC_FAKE_LABEL (sname) | 
 | 		  && !S_IS_WEAKREFR (symp)) | 
 | 		{ | 
 | 		  expressionS *e = symbol_get_value_expression (symp); | 
 |  | 
 | 		  as_bad (_("`%s' can't be equated to common symbol `%s'"), | 
 | 			  sname, S_GET_NAME (e->X_add_symbol)); | 
 | 		} | 
 | 	      if (S_GET_SEGMENT (symp) == reg_section) | 
 | 		{ | 
 | 		  /* Report error only if we know the symbol name.  */ | 
 | 		  if (S_GET_NAME (symp) != reg_section->name) | 
 | 		    as_bad (_("can't make global register symbol `%s'"), | 
 | 			    sname); | 
 | 		} | 
 | 	      symbol_remove (symp, &symbol_rootP, &symbol_lastP); | 
 | 	      continue; | 
 | 	    } | 
 |  | 
 | #ifdef obj_frob_symbol | 
 | 	  obj_frob_symbol (symp, punt); | 
 | #endif | 
 | #ifdef tc_frob_symbol | 
 | 	  if (! punt || symbol_used_in_reloc_p (symp)) | 
 | 	    tc_frob_symbol (symp, punt); | 
 | #endif | 
 |  | 
 | 	  /* If we don't want to keep this symbol, splice it out of | 
 | 	     the chain now.  If EMIT_SECTION_SYMBOLS is 0, we never | 
 | 	     want section symbols.  Otherwise, we skip local symbols | 
 | 	     and symbols that the frob_symbol macros told us to punt, | 
 | 	     but we keep such symbols if they are used in relocs.  */ | 
 | 	  if (symp == abs_section_sym | 
 | 	      || (! EMIT_SECTION_SYMBOLS | 
 | 		  && symbol_section_p (symp)) | 
 | 	      /* Note that S_IS_EXTERNAL and S_IS_LOCAL are not always | 
 | 		 opposites.  Sometimes the former checks flags and the | 
 | 		 latter examines the name...  */ | 
 | 	      || (!S_IS_EXTERNAL (symp) | 
 | 		  && (punt || S_IS_LOCAL (symp) || | 
 | 		      (S_IS_WEAKREFD (symp) && ! symbol_used_p (symp))) | 
 | 		  && ! symbol_used_in_reloc_p (symp))) | 
 | 	    { | 
 | 	      symbol_remove (symp, &symbol_rootP, &symbol_lastP); | 
 |  | 
 | 	      /* After symbol_remove, symbol_next(symp) still returns | 
 | 		 the one that came after it in the chain.  So we don't | 
 | 		 need to do any extra cleanup work here.  */ | 
 | 	      continue; | 
 | 	    } | 
 |  | 
 | 	  /* Make sure we really got a value for the symbol.  */ | 
 | 	  if (! symbol_resolved_p (symp)) | 
 | 	    { | 
 | 	      as_bad (_("can't resolve value for symbol `%s'"), | 
 | 		      S_GET_NAME (symp)); | 
 | 	      symbol_mark_resolved (symp); | 
 | 	    } | 
 |  | 
 | 	  /* Set the value into the BFD symbol.  Up til now the value | 
 | 	     has only been kept in the gas symbolS struct.  */ | 
 | 	  symbol_get_bfdsym (symp)->value = S_GET_VALUE (symp); | 
 |  | 
 | 	  /* A warning construct is a warning symbol followed by the | 
 | 	     symbol warned about.  Don't let anything object-format or | 
 | 	     target-specific muck with it; it's ready for output.  */ | 
 | 	  if (symbol_get_bfdsym (symp)->flags & BSF_WARNING) | 
 | 	    skip_next_symbol = true; | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Now do any format-specific adjustments to the symbol table, such | 
 |      as adding file symbols.  */ | 
 | #ifdef tc_adjust_symtab | 
 |   tc_adjust_symtab (); | 
 | #endif | 
 | #ifdef obj_adjust_symtab | 
 |   obj_adjust_symtab (); | 
 | #endif | 
 |  | 
 |   /* Stop if there is an error.  */ | 
 |   if (!flag_always_generate_output && had_errors ()) | 
 |     return; | 
 |  | 
 |   /* Now that all the sizes are known, and contents correct, we can | 
 |      start writing to the file.  */ | 
 |   set_symtab (); | 
 |  | 
 |   /* If *_frob_file changes the symbol value at this point, it is | 
 |      responsible for moving the changed value into symp->bsym->value | 
 |      as well.  Hopefully all symbol value changing can be done in | 
 |      *_frob_symbol.  */ | 
 | #ifdef tc_frob_file | 
 |   tc_frob_file (); | 
 | #endif | 
 | #ifdef obj_frob_file | 
 |   obj_frob_file (); | 
 | #endif | 
 | #ifdef obj_coff_generate_pdata | 
 |   obj_coff_generate_pdata (); | 
 | #endif | 
 |  | 
 |   bfd_map_over_sections (stdoutput, write_relocs, (char *) 0); | 
 |   reloc_list = NULL; | 
 |  | 
 | #ifdef tc_frob_file_after_relocs | 
 |   tc_frob_file_after_relocs (); | 
 | #endif | 
 | #ifdef obj_frob_file_after_relocs | 
 |   obj_frob_file_after_relocs (); | 
 | #endif | 
 |  | 
 | #if defined OBJ_ELF || defined OBJ_MAYBE_ELF | 
 |   if (IS_ELF && flag_use_elf_stt_common) | 
 |     stdoutput->flags |= BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON; | 
 | #endif | 
 |  | 
 |   /* Once all relocations have been written, we can compress the | 
 |      contents of the debug sections.  This needs to be done before | 
 |      we start writing any sections, because it will affect the file | 
 |      layout, which is fixed once we start writing contents.  */ | 
 |   if (flag_compress_debug != COMPRESS_DEBUG_NONE) | 
 |     { | 
 |       flagword flags = BFD_COMPRESS; | 
 |       if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB) | 
 | 	flags = BFD_COMPRESS | BFD_COMPRESS_GABI; | 
 |       else if (flag_compress_debug == COMPRESS_DEBUG_ZSTD) | 
 | 	flags = BFD_COMPRESS | BFD_COMPRESS_GABI | BFD_COMPRESS_ZSTD; | 
 |       stdoutput->flags |= flags & bfd_applicable_file_flags (stdoutput); | 
 |       if ((stdoutput->flags & BFD_COMPRESS) != 0) | 
 | 	bfd_map_over_sections (stdoutput, compress_debug, (char *) 0); | 
 |     } | 
 |  | 
 |   bfd_map_over_sections (stdoutput, write_contents, (char *) 0); | 
 | } | 
 |  | 
 | #ifdef TC_GENERIC_RELAX_TABLE | 
 | #ifndef md_generic_table_relax_frag | 
 | #define md_generic_table_relax_frag relax_frag | 
 | #endif | 
 |  | 
 | /* Relax a fragment by scanning TC_GENERIC_RELAX_TABLE.  */ | 
 |  | 
 | long | 
 | relax_frag (segT segment, fragS *fragP, long stretch) | 
 | { | 
 |   const relax_typeS *this_type; | 
 |   const relax_typeS *start_type; | 
 |   relax_substateT next_state; | 
 |   relax_substateT this_state; | 
 |   offsetT growth; | 
 |   offsetT aim; | 
 |   addressT target; | 
 |   addressT address; | 
 |   symbolS *symbolP; | 
 |   const relax_typeS *table; | 
 |  | 
 |   target = fragP->fr_offset; | 
 |   address = fragP->fr_address + fragP->fr_fix; | 
 |   table = TC_GENERIC_RELAX_TABLE; | 
 |   this_state = fragP->fr_subtype; | 
 |   start_type = this_type = table + this_state; | 
 |   symbolP = fragP->fr_symbol; | 
 |  | 
 |   if (symbolP) | 
 |     { | 
 |       fragS *sym_frag; | 
 |  | 
 |       sym_frag = symbol_get_frag (symbolP); | 
 |  | 
 | #ifndef DIFF_EXPR_OK | 
 |       know (sym_frag != NULL); | 
 | #endif | 
 |       know (S_GET_SEGMENT (symbolP) != absolute_section | 
 | 	    || sym_frag == &zero_address_frag); | 
 |       target += S_GET_VALUE (symbolP); | 
 |  | 
 |       /* If SYM_FRAG has yet to be reached on this pass, assume it | 
 | 	 will move by STRETCH just as we did, unless there is an | 
 | 	 alignment frag between here and SYM_FRAG.  An alignment may | 
 | 	 well absorb any STRETCH, and we don't want to choose a larger | 
 | 	 branch insn by overestimating the needed reach of this | 
 | 	 branch.  It isn't critical to calculate TARGET exactly;  We | 
 | 	 know we'll be doing another pass if STRETCH is non-zero.  */ | 
 |  | 
 |       if (stretch != 0 | 
 | 	  && sym_frag->relax_marker != fragP->relax_marker | 
 | 	  && S_GET_SEGMENT (symbolP) == segment) | 
 | 	{ | 
 | 	  if (stretch < 0 | 
 | 	      || sym_frag->region == fragP->region) | 
 | 	    target += stretch; | 
 | 	  /* If we get here we know we have a forward branch.  This | 
 | 	     relax pass may have stretched previous instructions so | 
 | 	     far that omitting STRETCH would make the branch | 
 | 	     negative.  Don't allow this in case the negative reach is | 
 | 	     large enough to require a larger branch instruction.  */ | 
 | 	  else if (target < address) | 
 | 	    return 0; | 
 | 	} | 
 |     } | 
 |  | 
 |   aim = target - address; | 
 | #ifdef TC_PCREL_ADJUST | 
 |   /* Currently only the ns32k and arc needs this.  */ | 
 |   aim += TC_PCREL_ADJUST (fragP); | 
 | #endif | 
 |  | 
 | #ifdef md_prepare_relax_scan | 
 |   /* Formerly called M68K_AIM_KLUDGE.  */ | 
 |   md_prepare_relax_scan (fragP, address, aim, this_state, this_type); | 
 | #endif | 
 |  | 
 |   if (aim < 0) | 
 |     { | 
 |       /* Look backwards.  */ | 
 |       for (next_state = this_type->rlx_more; next_state;) | 
 | 	if (aim >= this_type->rlx_backward) | 
 | 	  next_state = 0; | 
 | 	else | 
 | 	  { | 
 | 	    /* Grow to next state.  */ | 
 | 	    this_state = next_state; | 
 | 	    this_type = table + this_state; | 
 | 	    next_state = this_type->rlx_more; | 
 | 	  } | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Look forwards.  */ | 
 |       for (next_state = this_type->rlx_more; next_state;) | 
 | 	if (aim <= this_type->rlx_forward) | 
 | 	  next_state = 0; | 
 | 	else | 
 | 	  { | 
 | 	    /* Grow to next state.  */ | 
 | 	    this_state = next_state; | 
 | 	    this_type = table + this_state; | 
 | 	    next_state = this_type->rlx_more; | 
 | 	  } | 
 |     } | 
 |  | 
 |   growth = this_type->rlx_length - start_type->rlx_length; | 
 |   if (growth != 0) | 
 |     fragP->fr_subtype = this_state; | 
 |   return growth; | 
 | } | 
 |  | 
 | #endif /* defined (TC_GENERIC_RELAX_TABLE)  */ | 
 |  | 
 | /* Relax_align. Advance location counter to next address that has 'alignment' | 
 |    lowest order bits all 0s, return size of adjustment made.  */ | 
 | static relax_addressT | 
 | relax_align (relax_addressT address,	/* Address now.  */ | 
 | 	     int alignment	/* Alignment (binary).  */) | 
 | { | 
 |   relax_addressT mask; | 
 |   relax_addressT new_address; | 
 |  | 
 |   mask = ~((relax_addressT) ~0 << alignment); | 
 |   new_address = (address + mask) & (~mask); | 
 | #ifdef LINKER_RELAXING_SHRINKS_ONLY | 
 |   if (linkrelax) | 
 |     /* We must provide lots of padding, so the linker can discard it | 
 |        when needed.  The linker will not add extra space, ever.  */ | 
 |     new_address += (1 << alignment); | 
 | #endif | 
 |   return (new_address - address); | 
 | } | 
 |  | 
 | /* Now we have a segment, not a crowd of sub-segments, we can make | 
 |    fr_address values. | 
 |  | 
 |    Relax the frags. | 
 |  | 
 |    After this, all frags in this segment have addresses that are correct | 
 |    within the segment. Since segments live in different file addresses, | 
 |    these frag addresses may not be the same as final object-file | 
 |    addresses.  */ | 
 |  | 
 | int | 
 | relax_segment (struct frag *segment_frag_root, segT segment, int pass) | 
 | { | 
 |   unsigned long frag_count; | 
 |   struct frag *fragP; | 
 |   relax_addressT address; | 
 |   int region; | 
 |   int ret; | 
 |  | 
 |   /* In case md_estimate_size_before_relax() wants to make fixSs.  */ | 
 |   subseg_change (segment, 0); | 
 |  | 
 |   /* For each frag in segment: count and store  (a 1st guess of) | 
 |      fr_address.  */ | 
 |   address = 0; | 
 |   region = 0; | 
 |   for (frag_count = 0, fragP = segment_frag_root; | 
 |        fragP; | 
 |        fragP = fragP->fr_next, frag_count ++) | 
 |     { | 
 |       fragP->region = region; | 
 |       fragP->relax_marker = 0; | 
 |       fragP->fr_address = address; | 
 |       address += fragP->fr_fix; | 
 |  | 
 |       switch (fragP->fr_type) | 
 | 	{ | 
 | 	case rs_fill: | 
 | 	  address += fragP->fr_offset * fragP->fr_var; | 
 | 	  break; | 
 |  | 
 | 	case rs_align: | 
 | 	case rs_align_code: | 
 | 	case rs_align_test: | 
 | 	  { | 
 | 	    addressT offset = relax_align (address, (int) fragP->fr_offset); | 
 |  | 
 | 	    if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype) | 
 | 	      offset = 0; | 
 |  | 
 | 	    if (offset % fragP->fr_var != 0) | 
 | 	      { | 
 | 		as_bad_where (fragP->fr_file, fragP->fr_line, | 
 | 			      ngettext ("alignment padding (%lu byte) " | 
 | 					"not a multiple of %ld", | 
 | 					"alignment padding (%lu bytes) " | 
 | 					"not a multiple of %ld", | 
 | 					(unsigned long) offset), | 
 | 			      (unsigned long) offset, (long) fragP->fr_var); | 
 | 		offset -= (offset % fragP->fr_var); | 
 | 	      } | 
 |  | 
 | 	    address += offset; | 
 | 	    region += 1; | 
 | 	  } | 
 | 	  break; | 
 |  | 
 | 	case rs_org: | 
 | 	  /* Assume .org is nugatory. It will grow with 1st relax.  */ | 
 | 	  region += 1; | 
 | 	  break; | 
 |  | 
 | 	case rs_space: | 
 | 	case rs_space_nop: | 
 | 	  break; | 
 |  | 
 | 	case rs_machine_dependent: | 
 | 	  /* If fr_symbol is an expression, this call to | 
 | 	     resolve_symbol_value sets up the correct segment, which will | 
 | 	     likely be needed in md_estimate_size_before_relax.  */ | 
 | 	  if (fragP->fr_symbol) | 
 | 	    resolve_symbol_value (fragP->fr_symbol); | 
 |  | 
 | 	  address += md_estimate_size_before_relax (fragP, segment); | 
 | 	  break; | 
 |  | 
 | #ifndef WORKING_DOT_WORD | 
 | 	  /* Broken words don't concern us yet.  */ | 
 | 	case rs_broken_word: | 
 | 	  break; | 
 | #endif | 
 |  | 
 | 	case rs_leb128: | 
 | #if defined (TE_PE) && defined (O_secrel) | 
 | 	case rs_cv_comp: | 
 | #endif | 
 | 	  /* Initial guess is always 1; doing otherwise can result in | 
 | 	     stable solutions that are larger than the minimum.  */ | 
 | 	  address += fragP->fr_offset = 1; | 
 | 	  break; | 
 |  | 
 | 	case rs_cfa: | 
 | 	  address += eh_frame_estimate_size_before_relax (fragP); | 
 | 	  break; | 
 |  | 
 | 	case rs_dwarf2dbg: | 
 | 	  address += dwarf2dbg_estimate_size_before_relax (fragP); | 
 | 	  break; | 
 |  | 
 | 	case rs_sframe: | 
 | 	  /* Initial estimate can be set to atleast 1 byte.  */ | 
 | 	  address += sframe_estimate_size_before_relax (fragP); | 
 | 	  break; | 
 |  | 
 | 	default: | 
 | 	  BAD_CASE (fragP->fr_type); | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Do relax().  */ | 
 |   { | 
 |     unsigned long max_iterations; | 
 |  | 
 |     /* Cumulative address adjustment.  */ | 
 |     offsetT stretch; | 
 |  | 
 |     /* Have we made any adjustment this pass?  We can't just test | 
 |        stretch because one piece of code may have grown and another | 
 |        shrank.  */ | 
 |     int stretched; | 
 |  | 
 |     /* Most horrible, but gcc may give us some exception data that | 
 |        is impossible to assemble, of the form | 
 |  | 
 |        .align 4 | 
 |        .byte 0, 0 | 
 |        .uleb128 end - start | 
 |        start: | 
 |        .space 128*128 - 1 | 
 |        .align 4 | 
 |        end: | 
 |  | 
 |        If the leb128 is two bytes in size, then end-start is 128*128, | 
 |        which requires a three byte leb128.  If the leb128 is three | 
 |        bytes in size, then end-start is 128*128-1, which requires a | 
 |        two byte leb128.  We work around this dilemma by inserting | 
 |        an extra 4 bytes of alignment just after the .align.  This | 
 |        works because the data after the align is accessed relative to | 
 |        the end label. | 
 |  | 
 |        This counter is used in a tiny state machine to detect | 
 |        whether a leb128 followed by an align is impossible to | 
 |        relax.  */ | 
 |     int rs_leb128_fudge = 0; | 
 |  | 
 |     /* We want to prevent going into an infinite loop where one frag grows | 
 |        depending upon the location of a symbol which is in turn moved by | 
 |        the growing frag.  eg: | 
 |  | 
 | 	 foo = . | 
 | 	 .org foo+16 | 
 | 	 foo = . | 
 |  | 
 |        So we dictate that this algorithm can be at most O2.  */ | 
 |     max_iterations = frag_count * frag_count; | 
 |     /* Check for overflow.  */ | 
 |     if (max_iterations < frag_count) | 
 |       max_iterations = frag_count; | 
 |  | 
 |     ret = 0; | 
 |     do | 
 |       { | 
 | 	stretch = 0; | 
 | 	stretched = 0; | 
 |  | 
 | 	for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) | 
 | 	  { | 
 | 	    offsetT growth = 0; | 
 | 	    addressT was_address; | 
 | 	    offsetT offset; | 
 | 	    symbolS *symbolP; | 
 |  | 
 | 	    fragP->relax_marker ^= 1; | 
 | 	    was_address = fragP->fr_address; | 
 | 	    address = fragP->fr_address += stretch; | 
 | 	    symbolP = fragP->fr_symbol; | 
 | 	    offset = fragP->fr_offset; | 
 |  | 
 | 	    switch (fragP->fr_type) | 
 | 	      { | 
 | 	      case rs_fill:	/* .fill never relaxes.  */ | 
 | 		growth = 0; | 
 | 		break; | 
 |  | 
 | #ifndef WORKING_DOT_WORD | 
 | 		/* JF:  This is RMS's idea.  I do *NOT* want to be blamed | 
 | 		   for it I do not want to write it.  I do not want to have | 
 | 		   anything to do with it.  This is not the proper way to | 
 | 		   implement this misfeature.  */ | 
 | 	      case rs_broken_word: | 
 | 		{ | 
 | 		  struct broken_word *lie; | 
 | 		  struct broken_word *untruth; | 
 |  | 
 | 		  /* Yes this is ugly (storing the broken_word pointer | 
 | 		     in the symbol slot).  Still, this whole chunk of | 
 | 		     code is ugly, and I don't feel like doing anything | 
 | 		     about it.  Think of it as stubbornness in action.  */ | 
 | 		  growth = 0; | 
 | 		  for (lie = (struct broken_word *) (fragP->fr_symbol); | 
 | 		       lie && lie->dispfrag == fragP; | 
 | 		       lie = lie->next_broken_word) | 
 | 		    { | 
 |  | 
 | 		      if (lie->added) | 
 | 			continue; | 
 |  | 
 | 		      offset = (S_GET_VALUE (lie->add) | 
 | 				+ lie->addnum | 
 | 				- S_GET_VALUE (lie->sub)); | 
 | 		      if (offset <= -32768 || offset >= 32767) | 
 | 			{ | 
 | 			  if (flag_warn_displacement) | 
 | 			    { | 
 | 			      char buf[50]; | 
 |  | 
 | 			      bfd_sprintf_vma (stdoutput, buf, | 
 | 					       (addressT) lie->addnum); | 
 | 			      as_warn_where (fragP->fr_file, fragP->fr_line, | 
 | 					     _(".word %s-%s+%s didn't fit"), | 
 | 					     S_GET_NAME (lie->add), | 
 | 					     S_GET_NAME (lie->sub), | 
 | 					     buf); | 
 | 			    } | 
 | 			  if (fragP->fr_subtype == 0) | 
 | 			    { | 
 | 			      fragP->fr_subtype++; | 
 | 			      growth += md_short_jump_size; | 
 | 			    } | 
 |  | 
 | 			  /* Redirect *all* words of this table with the same | 
 | 			     target, lest we have to handle the case where the | 
 | 			     same target but with a offset that fits on this | 
 | 			     round overflows at the next relaxation round.  */ | 
 | 			  for (untruth = (struct broken_word *) (fragP->fr_symbol); | 
 | 			       untruth && untruth->dispfrag == lie->dispfrag; | 
 | 			       untruth = untruth->next_broken_word) | 
 | 			    if ((symbol_get_frag (untruth->add) | 
 | 				 == symbol_get_frag (lie->add)) | 
 | 				&& (S_GET_VALUE (untruth->add) | 
 | 				    == S_GET_VALUE (lie->add))) | 
 | 			      { | 
 | 				untruth->added = 2; | 
 | 				untruth->use_jump = lie; | 
 | 			      } | 
 |  | 
 | 			  lie->added = 1; | 
 | 			  growth += md_long_jump_size; | 
 | 			} | 
 | 		    } | 
 |  | 
 | 		  break; | 
 | 		}		/* case rs_broken_word  */ | 
 | #endif | 
 | 	      case rs_align: | 
 | 	      case rs_align_code: | 
 | 	      case rs_align_test: | 
 | 		{ | 
 | 		  addressT oldoff, newoff; | 
 |  | 
 | 		  oldoff = relax_align (was_address + fragP->fr_fix, | 
 | 					(int) offset); | 
 | 		  newoff = relax_align (address + fragP->fr_fix, | 
 | 					(int) offset); | 
 |  | 
 | 		  if (fragP->fr_subtype != 0) | 
 | 		    { | 
 | 		      if (oldoff > fragP->fr_subtype) | 
 | 			oldoff = 0; | 
 | 		      if (newoff > fragP->fr_subtype) | 
 | 			newoff = 0; | 
 | 		    } | 
 |  | 
 | 		  growth = newoff - oldoff; | 
 |  | 
 | 		  /* If this align happens to follow a leb128 and | 
 | 		     we have determined that the leb128 is bouncing | 
 | 		     in size, then break the cycle by inserting an | 
 | 		     extra alignment.  */ | 
 | 		  if (growth < 0 | 
 | 		      && (rs_leb128_fudge & 16) != 0 | 
 | 		      && (rs_leb128_fudge & 15) >= 2) | 
 | 		    { | 
 | 		      segment_info_type *seginfo = seg_info (segment); | 
 | 		      struct obstack *ob = &seginfo->frchainP->frch_obstack; | 
 | 		      struct frag *newf; | 
 |  | 
 | 		      newf = frag_alloc (ob, fragP->fr_var); | 
 | 		      memcpy (newf, fragP, SIZEOF_STRUCT_FRAG); | 
 | 		      memcpy (newf->fr_literal, | 
 | 			      fragP->fr_literal + fragP->fr_fix, | 
 | 			      fragP->fr_var); | 
 | 		      newf->fr_type = rs_fill; | 
 | 		      newf->fr_address = address + fragP->fr_fix + newoff; | 
 | 		      newf->fr_fix = 0; | 
 | 		      newf->fr_offset = (((offsetT) 1 << fragP->fr_offset) | 
 | 					 / fragP->fr_var); | 
 | 		      if (newf->fr_offset * newf->fr_var | 
 | 			  != (offsetT) 1 << fragP->fr_offset) | 
 | 			{ | 
 | 			  newf->fr_offset = (offsetT) 1 << fragP->fr_offset; | 
 | 			  newf->fr_var = 1; | 
 | 			} | 
 | 		      /* Include size of new frag in GROWTH.  */ | 
 | 		      growth += newf->fr_offset * newf->fr_var; | 
 | 		      /* Adjust the new frag address for the amount | 
 | 			 we'll add when we process the new frag.  */ | 
 | 		      newf->fr_address -= stretch + growth; | 
 | 		      newf->relax_marker ^= 1; | 
 | 		      fragP->fr_next = newf; | 
 | #ifdef DEBUG | 
 | 		      as_warn (_("padding added")); | 
 | #endif | 
 | 		    } | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	      case rs_org: | 
 | 		{ | 
 | 		  offsetT target = offset; | 
 | 		  addressT after; | 
 |  | 
 | 		  if (symbolP) | 
 | 		    { | 
 | 		      /* Convert from an actual address to an octet offset | 
 | 			 into the section.  Here it is assumed that the | 
 | 			 section's VMA is zero, and can omit subtracting it | 
 | 			 from the symbol's value to get the address offset.  */ | 
 | 		      know (S_GET_SEGMENT (symbolP)->vma == 0); | 
 | 		      target += S_GET_VALUE (symbolP) * OCTETS_PER_BYTE; | 
 | 		    } | 
 |  | 
 | 		  know (fragP->fr_next); | 
 | 		  after = fragP->fr_next->fr_address + stretch; | 
 | 		  growth = target - after; | 
 |  | 
 | 		  /* Growth may be negative, but variable part of frag | 
 | 		     cannot have fewer than 0 chars.  That is, we can't | 
 | 		     .org backwards.  */ | 
 | 		  if ((offsetT) (address + fragP->fr_fix) > target) | 
 | 		    { | 
 | 		      growth = 0; | 
 |  | 
 | 		      /* Don't error on first few frag relax passes. | 
 | 			 The symbol might be an expression involving | 
 | 			 symbol values from other sections.  If those | 
 | 			 sections have not yet been processed their | 
 | 			 frags will all have zero addresses, so we | 
 | 			 will calculate incorrect values for them.  The | 
 | 			 number of passes we allow before giving an | 
 | 			 error is somewhat arbitrary.  It should be at | 
 | 			 least one, with larger values requiring | 
 | 			 increasingly contrived dependencies between | 
 | 			 frags to trigger a false error.  */ | 
 | 		      if (pass < 2) | 
 | 			{ | 
 | 			  /* Force another pass.  */ | 
 | 			  ret = 1; | 
 | 			  break; | 
 | 			} | 
 |  | 
 | 		      as_bad_where (fragP->fr_file, fragP->fr_line, | 
 | 				    _("attempt to move .org backwards")); | 
 |  | 
 | 		      /* We've issued an error message.  Change the | 
 | 			 frag to avoid cascading errors.  */ | 
 | 		      fragP->fr_type = rs_align; | 
 | 		      fragP->fr_subtype = 0; | 
 | 		      fragP->fr_offset = 0; | 
 | 		      fragP->fr_fix = after - address; | 
 | 		    } | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	      case rs_space: | 
 | 	      case rs_space_nop: | 
 | 		growth = 0; | 
 | 		if (symbolP) | 
 | 		  { | 
 | 		    offsetT amount; | 
 |  | 
 | 		    amount = S_GET_VALUE (symbolP); | 
 | 		    if (S_GET_SEGMENT (symbolP) != absolute_section | 
 | 			|| S_IS_COMMON (symbolP) | 
 | 			|| ! S_IS_DEFINED (symbolP)) | 
 | 		      { | 
 | 			as_bad_where (fragP->fr_file, fragP->fr_line, | 
 | 				      _(".space, .nops or .fill specifies non-absolute value")); | 
 | 			/* Prevent repeat of this error message.  */ | 
 | 			fragP->fr_symbol = 0; | 
 | 		      } | 
 | 		    else if (amount < 0) | 
 | 		      { | 
 | 			/* Don't error on first few frag relax passes. | 
 | 			   See rs_org comment for a longer explanation.  */ | 
 | 			if (pass < 2) | 
 | 			  { | 
 | 			    ret = 1; | 
 | 			    break; | 
 | 			  } | 
 |  | 
 | 			as_warn_where (fragP->fr_file, fragP->fr_line, | 
 | 				       _(".space, .nops or .fill with negative value, ignored")); | 
 | 			fragP->fr_symbol = 0; | 
 | 		      } | 
 | 		    else | 
 | 		      growth = (was_address + fragP->fr_fix + amount | 
 | 				- fragP->fr_next->fr_address); | 
 | 		  } | 
 | 		break; | 
 |  | 
 | 	      case rs_machine_dependent: | 
 | #ifdef md_relax_frag | 
 | 		growth = md_relax_frag (segment, fragP, stretch); | 
 | #else | 
 | #ifdef TC_GENERIC_RELAX_TABLE | 
 | 		/* The default way to relax a frag is to look through | 
 | 		   TC_GENERIC_RELAX_TABLE.  */ | 
 | 		growth = md_generic_table_relax_frag (segment, fragP, | 
 | 						      stretch); | 
 | #endif /* TC_GENERIC_RELAX_TABLE  */ | 
 | #endif | 
 | 		break; | 
 |  | 
 | 	      case rs_leb128: | 
 | 		{ | 
 | 		  valueT value; | 
 | 		  offsetT size; | 
 |  | 
 | 		  value = resolve_symbol_value (fragP->fr_symbol); | 
 | 		  size = sizeof_leb128 (value, fragP->fr_subtype); | 
 | 		  growth = size - fragP->fr_offset; | 
 | 		  fragP->fr_offset = size; | 
 | 		} | 
 | 		break; | 
 |  | 
 | #if defined (TE_PE) && defined (O_secrel) | 
 | 	      case rs_cv_comp: | 
 | 		{ | 
 | 		  valueT value; | 
 | 		  offsetT size; | 
 |  | 
 | 		  value = resolve_symbol_value (fragP->fr_symbol); | 
 | 		  size = sizeof_cv_comp (value, fragP->fr_subtype); | 
 | 		  growth = size - fragP->fr_offset; | 
 | 		  fragP->fr_offset = size; | 
 | 		} | 
 | 	      break; | 
 | #endif | 
 |  | 
 | 	      case rs_cfa: | 
 | 		growth = eh_frame_relax_frag (fragP); | 
 | 		break; | 
 |  | 
 | 	      case rs_dwarf2dbg: | 
 | 		growth = dwarf2dbg_relax_frag (fragP); | 
 | 		break; | 
 |  | 
 | 	      case rs_sframe: | 
 | 		growth = sframe_relax_frag (fragP); | 
 | 		break; | 
 |  | 
 | 	      default: | 
 | 		BAD_CASE (fragP->fr_type); | 
 | 		break; | 
 | 	      } | 
 | 	    if (growth) | 
 | 	      { | 
 | 		stretch += growth; | 
 | 		stretched = 1; | 
 | 		if (fragP->fr_type == rs_leb128) | 
 | 		  rs_leb128_fudge += 16; | 
 | 		else if (fragP->fr_type == rs_align | 
 | 			 && (rs_leb128_fudge & 16) != 0 | 
 | 			 && stretch == 0) | 
 | 		  rs_leb128_fudge += 16; | 
 | 		else | 
 | 		  rs_leb128_fudge = 0; | 
 | 	      } | 
 | 	  } | 
 |  | 
 | 	if (stretch == 0 | 
 | 	    && (rs_leb128_fudge & 16) == 0 | 
 | 	    && (rs_leb128_fudge & -16) != 0) | 
 | 	  rs_leb128_fudge += 1; | 
 | 	else | 
 | 	  rs_leb128_fudge = 0; | 
 |       } | 
 |     /* Until nothing further to relax.  */ | 
 |     while (stretched && -- max_iterations); | 
 |  | 
 |     if (stretched) | 
 |       as_fatal (_("Infinite loop encountered whilst attempting to compute the addresses of symbols in section %s"), | 
 | 		segment_name (segment)); | 
 |   } | 
 |  | 
 |   for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) | 
 |     if (fragP->last_fr_address != fragP->fr_address) | 
 |       { | 
 | 	fragP->last_fr_address = fragP->fr_address; | 
 | 	ret = 1; | 
 |       } | 
 |   return ret; | 
 | } | 
 |  | 
 | void | 
 | number_to_chars_bigendian (char *buf, valueT val, int n) | 
 | { | 
 |   if (n <= 0) | 
 |     abort (); | 
 |   while (n--) | 
 |     { | 
 |       buf[n] = val & 0xff; | 
 |       val >>= 8; | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | number_to_chars_littleendian (char *buf, valueT val, int n) | 
 | { | 
 |   if (n <= 0) | 
 |     abort (); | 
 |   while (n--) | 
 |     { | 
 |       *buf++ = val & 0xff; | 
 |       val >>= 8; | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | write_print_statistics (FILE *file) | 
 | { | 
 |   fprintf (file, "fixups: %d\n", n_fixups); | 
 | } | 
 |  | 
 | /* For debugging.  */ | 
 | extern int indent_level; | 
 |  | 
 | void | 
 | print_fixup (fixS *fixp) | 
 | { | 
 |   indent_level = 1; | 
 |   fprintf (stderr, "fix %p %s:%d", fixp, fixp->fx_file, fixp->fx_line); | 
 |   if (fixp->fx_pcrel) | 
 |     fprintf (stderr, " pcrel"); | 
 |   if (fixp->fx_pcrel_adjust) | 
 |     fprintf (stderr, " pcrel_adjust=%d", fixp->fx_pcrel_adjust); | 
 |   if (fixp->fx_tcbit) | 
 |     fprintf (stderr, " tcbit"); | 
 |   if (fixp->fx_done) | 
 |     fprintf (stderr, " done"); | 
 |   fprintf (stderr, "\n    size=%d frag=%p", fixp->fx_size, fixp->fx_frag); | 
 |   fprintf (stderr, " where=%ld offset=%" PRIx64 " addnumber=%" PRIx64, | 
 | 	   fixp->fx_where, (uint64_t) fixp->fx_offset, | 
 | 	   (uint64_t) fixp->fx_addnumber); | 
 |   fprintf (stderr, "\n    %s (%d)", bfd_get_reloc_code_name (fixp->fx_r_type), | 
 | 	   fixp->fx_r_type); | 
 |   if (fixp->fx_addsy) | 
 |     { | 
 |       fprintf (stderr, "\n   +<"); | 
 |       print_symbol_value_1 (stderr, fixp->fx_addsy); | 
 |       fprintf (stderr, ">"); | 
 |     } | 
 |   if (fixp->fx_subsy) | 
 |     { | 
 |       fprintf (stderr, "\n   -<"); | 
 |       print_symbol_value_1 (stderr, fixp->fx_subsy); | 
 |       fprintf (stderr, ">"); | 
 |     } | 
 |   fprintf (stderr, "\n"); | 
 | #ifdef TC_FIX_DATA_PRINT | 
 |   TC_FIX_DATA_PRINT (stderr, fixp); | 
 | #endif | 
 | } |