sub_symbolP = fixP->fx_subsy; add_number = fixP->fx_offset; pcrel = fixP->fx_pcrel;
fixup_segment (segP, this_segment_type)     segment_info_type * segP;     segT this_segment_type;{  register fixS * fixP;  register symbolS *add_symbolP;  register symbolS *sub_symbolP;  long add_number;  register int size;  register char *place;  register long where;  register char pcrel;  register fragS *fragP;  register segT add_symbol_segment = absolute_section;  if (linkrelax)    return;  for (fixP = segP->fix_root; fixP; fixP = fixP->fx_next)    {      fragP = fixP->fx_frag;      know (fragP);      where = fixP->fx_where;      place = fragP->fr_literal + where;      size = fixP->fx_size;      add_symbolP = fixP->fx_addsy;#ifdef TC_I960      if (fixP->fx_tcbit && SF_GET_CALLNAME (add_symbolP))	{	  /* Relocation should be done via the associated 'bal' entry	     point symbol. */	  if (!SF_GET_BALNAME (tc_get_bal_of_call (add_symbolP)))	    {	      as_bad_where (fixP->fx_file, fixP->fx_line,			    "No 'bal' entry point for leafproc %s",			    S_GET_NAME (add_symbolP));	      continue;	    }	  fixP->fx_addsy = add_symbolP = tc_get_bal_of_call (add_symbolP);	}#endif      sub_symbolP = fixP->fx_subsy;      add_number = fixP->fx_offset;      pcrel = fixP->fx_pcrel;      if (add_symbolP != NULL	  && add_symbolP->sy_mri_common)	{	  know (add_symbolP->sy_value.X_op == O_symbol);	  add_number += S_GET_VALUE (add_symbolP);	  fixP->fx_offset = add_number;	  add_symbolP = fixP->fx_addsy = add_symbolP->sy_value.X_add_symbol;	}      if (add_symbolP)	{	  add_symbol_segment = S_GET_SEGMENT (add_symbolP);	}			/* if there is an addend */      if (sub_symbolP)	{	  if (add_symbolP == NULL || add_symbol_segment == absolute_section)	    {	      if (add_symbolP != NULL)		{		  add_number += S_GET_VALUE (add_symbolP);		  add_symbolP = NULL;		  fixP->fx_addsy = NULL;		}	      /* It's just -sym.  */	      if (S_GET_SEGMENT (sub_symbolP) == absolute_section)		{		  add_number -= S_GET_VALUE (sub_symbolP);		  fixP->fx_subsy = 0;		  fixP->fx_done = 1;		}	      else		{#ifndef TC_M68K		  as_bad_where (fixP->fx_file, fixP->fx_line,				"Negative of non-absolute symbol %s",				S_GET_NAME (sub_symbolP));#endif		  add_number -= S_GET_VALUE (sub_symbolP);		}		/* not absolute */	      /* if sub_symbol is in the same segment that add_symbol		 and add_symbol is either in DATA, TEXT, BSS or ABSOLUTE */	    }	  else if (S_GET_SEGMENT (sub_symbolP) == add_symbol_segment		   && SEG_NORMAL (add_symbol_segment))	    {	      /* Difference of 2 symbols from same segment.  Can't		 make difference of 2 undefineds: 'value' means		 something different for N_UNDF. */#ifdef TC_I960	      /* Makes no sense to use the difference of 2 arbitrary symbols	         as the target of a call instruction.  */	      if (fixP->fx_tcbit)		{		  as_bad_where (fixP->fx_file, fixP->fx_line,				"callj to difference of 2 symbols");		}#endif /* TC_I960 */	      add_number += S_GET_VALUE (add_symbolP) -		S_GET_VALUE (sub_symbolP);	      add_symbolP = NULL;	      if (!TC_FORCE_RELOCATION (fixP))		{		  fixP->fx_addsy = NULL;		  fixP->fx_subsy = NULL;		  fixP->fx_done = 1;#ifdef TC_M68K /* is this right? */		  pcrel = 0;		  fixP->fx_pcrel = 0;#endif		}	    }	  else	    {	      /* Different segments in subtraction. */	      know (!(S_IS_EXTERNAL (sub_symbolP) && (S_GET_SEGMENT (sub_symbolP) == absolute_section)));	      if ((S_GET_SEGMENT (sub_symbolP) == absolute_section))		{		  add_number -= S_GET_VALUE (sub_symbolP);		}#ifdef DIFF_EXPR_OK	      else if (S_GET_SEGMENT (sub_symbolP) == this_segment_type#if 0 /* Okay for 68k, at least... */		       && !pcrel#endif		       )		{		  /* Make it pc-relative.  */		  add_number += (md_pcrel_from (fixP)				 - S_GET_VALUE (sub_symbolP));		  pcrel = 1;		  fixP->fx_pcrel = 1;		  sub_symbolP = 0;		  fixP->fx_subsy = 0;		}#endif	      else		{		  as_bad_where (fixP->fx_file, fixP->fx_line,				"Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %ld.",				segment_name (S_GET_SEGMENT (sub_symbolP)),				S_GET_NAME (sub_symbolP),				(long) (fragP->fr_address + where));		}		/* if absolute */	    }	}			/* if sub_symbolP */      if (add_symbolP)	{	  if (add_symbol_segment == this_segment_type && pcrel)	    {	      /*	       * 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.	       */#ifdef TC_I960	      /* reloc_callj() may replace a 'call' with a 'calls' or a 'bal',	       * in which cases it modifies *fixP as appropriate.  In the case	       * of a 'calls', no further work is required, and *fixP has been	       * set up to make the rest of the code below a no-op.	       */	      reloc_callj (fixP);#endif /* TC_I960 */	      add_number += S_GET_VALUE (add_symbolP);	      add_number -= md_pcrel_from (fixP);#if defined (TC_I386) || defined (TE_LYNX)	      /* On the 386 we must adjust by the segment		 vaddr as well.  Ian Taylor.  */	      add_number -= segP->scnhdr.s_vaddr;#endif	      pcrel = 0;	/* Lie. Don't want further pcrel processing. */	      if (!TC_FORCE_RELOCATION (fixP))		{		  fixP->fx_addsy = NULL;		  fixP->fx_done = 1;		}	    }	  else	    {	      switch (add_symbol_segment)		{		case absolute_section:#ifdef TC_I960		  reloc_callj (fixP);	/* See comment about reloc_callj() above*/#endif /* TC_I960 */		  add_number += S_GET_VALUE (add_symbolP);		  add_symbolP = NULL;		  if (!TC_FORCE_RELOCATION (fixP))		    {		      fixP->fx_addsy = NULL;		      fixP->fx_done = 1;		    }		  break;		default:#if defined(TC_A29K) || (defined(TE_PE) && defined(TC_I386))		  /* This really should be handled in the linker, but		     backward compatibility forbids.  */		  add_number += S_GET_VALUE (add_symbolP);#else		  add_number += S_GET_VALUE (add_symbolP) +		    segment_info[S_GET_SEGMENT (add_symbolP)].scnhdr.s_paddr;#endif		  break;		case SEG_UNKNOWN:#ifdef TC_I960		  if ((int) fixP->fx_bit_fixP == 13)		    {		      /* This is a COBR instruction.  They have only a		       * 13-bit displacement and are only to be used		       * for local branches: flag as error, don't generate		       * relocation.		       */		      as_bad_where (fixP->fx_file, fixP->fx_line,				    "can't use COBR format with external label");		      fixP->fx_addsy = NULL;		      fixP->fx_done = 1;		      continue;		    }		/* COBR */#endif /* TC_I960 */#if (defined (TC_I386) || defined (TE_LYNX)) && !defined(TE_PE)		  /* 386 COFF uses a peculiar format in which the		     value of a common symbol is stored in the .text		     segment (I've checked this on SVR3.2 and SCO		     3.2.2) Ian Taylor <ian@cygnus.com>.  */		  if (S_IS_COMMON (add_symbolP))		    add_number += S_GET_VALUE (add_symbolP);#endif		  break;		}		/* switch on symbol seg */	    }			/* if not in local seg */	}			/* if there was a + symbol */      if (pcrel)	{#if !defined(TC_M88K) && !(defined(TE_PE) && defined(TC_I386)) && !defined(TC_A29K)	  /* This adjustment is not correct on the m88k, for which the	     linker does all the computation.  */	  add_number -= md_pcrel_from (fixP);#endif	  if (add_symbolP == 0)	    {	      fixP->fx_addsy = &abs_symbol;	    }			/* if there's an add_symbol */#if defined (TC_I386) || defined (TE_LYNX)	  /* On the 386 we must adjust by the segment vaddr	     as well.  Ian Taylor.  */	  add_number -= segP->scnhdr.s_vaddr;#endif	}			/* if pcrel */      if (!fixP->fx_bit_fixP)	{#ifndef TC_M88K	  /* The m88k uses the offset field of the reloc to get around	     this problem.  */	  if ((size == 1	       && (add_number & ~0xFF)	       && ((add_number & ~0xFF) != (-1 & ~0xFF)))	      || (size == 2		  && (add_number & ~0xFFFF)		  && ((add_number & ~0xFFFF) != (-1 & ~0xFFFF))))	    {	      as_bad_where (fixP->fx_file, fixP->fx_line,			    "Value of %ld too large for field of %d bytes at 0x%lx",			    (long) add_number, size,			    (unsigned long) (fragP->fr_address + where));	    }#endif#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	      && 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,			  (unsigned long) (fragP->fr_address + where));#endif	}			/* not a bit fix */      /* Once this fix has been applied, we don't have to output	 anything nothing more need be done.  */#ifdef MD_APPLY_FIX3      md_apply_fix3 (fixP, &add_number, this_segment_type);#else      md_apply_fix (fixP, add_number);#endif    }				/* For each fixS in this segment. */}				/* fixup_segment() */