Пример #1
0
/*
 *			local_label_name()
 *
 * Caller must copy returned name: we re-use the area for the next name.
 */
char *				/* Return local label name. */
local_label_name(
int n,		/* we just saw "n:", "nf" or "nb" : n a digit */
int augend)	/* 0 for nb, 1 for n:, nf */
{
  register char *	p;
  register char *	q;
  char symbol_name_temporary[10]; /* build up a number, BACKWARDS */

  know( n >= 0 );
  know( augend == 0 || augend == 1 );
  p = symbol_name_build;
  * p ++ = 'L';
  * p ++ = n + '0';		/* Make into ASCII */
  * p ++ = 1;			/* ^A */
  n = local_label_counter [ n ] + augend;
				/* version number of this local label */
  /*
   * Next code just does sprintf( {}, "%d", n);
   * It is more elegant to do the next part recursively, but a procedure
   * call for each digit emitted is considered too costly.
   */
  q = symbol_name_temporary;
  for (*q++=0; n; q++)		/* emits NOTHING if n starts as 0 */
    {
      know(n>0);		/* We expect n > 0 always */
      *q = n % 10 + '0';
      n /= 10;
    }
  while (( * p ++ = * -- q ))
    {
    }
  /* The label, as a '\0' ended string, starts at symbol_name_build. */
  return (symbol_name_build);
}
Пример #2
0
void
coff_obj_read_begin_hook (void)
{
  /* These had better be the same.  Usually 18 bytes.  */
  know (sizeof (SYMENT) == sizeof (AUXENT));
  know (SYMESZ == AUXESZ);
  tag_init ();
}
Пример #3
0
/*
 *			frag_new()
 *
 * Call this to close off a completed frag, and start up a new (empty)
 * frag, in the same subsegment as the old frag.
 * [frchain_now remains the same but frag_now is updated.]
 * Because this calculates the correct value of fr_fix by
 * looking at the obstack 'frags', it needs to know how many
 * characters at the end of the old frag belong to (the maximal)
 * fr_var: the rest must belong to fr_fix.
 * It doesn't actually set up the old frag's fr_var: you may have
 * set fr_var == 1, but allocated 10 chars to the end of the frag:
 * in this case you pass old_frags_var_max_size == 10.
 *
 * Make a new frag, initialising some components. Link new frag at end
 * of frchain_now.
 */
void
frag_new(
    int old_frags_var_max_size)	/* Number of chars (already allocated on obstack
				   frags) in variable_length part of frag. */
{
    register    fragS * former_last_fragP;
    /*    char   *throw_away_pointer; JF unused */
    register    frchainS * frchP;
    long	tmp;		/* JF */

    if(frags.chunk_size == 0) {
        know(flagseen['n']);
        as_fatal("with -n a section directive must be seen before assembly "
                 "can begin");
    }

    frag_now->fr_fix = (char *) (obstack_next_free (&frags)) -
                       (frag_now->fr_literal) - old_frags_var_max_size;
    /* Fix up old frag's fr_fix. */

    obstack_finish (&frags);
    /* This will align the obstack so the */
    /* next struct we allocate on it will */
    /* begin at a correct boundary. */
    frchP = frchain_now;
    know (frchP);
    former_last_fragP = frchP->frch_last;
    know (former_last_fragP);
    know (former_last_fragP == frag_now);
    obstack_blank (&frags, SIZEOF_STRUCT_FRAG);
    /* We expect this will begin at a correct */
    /* boundary for a struct. */
    tmp=obstack_alignment_mask(&frags);
    obstack_alignment_mask(&frags)=0;		/* Turn off alignment */
    /* If we ever hit a machine
    where strings must be
    aligned, we Lose Big */
    frag_now=(fragS *)obstack_finish(&frags);
    obstack_alignment_mask(&frags)=tmp;		/* Restore alignment */

    /* Just in case we don't get zero'd bytes */
    memset(frag_now, '\0', SIZEOF_STRUCT_FRAG);

    /*    obstack_unaligned_done (&frags, &frag_now); */
    /*    know (frags.obstack_c_next_free == frag_now->fr_literal); */
    /* Generally, frag_now->points to an */
    /* address rounded up to next alignment. */
    /* However, characters will add to obstack */
    /* frags IMMEDIATELY after the struct frag, */
    /* even if they are not starting at an */
    /* alignment address. */
    former_last_fragP->fr_next = frag_now;
    frchP->frch_last = frag_now;
    frag_now->fr_next = NULL;
}				/* frag_new() */
Пример #4
0
/*
 *			symbol_table_insert()
 *
 * Die if we can't insert the symbol.
 *
 */
void
symbol_table_insert(
struct symbol *symbolP)
{
  register char *	error_string;

  know( symbolP );
  know( symbolP -> sy_name );
  if ( * (error_string = hash_jam (sy_hash, symbolP -> sy_name, (char *)symbolP)))
    {
      as_fatal( "Inserting \"%s\" into symbol table failed: %s",
	      symbolP -> sy_name, error_string);
    }
}
Пример #5
0
/*
 *			symbol_table_insert()
 *
 * Die if we can't insert the symbol.
 *
 */
void
symbol_table_insert(
struct symbol *symbolP)
{
  const char *	error_string;

  know( symbolP );
  know( symbolP -> sy_name );
  error_string = hash_jam (sy_hash, symbolP -> sy_name, (char *)symbolP);
  if (error_string != NULL && error_string[0] != '\0')
    {
      as_fatal( "Inserting \"%s\" into symbol table failed: %s",
	      symbolP -> sy_name, error_string);
    }
}
Пример #6
0
char *				/* Return local label name.  */
fb_label_name (long n,	/* We just saw "n:", "nf" or "nb" : n a number.  */
	       long augend	/* 0 for nb, 1 for n:, nf.  */)
{
  long i;
  /* Returned to caller, then copied.  Used for created names ("4f").  */
  static char symbol_name_build[24];
  register char *p;
  register char *q;
  char symbol_name_temporary[20];	/* Build up a number, BACKWARDS.  */

  know (n >= 0);
#ifdef TC_MMIX
  know ((unsigned long) augend <= 2 /* See mmix_fb_label.  */);
#else
  know ((unsigned long) augend <= 1);
#endif
  p = symbol_name_build;
#ifdef LOCAL_LABEL_PREFIX
  *p++ = LOCAL_LABEL_PREFIX;
#endif
  *p++ = 'L';

  /* Next code just does sprintf( {}, "%d", n);  */
  /* Label number.  */
  q = symbol_name_temporary;
  for (*q++ = 0, i = n; i; ++q)
    {
      *q = i % 10 + '0';
      i /= 10;
    }
  while ((*p = *--q) != '\0')
    ++p;

  *p++ = LOCAL_LABEL_CHAR;		/* ^B  */

  /* Instance number.  */
  q = symbol_name_temporary;
  for (*q++ = 0, i = fb_label_instance (n) + augend; i; ++q)
    {
      *q = i % 10 + '0';
      i /= 10;
    }
  while ((*p++ = *--q) != '\0');;

  /* The label, as a '\0' ended string, starts at symbol_name_build.  */
  return (symbol_name_build);
}
Пример #7
0
/*
 *			frag_grow()
 *
 * Try to augment current frag by nchars chars.
 * If there is no room, close of the current frag with a ".fill 0"
 * and begin a new frag. Unless the new frag has nchars chars available
 * do not return. Do not set up any fields of *now_frag.
 */
void
frag_grow(
    unsigned int nchars)
{
    if(frags.chunk_size == 0) {
        know(flagseen['n']);
        as_fatal("with -n a section directive must be seen before assembly "
                 "can begin");
    }
    if ((int)(obstack_room(&frags)) < nchars) {
        unsigned int n,oldn;
        long oldc;

        frag_wane (frag_now);
        frag_new (0);
        oldn=(unsigned)-1;
        oldc=frags.chunk_size;
        frags.chunk_size=2*nchars;
        while((int)(n=obstack_room(&frags)) < nchars && n < oldn) {
            frag_wane(frag_now);
            frag_new(0);
            oldn=n;
        }
        frags.chunk_size=oldc;
    }
    if ((int)(obstack_room(&frags)) < nchars)
        as_fatal ("Can't extend frag %d. chars", nchars);
}
Пример #8
0
static void
s_common()
{
    register char *name;
    register char c;
    register char *p;
    register int temp;
    register symbolS *	symbolP;

    name = input_line_pointer;
    c = get_symbol_end();
    /* just after name is now '\0' */
    p = input_line_pointer;
    *p = c;
    SKIP_WHITESPACE();
    if ( * input_line_pointer != ',' ) {
	as_warn("Expected comma after symbol-name");
	ignore_rest_of_line();
	return;
    }
    input_line_pointer ++; /* skip ',' */
    if ( (temp = get_absolute_expression ()) < 0 ) {
	as_warn(".COMMon length (%d.) <0! Ignored.", temp);
	ignore_rest_of_line();
	return;
    }
    *p = 0;
    symbolP = symbol_find_or_make (name);
    *p = c;
    if (   (symbolP->sy_type & N_TYPE) != N_UNDF ||
        symbolP->sy_other != 0 || symbolP->sy_desc != 0) {
	as_warn( "Ignoring attempt to re-define symbol");
	ignore_rest_of_line();
	return;
    }
    if (symbolP->sy_value) {
	if (symbolP->sy_value != temp) {
	    as_warn( "Length of .comm \"%s\" is already %d. Not changed to %d.",
		symbolP->sy_name, symbolP->sy_value, temp);
	}
    } else {
	symbolP->sy_value = temp;
	symbolP->sy_type |= N_EXT;
    }
    know(symbolP->sy_frag == &zero_address_frag);
    if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0) {
	p=input_line_pointer;
	while(*p && *p!='\n')
		p++;
	c= *p;
	*p='\0';
	as_warn("bad .common segment: `%s'", input_line_pointer);
	*p=c;
	return;
    }
    input_line_pointer += 6;
    demand_empty_rest_of_line();
    return;
}
Пример #9
0
void
input_scrub_begin (void)
{
  know (strlen (BEFORE_STRING) == BEFORE_SIZE);
  know (strlen (AFTER_STRING) == AFTER_SIZE
	|| (AFTER_STRING[0] == '\0' && AFTER_SIZE == 1));

  input_file_begin ();

  buffer_length = input_file_buffer_size ();

  buffer_start = xmalloc ((BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
  memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE);

  /* Line number things.  */
  logical_input_line = -1;
  logical_input_file = (char *) NULL;
  physical_input_file = NULL;	/* No file read yet.  */
  next_saved_file = NULL;	/* At EOF, don't pop to any other file */
  do_scrub_begin (flag_m68k_mri);
}
Пример #10
0
void
obj_som_init_stab_section (segT seg)
{
  segT saved_seg = now_seg;
  segT space;
  subsegT saved_subseg = now_subseg;
  char *p, *file;
  unsigned int stroff;

  /* Make the space which will contain the debug subspaces.  */
  space = bfd_make_section_old_way (stdoutput, "$GDB_DEBUG$");

  /* Set SOM specific attributes for the space.  In particular we set
     the space "defined", "private", "sort_key", and "spnum" values.

     Due to a bug in pxdb (called by hpux linker), the sort keys
     of the various stabs spaces/subspaces need to be "small".  We
     reserve range 72/73 which appear to work well.  */
  obj_set_section_attributes (space, 1, 1, 72, 2);
  bfd_set_section_alignment (stdoutput, space, 2);

  /* Set the containing space for both stab sections to be $GDB_DEBUG$
     (just created above).  Also set some attributes which BFD does
     not understand.  In particular, access bits, sort keys, and load
     quadrant.  */
  obj_set_subsection_attributes (seg, space, 0x1f, 73, 0, 0, 0, 0);
  bfd_set_section_alignment (stdoutput, seg, 2);

  /* Make some space for the first special stab entry and zero the memory.
     It contains information about the length of this file's
     stab string and the like.  Using it avoids the need to
     relocate the stab strings.

     The $GDB_STRINGS$ space will be created as a side effect of
     the call to get_stab_string_offset.  */
  p = frag_more (12);
  memset (p, 0, 12);
  as_where (&file, (unsigned int *) NULL);
  stroff = get_stab_string_offset (file, "$GDB_STRINGS$");
  know (stroff == 1);
  md_number_to_chars (p, stroff, 4);
  seg_info (seg)->stabu.p = p;

  /* Set the containing space for both stab sections to be $GDB_DEBUG$
     (just created above).  Also set some attributes which BFD does
     not understand.  In particular, access bits, sort keys, and load
     quadrant.  */
  seg = bfd_get_section_by_name (stdoutput, "$GDB_STRINGS$");
  obj_set_subsection_attributes (seg, space, 0x1f, 72, 0, 0, 0, 0);
  bfd_set_section_alignment (stdoutput, seg, 2);

  subseg_set (saved_seg, saved_subseg);
}
Пример #11
0
Файл: game.c Проект: phoboz/edom
void update_screen(coord x, coord y)
{
  coord sx, sy, px, py;

  /* Find the current general section. */
  get_current_section_coordinates(d.px, d.py, &sx, &sy);

#ifdef UPDATE_PANEL_VIEW
  coord opsx, opsy;

  /* Memorize the old panel view. */
  opsx = d.psx;
  opsy = d.psy;
  
  /* Adjust the panel view. */
  while (sx < d.psx)
    d.psx--;
  while (d.psx + 4 < sx)
    d.psx++;
  while (sy < d.psy)
    d.psy--;
  while (d.psy + 1 < sy)
    d.psy++;

  /* Repaint the whole screen map if necessary. */
  if (opsx != d.psx || opsy != d.psy)
    paint_map();
#endif

  /* Make the immediate surroundings known. */
  for (px = x - 1; px <= x + 1; px++)
    for (py = y - 1; py <= y + 1; py++)
      know(px, py);

  /* Check whether the PC is in a room or not. */
  get_current_section(d.px, d.py, &sx, &sy);

  /* Make rooms known. */
  if (sx != -1 && sy != -1)
    know_section(sx, sy);

  move_dungeon();

  draw_dungeon();
  draw_monsters();
  draw_actor(&d.pa);

  draw_player_status();

  flip();
}
Пример #12
0
void
frag_new (int old_frags_var_max_size
	  /* Number of chars (already allocated on obstack frags) in
	     variable_length part of frag.  */)
{
  fragS *former_last_fragP;
  frchainS *frchP;

  assert (frchain_now->frch_last == frag_now);

  /* Fix up old frag's fr_fix.  */
  frag_now->fr_fix = frag_now_fix_octets () - old_frags_var_max_size;
  /* Make sure its type is valid.  */
  assert (frag_now->fr_type != 0);

  /* This will align the obstack so the next struct we allocate on it
     will begin at a correct boundary.  */
  obstack_finish (&frchain_now->frch_obstack);
  frchP = frchain_now;
  know (frchP);
  former_last_fragP = frchP->frch_last;
  assert (former_last_fragP != 0);
  assert (former_last_fragP == frag_now);
  frag_now = frag_alloc (&frchP->frch_obstack);

  as_where (&frag_now->fr_file, &frag_now->fr_line);

  /* Generally, frag_now->points to an address rounded up to next
     alignment.  However, characters will add to obstack frags
     IMMEDIATELY after the struct frag, even if they are not starting
     at an alignment address.  */
  former_last_fragP->fr_next = frag_now;
  frchP->frch_last = frag_now;

#ifndef NO_LISTING
  {
    extern struct list_info_struct *listing_tail;
    frag_now->line = listing_tail;
  }
#endif

  assert (frchain_now->frch_last == frag_now);

  frag_now->fr_next = NULL;
}
Пример #13
0
int main()
{
    char s[300][300],temp;
    int i,j,k,l;
    int ans[10];
    int t,n,m,sum;
    while(scanf("%d",&t)!=EOF)
    {
        while(t--)
        {
            scanf("%d%d",&n,&m);
            scanf("%c",&temp);
            for(i=1; i<=n; i++)
            {
                for(j=1; j<=m; j++)
                {
                    scanf("%c",&s[i][j]);
                }
                scanf("%c",&temp);
            }
            sum=0;
            for(i=1; i<n; i++)
            {
                for(j=i+1; j<=n; j++)
                {
                    memset(ans,0,sizeof(ans));
                    for(k=1; k<=m; k++)
                    {
                        if(s[i][k]==s[j][k])
                        {
                            ans[know(s[j][k])]++;
                        }
                    }
                    for(l=1; l<=5; l++)
                    {
                        sum+=ans[l]*(ans[l]-1)/2;
                    }
                }
            }
            printf("%d\n",sum);
        }
    }
    return 0;
}
Пример #14
0
/*
 * layout_addresses() is called after all the assembly code has been read and
 * fragments, symbols and fixups have been created.  This routine sets the
 * address of the fragments and symbols.  Then it does the fixups of the frags
 * and prepares the fixes so relocation entries can be created from them.
 */
void
layout_addresses(
void)
{
    struct frchain *frchainP;
    fragS *fragP;
    relax_addressT slide, tmp;
    symbolS *symbolP;
    unsigned long nbytes, fill_size, repeat_expression, partial_bytes;

	if(frchain_root == NULL)
	    return;

	/*
	 * If there is any current frag close it off.
	 */
	if(frag_now != NULL && frag_now->fr_fix == 0){
	    frag_now->fr_fix = obstack_next_free(&frags) -
			       frag_now->fr_literal;
	    frag_wane(frag_now);
	}

	/*
	 * For every section, add a last ".fill 0" frag that will later be used
	 * as the ending address of that section.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    /*
	     * We must do the obstack_finish(), so the next object we put on
	     * obstack frags will not appear to start at the fr_literal of the
	     * current frag.  Also, it ensures that the next object will begin
	     * on a address that is aligned correctly for the engine that runs
	     * the assembler.
	     */
	    obstack_finish(&frags);

	    /*
	     * Make a fresh frag for the last frag.
	     */
	    frag_now = (fragS *)obstack_alloc(&frags, SIZEOF_STRUCT_FRAG);
	    memset(frag_now, '\0', SIZEOF_STRUCT_FRAG);
	    frag_now->fr_next = NULL;
	    obstack_finish(&frags);

	    /*
	     * Append the new frag to current frchain.
	     */
	    frchainP->frch_last->fr_next = frag_now;
	    frchainP->frch_last = frag_now;
	    frag_wane(frag_now);

	}

	/*
	 * Now set the relitive addresses of frags within the section by
	 * relaxing each section.  That is all sections will start at address
	 * zero and addresses of the frags in that section will increase from
	 * there.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL)
		continue;
	    /*
	     * This is done so in case md_estimate_size_before_relax() (called
	     * by relax_section) wants to make fixSs they are for this
	     * section.
	     */
	    frchain_now = frchainP;

	    relax_section(frchainP->frch_root, frchainP->frch_nsect);
	}

	/*
	 * Now set the absolute addresses of all frags by sliding the frags in
	 * each non-zerofill section by the address ranges taken up by the
	 * sections before it.
	 */ 
	slide = 0;
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL)
		continue;
	    slide = round(slide, 1 << frchainP->frch_section.align);
	    tmp = frchainP->frch_last->fr_address;
	    if(slide != 0){
		for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
		    fragP->fr_address += slide;
		}
	    }
	    slide += tmp;
	}
	/*
	 * Now with the non-zerofill section addresses set set all of the
	 * addresses of the zerofill sections.  Comming in the fr_address is
	 * the size of the section and going out it is the start address.  This
	 * will make layout_symbols() work out naturally.  The only funky thing
	 * is that section numbers do not end up in address order.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) != S_ZEROFILL)
		continue;
	    slide = round(slide, 1 << frchainP->frch_section.align);

	    tmp = frchainP->frch_root->fr_address;
	    frchainP->frch_root->fr_address = slide;
	    frchainP->frch_last->fr_address = tmp + slide;
	    slide += tmp;
	}

	/*
	 * Set the symbol addresses based on there frag's address.
	 * First forward references are handled.
	 */
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    if(symbolP->sy_forward != NULL){
		if(symbolP->sy_nlist.n_type & N_STAB)
		    symbolP->sy_other = symbolP->sy_forward->sy_other;
		symbolP->sy_value += symbolP->sy_forward->sy_value +
				     symbolP->sy_forward->sy_frag->fr_address;
		symbolP->sy_forward = 0;
	    }
	}
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    symbolP->sy_value += symbolP->sy_frag->fr_address;
	}

	/*
	 * At this point the addresses of frags now reflect addresses we use in 
	 * the object file and the symbol values are correct.
	 * Scan the frags, converting any ".org"s and ".align"s to ".fill"s.
	 * Also converting any machine-dependent frags using md_convert_frag();
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    /*
	     * This is done so any fixes created by md_convert_frag() are for
	     * this section.
	     */
	    frchain_now = frchainP;

	    for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
		switch(fragP->fr_type){
		case rs_align:
		case rs_org:
		    /* convert this frag to an rs_fill type */
		    fragP->fr_type = rs_fill;
		    /*
		     * Calculate the number of bytes the variable part of the
		     * the rs_fill frag will need to fill.  Then calculate this
		     * as the fill_size * repeat_expression + partial_bytes.
		     */
		    know(fragP->fr_next != NULL);
		    nbytes = fragP->fr_next->fr_address -
			     fragP->fr_address -
			     fragP->fr_fix;
		    if(nbytes < 0){
			as_warn("rs_org invalid, dot past value by %ld bytes",
				nbytes);
			nbytes = 0;
		    }
		    fill_size = fragP->fr_var;
		    repeat_expression = nbytes / fill_size;
		    partial_bytes = nbytes - (repeat_expression * fill_size);
		    /*
		     * Now set the fr_offset to the fill repeat_expression
		     * since this is now an rs_fill type.  The fr_var is still
		     * the fill_size.
		     */
		    fragP->fr_offset = repeat_expression;
		    /*
		     * For rs_align frags there may be partial_bytes to fill
		     * with zeros before we can fill with the fill_expression
		     * of fill_size.  When the rs_align frag was created it was
		     * created with fill_size-1 extra bytes in the fixed part.
		     */
		    if(partial_bytes != 0){
			/* moved the fill_expression bytes foward */
			memmove(fragP->fr_literal +fragP->fr_fix +partial_bytes,
				fragP->fr_literal +fragP->fr_fix,
				fragP->fr_var);
    			/* zero out the partial_bytes */
    			memset(fragP->fr_literal + fragP->fr_fix,
			       '\0',
			       partial_bytes);
			/* adjust the fixed part of the frag */
    			fragP->fr_fix += partial_bytes;
		    }
		    break;

		case rs_fill:
		    break;

		case rs_machine_dependent:
		    md_convert_frag(fragP);
		    /*
		     * After md_convert_frag, we make the frag into a ".fill 0"
		     * md_convert_frag() should set up any fixSs and constants
		     * required.
		     */
		    frag_wane(fragP);
		    break;

		default:
		    BAD_CASE(fragP->fr_type);
		    break;
		}
	    }
	}

	/*
	 * For each section do the fixups for the frags.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    fixup_section(frchainP->frch_fix_root, frchainP->frch_nsect);
	}
}
Пример #15
0
void
colon(		/* just seen "x:" - rattle symbols & frags */
char *sym_name) /* symbol name, as a cannonical string */
		/* We copy this string: OK to alter later. */
{
  register struct symbol * symbolP; /* symbol we are working with */

  if (frchain_now == NULL)
    {
      know(flagseen['n']);
      as_fatal("with -n a section directive must be seen before assembly "
	       "can begin");
    }
  if ((symbolP = symbol_table_lookup( sym_name )))
    {
      /*
       *	Now check for undefined symbols
       */
      if ((symbolP -> sy_type & N_TYPE) == N_UNDF)
	{
	  temp = symbolP->sy_desc;
	  if(   symbolP -> sy_other == 0
	     /* bug #50416 -O causes this not to work for:
	     && ((symbolP->sy_desc) & (~REFERENCE_TYPE)) == 0
	     */
	     && (temp & (~(REFERENCE_TYPE | N_WEAK_REF | N_WEAK_DEF |
			   N_ARM_THUMB_DEF |
			   N_NO_DEAD_STRIP | REFERENCED_DYNAMICALLY))) == 0
	     && symbolP -> sy_value == 0)
	    {
	      symbolP -> sy_frag  = frag_now;
	      symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal;
	      know( N_UNDF == 0 );
	      symbolP -> sy_type |= N_SECT; /* keep N_EXT bit */
	      symbolP -> sy_other = frchain_now->frch_nsect;
	      symbolP -> sy_desc &= ~REFERENCE_TYPE;
	      symbolP -> sy_desc &= ~N_WEAK_REF;
	      symbol_assign_index(symbolP);
	      if((symbolP->sy_desc & N_WEAK_DEF) == N_WEAK_DEF &&
		 (frchain_now->frch_section.flags & S_COALESCED) != S_COALESCED)
		  as_fatal("symbol: %s can't be a weak_definition (currently "
			   "only supported in section of type coalesced)",
			   sym_name);
#ifdef NeXT_MOD	/* generate stabs for debugging assembly code */
	      if(flagseen['g'])
		  make_stab_for_symbol(symbolP);
#endif
	    }
	  else
	    {
	      as_fatal( "Symbol \"%s\" is already defined as \"%s\"/%d.%d."
			TA_DFMT ".",
		      sym_name,
		      seg_name [(int) N_TYPE_seg [symbolP -> sy_type & N_TYPE]],
		      symbolP -> sy_other, symbolP -> sy_desc,
			TA_DFT_CAST(symbolP -> sy_value));
	    }
	}
      else
	{
	  as_fatal("Symbol %s already defined.",sym_name);
	}
    }
  else
    {
      symbolP = symbol_new (sym_name,
			    N_SECT,
	      		    frchain_now->frch_nsect,
			    0,
			    (valueT)(obstack_next_free(&frags)-frag_now->fr_literal),
			    frag_now);
      symbol_table_insert (symbolP);
      symbol_assign_index (symbolP);
#ifdef NeXT_MOD	/* generate stabs for debugging assembly code */
      if(flagseen['g'])
	  make_stab_for_symbol(symbolP);
#endif
    }
#ifdef tc_frob_label
    tc_frob_label(symbolP);
#endif
}
Пример #16
0
/*
 * We allow an empty expression, and just assume (absolute,0) silently.
 * Unary operators and parenthetical expressions are treated as operands.
 * As usual, Q==quantity==operand, O==operator, X==expression mnemonics.
 *
 * Most expressions are either register (which does not even reach here)
 * or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common.
 *
 * After expr(RANK,resultP) input_line_pointer -> operator of rank <= RANK.
 * Also, we have consumed any leading or trailing spaces (operand does that)
 * and done all intervening operators.
 */
static
segT	/* Return resultP -> X_seg */
expr(
operator_rankT	rank, /* larger # is higher rank */
expressionS *resultP) /* deliver result here */
{
    expressionS	right;
    operatorT	op_left;
    char	c_left;	/* 1st operator character. */
    operatorT	op_right;
    char	c_right;

	know(rank >= 0);

	(void)operand(resultP);
	know(*input_line_pointer != ' '); /* Operand() gobbles spaces. */

	c_left = *input_line_pointer; /* Potential operator character. */
	op_left = (operatorT)op_encoding[(int)c_left];
	if(op_left == two_char_operator)
	    op_left = two_char_op_encoding(c_left);

	while(op_left != O_illegal && op_rank[op_left] > rank){

	    input_line_pointer += op_size[op_left];
	    /* -> after 1st character of operator. */

	    if(SEG_NONE == expr(op_rank[op_left], &right)){
		as_warn("Missing operand value assumed absolute 0.");
		resultP->X_add_number		= 0;
		resultP->X_subtract_symbol	= NULL;
		resultP->X_add_symbol		= NULL;
		resultP->X_seg			= SEG_ABSOLUTE;
	    }
	    know(*input_line_pointer != ' ');

	    c_right = *input_line_pointer;
	    op_right = (operatorT)op_encoding[(int)c_right];
	    if(op_right == two_char_operator)
		op_right = two_char_op_encoding(c_right);

	    /* -> after 1st character of operator. */
	    know(op_right == 0 || op_rank [op_right] <= op_rank[op_left]);

	    /* input_line_pointer -> after right-hand quantity. */
	    /* left-hand quantity in resultP */
	    /* right-hand quantity in right. */
	    /* operator in op_left. */

	    /*
	     * Operations are not supported on bignums or floating-point
	     * operands.
	     */
	    if(resultP->X_seg == SEG_BIG){
		as_warn("Left operand of %c is a %s integer 0 assumed",
			c_left, resultP->X_add_number > 0 ? "bignum" :
			"float");
		resultP->X_seg = SEG_ABSOLUTE;
		resultP->X_add_symbol = 0;
		resultP->X_subtract_symbol = 0;
		resultP->X_add_number = 0;
	    }
	    if(right.X_seg == SEG_BIG){
		as_warn("Right operand of %c is a %s integer 0 assumed",
			c_left, right.X_add_number > 0 ? "bignum" :
			"float");
		right.X_seg = SEG_ABSOLUTE;
		right.X_add_symbol = 0;
		right.X_subtract_symbol = 0;
		right.X_add_number = 0;
	    }
	    if(op_left == O_subtract){
		/*
		 * Convert - into + by exchanging symbols and negating
		 * number. I know -infinity can't be negated in 2's
		 * complement: but then it can't be subtracted either.
		 * This trick does not cause any further inaccuracy.
		 */
		struct symbol *symbolP;

		right.X_add_number      = - right.X_add_number;
		symbolP                 = right.X_add_symbol;
		right.X_add_symbol	    = right.X_subtract_symbol;
		right.X_subtract_symbol = symbolP;
		if(symbolP){
/* This is not used, as it drops in to the next if */
		    right.X_seg	    = SEG_DIFFSECT;
		}
		op_left = O_add;
	    }
	    if(op_left == O_add){
		segT seg1;
		segT seg2;
		
/* not SEG_NONE and not SEG_BIG */
		know(resultP->X_seg == SEG_SECT ||
		     resultP->X_seg == SEG_UNKNOWN ||
		     resultP->X_seg == SEG_DIFFSECT ||
		     resultP->X_seg == SEG_ABSOLUTE);
/* not SEG_NONE and not SEG_BIG */
		know(right.X_seg == SEG_SECT ||
		     right.X_seg == SEG_UNKNOWN ||
		     right.X_seg == SEG_DIFFSECT ||
		     right.X_seg == SEG_ABSOLUTE);
		
		clean_up_expression(&right);
		clean_up_expression(resultP);

/* could this just return -1 instead of SEG_PASS1? and tested in the below if
statement */
		seg1 = expr_part(&resultP->X_add_symbol,
				 right.X_add_symbol);
		seg2 = expr_part(&resultP->X_subtract_symbol,
				 right.X_subtract_symbol);
		if((int)seg1 == -1 || (int)seg2 == -1){
		    as_warn("Can't relocate expression. Absolute 0 assumed.");
		    resultP->X_seg        = SEG_ABSOLUTE;
		    resultP->X_add_number = 0;
		}
		else{
		    if(seg2 == SEG_ABSOLUTE){
			resultP->X_seg = seg1;
		    }
		    else{
/* also know seg2 != -1 (SEG_PASS1) */
			know(seg2 != SEG_ABSOLUTE);
/* seg2 is for the subtract symbols, since seg2 != SEG_ABSOLUTE as would be
returned when there is no subtract symbols then expr_part() must have
combined a symbol into resultP->X_subtract_symbol that is either undefined
or defined in a section. */
			know(resultP->X_subtract_symbol);
			/*
			 * If we are not to use the new incompatible features
			 * then "symbol1 - symbol2" must both be in the same
			 * section and will turn out as absolute.
			 */
			if(!flagseen['k']){
			    if(seg1 != SEG_UNKNOWN &&
			       seg1 != SEG_ABSOLUTE &&
			       seg2 != SEG_UNKNOWN &&
			       seg1 != seg2 &&
			       resultP->X_add_symbol->sy_other !=
			       resultP->X_subtract_symbol->sy_other){
				know(seg1 == SEG_SECT);
				know(seg2 == SEG_SECT);
				know(resultP->X_add_symbol);
				know(resultP->X_subtract_symbol);
				as_warn("Expression too complex: "
				       "forgetting %s - %s",
				       resultP->X_add_symbol->sy_name,
				       resultP->X_subtract_symbol->sy_name);
				resultP->X_seg = SEG_ABSOLUTE;
				/* Clean_up_expression() will do the rest */
			    }
			    else{
/* this can result in returning an expression that is NULL - symbol and the
caller must deal with this being illegal.  maybe this should be put in
expression() routine (not a macro).  Note the code in cons() */
				resultP->X_seg = SEG_DIFFSECT;
			    }	/* If relocation too complex. */
			}
			else{
			    resultP->X_seg = SEG_DIFFSECT;
			}

		    }		/* If seg2 == SEG_ABSOLUTE. */
		}		/* If need pass 2. */
		resultP->X_add_number += right.X_add_number;
		clean_up_expression(resultP);
	    }
	    else{	/* Not +. */
		if(resultP->X_seg == SEG_UNKNOWN ||
		   right.X_seg == SEG_UNKNOWN){
		    as_warn("Can't relocate expression. Absolute 0 assumed.");
		    resultP->X_seg        = SEG_ABSOLUTE;
		    resultP->X_add_number = 0;
		}
		else{
		    /*
		     * Will be SEG_ABSOLUTE. (or error)
		     */
		    try_to_make_absolute(resultP);
		    try_to_make_absolute(&right);
		    resultP->X_subtract_symbol = NULL;
		    resultP->X_add_symbol = NULL;
		    if(resultP->X_seg != SEG_ABSOLUTE ||
		       right.X_seg != SEG_ABSOLUTE){
			as_warn("Relocation error. Absolute 0 assumed");
			resultP->X_seg        = SEG_ABSOLUTE;
			resultP->X_add_number = 0;
		    }
		    else{
			/*
			 * Both are absolute so perform the operation
			 * on the constants.
			 */
			switch(op_left){
			case O_bit_inclusive_or:
			    resultP->X_add_number |= right.X_add_number;
			    break;
			  
			case O_modulus:
			    if(right.X_add_number){
				resultP->X_add_number %=
					right.X_add_number;
			    }
			    else{
				as_warn("Division by 0. 0 assumed.");
				resultP->X_add_number = 0;
			    }
			    break;
			  
			case O_bit_and:
			    resultP->X_add_number &= right.X_add_number;
			    break;
			  
			case O_multiply:
			    resultP->X_add_number *= right.X_add_number;
			    break;
			  
			case O_divide:
			    if(right.X_add_number){
				resultP->X_add_number /=
					right.X_add_number;
			    }
			    else{
				as_warn("Division by 0. 0 assumed.");
				resultP->X_add_number = 0;
			    }
			    break;
			  
			case O_left_shift:
			    resultP->X_add_number <<=
				right.X_add_number;
			    break;
			  
			case O_right_shift:
			    resultP->X_add_number >>=
				right.X_add_number;
			    break;
			  
			case O_bit_exclusive_or:
			    resultP->X_add_number ^= right.X_add_number;
			    break;
			  
			case O_bit_or_not:
			    resultP->X_add_number |=
				~right.X_add_number;
			    break;

			case O_less_than:
			    resultP->X_add_number =
			       (resultP->X_add_number <
				  right.X_add_number);
			    break;
		      
			case O_greater_than:
			    resultP->X_add_number =
			       (resultP->X_add_number >
				  right.X_add_number);
			    break;
		      
			case O_less_than_or_equal:
			    resultP->X_add_number =
			       (resultP->X_add_number <=
				  right.X_add_number);
			    break;
		      
			case O_greater_than_or_equal:
			    resultP->X_add_number =
			       (resultP->X_add_number >=
				  right.X_add_number);
			    break;
		      
			case O_equal:
			    resultP->X_add_number =
			       (resultP->X_add_number ==
				  right.X_add_number);
			    break;
		      
			case O_not_equal:
			    resultP->X_add_number =
			       (resultP->X_add_number !=
				  right.X_add_number);
			    break;
			  
			default:
			    BAD_CASE( op_left );
			    break;
			}	/* switch(op_left) */
		    }
		}		/* If we have to force need_pass_2 */
	    } 		/* If operator was + */
	    op_left = op_right;
	}			/* While next operator is >= this rank */
	return(resultP->X_seg);
}
Пример #17
0
/*
 * relax_section() here we set the fr_address values in the frags.
 * After this, all frags in this segment have addresses that are correct
 * relative to the section (that is the section starts at address zero).
 * After all of the sections have been processed by this call and their sizes
 * are know then they can be slid to their final address.
 */
static
void
relax_section(
struct frag *frag_root,
int nsect)
{
    struct frag *fragP;
    relax_addressT address;

    long stretch; /* May be any size, 0 or negative. */
		  /* Cumulative number of addresses we have */
		  /* relaxed this pass. */
		  /* We may have relaxed more than one address. */
    long stretched;  /* Have we stretched on this pass? */
		    /* This is 'cuz stretch may be zero, when,
		       in fact some piece of code grew, and
		       another shrank.  If a branch instruction
		       doesn't fit anymore, we need another pass */

    const relax_typeS *this_type;
    const relax_typeS *start_type;
    relax_substateT next_state;
    relax_substateT this_state;

    long growth;
    unsigned long was_address;
    long offset;
    symbolS *symbolP;
    long target;
    long after;
    long aim;
    unsigned long oldoff, newoff;

	growth = 0;

	/*
	 * For each frag in segment count and store (a 1st guess of) fr_address.
	 */
	address = 0;
	for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
	    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:
		offset = relax_align (address, (int) fragP->fr_offset);
		/*
		 * If a maximum number of bytes to fill was specified for this
		 * align (stored in fr_subtype) then check to see if this align
		 * can be done.  If not ignore it.  If so and this alignment is
		 * larger than any previous alignment then this becomes the
		 * section's alignment.
		 */
		if(fragP->fr_subtype != 0){
		    if(offset > (long)fragP->fr_subtype){
			offset = 0;
		    }
		    else{
			if(frchain_now->frch_section.align <
			   (unsigned long)fragP->fr_offset)
			    frchain_now->frch_section.align = fragP->fr_offset;
		    }
		}
		address += offset;
		break;

	    case rs_org:
		/*
		 * Assume .org is nugatory. It will grow with 1st relax.
		 */
		break;

	    case rs_machine_dependent:
		address += md_estimate_size_before_relax(fragP, nsect);
		break;

	    default:
		BAD_CASE(fragP->fr_type);
		break;
	    }
	}

	/*
	 * Do relax().
	 * Make repeated passes over the chain of frags allowing each frag to
	 * grow if needed.  On each pass each frag's address is incremented by
	 * the accumulated growth, kept in stretched.  Passes are continued 
	 * until there is no stretch on the previous pass.
	 */
	do{
	    stretch = 0;
	    stretched = 0;
	    for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
		was_address = fragP->fr_address;
		fragP->fr_address += stretch;
		address = fragP->fr_address;
		symbolP = fragP->fr_symbol;
		offset = fragP->fr_offset;
		switch(fragP->fr_type){
		case rs_fill:	/* .fill never relaxes. */
		    growth = 0;
		    break;

		case rs_align:
		    oldoff = relax_align(was_address + fragP->fr_fix, offset);
		    newoff = relax_align(address + fragP->fr_fix, offset);
		    /*
		     * Check if a maximum number of bytes to fill was specified
		     * for this align (stored in fr_subtype).
		     */
		    if(fragP->fr_subtype != 0){
			if(oldoff > fragP->fr_subtype)
			    oldoff = 0;
			if(newoff > fragP->fr_subtype)
			    newoff = 0;
		    }
		    growth = newoff - oldoff;
		    break;

		case rs_org:
		    target = offset;
		    if(symbolP != NULL){
			know(((symbolP->sy_type & N_TYPE) == N_ABS) ||
			     ((symbolP->sy_type & N_TYPE) == N_SECT));
			know(symbolP->sy_frag);
			know((symbolP->sy_type & N_TYPE) != N_ABS ||
			     symbolP->sy_frag == &zero_address_frag );
			target += symbolP->sy_value +
				  symbolP->sy_frag->fr_address;
		    }
		    know(fragP->fr_next);
		    after = fragP->fr_next->fr_address;
		    /*
		     * Growth may be negative, but variable part of frag cannot
		     * have < 0 chars. That is, we can't .org backwards.
		     */
		    growth = ((target - after ) > 0) ? (target - after) : 0;

		    growth -= stretch;	/* This is an absolute growth factor */
		    break;

		case rs_machine_dependent:
		    this_state = fragP->fr_subtype;
		    this_type = md_relax_table + this_state;
		    start_type = this_type;

		    target = offset;
		    if(symbolP){
			know(((symbolP->sy_type & N_TYPE) == N_ABS) ||
			     ((symbolP->sy_type & N_TYPE) == N_SECT));
			know(symbolP->sy_frag);
			know((symbolP->sy_type & N_TYPE) != N_ABS ||
			     symbolP->sy_frag == &zero_address_frag);

			target += symbolP->sy_value +
				  symbolP->sy_frag->fr_address;
			/*
			 * If frag has yet to be reached on this pass,
			 * assume it will move by STRETCH just as we did.
			 * If this is not so, it will be because some frag
			 * between grows, and that will force another pass.
			 */
			if(symbolP->sy_frag->fr_address >= was_address &&
			   is_down_range(fragP, symbolP->sy_frag))
			    target += stretch;
		    }
		    aim = target - address - fragP->fr_fix;
		    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 = md_relax_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 = md_relax_table + this_state;
				next_state = this_type->rlx_more;
			    }
			}
		    }
		    if((growth = this_type->rlx_length -start_type->rlx_length))
			  fragP->fr_subtype = this_state;
		    break;

		  default:
		      BAD_CASE(fragP->fr_type);
		      break;
		}
		if(growth) {
		    stretch += growth;
		    stretched++;
		}
	    }			/* For each frag in the segment. */
	}while(stretched);	/* Until nothing further to relax. */

	/*
	 * We now have valid fr_address'es for each frag.  All fr_address's
	 * are correct, relative to their own section.  We have made all the
	 * fixS for this section that will be made.
	 */
}
Пример #18
0
/*
 * layout_addresses() is called after all the assembly code has been read and
 * fragments, symbols and fixups have been created.  This routine sets the
 * address of the fragments and symbols.  Then it does the fixups of the frags
 * and prepares the fixes so relocation entries can be created from them.
 */
void
layout_addresses(
void)
{
    struct frchain *frchainP;
    fragS *fragP;
    relax_addressT slide, tmp;
    symbolS *symbolP;
    uint32_t nbytes, fill_size, repeat_expression, partial_bytes, layout_pass;
    relax_stateT old_fr_type;
    int changed;

	if(frchain_root == NULL)
	    return;

	/*
	 * If there is any current frag close it off.
	 */
	if(frag_now != NULL && frag_now->fr_fix == 0){
	    frag_now->fr_fix = obstack_next_free(&frags) -
			       frag_now->fr_literal;
	    frag_wane(frag_now);
	}

	/*
	 * For every section, add a last ".fill 0" frag that will later be used
	 * as the ending address of that section.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    /*
	     * We must do the obstack_finish(), so the next object we put on
	     * obstack frags will not appear to start at the fr_literal of the
	     * current frag.  Also, it ensures that the next object will begin
	     * on a address that is aligned correctly for the engine that runs
	     * the assembler.
	     */
	    (void)obstack_finish(&frags);

	    /*
	     * Make a fresh frag for the last frag.
	     */
	    frag_now = (fragS *)obstack_alloc(&frags, SIZEOF_STRUCT_FRAG);
	    memset(frag_now, '\0', SIZEOF_STRUCT_FRAG);
	    frag_now->fr_next = NULL;
	    (void)obstack_finish(&frags);

	    /*
	     * Append the new frag to current frchain.
	     */
	    frchainP->frch_last->fr_next = frag_now;
	    frchainP->frch_last = frag_now;
	    frag_wane(frag_now);

	}

	/*
	 * Now set the relative addresses of frags within the section by
	 * relaxing each section.  That is all sections will start at address
	 * zero and addresses of the frags in that section will increase from
	 * there.
	 *
	 * The debug sections are done last as other section are needed to be
	 * done first becase debug sections may have line numbers with .loc
	 * directives in them and their sizes need to be set before processing
	 * the line number sections.  We also do sections that have rs_leb128s
	 * in them before debug sections but after other sections since they
	 * are used for things like exception tables and they may be refering to
	 * sections such that their sizes too must be known first.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & S_ATTR_DEBUG) == S_ATTR_DEBUG)
		frchainP->layout_pass = 2;
	    else if(frchainP->has_rs_leb128s == TRUE)
		frchainP->layout_pass = 1;
	    else
		frchainP->layout_pass = 0;
	}
	for(layout_pass = 0; layout_pass < 3; layout_pass++){
	    do{
		changed = 0;
		for(frchainP = frchain_root;
		    frchainP;
		    frchainP = frchainP->frch_next){
		    if(frchainP->layout_pass != layout_pass)
			continue;
		    if((frchainP->frch_section.flags & SECTION_TYPE) ==
		       S_ZEROFILL)
			continue;
		    /*
		     * This is done so in case md_estimate_size_before_relax()
		     * (called by relax_section) wants to make fixSs they are
		     * for this section.
		     */
		    frchain_now = frchainP;

		    changed += relax_section(frchainP->frch_root,
					    frchainP->frch_nsect);
		}
	    }
	    while(changed != 0);
	}

	/*
	 * Now set the absolute addresses of all frags by sliding the frags in
	 * each non-zerofill section by the address ranges taken up by the
	 * sections before it.
	 */ 
	slide = 0;
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL)
		continue;
	    slide = round(slide, 1 << frchainP->frch_section.align);
	    tmp = frchainP->frch_last->fr_address;
	    if(slide != 0){
		for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
		    fragP->fr_address += slide;
		}
	    }
	    slide += tmp;
	}
	/*
	 * Now with the non-zerofill section addresses set set all of the
	 * addresses of the zerofill sections.  Comming in the fr_address is
	 * the size of the section and going out it is the start address.  This
	 * will make layout_symbols() work out naturally.  The only funky thing
	 * is that section numbers do not end up in address order.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) != S_ZEROFILL)
		continue;
	    slide = round(slide, 1 << frchainP->frch_section.align);

	    tmp = frchainP->frch_root->fr_address;
	    frchainP->frch_root->fr_address = slide;
	    frchainP->frch_last->fr_address = tmp + slide;
	    slide += tmp;
	}

	/*
	 * Set the symbol addresses based on their frag's address.
	 * First forward references are handled.
	 */
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    if(symbolP->sy_forward != NULL){
		if(symbolP->sy_nlist.n_type & N_STAB)
		    symbolP->sy_other = symbolP->sy_forward->sy_other;
		symbolP->sy_value += symbolP->sy_forward->sy_value +
				     symbolP->sy_forward->sy_frag->fr_address;
		symbolP->sy_forward = 0;
	    }
	}
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    symbolP->sy_value += symbolP->sy_frag->fr_address;
	}

	/*
	 * At this point the addresses of frags now reflect addresses we use in 
	 * the object file and the symbol values are correct.
	 * Scan the frags, converting any ".org"s and ".align"s to ".fill"s.
	 * Also converting any machine-dependent frags using md_convert_frag();
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    /*
	     * This is done so any fixes created by md_convert_frag() are for
	     * this section.
	     */
	    frchain_now = frchainP;

	    for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
		switch(fragP->fr_type){
		case rs_align:
		case rs_org:
		    old_fr_type = fragP->fr_type;
		    /* convert this frag to an rs_fill type */
		    fragP->fr_type = rs_fill;
		    /*
		     * Calculate the number of bytes the variable part of the
		     * the rs_fill frag will need to fill.  Then calculate this
		     * as the fill_size * repeat_expression + partial_bytes.
		     */
		    know(fragP->fr_next != NULL);
		    nbytes = fragP->fr_next->fr_address -
			     fragP->fr_address -
			     fragP->fr_fix;
		    if(nbytes < 0){
			as_warn("rs_org invalid, dot past value by %d bytes",
				nbytes);
			nbytes = 0;
		    }
		    fill_size = fragP->fr_var;
		    repeat_expression = nbytes / fill_size;
#ifdef I386
		    /*
		     * For x86 architecures in sections containing only
		     * instuctions being padded with nops that are aligned to 16
		     * bytes or less and are assembled with -dynamic we will
		     * actually end up padding with the optimal nop sequence.
		     * Previously there has been the maximum number of bytes
		     * allocated in the frag to use for this.
		     */
		    if(old_fr_type == rs_align &&
		       (frchain_now->frch_section.flags &
			S_ATTR_PURE_INSTRUCTIONS) != 0 &&
			 fill_size == 1 &&
			 fragP->fr_literal[fragP->fr_fix] == (char)0x90 &&
			 nbytes > 0 && nbytes < 16 &&
			 flagseen['k'] == TRUE){
			i386_align_code(fragP, nbytes);
			/*
			 * The call to i386_align_code() has set the fill_size
			 * in fragP->fr_var to nbytes. So we set the fr_offset
			 * to the fill repeat_expression to 1 to match for this
			 * now an rs_fill type frag.
			 */ 
			fragP->fr_offset = 1;
			break;
		    }
#endif /* I386 */
		    partial_bytes = nbytes - (repeat_expression * fill_size);
		    /*
		     * Now set the fr_offset to the fill repeat_expression
		     * since this is now an rs_fill type.  The fr_var is still
		     * the fill_size.
		     */
		    fragP->fr_offset = repeat_expression;
		    /*
		     * For rs_align frags there may be partial_bytes to fill
		     * with zeros before we can fill with the fill_expression
		     * of fill_size.  When the rs_align frag was created it was
		     * created with fill_size-1 extra bytes in the fixed part.
		     */
		    if(partial_bytes != 0){
			/* moved the fill_expression bytes foward */
			memmove(fragP->fr_literal +fragP->fr_fix +partial_bytes,
				fragP->fr_literal +fragP->fr_fix,
				fragP->fr_var);
    			/* zero out the partial_bytes */
    			memset(fragP->fr_literal + fragP->fr_fix,
			       '\0',
			       partial_bytes);
			/* adjust the fixed part of the frag */
    			fragP->fr_fix += partial_bytes;
		    }
		    break;

		case rs_fill:
		    break;

		case rs_machine_dependent:
		    md_convert_frag(fragP);
		    /*
		     * After md_convert_frag, we make the frag into a ".fill 0"
		     * md_convert_frag() should set up any fixSs and constants
		     * required.
		     */
		    frag_wane(fragP);
		    break;

		case rs_dwarf2dbg:
		    dwarf2dbg_convert_frag(fragP);
		    break;

		case rs_leb128:
		  {
		    int size;
#ifdef OLD
		    valueT value = S_GET_VALUE (fragP->fr_symbol);
#else
		    valueT value;
  		      expressionS *expression;
  		
		      if(fragP->fr_symbol->expression != NULL){
			expression =
			  (expressionS *)fragP->fr_symbol->expression;
			value = 0;
			if(expression->X_add_symbol != NULL)
			    value += expression->X_add_symbol->sy_nlist.n_value;
			if(expression->X_subtract_symbol != NULL)
			   value -= 
			     expression->X_subtract_symbol->sy_nlist.n_value;
			value += expression->X_add_number;
		      }
		      else{
			value = fragP->fr_symbol->sy_nlist.n_value +
				fragP->fr_address;
		      }
#endif

		    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;


		default:
		    BAD_CASE(fragP->fr_type);
		    break;
		}
	    }
	}

	/*
	 * For each section do the fixups for the frags.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    now_seg = frchainP->frch_nsect;
	    fixup_section(frchainP->frch_fix_root, frchainP->frch_nsect);
	}
}
Пример #19
0
void
subsegs_begin ()
{
  /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
  know (SEG_ABSOLUTE == 0);
  know (SEG_TEXT == 1);
  know (SEG_DATA == 2);
  know (SEG_BSS == 3);
  know (SEG_UNKNOWN == 4);
  know (SEG_GOOF == 5);
  know (SEG_EXPR == 6);
  know (SEG_DEBUG == 7);
  know (SEG_NTV == 8);
  know (SEG_PTV == 9);
  know (SEG_REGISTER == 10);
  know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER);
#endif

  obstack_begin (&frchains, chunksize);
#if __GNUC__ >= 2
  obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
#endif

  frchain_root = NULL;
  frchain_now = NULL;		/* Warn new_subseg() that we are booting.  */

  frag_now = &dummy_frag;

#ifndef BFD_ASSEMBLER
  now_subseg = 42;		/* Lie for 1st call to subseg_new.  */
#ifdef MANY_SEGMENTS
  {
    int i;
    for (i = SEG_E0; i < SEG_UNKNOWN; i++)
      {
	subseg_set (i, 0);
	segment_info[i].frchainP = frchain_now;
      }
  }
#else
  subseg_set (SEG_DATA, 0);	/* .data 0 */
  data0_frchainP = frchain_now;

  subseg_set (SEG_BSS, 0);
  bss0_frchainP = frchain_now;

#endif /* ! MANY_SEGMENTS */
#endif /* ! BFD_ASSEMBLER */

  absolute_frchain.frch_seg = absolute_section;
  absolute_frchain.frch_subseg = 0;
#ifdef BFD_ASSEMBLER
  absolute_frchain.fix_root = absolute_frchain.fix_tail = 0;
#endif
  absolute_frchain.frch_frag_now = &zero_address_frag;
  absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag;
}
Пример #20
0
/*
 * Summary of operand().
 *
 * in:	Input_line_pointer points to 1st char of operand, which may
 *	be a space.
 *
 * out:	A expressionS. X_seg determines how to understand the rest of the
 *	expressionS.
 *	The operand may have been empty: in this case X_seg == SEG_NONE.
 *	Input_line_pointer -> (next non-blank) char after operand.
 *
 */
static
segT
operand(
expressionS *expressionP)
{
    char c, q;
    char *name;	/* points to name of symbol */
    struct symbol *symbolP; /* Points to symbol */


	SKIP_WHITESPACE();	/* Leading whitespace is part of operand. */
	c = *input_line_pointer++;/* Input_line_pointer -> past char in c. */

	if(isdigit(c)){
	    signed_expr_t
			number; /* offset or (absolute) value */
	    int digit;		/* value of next digit in current radix */
				/* invented for humans only, hope */
				/* optimising compiler flushes it! */
	    int radix;		/* 8, 10 or 16 */
				/* 0 means we saw start of a floating- */
				/* point constant. */
	    int maxdig;		/* Highest permitted digit value. */
	    int	too_many_digits;/* If we see >= this number of */
				/* digits, assume it is a bignum. */
	    char *digit_2;	/* -> 2nd digit of number. */
	    int	small;		/* TRUE if fits in 32 bits. */
	    int	force_bignum;	/* TRUE if number is 0xb...  */

	    force_bignum = FALSE;
	    /*
	     * These two initiaizations are to shut up compiler warning as the
	     * may be used with out being set.  There used only if radix != 0
	     * when the number is not a floating-point number.
	     */
	    maxdig = 0;
	    too_many_digits = 0;

	    if(c == '0'){ /* non-decimal radix */
		c = *input_line_pointer++;
		if(c == 'x' || c=='X'){
		    c = *input_line_pointer++; /* read past "0x" or "0X" */
		    maxdig = 16;
		    radix = 16;
		    too_many_digits = 9;
		}
		/*
		 * If we have "0b" and some hex digits then treat it as a hex
		 * number and return a bignum.   This is for hex immediate
		 * bit-patterns for floating-point immediate constants.
		 */
		else if((c == 'b' || c == 'B') &&
			(*input_line_pointer != '\0') &&
			strchr("0123456789abcdefABCDEF",
			       *input_line_pointer) != NULL){
		    force_bignum = TRUE;
		    c = *input_line_pointer++; /* read past "0b" or "0B" */
		    maxdig = 16;
		    radix = 16;
		    too_many_digits = 9;
		}
		else{
		    /*
		     * If it says '0f' and the line ends or it DOESN'T look like
		     * a floating point #, its a local label ref.
		     */
		    if(c == 'f' &&
		       (*input_line_pointer == '\0' ||
			(strchr("+-.0123456789", *input_line_pointer) == NULL &&
			 strchr(md_EXP_CHARS, *input_line_pointer) == NULL) )){
			maxdig = 10;
			radix = 10;
			too_many_digits = 11;
			c = '0';
			input_line_pointer -= 2;
		    }
		    else if(c != '\0' && strchr(md_FLT_CHARS, c) != NULL){
			radix = 0;/* Start of floating-point constant. */
				  /* input_line_pointer -> 1st char of number */
			expressionP->X_add_number =
				- (isupper(c) ? tolower(c) : c);
		    }
		    else{	/* By elimination, assume octal radix. */
			radix = 8;
			maxdig = 10;	/* Un*x sux. Compatibility. */
			too_many_digits = 11;
		    }
		}
		/* c == char after "0" or "0x" or "0X" or "0e" etc.*/
	    }
	    else{
		maxdig = 10;
		radix = 10;
		too_many_digits = 11;
	    }

	    /*
	     * Expressions are now evaluated as 64-bit values so the number
	     * digits allowed is twice that for 32-bit expressions.
	     */
	    too_many_digits *= 2;

	    if(radix != 0){ /* Fixed-point integer constant. */
			    /* May be bignum, or may fit in 32 bits. */
		/*
		 * Most numbers fit into 32 bits, and we want this case to be
		 * fast.  So we pretend it will fit into 32 bits. If, after
		 * making up a 32 bit number, we realize that we have scanned
		 * more digits than comfortably fit into 32 bits, we re-scan the
		 * digits coding them into a bignum.  For decimal and octal
		 * numbers we are conservative: some numbers may be assumed
		 * bignums when in fact they do fit into 32 bits.  Numbers of
		 * any radix can have excess leading zeros: we strive to
		 * recognise this and cast them back into 32 bits.  We must
		 * check that the bignum really is more than 32 bits, and
		 * change it back to a 32-bit number if it fits.  The number we
		 * are looking for is expected to be positive, but if it fits
		 * into 32 bits as an unsigned number, we let it be a 32-bit
		 * number. The cavalier approach is for speed in ordinary cases.
		 */
		digit_2 = input_line_pointer;
		for(number = 0;
		    (digit = hex_value[(int)c]) < maxdig;
		    c = *input_line_pointer++){
		    number = number * radix + digit;
		}
		/* c contains character after number. */
		/* Input_line_pointer -> char after c. */
		small = input_line_pointer - digit_2 < too_many_digits;
		if(force_bignum == TRUE)
		      small = FALSE;
		if(small == FALSE){
		    /*
		     * Manufacture a bignum.
		     */
		    /* -> high order littlenum of the bignum. */
		    LITTLENUM_TYPE *leader;
		    /* -> littlenum we are frobbing now. */
		    LITTLENUM_TYPE *pointer;
		    long carry;

		    leader = generic_bignum;
		    generic_bignum [0] = 0;
		    /* We could just use digit_2, but lets be mnemonic. */
		    input_line_pointer = --digit_2; /* -> 1st digit. */
		    c = *input_line_pointer++;
		    for( ;
			(carry = hex_value[(int)c]) < maxdig;
			c = * input_line_pointer++){
			for(pointer = generic_bignum;
			    pointer <= leader;
			    pointer++){
			    long work;

			    work = carry + radix * *pointer;
			    *pointer = work & LITTLENUM_MASK;
			    carry = work >> LITTLENUM_NUMBER_OF_BITS;
			}
			if(carry){
			    if(leader < generic_bignum +
					SIZE_OF_LARGE_NUMBER - 1){
					/* Room to grow a longer bignum. */
				*++leader = carry;
			    }
			}
		    }
		    /* Again, C is char after number, */
		    /* input_line_pointer -> after C. */
		    /* know(BITS_PER_INT == 32); */
		    know(LITTLENUM_NUMBER_OF_BITS == 16);
		    /* Hence the constant "2" in the next line. */
		    if(leader < generic_bignum + 2 && force_bignum == FALSE)
		    {		/* Will fit into 32 bits. */
			number = ((generic_bignum[1] & LITTLENUM_MASK) <<
				   LITTLENUM_NUMBER_OF_BITS) |
			  	  (generic_bignum[0] & LITTLENUM_MASK);
			small = TRUE;
		    }
		    else{
			/* Number of littlenums in the bignum. */
			number = leader - generic_bignum + 1;
		    }
		}
		if(small){
		    /*
		     * Here with number, in correct radix. c is the next char.
		     * Note that unlike Un*x, we allow "011f" "0x9f" to both
		     * mean the same as the (conventional) "9f". This is simply
		     * easier than checking for strict canonical form.
		     */
		    if(number < 10){
			if(c == 'b'){
			    /*
			     * Backward ref to local label.
			     * Because it is backward, expect it to be DEFINED.
			     */
			    /*
			     * Construct a local label.
			     */
			    name = local_label_name((int)number, 0);
			    symbolP = symbol_table_lookup(name);
			    if((symbolP != NULL) &&
			       (symbolP->sy_type & N_TYPE) != N_UNDF){
				/* Expected path: symbol defined. */
				/* Local labels are never absolute. Don't waste
				   time checking absoluteness. */
				know((symbolP->sy_type & N_TYPE) == N_SECT);
				expressionP->X_add_symbol = symbolP;
				expressionP->X_add_number = 0;
				expressionP->X_seg        = SEG_SECT;
			    }
			    else{ /* Either not seen or not defined. */
				as_warn("Backw. ref to unknown label \"%lld\","
				"0 assumed.", number);
				expressionP->X_add_number = 0;
				expressionP->X_seg        = SEG_ABSOLUTE;
			    }
			}
			else if(c == 'f'){
			    /*
			     * Forward reference. Expect symbol to be
			     * undefined or unknown. Undefined: seen it
			     * before. Unknown: never seen it in this pass.
			     * Construct a local label name, then an
			     * undefined symbol.  Don't create a XSEG frag
			     * for it: caller may do that.
			     * Just return it as never seen before.
			     */
			    name = local_label_name((int)number, 1);
			    symbolP = symbol_table_lookup(name);
			    if(symbolP != NULL){
				/* We have no need to check symbol
				   properties. */
				know((symbolP->sy_type & N_TYPE) == N_UNDF ||
				     (symbolP->sy_type & N_TYPE) == N_SECT);
			    }
			    else{
				symbolP = symbol_new(name, N_UNDF, 0,0,0,
						     &zero_address_frag);
				symbol_table_insert(symbolP);
			    }
			    expressionP->X_add_symbol      = symbolP;
			    expressionP->X_seg             = SEG_UNKNOWN;
			    expressionP->X_subtract_symbol = NULL;
			    expressionP->X_add_number      = 0;
			}
			else{	/* Really a number, not a local label. */
			    ignore_c_ll_or_ull(c);
			    expressionP->X_add_number = number;
			    expressionP->X_seg        = SEG_ABSOLUTE;
			    input_line_pointer--; /* restore following char */
		        }
		    }
		    else{ /* a number >= 10 */
			ignore_c_ll_or_ull(c);
			expressionP->X_add_number = number;
			expressionP->X_seg        = SEG_ABSOLUTE;
			input_line_pointer--; /* restore following char */
		    }
		} /* not a small number encode returning a bignum */
		else{
		    ignore_c_ll_or_ull(c);
		    expressionP->X_add_number = number;
		    expressionP->X_seg = SEG_BIG;
		    input_line_pointer--; /* -> char following number. */
		} /* if (small) */
	    } /* (If integer constant) */
Пример #21
0
static void
obj_coff_endef (int ignore ATTRIBUTE_UNUSED)
{
  symbolS *symbolP = NULL;

  dim_index = 0;
  if (def_symbol_in_progress == NULL)
    {
      as_warn (_(".endef pseudo-op used outside of .def/.endef: ignored."));
      demand_empty_rest_of_line ();
      return;
    }

  /* Set the section number according to storage class.  */
  switch (S_GET_STORAGE_CLASS (def_symbol_in_progress))
    {
    case C_STRTAG:
    case C_ENTAG:
    case C_UNTAG:
      SF_SET_TAG (def_symbol_in_progress);
      /* Fall through.  */
    case C_FILE:
    case C_TPDEF:
      SF_SET_DEBUG (def_symbol_in_progress);
      S_SET_SEGMENT (def_symbol_in_progress, fetch_coff_debug_section ());
      break;

    case C_EFCN:
      SF_SET_LOCAL (def_symbol_in_progress);	/* Do not emit this symbol.  */
      /* Fall through.  */
    case C_BLOCK:
      SF_SET_PROCESS (def_symbol_in_progress);	/* Will need processing before writing.  */
      /* Fall through.  */
    case C_FCN:
      {
	const char *name;

	S_SET_SEGMENT (def_symbol_in_progress, text_section);

	name = S_GET_NAME (def_symbol_in_progress);
	if (name[0] == '.' && name[2] == 'f' && name[3] == '\0')
	  {
	    switch (name[1])
	      {
	      case 'b':
		/* .bf */
		if (! in_function ())
		  as_warn (_("`%s' symbol without preceding function"), name);
		/* Will need relocating.  */
		SF_SET_PROCESS (def_symbol_in_progress);
		clear_function ();
		break;
#ifdef TE_PE
	      case 'e':
		/* .ef */
		/* The MS compilers output the actual endline, not the
		   function-relative one... we want to match without
		   changing the assembler input.  */
		SA_SET_SYM_LNNO (def_symbol_in_progress,
				 (SA_GET_SYM_LNNO (def_symbol_in_progress)
				  + coff_line_base));
		break;
#endif
	      }
	  }
      }
      break;

#ifdef C_AUTOARG
    case C_AUTOARG:
#endif /* C_AUTOARG */
    case C_AUTO:
    case C_REG:
    case C_ARG:
    case C_REGPARM:
    case C_FIELD:

    /* According to the COFF documentation:

       http://osr5doc.sco.com:1996/topics/COFF_SectNumFld.html

       A special section number (-2) marks symbolic debugging symbols,
       including structure/union/enumeration tag names, typedefs, and
       the name of the file. A section number of -1 indicates that the
       symbol has a value but is not relocatable. Examples of
       absolute-valued symbols include automatic and register variables,
       function arguments, and .eos symbols.

       But from Ian Lance Taylor:

       http://sources.redhat.com/ml/binutils/2000-08/msg00202.html

       the actual tools all marked them as section -1. So the GNU COFF
       assembler follows historical COFF assemblers.

       However, it causes problems for djgpp

       http://sources.redhat.com/ml/binutils/2000-08/msg00210.html

       By defining STRICTCOFF, a COFF port can make the assembler to
       follow the documented behavior.  */
#ifdef STRICTCOFF
    case C_MOS:
    case C_MOE:
    case C_MOU:
    case C_EOS:
#endif
      SF_SET_DEBUG (def_symbol_in_progress);
      S_SET_SEGMENT (def_symbol_in_progress, absolute_section);
      break;

#ifndef STRICTCOFF
    case C_MOS:
    case C_MOE:
    case C_MOU:
    case C_EOS:
      S_SET_SEGMENT (def_symbol_in_progress, absolute_section);
      break;
#endif

    case C_EXT:
    case C_WEAKEXT:
#ifdef TE_PE
    case C_NT_WEAK:
#endif
    case C_STAT:
    case C_LABEL:
      /* Valid but set somewhere else (s_comm, s_lcomm, colon).  */
      break;

    default:
    case C_USTATIC:
    case C_EXTDEF:
    case C_ULABEL:
      as_warn (_("unexpected storage class %d"),
	       S_GET_STORAGE_CLASS (def_symbol_in_progress));
      break;
    }

  /* Now that we have built a debug symbol, try to find if we should
     merge with an existing symbol or not.  If a symbol is C_EFCN or
     absolute_section or untagged SEG_DEBUG it never merges.  We also
     don't merge labels, which are in a different namespace, nor
     symbols which have not yet been defined since they are typically
     unique, nor do we merge tags with non-tags.  */

  /* Two cases for functions.  Either debug followed by definition or
     definition followed by debug.  For definition first, we will
     merge the debug symbol into the definition.  For debug first, the
     lineno entry MUST point to the definition function or else it
     will point off into space when obj_crawl_symbol_chain() merges
     the debug symbol into the real symbol.  Therefor, let's presume
     the debug symbol is a real function reference.  */

  /* FIXME-SOON If for some reason the definition label/symbol is
     never seen, this will probably leave an undefined symbol at link
     time.  */

  if (S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_EFCN
      || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_LABEL
      || (streq (bfd_get_section_name (stdoutput,
				       S_GET_SEGMENT (def_symbol_in_progress)),
		 "*DEBUG*")
	  && !SF_GET_TAG (def_symbol_in_progress))
      || S_GET_SEGMENT (def_symbol_in_progress) == absolute_section
      || ! symbol_constant_p (def_symbol_in_progress)
      || (symbolP = symbol_find (S_GET_NAME (def_symbol_in_progress))) == NULL
      || SF_GET_TAG (def_symbol_in_progress) != SF_GET_TAG (symbolP))
    {
      /* If it already is at the end of the symbol list, do nothing */
      if (def_symbol_in_progress != symbol_lastP)
	{
	  symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
	  symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP,
			 &symbol_lastP);
	}
    }
  else
    {
      /* This symbol already exists, merge the newly created symbol
	 into the old one.  This is not mandatory. The linker can
	 handle duplicate symbols correctly. But I guess that it save
	 a *lot* of space if the assembly file defines a lot of
	 symbols. [loic]  */

      /* The debug entry (def_symbol_in_progress) is merged into the
	 previous definition.  */

      c_symbol_merge (def_symbol_in_progress, symbolP);
      symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);

      def_symbol_in_progress = symbolP;

      if (SF_GET_FUNCTION (def_symbol_in_progress)
	  || SF_GET_TAG (def_symbol_in_progress)
	  || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_STAT)
	{
	  /* For functions, and tags, and static symbols, the symbol
	     *must* be where the debug symbol appears.  Move the
	     existing symbol to the current place.  */
	  /* If it already is at the end of the symbol list, do nothing.  */
	  if (def_symbol_in_progress != symbol_lastP)
	    {
	      symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
	      symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP);
	    }
	}
    }

  if (SF_GET_TAG (def_symbol_in_progress))
    {
      symbolS *oldtag;

      oldtag = symbol_find (S_GET_NAME (def_symbol_in_progress));
      if (oldtag == NULL || ! SF_GET_TAG (oldtag))
	tag_insert (S_GET_NAME (def_symbol_in_progress),
		    def_symbol_in_progress);
    }

  if (SF_GET_FUNCTION (def_symbol_in_progress))
    {
      know (sizeof (def_symbol_in_progress) <= sizeof (long));
      set_function (def_symbol_in_progress);
      SF_SET_PROCESS (def_symbol_in_progress);

      if (symbolP == NULL)
	/* That is, if this is the first time we've seen the
	   function.  */
	symbol_table_insert (def_symbol_in_progress);

    }

  def_symbol_in_progress = NULL;
  demand_empty_rest_of_line ();
}
Пример #22
0
/*
 * relax_section() here we set the fr_address values in the frags.
 * After this, all frags in this segment have addresses that are correct
 * relative to the section (that is the section starts at address zero).
 * After all of the sections have been processed by this call and their sizes
 * are know then they can be slid to their final address.
 */
static
int
relax_section(
struct frag *frag_root,
int nsect)
{
    struct frag *fragP;
    relax_addressT address;

    int32_t stretch; /* May be any size, 0 or negative. */
		     /* Cumulative number of addresses we have */
		     /* relaxed this pass. */
		     /* We may have relaxed more than one address. */
    int32_t stretched;  /* Have we stretched on this pass? */
		    /* This is 'cuz stretch may be zero, when,
		       in fact some piece of code grew, and
		       another shrank.  If a branch instruction
		       doesn't fit anymore, we need another pass */

#ifndef ARM
    const relax_typeS *this_type;
    const relax_typeS *start_type;
    relax_substateT next_state;
    relax_substateT this_state;
    int32_t aim;
#endif /* !defined(ARM) */

    int32_t growth;
    uint32_t was_address;
    int32_t offset;
    symbolS *symbolP;
    int32_t target;
    int32_t after;
    uint32_t oldoff, newoff;
    int ret;

	ret = 0;
	growth = 0;

	/*
	 * For each frag in segment count and store (a 1st guess of) fr_address.
	 */
	address = 0;
	for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
#ifdef ARM
            fragP->relax_marker = 0;
#endif /* ARM */
	    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:
		offset = relax_align (address, (int) fragP->fr_offset);
		/*
		 * If a maximum number of bytes to fill was specified for this
		 * align (stored in fr_subtype) then check to see if this align
		 * can be done.  If not ignore it.  If so and this alignment is
		 * larger than any previous alignment then this becomes the
		 * section's alignment.
		 */
		if(fragP->fr_subtype != 0){
		    if(offset > (int32_t)fragP->fr_subtype){
			offset = 0;
		    }
		    else{
			if(frchain_now->frch_section.align <
			   (uint32_t)fragP->fr_offset)
			    frchain_now->frch_section.align = fragP->fr_offset;
		    }
		}
		address += offset;
		break;

	    case rs_org:
		/*
		 * Assume .org is nugatory. It will grow with 1st relax.
		 */
		break;

	    case rs_machine_dependent:
		address += md_estimate_size_before_relax(fragP, nsect);
		break;

	    case rs_dwarf2dbg:
		address += dwarf2dbg_estimate_size_before_relax(fragP);
		break;

	    case rs_leb128:
	      /* Initial guess is always 1; doing otherwise can result in
		 stable solutions that are larger than the minimum.  */
	      address += fragP->fr_offset = 1;
	      break;

	    default:
		BAD_CASE(fragP->fr_type);
		break;
	    }
	}

	/*
	 * Do relax().
	 * Make repeated passes over the chain of frags allowing each frag to
	 * grow if needed.  On each pass each frag's address is incremented by
	 * the accumulated growth, kept in stretched.  Passes are continued 
	 * until there is no stretch on the previous pass.
	 */
	do{
	    stretch = 0;
	    stretched = 0;
	    for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
#ifdef ARM
                fragP->relax_marker ^= 1;
#endif /* ARM */
		was_address = fragP->fr_address;
		fragP->fr_address += stretch;
		address = fragP->fr_address;
		symbolP = fragP->fr_symbol;
		offset = fragP->fr_offset;
		switch(fragP->fr_type){
		case rs_fill:	/* .fill never relaxes. */
		    growth = 0;
		    break;

		case rs_align:
		    oldoff = relax_align(was_address + fragP->fr_fix, offset);
		    newoff = relax_align(address + fragP->fr_fix, offset);
		    /*
		     * Check if a maximum number of bytes to fill was specified
		     * for this align (stored in fr_subtype).
		     */
		    if(fragP->fr_subtype != 0){
			if(oldoff > fragP->fr_subtype)
			    oldoff = 0;
			if(newoff > fragP->fr_subtype)
			    newoff = 0;
		    }
		    growth = newoff - oldoff;
		    break;

		case rs_org:
		    target = offset;
		    if(symbolP != NULL){
			know(((symbolP->sy_type & N_TYPE) == N_ABS) ||
			     ((symbolP->sy_type & N_TYPE) == N_SECT));
			know(symbolP->sy_frag);
			know((symbolP->sy_type & N_TYPE) != N_ABS ||
			     symbolP->sy_frag == &zero_address_frag );
			target += symbolP->sy_value +
				  symbolP->sy_frag->fr_address;
		    }
		    know(fragP->fr_next);
		    after = fragP->fr_next->fr_address;
		    /*
		     * Growth may be negative, but variable part of frag cannot
		     * have < 0 chars. That is, we can't .org backwards.
		     */
		    growth = ((target - after ) > 0) ? (target - after) : 0;

		    growth -= stretch;	/* This is an absolute growth factor */
		    break;

		case rs_machine_dependent:
#ifdef ARM
		    growth = arm_relax_frag(nsect, fragP, stretch);
#else /* !defined(ARM) */
		    this_state = fragP->fr_subtype;
		    this_type = md_relax_table + this_state;
		    start_type = this_type;

		    target = offset;
		    if(symbolP){
			know(((symbolP->sy_type & N_TYPE) == N_ABS) ||
			     ((symbolP->sy_type & N_TYPE) == N_SECT));
			know(symbolP->sy_frag);
			know((symbolP->sy_type & N_TYPE) != N_ABS ||
			     symbolP->sy_frag == &zero_address_frag);

			target += symbolP->sy_value +
				  symbolP->sy_frag->fr_address;
			/*
			 * If frag has yet to be reached on this pass,
			 * assume it will move by STRETCH just as we did.
			 * If this is not so, it will be because some frag
			 * between grows, and that will force another pass.
			 */
			if(symbolP->sy_frag->fr_address >= was_address &&
			   is_down_range(fragP, symbolP->sy_frag))
			    target += stretch;
		    }
		    aim = target - address - fragP->fr_fix;
		    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 = md_relax_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 = md_relax_table + this_state;
				next_state = this_type->rlx_more;
			    }
			}
		    }
		    if((growth = this_type->rlx_length -start_type->rlx_length))
			  fragP->fr_subtype = this_state;
#endif /* !defined(ARM) */
		    break;
		  case rs_dwarf2dbg:
		      growth = dwarf2dbg_relax_frag(fragP);
		      break;

		  case rs_leb128:
		    {
		      valueT value;
		      offsetT size;
#ifdef OLD
		      value = resolve_symbol_value (fragP->fr_symbol);
#else
  		      expressionS *expression;
  		
		      if(fragP->fr_symbol->expression != NULL){
			expression =
			  (expressionS *)fragP->fr_symbol->expression;
			value = 0;
			if(expression->X_add_symbol != NULL)
			    value +=
			     (expression->X_add_symbol->sy_nlist.n_value +
			      expression->X_add_symbol->sy_frag->fr_address);
			if(expression->X_subtract_symbol != NULL)
			   value -= 
			     (expression->X_subtract_symbol->sy_nlist.n_value +
			      expression->X_subtract_symbol->
							   sy_frag->fr_address);
			value += expression->X_add_number;
		      }
		      else{
			value = fragP->fr_symbol->sy_nlist.n_value +
				fragP->fr_address;
		      }
#endif
		      size = sizeof_leb128 (value, fragP->fr_subtype);
		      growth = size - fragP->fr_offset;
		      fragP->fr_offset = size;
		    }
		    break;

		  default:
		      BAD_CASE(fragP->fr_type);
		      break;
		}
		if(growth) {
		    stretch += growth;
		    stretched++;
		}
	    }			/* For each frag in the segment. */
	}while(stretched);	/* Until nothing further to relax. */

	/*
	 * We now have valid fr_address'es for each frag.  All fr_address's
	 * are correct, relative to their own section.  We have made all the
	 * fixS for this section that will be made.
	 */

	for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
	    if(fragP->last_fr_address != fragP->fr_address){
		fragP->last_fr_address = fragP->fr_address;
		ret = 1;
	    }
	}
	return(ret);
}
Пример #23
0
/*
 * write_object() writes a Mach-O object file from the built up data structures.
 */
void
write_object(
char *out_file_name)
{
    /* The structures for Mach-O relocatables */
    mach_header_t		header;
    segment_command_t		reloc_segment;
    struct symtab_command	symbol_table;
    struct dysymtab_command	dynamic_symbol_table;
    uint32_t			section_type;
    uint32_t			*indirect_symbols;
    isymbolS			*isymbolP;
    uint32_t			i, j, nsects, nsyms, strsize, nindirectsyms;

    /* locals to fill in section struct fields */
    uint32_t offset, zero;

    /* The GAS data structures */
    struct frchain *frchainP, *p;
    struct symbol *symbolP;
    struct frag *fragP;
    struct fix *fixP;

    uint32_t output_size;
    char *output_addr;
    kern_return_t r;

    enum byte_sex host_byte_sex;
    uint32_t reloff, nrelocs;
    int32_t count;
    char *fill_literal;
    int32_t fill_size;
    int32_t num_bytes;
    char *symbol_name;
    int fd;
    uint32_t local;
    struct stat stat_buf;

#ifdef I860
	I860_tweeks();
#endif
	i = 0; /* to shut up a compiler "may be used uninitialized" warning */

	/*
	 * The first group of things to do is to set all the fields in the
	 * header structures which includes offsets and determining the final
	 * sizes of things.
	 */

	/* 
	 * Fill in the addr and size fields of each section structure and count
	 * the number of sections.
	 */
	nsects = 0;
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    frchainP->frch_section.addr = frchainP->frch_root->fr_address;
	    frchainP->frch_section.size = frchainP->frch_last->fr_address -
		   			  frchainP->frch_root->fr_address;
	    nsects++;
	}

	/*
	 * Setup the indirect symbol tables by looking up or creating symbol
	 * from the indirect symbol names and recording the symbol pointers.
	 */
	nindirectsyms = layout_indirect_symbols();

	/*
	 * Setup the symbol table to include only those symbols that will be in
	 * the object file, assign the string table offsets into the symbols
	 * and size the string table.
	 */
	nsyms = 0;
	strsize = 0;
	layout_symbols((int32_t *)&nsyms, (int32_t *)&strsize);

	/* fill in the Mach-O header */
	header.magic = MH_MAGIC_VALUE;
	header.cputype = md_cputype;
	if(archflag_cpusubtype != -1)
	    header.cpusubtype = archflag_cpusubtype;
	else
	    header.cpusubtype = md_cpusubtype;

	header.filetype = MH_OBJECT;
	header.ncmds = 0;
	header.sizeofcmds = 0;
	if(nsects != 0){
	    header.ncmds += 1;
	    header.sizeofcmds += sizeof(segment_command_t) +
				 nsects * sizeof(section_t);
	}
	if(nsyms != 0){
	    header.ncmds += 1;
	    header.sizeofcmds += sizeof(struct symtab_command);
	    if(flagseen['k']){
		header.ncmds += 1;
		header.sizeofcmds += sizeof(struct dysymtab_command);
	    }
	}
	else
	    strsize = 0;
	header.flags = 0;
	if(subsections_via_symbols == TRUE)
	    header.flags |= MH_SUBSECTIONS_VIA_SYMBOLS;
#ifdef ARCH64
	header.reserved = 0;
#endif

	/* fill in the segment command */
	memset(&reloc_segment, '\0', sizeof(segment_command_t));
	reloc_segment.cmd = LC_SEGMENT_VALUE;
	reloc_segment.cmdsize = sizeof(segment_command_t) +
				nsects * sizeof(section_t);
	/* leave reloc_segment.segname full of zeros */
	reloc_segment.vmaddr = 0;
	reloc_segment.vmsize = 0;
	reloc_segment.filesize = 0;
	offset = header.sizeofcmds + sizeof(mach_header_t);
	reloc_segment.fileoff = offset;
	reloc_segment.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
	reloc_segment.initprot= VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
	reloc_segment.nsects = nsects;
	reloc_segment.flags = 0;
	/*
	 * Set the offsets to the contents of the sections (for non-zerofill
	 * sections) and set the filesize and vmsize of the segment.  This is
	 * complicated by the fact that all the zerofill sections have addresses
	 * after the non-zerofill sections and that the alignment of sections
	 * produces gaps that are not in any section.  For the vmsize we rely on
	 * the fact the the sections start at address 0 so it is just the last
	 * zerofill section or the last not-zerofill section.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL)
		continue;
	    for(p = frchainP->frch_next; p != NULL; p = p->frch_next)
		if((p->frch_section.flags & SECTION_TYPE) != S_ZEROFILL)
		    break;
	    if(p != NULL)
		i = p->frch_section.addr - frchainP->frch_section.addr;
	    else
		i = frchainP->frch_section.size;
	    reloc_segment.filesize += i;
	    frchainP->frch_section.offset = offset;
	    offset += i;
	    reloc_segment.vmsize = frchainP->frch_section.addr +
				   frchainP->frch_section.size;
	}
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) != S_ZEROFILL)
		continue;
	    reloc_segment.vmsize = frchainP->frch_section.addr +
				   frchainP->frch_section.size;
	}
	offset = round(offset, sizeof(int32_t));

	/*
	 * Count the number of relocation entries for each section.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    frchainP->frch_section.nreloc = 0;
	    for(fixP = frchainP->frch_fix_root; fixP; fixP = fixP->fx_next){
		frchainP->frch_section.nreloc += nrelocs_for_fix(fixP);
	    }
	}

	/*
	 * Fill in the offset to the relocation entries of the sections.
	 */
	offset = round(offset, sizeof(int32_t));
	reloff = offset;
	nrelocs = 0;
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if(frchainP->frch_section.nreloc == 0)
		frchainP->frch_section.reloff = 0;
	    else
		frchainP->frch_section.reloff = offset;
	    offset += frchainP->frch_section.nreloc *
		      sizeof(struct relocation_info);
	    nrelocs += frchainP->frch_section.nreloc;
	}

	if(flagseen['k']){
	    /* fill in the fields of the dysymtab_command */
	    dynamic_symbol_table.cmd = LC_DYSYMTAB;
	    dynamic_symbol_table.cmdsize = sizeof(struct dysymtab_command);

	    dynamic_symbol_table.ilocalsym = ilocalsym;
	    dynamic_symbol_table.nlocalsym = nlocalsym;
	    dynamic_symbol_table.iextdefsym = iextdefsym;
	    dynamic_symbol_table.nextdefsym = nextdefsym;
	    dynamic_symbol_table.iundefsym = iundefsym;
	    dynamic_symbol_table.nundefsym = nundefsym;

	    if(nindirectsyms == 0){
		dynamic_symbol_table.nindirectsyms = 0;
		dynamic_symbol_table.indirectsymoff = 0;
	    }
	    else{
		dynamic_symbol_table.nindirectsyms = nindirectsyms;
		dynamic_symbol_table.indirectsymoff = offset;
		offset += nindirectsyms * sizeof(uint32_t);
	    }

	    dynamic_symbol_table.tocoff = 0;
	    dynamic_symbol_table.ntoc = 0;
	    dynamic_symbol_table.modtaboff = 0;
	    dynamic_symbol_table.nmodtab = 0;
	    dynamic_symbol_table.extrefsymoff = 0;
	    dynamic_symbol_table.nextrefsyms = 0;
	    dynamic_symbol_table.extreloff = 0;
	    dynamic_symbol_table.nextrel = 0;
	    dynamic_symbol_table.locreloff = 0;
	    dynamic_symbol_table.nlocrel = 0;
	}

	/* fill in the fields of the symtab_command (except the string table) */
	symbol_table.cmd = LC_SYMTAB;
	symbol_table.cmdsize = sizeof(struct symtab_command);
	if(nsyms == 0)
	    symbol_table.symoff = 0;
	else
	    symbol_table.symoff = offset;
	symbol_table.nsyms = nsyms;
	offset += symbol_table.nsyms * sizeof(nlist_t);

	/* fill in the string table fields of the symtab_command */
	if(strsize == 0)
	    symbol_table.stroff = 0;
	else
	    symbol_table.stroff = offset;
	symbol_table.strsize = round(strsize, sizeof(uint32_t));
	offset += round(strsize, sizeof(uint32_t));

	/*
	 * The second group of things to do is now with the size of everything
	 * known the object file and the offsets set in the various structures
	 * the contents of the object file can be created.
	 */

	/*
	 * Create the buffer to copy the parts of the output file into.
	 */
	output_size = offset;
	if((r = vm_allocate(mach_task_self(), (vm_address_t *)&output_addr,
			    output_size, TRUE)) != KERN_SUCCESS)
	    as_fatal("can't vm_allocate() buffer for output file of size %u",
		     output_size);

	/* put the headers in the output file's buffer */
	host_byte_sex = get_host_byte_sex();
	offset = 0;

	/* put the mach_header in the buffer */
	memcpy(output_addr + offset, &header, sizeof(mach_header_t));
	if(host_byte_sex != md_target_byte_sex)
	    swap_mach_header_t((mach_header_t *)(output_addr + offset),
			       md_target_byte_sex);
	offset += sizeof(mach_header_t);

	/* put the segment_command in the buffer */
	if(nsects != 0){
	    memcpy(output_addr + offset, &reloc_segment,
		   sizeof(segment_command_t));
	    if(host_byte_sex != md_target_byte_sex)
		swap_segment_command_t((segment_command_t *)
				       (output_addr + offset),
				       md_target_byte_sex);
	    offset += sizeof(segment_command_t);
	}

	/* put the segment_command's section structures in the buffer */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    memcpy(output_addr + offset, &(frchainP->frch_section),
		   sizeof(section_t));
	    if(host_byte_sex != md_target_byte_sex)
		swap_section_t((section_t *)(output_addr + offset), 1,
			       md_target_byte_sex);
	    offset += sizeof(section_t);
	}

	/* put the symbol_command in the buffer */
	if(nsyms != 0){
	    memcpy(output_addr + offset, &symbol_table,
		   sizeof(struct symtab_command));
	    if(host_byte_sex != md_target_byte_sex)
		swap_symtab_command((struct symtab_command *)
				     (output_addr + offset),
				     md_target_byte_sex);
	    offset += sizeof(struct symtab_command);
	}

	if(flagseen['k']){
	    /* put the dysymbol_command in the buffer */
	    if(nsyms != 0){
		memcpy(output_addr + offset, &dynamic_symbol_table,
		       sizeof(struct dysymtab_command));
		if(host_byte_sex != md_target_byte_sex)
		    swap_dysymtab_command((struct dysymtab_command *)
					  (output_addr + offset),
					  md_target_byte_sex);
		offset += sizeof(struct dysymtab_command);
	    }
	}

	/* put the section contents (frags) in the buffer */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    offset = frchainP->frch_section.offset;
	    for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
		know(fragP->fr_type == rs_fill);
		/* put the fixed part of the frag in the buffer */
		memcpy(output_addr + offset, fragP->fr_literal, fragP->fr_fix);
		offset += fragP->fr_fix;

		/* put the variable repeated part of the frag in the buffer */
		fill_literal = fragP->fr_literal + fragP->fr_fix;
		fill_size = fragP->fr_var;
		num_bytes = fragP->fr_offset * fragP->fr_var;
		for(count = 0; count < num_bytes; count += fill_size){
		    memcpy(output_addr + offset, fill_literal, fill_size);
		    offset += fill_size;
		}
	    }
	}


	/* put the symbols in the output file's buffer */
	offset = symbol_table.symoff;
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    if((symbolP->sy_type & N_EXT) == 0){
		symbol_name = symbolP->sy_name;
		symbolP->sy_nlist.n_un.n_strx = symbolP->sy_name_offset;
		if(symbolP->expression != 0) {
		    expressionS *exp;

		    exp = (expressionS *)symbolP->expression;
		    if((exp->X_add_symbol->sy_type & N_TYPE) == N_UNDF)
	    		as_fatal("undefined symbol `%s' in operation setting "
				 "`%s'", exp->X_add_symbol->sy_name,
				 symbol_name);
		    if((exp->X_subtract_symbol->sy_type & N_TYPE) == N_UNDF)
	    		as_fatal("undefined symbol `%s' in operation setting "
				 "`%s'", exp->X_subtract_symbol->sy_name,
				 symbol_name);
		    if(exp->X_add_symbol->sy_other !=
		       exp->X_subtract_symbol->sy_other)
	    		as_fatal("invalid sections for operation on `%s' and "
				 "`%s' setting `%s'",exp->X_add_symbol->sy_name,
				 exp->X_subtract_symbol->sy_name, symbol_name);
		    symbolP->sy_nlist.n_value +=
			exp->X_add_symbol->sy_value -
			exp->X_subtract_symbol->sy_value;
		}
		memcpy(output_addr + offset, (char *)(&symbolP->sy_nlist),
		       sizeof(nlist_t));
		symbolP->sy_name = symbol_name;
		offset += sizeof(nlist_t);
	    }
	}
	for(i = 0; i < nextdefsym; i++){
	    symbol_name = extdefsyms[i]->sy_name;
	    extdefsyms[i]->sy_nlist.n_un.n_strx = extdefsyms[i]->sy_name_offset;
	    memcpy(output_addr + offset, (char *)(&extdefsyms[i]->sy_nlist),
	           sizeof(nlist_t));
	    extdefsyms[i]->sy_name = symbol_name;
	    offset += sizeof(nlist_t);
	}
	for(j = 0; j < nundefsym; j++){
	    symbol_name = undefsyms[j]->sy_name;
	    undefsyms[j]->sy_nlist.n_un.n_strx = undefsyms[j]->sy_name_offset;
	    memcpy(output_addr + offset, (char *)(&undefsyms[j]->sy_nlist),
	           sizeof(nlist_t));
	    undefsyms[j]->sy_name = symbol_name;
	    offset += sizeof(nlist_t);
	}
	if(host_byte_sex != md_target_byte_sex)
	    swap_nlist_t((nlist_t *)(output_addr + symbol_table.symoff),
		         symbol_table.nsyms, md_target_byte_sex);

	/*
	 * Put the relocation entries for each section in the buffer.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    offset = frchainP->frch_section.reloff;
	    for(fixP = frchainP->frch_fix_root; fixP; fixP = fixP->fx_next){
		offset += fix_to_relocation_entries(
					fixP,
					frchainP->frch_section.addr,
					(struct relocation_info *)(output_addr +
								   offset),
				        frchainP->frch_section.flags &
					  S_ATTR_DEBUG);
	    }
	}
	if(host_byte_sex != md_target_byte_sex)
	    swap_relocation_info((struct relocation_info *)
		(output_addr + reloff), nrelocs, md_target_byte_sex);

	if(flagseen['k']){
	    /* put the indirect symbol table in the buffer */
	    offset = dynamic_symbol_table.indirectsymoff;
	    for(frchainP = frchain_root;
		frchainP != NULL;
		frchainP = frchainP->frch_next){
		section_type = frchainP->frch_section.flags & SECTION_TYPE;
		if(section_type == S_NON_LAZY_SYMBOL_POINTERS ||
		   section_type == S_LAZY_SYMBOL_POINTERS ||
		   section_type == S_SYMBOL_STUBS){
		    /*
		     * For each indirect symbol put out the symbol number.
		     */
		    for(isymbolP = frchainP->frch_isym_root;
			isymbolP != NULL;
			isymbolP = isymbolP->isy_next){
			/*
			 * If this is a non-lazy pointer symbol section and
			 * if the symbol is a local symbol then put out
			 * INDIRECT_SYMBOL_LOCAL as the indirect symbol table
			 * entry.  This is used with code gen for fix-n-continue
			 * where the compiler generates indirection for static
			 * data references.  See the comments at the end of
			 * fixup_section() that explains the assembly code used.
			 */
			if(section_type == S_NON_LAZY_SYMBOL_POINTERS &&
			   (isymbolP->isy_symbol->sy_nlist.n_type & N_EXT) !=
			    N_EXT){
    			    local = INDIRECT_SYMBOL_LOCAL;
			    if((isymbolP->isy_symbol->sy_nlist.n_type &
				N_TYPE) == N_ABS)
				local |= INDIRECT_SYMBOL_ABS;
			    memcpy(output_addr + offset, (char *)(&local),
	   			   sizeof(uint32_t));
			}
			else{
			    memcpy(output_addr + offset,
				   (char *)(&isymbolP->isy_symbol->sy_number),
				   sizeof(uint32_t));
			}
			offset += sizeof(uint32_t);
		    }
		}
	    }
	    if(host_byte_sex != md_target_byte_sex){
		indirect_symbols = (uint32_t *)(output_addr +
				    dynamic_symbol_table.indirectsymoff);
		swap_indirect_symbols(indirect_symbols, nindirectsyms, 
				      md_target_byte_sex);
	    }
	}

	/* put the strings in the output file's buffer */
	offset = symbol_table.stroff;
	if(symbol_table.strsize != 0){
	    zero = 0;
	    memcpy(output_addr + offset, (char *)&zero, sizeof(char));
	    offset += sizeof(char);
	}
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    /* Ordinary case: not .stabd. */
	    if(symbolP->sy_name != NULL){
		if((symbolP->sy_type & N_EXT) != 0){
		    memcpy(output_addr + offset, symbolP->sy_name,
			   strlen(symbolP->sy_name) + 1);
		    offset += strlen(symbolP->sy_name) + 1;
		}
	    }
	}
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    /* Ordinary case: not .stabd. */
	    if(symbolP->sy_name != NULL){
		if((symbolP->sy_type & N_EXT) == 0){
		    memcpy(output_addr + offset, symbolP->sy_name,
			   strlen(symbolP->sy_name) + 1);
		    offset += strlen(symbolP->sy_name) + 1;
		}
	    }
	}
	/*
         * Create the output file.  The unlink() is done to handle the problem
         * when the out_file_name is not writable but the directory allows the
         * file to be removed (since the file may not be there the return code
         * of the unlink() is ignored).
         */
	if(bad_error != 0)
	    return;
	/*
	 * Avoid doing the unlink() on special files, just unlink regular files
	 * that exist.
	 */
	if(stat(out_file_name, &stat_buf) != -1){
	    if(stat_buf.st_mode & S_IFREG)
		(void)unlink(out_file_name);
	}
	if((fd = open(out_file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1)
	    as_fatal("can't create output file: %s", out_file_name);
	if(write(fd, output_addr, output_size) != (int)output_size)
	    as_fatal("can't write output file");
	if(close(fd) == -1)
	    as_fatal("can't close output file");
}
Пример #24
0
/*
 * fixup_section() does the fixups of the frags and prepares the fixes so
 * relocation entries can be created from them.  The fixups cause the contents
 * of the frag to have the value for the fixup expression.  A fix structure that
 * ends up with a non-NULL fx_addsy will have a relocation entry created for it.
 */
static
void
fixup_section(
fixS *fixP,
int nsect)
{
    symbolS *add_symbolP;
    symbolS *sub_symbolP;
    signed_expr_t value;
    int size;
    char *place;
    int32_t where;
    char pcrel;
    fragS *fragP;
    int	add_symbol_N_TYPE;
    int	add_symbol_nsect;
#ifndef SPARC
    int sub_symbol_nsect;
#endif

	/*
	 * The general fix expression is "fx_addsy - fx_subsy + fx_offset".
	 * The goal is to put the result of this expression into the frag at
	 * "place" for size "size".  The value of the expression is calculated
	 * in the variable "value" and starts with just the fx_offset.
	 */
	for( ; fixP != NULL; fixP = fixP->fx_next){
	    fragP       = fixP->fx_frag;
	    know(fragP);
	    where	= fixP->fx_where;
	    place       = fragP->fr_literal + where;
	    size	= fixP->fx_size;
#ifdef TC_FIXUP_SYMBOL
		fixP->fx_offset += TC_FIXUP_SYMBOL(fixP, nsect, &fixP->fx_addsy);
		fixP->fx_offset -= TC_FIXUP_SYMBOL(fixP, nsect, &fixP->fx_subsy);
#endif
#if defined(I386) && defined(ARCH64)
		if(fixP->fx_addsy == fixP->fx_subsy){
			/*
			 * If we've fixed up both symbols to the same location,
			 * we don't need a relocation entry.
			 */
			fixP->fx_addsy = NULL;
			fixP->fx_subsy = NULL;
		}
#endif
	    add_symbolP = fixP->fx_addsy;
	    sub_symbolP = fixP->fx_subsy;
	    value  	= fixP->fx_offset;
	    pcrel       = fixP->fx_pcrel;

#if ARM
	    /* If the symbol is defined in this file, the linker won't set the
	       low-order bit for a Thumb symbol, so we have to do it here.  */
	    if(add_symbolP != NULL && add_symbolP->sy_desc & N_ARM_THUMB_DEF &&
	       !(sub_symbolP != NULL && sub_symbolP->sy_desc & N_ARM_THUMB_DEF) &&
	       !pcrel){
	        value |= 1;
	    }
#endif

	    add_symbol_N_TYPE = 0;
	    add_symbol_nsect = 0;

	    if(add_symbolP != NULL){
		add_symbol_N_TYPE = add_symbolP->sy_type & N_TYPE;
		if(add_symbol_N_TYPE == N_SECT)
		    add_symbol_nsect = add_symbolP->sy_other;
	    }

	    /*
	     * Is there a subtract symbol?
	     */
	    if(sub_symbolP){
		/* is it just -sym ? */
		if(add_symbolP == NULL){
		    if(sub_symbolP->sy_type != N_ABS)
			as_warn("Negative of non-absolute symbol %s",
				sub_symbolP->sy_name);
#if !(defined(I386) && defined(ARCH64))
			/* Symbol offsets are not part of fixups for x86_64. */
		    value -= sub_symbolP->sy_value;
#endif
		    fixP->fx_subsy = NULL;
		}
		/*
		 * There are both an add symbol and a subtract symbol at this
		 * point.
		 *
		 * If both symbols are absolute then just calculate the
		 * value of the fix expression and no relocation entry will be
		 * needed.
		 */
		else if((sub_symbolP->sy_type & N_TYPE) == N_ABS &&
		        (add_symbolP->sy_type & N_TYPE) == N_ABS){
		    value += add_symbolP->sy_value - sub_symbolP->sy_value;
		    add_symbolP = NULL;
		    fixP->fx_addsy = NULL; /* no relocation entry */
		    fixP->fx_subsy = NULL;
		}
		/*
		 * If both symbols are defined in a section then calculate the
		 * value of the fix expression and let a section difference
		 * relocation entry be created.
		 */
		else if((sub_symbolP->sy_type & N_TYPE) == N_SECT &&
		        (add_symbolP->sy_type & N_TYPE) == N_SECT){
		    /*
		     * We are use the new features that are incompatible with
		     * 3.2 then just calculate the value and let this create a
		     * SECTDIFF relocation type.
		     */
#ifdef SPARC
		    /*
		     * Special case dealing with assembler internal relocation
		     * entries SPARC_RELOC_13 and RELOC_22. The can not be
		     * output and must be resolved.
		     */
		    if((fixP->fx_r_type == SPARC_RELOC_13) ||
		       (fixP->fx_r_type == SPARC_RELOC_22)){
			if(sub_symbolP->sy_other == add_symbolP->sy_other){
			    value += add_symbolP->sy_value -
			    sub_symbolP->sy_value;
			    add_symbolP = NULL;
			    fixP->fx_addsy = NULL; /* no relocation entry */
			    fixP->fx_subsy = NULL;
			}
			else{
			    as_warn("Can't emit reloc type %u {-symbol \"%s\"} "
			            "@ file address %llu (mode?).",
				    fixP->fx_r_type, sub_symbolP->sy_name,
				    fragP->fr_address + where);
			}
		    }
		    else
			value += add_symbolP->sy_value - sub_symbolP->sy_value;
#else
#if !(defined(I386) && defined(ARCH64))
			/*
			 * Special case for x86_64.  'value' doesn't include
			 * the difference between the two symbols because
			 * that's handled by the subtractor/vanilla reloc pair.
			 */
		    value += add_symbolP->sy_value;
		    value -= sub_symbolP->sy_value;
#else
		    /*
		     * But for x86_64 expressions in the debug section must
		     * be the actual value of the expression.
		     */
		    if(is_section_debug(nsect)){
			value += add_symbolP->sy_value;
			value -= sub_symbolP->sy_value;
		    }
#endif
		    sub_symbol_nsect = sub_symbolP->sy_other;
		    /*
		     * If we have the special assembly time constant expression
		     * of the difference of two symbols defined in the same
		     * section then divided by exactly 2 adjust the value and
		     * make sure these symbols will produce an assembly time
		     * constant.
		     */
		    if(fixP->fx_sectdiff_divide_by_two == 1){
			value = value / 2;
			if(is_assembly_time_constant_subtraction_expression(
				add_symbolP, add_symbol_nsect,
				sub_symbolP, sub_symbol_nsect) == TRUE){
			    fixP->fx_addsy = NULL; /* no relocation entry */
			    goto down;
			}
			else{
			    layout_line = fixP->line;
			    layout_file = fixP->file;
			    as_warn("section difference divide by two "
				    "expression, \"%s\" minus \"%s\" divide by "
				    "2 will not produce an assembly time "
				    "constant", add_symbolP->sy_name,
				    sub_symbolP->sy_name);
			}
		    }
		    if(is_end_section_address(add_symbol_nsect,
					      add_symbolP->sy_value) ||
		       is_end_section_address(sub_symbol_nsect,
					      sub_symbolP->sy_value)){
			if(is_assembly_time_constant_subtraction_expression(
				add_symbolP, add_symbol_nsect,
				sub_symbolP, sub_symbol_nsect) == TRUE){
			    fixP->fx_addsy = NULL; /* no relocation entry */
			    goto down;
			}
			if(is_section_debug(nsect) &&
	   		   strcmp(add_symbolP->sy_name, FAKE_LABEL_NAME) == 0 &&
	   		   strcmp(sub_symbolP->sy_name, FAKE_LABEL_NAME) == 0){
			    fixP->fx_addsy = NULL; /* no relocation entry */
			    goto down;
			}
			layout_line = fixP->line;
			layout_file = fixP->file;
			as_warn("section difference relocatable subtraction "
				"expression, \"%s\" minus \"%s\" using a "
				"symbol at the end of section will not "
				"produce an assembly time constant",
				add_symbolP->sy_name, sub_symbolP->sy_name);
			as_warn("use a symbol with a constant value created "
				"with an assignment instead of the expression, "
				"L_const_sym = %s - %s", add_symbolP->sy_name,
				sub_symbolP->sy_name);
			layout_line = 0;
			layout_file = NULL;
		    }
#endif
		    goto down;
		}
		/*
		 * If the subtract symbol is absolute subtract it's value from
		 * the fix expression and let a relocation entry get created
		 * that is not a section difference type.
		 */
		else if(sub_symbolP->sy_type == N_ABS){
		    value -= sub_symbolP->sy_value;
		    fixP->fx_subsy = NULL; /* no SECTDIFF relocation entry */
		}
		/*
		 * At this point we have something we can't generate a
		 * relocation entry for (two undefined symbols, etc.).
		 */
	        else{
		     layout_line = fixP->line;
		     layout_file = fixP->file;
		     as_bad("non-relocatable subtraction expression, \"%s\" "
			     "minus \"%s\"", add_symbolP->sy_name,
			     sub_symbolP->sy_name);
		     if((add_symbolP->sy_type & N_TYPE) == N_UNDF)
			as_bad("symbol: \"%s\" can't be undefined in a "
				"subtraction expression", add_symbolP->sy_name);
		     if((sub_symbolP->sy_type & N_TYPE) == N_UNDF)
			as_bad("symbol: \"%s\" can't be undefined in a "
				"subtraction expression", sub_symbolP->sy_name);
		     layout_line = 0;
		     layout_file = NULL;
		}
	    }

	    /*
	     * If a there is an add symbol in the fixup expression then add
	     * the symbol value into the fixup expression's value.
	     */
	    if(add_symbolP){
		/*
		 * If this symbol is in this section and is pc-relative and we
		 * do not want to force a pc-relative relocation entry (to
		 * support scattered loading) then just calculate the value.
		 */
		if(add_symbol_nsect == nsect
		   /* FROM write.c line 2659 */
#ifdef ARM
		   && !TC_FORCE_RELOCATION_LOCAL (fixP)
#else
		   && pcrel
#endif
		   && !(fixP->fx_pcrel_reloc)){
		    /*
		     * This fixup was made when the symbol's section was
		     * unknown, but it is now in this section. So we know how
		     * to do the address without relocation.
		     */
		    value += add_symbolP->sy_value;
#ifdef ARM
		    /* FROM write.c line 2667 */
		    value -= MD_PCREL_FROM_SECTION (fixP, nsect);
#else
		    value -= size + where + fragP->fr_address;
#endif
		    pcrel = 0;	/* Lie. Don't want further pcrel processing. */
		    fixP->fx_addsy = NULL; /* No relocations please. */
		    /*
		     * It would be nice to check that the address does not
		     * overflow.
		     * I didn't do this check because:
		     * +  It is machine dependent in the general case (eg 32032)
		     * +  Compiler output will never need this checking, so why
		     *    slow down the usual case?
		     */
		}
		else{
		    switch(add_symbol_N_TYPE){
		    case N_ABS:
			/*
			 * If the value of the symbol was an expression then
			 * now evaluate the expression now.  This can happen
			 * when symbols like:
			 *	.set x,a-b
			 * are used and the value of x is not known till all
			 * of the symbols are seen and had their values set.
			 */
			if(add_symbolP->expression != NULL){
			    expressionS *exp;

			    exp = (expressionS *)add_symbolP->expression;
			    value +=
				exp->X_add_symbol->sy_value +
				exp->X_add_number -
				exp->X_subtract_symbol->sy_value;
			}
			else
			{
			    value += add_symbolP->sy_value;
			}
			fixP->fx_addsy = NULL; /* no relocation entry */
			add_symbolP = NULL;
			break;
			
		    case N_SECT:
#if (defined(I386) && defined(ARCH64))
			/*
			 * Symbol offsets are not part of fixups for external
			 * symbols for x86_64.
			 */
			if((is_section_debug(nsect) &&
			    add_symbol_N_TYPE != N_UNDF) ||
			   (add_symbol_N_TYPE == N_SECT &&
			    is_local_symbol(add_symbolP) &&
			    !is_section_cstring_literals(add_symbol_nsect)) )
#else
			if(((add_symbolP->sy_type & N_EXT) != N_EXT ||
			    add_symbol_N_TYPE != N_SECT ||
			    !is_section_coalesced(add_symbol_nsect)) &&
			   (add_symbolP->sy_desc & N_WEAK_DEF) != N_WEAK_DEF)
#endif
			    value += add_symbolP->sy_value;
			break;
			
		    case N_UNDF:
			break;
			
		    default:
			BAD_CASE(add_symbol_N_TYPE);
			break;
		    }
		}
	    }
down:
	    /*
	     * If the fixup expression is pc-relative then the value of the pc
	     * will be added to the expression when the machine executes the
	     * the instruction so we adjust the fixup expression's value by
	     * subtracting off the pc value (where) and adjust for insn size.
	     */
	    if(pcrel){
#ifdef ARM
	        /* This should work for both */
	        /* FROM write.c line 2688 */
		value -= MD_PCREL_FROM_SECTION (fixP, nsect);
#elif !(defined(I386) && defined(ARCH64))
		/* Symbol offsets are not part of fixups for x86_64. */
		value -= size + where + fragP->fr_address;
#endif
		if(add_symbolP == NULL){
		    fixP->fx_addsy = &abs_symbol; /* force relocation entry */
		}
	    }

	    if((size == 1 && (value & 0xffffff00) &&
			    ((value & 0xffffff80) != 0xffffff80)) ||
	       (size == 2 && (value & 0xffff0000) &&
			    ((value & 0xffff8000) != 0xffff8000))){
		layout_line = fixP->line;
		layout_file = fixP->file;
		as_bad("Fixup of %lld too large for field width of %d",
			value, size);
		layout_line = 0;
		layout_file = NULL;
	    }

	    /*
	     * Now place the fix expression's value in the place for the size.
	     * And save the fix expression's value to be used when creating
	     * a relocation entry if required.
	     */
	    md_number_to_imm((unsigned char *)place, value, size, fixP, nsect);
	    fixP->fx_value = value;

	    /*
	     * If this is a non-lazy pointer section and this fix is for a
	     * local symbol without an subtract symbol then cause this not to
	     * generate a relocation entry.  This is used with code gen for
	     * fix-n-continue where the compiler generates indirection for
	     * static data references.  So the assembly looks like this:
	     *
	     * 	.non_lazy_symbol_pointer
	     * 	L_i$non_lazy_ptr:
       	     * 	.indirect_symbol _i
       	     * 	.long   _i
	     *
	     * this allows the value of the symbol to be set into the pointer
	     * but not cause the relocation entry to be created.  The code in
	     * write_object() then changes the indirect symbol table entry to
	     * INDIRECT_SYMBOL_LOCAL when the symbol is local.  This is what
	     * the static and dynamic linkers expect and will then cause the
	     * pointer to be correctly relocated.
	     */
	    if(is_section_non_lazy_symbol_pointers(nsect) &&
	       (add_symbolP->sy_type & N_EXT) != N_EXT &&
	       sub_symbolP == NULL){
		fixP->fx_addsy = NULL; /* no relocation entry */
	    }
	}
}
Пример #25
0
/*
 * fixup_section() does the fixups of the frags and prepares the fixes so
 * relocation entries can be created from them.  The fixups cause the contents
 * of the frag to have the value for the fixup expression.  A fix structure that
 * ends up with a non NULL fx_addsy will have a relocation entry created for it.
 */
static
void
fixup_section(
fixS *fixP,
int nsect)
{
    symbolS *add_symbolP;
    symbolS *sub_symbolP;
    long value;
    int size;
    char *place;
    long where;
    char pcrel;
    fragS *fragP;
    int	add_symbol_N_TYPE;
    int	add_symbol_nsect;
#ifndef SPARC
    int sub_symbol_nsect;
#endif

	/*
	 * The general fix expression is "fx_addsy - fx_subsy + fx_offset".
	 * The goal is to put the result of this expression into the frag at
	 * "place" for size "size".  The value of the expression is calculated
	 * in the variable "value" and starts with just the fx_offset.
	 */
	for( ; fixP != NULL; 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;
	    sub_symbolP = fixP->fx_subsy;
	    value  	= fixP->fx_offset;
	    pcrel       = fixP->fx_pcrel;

	    add_symbol_N_TYPE = 0;
	    add_symbol_nsect = 0;

	    if(add_symbolP != NULL){
		add_symbol_N_TYPE = add_symbolP->sy_type & N_TYPE;
		if(add_symbol_N_TYPE == N_SECT)
		    add_symbol_nsect = add_symbolP->sy_other;
	    }

	    /*
	     * Is there a subtract symbol?
	     */
	    if(sub_symbolP){
		/* is it just -sym ? */
		if(add_symbolP == NULL){
		    if(sub_symbolP->sy_type != N_ABS)
			as_warn("Negative of non-absolute symbol %s",
				sub_symbolP->sy_name);
		    value -= sub_symbolP->sy_value;
		    fixP->fx_subsy = NULL;
		}
		/*
		 * There are both an add symbol and a subtract symbol at this
		 * point.
		 *
		 * If both symbols are absolute then just calculate the
		 * value of the fix expression and no relocation entry will be
		 * needed.
		 */
		else if((sub_symbolP->sy_type & N_TYPE) == N_ABS &&
		        (add_symbolP->sy_type & N_TYPE) == N_ABS){
		    value += add_symbolP->sy_value - sub_symbolP->sy_value;
		    add_symbolP = NULL;
		    fixP->fx_addsy = NULL; /* no relocation entry */
		    fixP->fx_subsy = NULL;
		}
		/*
		 * If both symbols are defined in a section then calculate the
		 * value of the fix expression and let a section difference
		 * relocation entry be created.
		 */
		else if((sub_symbolP->sy_type & N_TYPE) == N_SECT &&
		        (add_symbolP->sy_type & N_TYPE) == N_SECT){
		    /*
		     * We are use the new features that are incompatible with
		     * 3.2 then just calculate the value and let this create a
		     * SECTDIFF relocation type.
		     */
#ifdef SPARC
		    /*
		     * Special case dealing with assembler internal relocation
		     * entries SPARC_RELOC_13 and RELOC_22. The can not be
		     * output and must be resolved.
		     */
		    if((fixP->fx_r_type == SPARC_RELOC_13) ||
		       (fixP->fx_r_type == SPARC_RELOC_22)){
			if(sub_symbolP->sy_other == add_symbolP->sy_other){
			    value += add_symbolP->sy_value -
			    sub_symbolP->sy_value;
			    add_symbolP = NULL;
			    fixP->fx_addsy = NULL; /* no relocation entry */
			    fixP->fx_subsy = NULL;
			}
			else{
			    as_warn("Can't emit reloc type %u {-symbol \"%s\"} "
			            "@ file address %ld (mode?).",
				    fixP->fx_r_type, sub_symbolP->sy_name,
				    fragP->fr_address + where);
			}
		    }
		    else
			value += add_symbolP->sy_value - sub_symbolP->sy_value;
#else
		    value += add_symbolP->sy_value - sub_symbolP->sy_value;
		    sub_symbol_nsect = sub_symbolP->sy_other;
		    if(is_end_section_address(add_symbol_nsect,
					      add_symbolP->sy_value) ||
		       is_end_section_address(sub_symbol_nsect,
					      sub_symbolP->sy_value)){
			layout_line = fixP->line;
			layout_file = fixP->file;
			as_warn("section difference relocatable subtraction "
				"expression, \"%s\" minus \"%s\" using a "
				"symbol at the end of section will not "
				"produce an assembly time constant",
				add_symbolP->sy_name, sub_symbolP->sy_name);
			as_warn("use a symbol with a constant value created "
				"with an assignment instead of the expression, "
				"L_const_sym = %s - %s", add_symbolP->sy_name,
				sub_symbolP->sy_name);
			layout_line = 0;
			layout_file = NULL;
		    }
#endif
		    goto down;
		}
		/*
		 * If the subtract symbol is absolute subtract it's value from
		 * the fix expression and let a relocation entry get created
		 * that is not a section difference type.
		 */
		else if(sub_symbolP->sy_type == N_ABS){
		    value -= sub_symbolP->sy_value;
		    fixP->fx_subsy = NULL; /* no SECTDIFF relocation entry */
		}
		/*
		 * At this point we have something we can't generate a
		 * relocation entry for (two undefined symbols, etc.).
		 */
	        else{
		     layout_line = fixP->line;
		     layout_file = fixP->file;
		     as_warn("non-relocatable subtraction expression, \"%s\" "
			     "minus \"%s\"", add_symbolP->sy_name,
			     sub_symbolP->sy_name);
		     if((add_symbolP->sy_type & N_TYPE) == N_UNDF)
			as_warn("symbol: \"%s\" can't be undefined in a "
				"subtraction expression", add_symbolP->sy_name);
		     if((sub_symbolP->sy_type & N_TYPE) == N_UNDF)
			as_warn("symbol: \"%s\" can't be undefined in a "
				"subtraction expression", sub_symbolP->sy_name);
		     layout_line = 0;
		     layout_file = NULL;
		}
	    }

	    /*
	     * If a there is an add symbol in the fixup expression then add
	     * the symbol value into the fixup expression's value.
	     */
	    if(add_symbolP){
		/*
		 * If this symbol is in this section and is pc-relative and we
		 * do not want to force a pc-relative relocation entry (to
		 * support scattered loading) then just calculate the value.
		 */
		if(add_symbol_nsect == nsect &&
		   pcrel && !(fixP->fx_pcrel_reloc)){
		    /*
		     * This fixup was made when the symbol's section was
		     * unknown, but it is now in this section. So we know how
		     * to do the address without relocation.
		     */
		    value += add_symbolP->sy_value;
		    value -= size + where + fragP->fr_address;
		    pcrel = 0;	/* Lie. Don't want further pcrel processing. */
		    fixP->fx_addsy = NULL; /* No relocations please. */
		    /*
		     * It would be nice to check that the address does not
		     * overflow.
		     * I didn't do this check because:
		     * +  It is machine dependent in the general case (eg 32032)
		     * +  Compiler output will never need this checking, so why
		     *    slow down the usual case?
		     */
		}
		else{
		    switch(add_symbol_N_TYPE){
		    case N_ABS:
			/*
			 * If the value of the symbol was an expression then
			 * now evaluate the expression now.  This can happen
			 * when symbols like:
			 *	.set x,a-b
			 * are used and the value of x is not known till all
			 * of the symbols are seen and had their values set.
			 */
			if(add_symbolP->expression != NULL){
			    expressionS *exp;

			    exp = (expressionS *)add_symbolP->expression;
			    value +=
				exp->X_add_symbol->sy_value -
				exp->X_subtract_symbol->sy_value;
			}
			else
			    value += add_symbolP->sy_value;
			fixP->fx_addsy = NULL; /* no relocation entry */
			add_symbolP = NULL;
			break;
			
		    case N_SECT:
			if((add_symbolP->sy_type & N_EXT) != N_EXT ||
			   add_symbol_N_TYPE != N_SECT ||
			   !is_section_coalesced(add_symbol_nsect))
			    value += add_symbolP->sy_value;
			break;
			
		    case N_UNDF:
			break;
			
		    default:
			BAD_CASE(add_symbol_N_TYPE);
			break;
		    }
		}
	    }
down:
	    /*
	     * If the fixup expression is pc-relative then the value of the pc
	     * will be added to the expression when the machine executes the
	     * the instruction so we adjust the fixup expression's value by
	     * subtracting off the pc value (where) and adjust for insn size.
	     */
	    if(pcrel){
		value -= size + where + fragP->fr_address;
		if(add_symbolP == NULL){
		    fixP->fx_addsy = &abs_symbol; /* force relocation entry */
		}
	    }

	    if((size == 1 && (value & 0xffffff00) &&
			    ((value & 0xffffff80) != 0xffffff80)) ||
	       (size == 2 && (value & 0xffff8000) &&
			    ((value & 0xffff8000) != 0xffff8000)))
		as_warn("Fixup of %ld too large for field width of %d",
			value, size);

	    /*
	     * Now place the fix expression's value in the place for the size.
	     * And save the fix expression's value to be used when creating
	     * a relocation entry if required.
	     */
	    md_number_to_imm((unsigned char *)place, value, size, fixP, nsect);
	    fixP->fx_value = value;

	    /*
	     * If this is a non-lazy pointer section and this fix is for a
	     * local symbol without an subtract symbol then cause this not to
	     * generate a relocation entry.  This is used with code gen for
	     * fix-n-continue where the compiler generates indirection for
	     * static data references.  So the assembly looks like this:
	     *
	     * 	.non_lazy_symbol_pointer
	     * 	L_i$non_lazy_ptr:
       	     * 	.indirect_symbol _i
       	     * 	.long   _i
	     *
	     * this allows the value of the symbol to be set into the pointer
	     * but not cause the relocation entry to be created.  The code in
	     * write_object() then changes the indirect symbol table entry to
	     * INDIRECT_SYMBOL_LOCAL when the symbol is local.  This is what
	     * the static and dynamic linkers expect and will then cause the
	     * pointer to be correctly relocated.
	     */
	    if(is_section_non_lazy_symbol_pointers(nsect) &&
	       (add_symbolP->sy_type & N_EXT) != N_EXT &&
	       sub_symbolP == NULL){
		fixP->fx_addsy = NULL; /* no relocation entry */
	    }
	}
}