old-cross-binutils/gas/config/obj-coff.c
Ken Raeburn 71b4de6fb8 * config/obj-coff.h, config/obj-coff.c: Deleted all code used only when
BFD_ASSEMBLER is not defined, and all conditionals relating to such code.  No
such targets remain.

Fixes for stabs-in-coff:
* config/obj-coff.c: Include subsegs.h.
(coff_frob_section): New function.
(obj_coff_init_stab_section): New function.
* config/obj-coff.h (obj_coff_init_stab_section, coff_frob_section): Declare.
(obj_frob_section): New macro; uses coff_frob_section.
(INIT_STAB_SECTION): New macro; uses obj_coff_init_stab_section.
1994-04-20 23:01:40 +00:00

1273 lines
31 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* coff object file format
Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994
Free Software Foundation, Inc.
This file is part of GAS.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "as.h"
#include "subsegs.h"
#include "obstack.h"
const char *s_get_name PARAMS ((symbolS * s));
static symbolS *tag_find_or_make PARAMS ((char *name));
static symbolS *tag_find PARAMS ((char *name));
static void obj_coff_def PARAMS ((int what));
static void obj_coff_dim PARAMS ((int));
static void obj_coff_endef PARAMS ((int));
static void obj_coff_line PARAMS ((int));
static void obj_coff_ln PARAMS ((int));
static void obj_coff_scl PARAMS ((int));
static void obj_coff_size PARAMS ((int));
static void obj_coff_tag PARAMS ((int));
static void obj_coff_type PARAMS ((int));
static void obj_coff_val PARAMS ((int));
static void tag_init PARAMS ((void));
static void tag_insert PARAMS ((const char *name, symbolS * symbolP));
static void SA_SET_SYM_TAGNDX PARAMS ((symbolS *, symbolS *));
static struct hash_control *tag_hash;
static symbolS *def_symbol_in_progress;
const pseudo_typeS obj_pseudo_table[] =
{
#ifndef IGNORE_DEBUG
{"def", obj_coff_def, 0},
{"dim", obj_coff_dim, 0},
{"endef", obj_coff_endef, 0},
{"line", obj_coff_line, 0},
{"ln", obj_coff_ln, 0},
{"appline", obj_coff_ln, 1},
{"scl", obj_coff_scl, 0},
{"size", obj_coff_size, 0},
{"tag", obj_coff_tag, 0},
{"type", obj_coff_type, 0},
{"val", obj_coff_val, 0},
#else
{"def", s_ignore, 0},
{"dim", s_ignore, 0},
{"endef", s_ignore, 0},
{"line", s_ignore, 0},
{"ln", s_ignore, 0},
{"scl", s_ignore, 0},
{"size", s_ignore, 0},
{"tag", s_ignore, 0},
{"type", s_ignore, 0},
{"val", s_ignore, 0},
#endif /* ignore debug */
{ "section", obj_coff_section, 0 },
{"ident", s_ignore, 0}, /* we don't yet handle this. */
{"optim", s_ignore, 0}, /* For sun386i cc (?) */
/* other stuff */
{"ABORT", s_abort, 0},
{NULL} /* end sentinel */
}; /* obj_pseudo_table */
struct line_no {
struct line_no *next;
fragS *frag;
alent l;
};
#define GET_FILENAME_STRING(X) \
((char*)(&((X)->sy_symbol.ost_auxent->x_file.x_n.x_offset))[1])
/* @@ Ick. */
static segT
fetch_coff_debug_section ()
{
static segT debug_section;
if (!debug_section)
{
CONST asymbol *s;
s = bfd_make_debug_symbol (stdoutput, (char *) 0, 0);
assert (s != 0);
debug_section = s->section;
}
return debug_section;
}
void
SA_SET_SYM_ENDNDX (sym, val)
symbolS *sym;
symbolS *val;
{
combined_entry_type *entry, *p;
entry = &coffsymbol (sym->bsym)->native[1];
p = coffsymbol (val->bsym)->native;
entry->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = p;
entry->fix_end = 1;
}
static void
SA_SET_SYM_TAGNDX (sym, val)
symbolS *sym;
symbolS *val;
{
combined_entry_type *entry, *p;
entry = &coffsymbol (sym->bsym)->native[1];
p = coffsymbol (val->bsym)->native;
entry->u.auxent.x_sym.x_tagndx.p = p;
entry->fix_tag = 1;
}
static int
S_GET_DATA_TYPE (sym)
symbolS *sym;
{
return coffsymbol (sym->bsym)->native->u.syment.n_type;
}
int
S_SET_DATA_TYPE (sym, val)
symbolS *sym;
int val;
{
coffsymbol (sym->bsym)->native->u.syment.n_type = val;
return val;
}
int
S_GET_STORAGE_CLASS (sym)
symbolS *sym;
{
return coffsymbol (sym->bsym)->native->u.syment.n_sclass;
}
int
S_SET_STORAGE_CLASS (sym, val)
symbolS *sym;
int val;
{
coffsymbol (sym->bsym)->native->u.syment.n_sclass = val;
return val;
}
/* Merge a debug symbol containing debug information into a normal symbol. */
void
c_symbol_merge (debug, normal)
symbolS *debug;
symbolS *normal;
{
S_SET_DATA_TYPE (normal, S_GET_DATA_TYPE (debug));
S_SET_STORAGE_CLASS (normal, S_GET_STORAGE_CLASS (debug));
if (S_GET_NUMBER_AUXILIARY (debug) > S_GET_NUMBER_AUXILIARY (normal))
/* take the most we have */
S_SET_NUMBER_AUXILIARY (normal, S_GET_NUMBER_AUXILIARY (debug));
if (S_GET_NUMBER_AUXILIARY (debug) > 0)
{
/* Move all the auxiliary information. */
/* @@ How many fields do we want to preserve? Would it make more
sense to pick and choose those we want to copy? Should look
into this further.... [raeburn:19920512.2209EST] */
alent *linenos;
linenos = coffsymbol (normal->bsym)->lineno;
memcpy ((char *) &coffsymbol (normal->bsym)->native,
(char *) &coffsymbol (debug->bsym)->native,
S_GET_NUMBER_AUXILIARY(debug) * AUXESZ);
coffsymbol (normal->bsym)->lineno = linenos;
}
/* Move the debug flags. */
SF_SET_DEBUG_FIELD (normal, SF_GET_DEBUG_FIELD (debug));
}
static symbolS *previous_file_symbol;
void
c_dot_file_symbol (filename)
char *filename;
{
symbolS *symbolP;
symbolP = symbol_new (filename, &bfd_abs_section, 0,
&zero_address_frag);
S_SET_STORAGE_CLASS (symbolP, C_FILE);
S_SET_NUMBER_AUXILIARY (symbolP, 1);
symbolP->bsym->flags = BSF_DEBUGGING;
#ifndef NO_LISTING
{
extern int listing;
if (listing)
{
listing_source_file (filename);
}
}
#endif
S_SET_VALUE (symbolP, (long) previous_file_symbol);
previous_file_symbol = symbolP;
/* Make sure that the symbol is first on the symbol chain */
if (symbol_rootP != symbolP)
{
if (symbolP == symbol_lastP)
{
symbol_lastP = symbol_lastP->sy_previous;
} /* if it was the last thing on the list */
symbol_remove (symbolP, &symbol_rootP, &symbol_lastP);
symbol_insert (symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP);
symbol_rootP = symbolP;
} /* if not first on the list */
}
/*
* Build a 'section static' symbol.
*/
char *
c_section_symbol (name, value, length, nreloc, nlnno)
char *name;
long value;
long length;
unsigned short nreloc;
unsigned short nlnno;
{
symbolS *symbolP;
symbolP = symbol_new (name,
(name[1] == 't'
? text_section
: name[1] == 'd'
? data_section
: bss_section),
value,
&zero_address_frag);
S_SET_STORAGE_CLASS (symbolP, C_STAT);
S_SET_NUMBER_AUXILIARY (symbolP, 1);
SA_SET_SCN_SCNLEN (symbolP, length);
SA_SET_SCN_NRELOC (symbolP, nreloc);
SA_SET_SCN_NLINNO (symbolP, nlnno);
SF_SET_STATICS (symbolP);
return (char *) symbolP;
}
/* Line number handling */
int coff_line_base;
/* Symbol of last function, which we should hang line#s off of. */
static symbolS *line_fsym;
#define in_function() (line_fsym != 0)
#define clear_function() (line_fsym = 0)
#define set_function(F) (line_fsym = (F), coff_add_linesym (F))
void
obj_symbol_new_hook (symbolP)
symbolS *symbolP;
{
char underscore = 0; /* Symbol has leading _ */
{
long sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type);
char *s = (char *) bfd_alloc_by_size_t (stdoutput, sz);
memset (s, 0, sz);
coffsymbol (symbolP->bsym)->native = (combined_entry_type *) s;
}
S_SET_DATA_TYPE (symbolP, T_NULL);
S_SET_STORAGE_CLASS (symbolP, 0);
S_SET_NUMBER_AUXILIARY (symbolP, 0);
#ifdef STRIP_UNDERSCORE
/* Remove leading underscore at the beginning of the symbol.
This is to be compatible with the standard librairies. */
if (*S_GET_NAME (symbolP) == '_')
{
underscore = 1;
S_SET_NAME (symbolP, S_GET_NAME (symbolP) + 1);
}
#endif /* STRIP_UNDERSCORE */
if (S_IS_STRING (symbolP))
SF_SET_STRING (symbolP);
if (!underscore && S_IS_LOCAL (symbolP))
SF_SET_LOCAL (symbolP);
}
/* stack stuff */
stack *
stack_init (chunk_size, element_size)
unsigned long chunk_size;
unsigned long element_size;
{
stack *st;
st = (stack *) malloc (sizeof (stack));
if (!st)
return 0;
st->data = malloc (chunk_size);
if (!st->data)
{
free (st);
return 0;
}
st->pointer = 0;
st->size = chunk_size;
st->chunk_size = chunk_size;
st->element_size = element_size;
return st;
}
void
stack_delete (st)
stack *st;
{
free (st->data);
free (st);
}
char *
stack_push (st, element)
stack *st;
char *element;
{
if (st->pointer + st->element_size >= st->size)
{
st->size += st->chunk_size;
if ((st->data = xrealloc (st->data, st->size)) == (char *) 0)
return (char *) 0;
}
memcpy (st->data + st->pointer, element, st->element_size);
st->pointer += st->element_size;
return st->data + st->pointer;
}
char *
stack_pop (st)
stack *st;
{
if (st->pointer < st->element_size)
{
st->pointer = 0;
return (char *) 0;
}
st->pointer -= st->element_size;
return st->data + st->pointer;
}
char *
stack_top (st)
stack *st;
{
return st->data + st->pointer - st->element_size;
}
/*
* Handle .ln directives.
*/
static symbolS *current_lineno_sym;
static struct line_no *line_nos;
static void
add_lineno (frag, offset, num)
fragS *frag;
int offset;
int num;
{
struct line_no *new_line = (struct line_no *) bfd_alloc_by_size_t (stdoutput,
sizeof (struct line_no));
if (!current_lineno_sym)
{
abort ();
}
new_line->next = line_nos;
new_line->frag = frag;
new_line->l.line_number = num;
new_line->l.u.offset = offset;
line_nos = new_line;
}
void
coff_add_linesym (sym)
symbolS *sym;
{
if (line_nos)
{
add_lineno (0, 0, 0);
coffsymbol (current_lineno_sym->bsym)->lineno = (alent *) line_nos;
line_nos = 0;
}
current_lineno_sym = sym;
}
static void
obj_coff_ln (appline)
int appline;
{
int l;
if (! appline && def_symbol_in_progress != NULL)
{
as_warn (".ln pseudo-op inside .def/.endef: ignored.");
demand_empty_rest_of_line ();
return;
}
l = get_absolute_expression ();
if (!appline)
{
add_lineno (frag_now, frag_now_fix (), l);
}
#ifndef NO_LISTING
{
extern int listing;
if (listing)
{
if (! appline)
l += coff_line_base - 1;
listing_source_line (l);
}
}
#endif
demand_empty_rest_of_line ();
}
/*
* def()
*
* Handle .def directives.
*
* One might ask : why can't we symbol_new if the symbol does not
* already exist and fill it with debug information. Because of
* the C_EFCN special symbol. It would clobber the value of the
* function symbol before we have a chance to notice that it is
* a C_EFCN. And a second reason is that the code is more clear this
* way. (at least I think it is :-).
*
*/
#define SKIP_SEMI_COLON() while (*input_line_pointer++ != ';')
#define SKIP_WHITESPACES() while (*input_line_pointer == ' ' || \
*input_line_pointer == '\t') \
input_line_pointer++;
static void
obj_coff_def (what)
int what;
{
char name_end; /* Char after the end of name */
char *symbol_name; /* Name of the debug symbol */
char *symbol_name_copy; /* Temporary copy of the name */
unsigned int symbol_name_length;
if (def_symbol_in_progress != NULL)
{
as_warn (".def pseudo-op used inside of .def/.endef: ignored.");
demand_empty_rest_of_line ();
return;
} /* if not inside .def/.endef */
SKIP_WHITESPACES ();
symbol_name = input_line_pointer;
#ifdef STRIP_UNDERSCORE
if (symbol_name[0] == '_' && symbol_name[1] != 0)
symbol_name++;
#endif /* STRIP_UNDERSCORE */
name_end = get_symbol_end ();
symbol_name_length = strlen (symbol_name);
symbol_name_copy = xmalloc (symbol_name_length + 1);
strcpy (symbol_name_copy, symbol_name);
/* Initialize the new symbol */
def_symbol_in_progress = symbol_make (symbol_name_copy);
def_symbol_in_progress->sy_frag = &zero_address_frag;
S_SET_VALUE (def_symbol_in_progress, 0);
if (S_IS_STRING (def_symbol_in_progress))
SF_SET_STRING (def_symbol_in_progress);
*input_line_pointer = name_end;
demand_empty_rest_of_line ();
}
unsigned int dim_index;
static void
obj_coff_endef (ignored)
int ignored;
{
symbolS *symbolP;
/* DIM BUG FIX sac@cygnus.com */
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;
} /* if not inside .def/.endef */
/* 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);
/* intentional fallthrough */
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. */
/* intentional fallthrough */
case C_BLOCK:
SF_SET_PROCESS (def_symbol_in_progress); /* Will need processing before writing */
/* intentional fallthrough */
case C_FCN:
{
CONST char *name;
S_SET_SEGMENT (def_symbol_in_progress, text_section);
name = bfd_asymbol_name (def_symbol_in_progress->bsym);
if (name[1] == 'b' && name[2] == 'f')
{
if (! in_function ())
as_warn ("`%s' symbol without preceding function", name);
/* SA_SET_SYM_LNNO (def_symbol_in_progress, 12345);*/
/* Will need relocating */
SF_SET_PROCESS (def_symbol_in_progress);
clear_function ();
}
}
break;
#ifdef C_AUTOARG
case C_AUTOARG:
#endif /* C_AUTOARG */
case C_AUTO:
case C_REG:
case C_MOS:
case C_MOE:
case C_MOU:
case C_ARG:
case C_REGPARM:
case C_FIELD:
case C_EOS:
SF_SET_DEBUG (def_symbol_in_progress);
S_SET_SEGMENT (def_symbol_in_progress, absolute_section);
break;
case C_EXT:
case C_STAT:
case C_LABEL:
/* Valid but set somewhere else (s_comm, s_lcomm, colon) */
break;
case C_USTATIC:
case C_EXTDEF:
case C_ULABEL:
as_warn ("unexpected storage class %d",
S_GET_STORAGE_CLASS (def_symbol_in_progress));
break;
} /* switch on storage class */
/* 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
SEG_ABSOLUTE or untagged SEG_DEBUG it never merges. */
/* 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
|| (!strcmp (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
|| (symbolP = symbol_find_base (S_GET_NAME (def_symbol_in_progress), DO_NOT_STRIP)) == NULL)
{
if (def_symbol_in_progress != 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);
/* FIXME-SOON Should *def_symbol_in_progress be free'd? xoxorich. */
def_symbol_in_progress = symbolP;
if (SF_GET_FUNCTION (def_symbol_in_progress)
|| SF_GET_TAG (def_symbol_in_progress))
{
/* For functions, and tags, 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)
&& symbol_find_base (S_GET_NAME (def_symbol_in_progress), DO_NOT_STRIP) == NULL)
{
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);
} /* definition follows debug */
} /* Create the line number entry pointing to the function being defined */
def_symbol_in_progress = NULL;
demand_empty_rest_of_line ();
}
static void
obj_coff_dim (ignored)
int ignored;
{
int dim_index;
if (def_symbol_in_progress == NULL)
{
as_warn (".dim pseudo-op used outside of .def/.endef: ignored.");
demand_empty_rest_of_line ();
return;
} /* if not inside .def/.endef */
S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
for (dim_index = 0; dim_index < DIMNUM; dim_index++)
{
SKIP_WHITESPACES ();
SA_SET_SYM_DIMEN (def_symbol_in_progress, dim_index,
get_absolute_expression ());
switch (*input_line_pointer)
{
case ',':
input_line_pointer++;
break;
default:
as_warn ("badly formed .dim directive ignored");
/* intentional fallthrough */
case '\n':
case ';':
dim_index = DIMNUM;
break;
}
}
demand_empty_rest_of_line ();
}
static void
obj_coff_line (ignored)
int ignored;
{
int this_base;
if (def_symbol_in_progress == NULL)
{
/* Probably stabs-style line? */
obj_coff_ln (0);
return;
}
this_base = get_absolute_expression ();
if (this_base > coff_line_base)
coff_line_base = this_base;
S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
SA_SET_SYM_LNNO (def_symbol_in_progress, coff_line_base);
demand_empty_rest_of_line ();
}
static void
obj_coff_size (ignored)
int ignored;
{
if (def_symbol_in_progress == NULL)
{
as_warn (".size pseudo-op used outside of .def/.endef ignored.");
demand_empty_rest_of_line ();
return;
} /* if not inside .def/.endef */
S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
SA_SET_SYM_SIZE (def_symbol_in_progress, get_absolute_expression ());
demand_empty_rest_of_line ();
}
static void
obj_coff_scl (ignored)
int ignored;
{
if (def_symbol_in_progress == NULL)
{
as_warn (".scl pseudo-op used outside of .def/.endef ignored.");
demand_empty_rest_of_line ();
return;
} /* if not inside .def/.endef */
S_SET_STORAGE_CLASS (def_symbol_in_progress, get_absolute_expression ());
demand_empty_rest_of_line ();
}
static void
obj_coff_tag (ignored)
int ignored;
{
char *symbol_name;
char name_end;
if (def_symbol_in_progress == NULL)
{
as_warn (".tag pseudo-op used outside of .def/.endef ignored.");
demand_empty_rest_of_line ();
return;
}
S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
symbol_name = input_line_pointer;
name_end = get_symbol_end ();
/* Assume that the symbol referred to by .tag is always defined.
This was a bad assumption. I've added find_or_make. xoxorich. */
SA_SET_SYM_TAGNDX (def_symbol_in_progress,
tag_find_or_make (symbol_name));
if (SA_GET_SYM_TAGNDX (def_symbol_in_progress) == 0L)
{
as_warn ("tag not found for .tag %s", symbol_name);
} /* not defined */
SF_SET_TAGGED (def_symbol_in_progress);
*input_line_pointer = name_end;
demand_empty_rest_of_line ();
}
static void
obj_coff_type (ignored)
int ignored;
{
if (def_symbol_in_progress == NULL)
{
as_warn (".type pseudo-op used outside of .def/.endef ignored.");
demand_empty_rest_of_line ();
return;
} /* if not inside .def/.endef */
S_SET_DATA_TYPE (def_symbol_in_progress, get_absolute_expression ());
if (ISFCN (S_GET_DATA_TYPE (def_symbol_in_progress)) &&
S_GET_STORAGE_CLASS (def_symbol_in_progress) != C_TPDEF)
{
SF_SET_FUNCTION (def_symbol_in_progress);
} /* is a function */
demand_empty_rest_of_line ();
}
static void
obj_coff_val (ignored)
int ignored;
{
if (def_symbol_in_progress == NULL)
{
as_warn (".val pseudo-op used outside of .def/.endef ignored.");
demand_empty_rest_of_line ();
return;
} /* if not inside .def/.endef */
if (is_name_beginner (*input_line_pointer))
{
char *symbol_name = input_line_pointer;
char name_end = get_symbol_end ();
if (!strcmp (symbol_name, "."))
{
def_symbol_in_progress->sy_frag = frag_now;
S_SET_VALUE (def_symbol_in_progress, obstack_next_free (&frags) - frag_now->fr_literal);
/* If the .val is != from the .def (e.g. statics) */
}
else if (strcmp (S_GET_NAME (def_symbol_in_progress), symbol_name))
{
def_symbol_in_progress->sy_value.X_op = O_symbol;
def_symbol_in_progress->sy_value.X_add_symbol =
symbol_find_or_make (symbol_name);
def_symbol_in_progress->sy_value.X_op_symbol = NULL;
def_symbol_in_progress->sy_value.X_add_number = 0;
/* If the segment is undefined when the forward reference is
resolved, then copy the segment id from the forward
symbol. */
SF_SET_GET_SEGMENT (def_symbol_in_progress);
}
/* Otherwise, it is the name of a non debug symbol and its value will be calculated later. */
*input_line_pointer = name_end;
}
else
{
S_SET_VALUE (def_symbol_in_progress, get_absolute_expression ());
} /* if symbol based */
demand_empty_rest_of_line ();
}
/*
* Maintain a list of the tagnames of the structres.
*/
static void
tag_init ()
{
tag_hash = hash_new ();
}
static void
tag_insert (name, symbolP)
const char *name;
symbolS *symbolP;
{
const char *error_string;
if ((error_string = hash_jam (tag_hash, name, (char *) symbolP)))
{
as_fatal ("Inserting \"%s\" into structure table failed: %s",
name, error_string);
}
}
static symbolS *
tag_find_or_make (name)
char *name;
{
symbolS *symbolP;
if ((symbolP = tag_find (name)) == NULL)
{
symbolP = symbol_new (name, undefined_section,
0, &zero_address_frag);
tag_insert (S_GET_NAME (symbolP), symbolP);
symbol_table_insert (symbolP);
} /* not found */
return symbolP;
}
static symbolS *
tag_find (name)
char *name;
{
#ifdef STRIP_UNDERSCORE
if (*name == '_')
name++;
#endif /* STRIP_UNDERSCORE */
return (symbolS *) hash_find (tag_hash, name);
}
void
obj_read_begin_hook ()
{
/* These had better be the same. Usually 18 bytes. */
#ifndef BFD_HEADERS
know (sizeof (SYMENT) == sizeof (AUXENT));
know (SYMESZ == AUXESZ);
#endif
tag_init ();
}
symbolS *coff_last_function;
void
coff_frob_symbol (symp, punt)
symbolS *symp;
int *punt;
{
static symbolS *last_tagP;
static stack *block_stack;
static symbolS *set_end;
if (symp == &abs_symbol)
{
*punt = 1;
return;
}
if (current_lineno_sym)
coff_add_linesym ((symbolS *) 0);
if (!block_stack)
block_stack = stack_init (512, sizeof (symbolS*));
if (!S_IS_DEFINED (symp) && S_GET_STORAGE_CLASS (symp) != C_STAT)
S_SET_STORAGE_CLASS (symp, C_EXT);
if (!SF_GET_DEBUG (symp))
{
symbolS *real;
if (!SF_GET_LOCAL (symp)
&& (real = symbol_find_base (S_GET_NAME (symp), DO_NOT_STRIP))
&& real != symp)
{
c_symbol_merge (symp, real);
*punt = 1;
}
if (!S_IS_DEFINED (symp) && !SF_GET_LOCAL (symp))
{
assert (S_GET_VALUE (symp) == 0);
S_SET_EXTERNAL (symp);
}
else if (S_GET_STORAGE_CLASS (symp) == C_NULL)
{
if (S_GET_SEGMENT (symp) == text_section)
S_SET_STORAGE_CLASS (symp, C_LABEL);
else
S_SET_STORAGE_CLASS (symp, C_STAT);
}
if (SF_GET_PROCESS (symp))
{
if (S_GET_STORAGE_CLASS (symp) == C_BLOCK)
{
if (!strcmp (S_GET_NAME (symp), ".bb"))
stack_push (block_stack, (char *) &symp);
else
{
symbolS *begin;
begin = *(symbolS **) stack_pop (block_stack);
if (begin == 0)
as_warn ("mismatched .eb");
else
set_end = begin;
}
}
if (coff_last_function == 0 && SF_GET_FUNCTION (symp))
{
union internal_auxent *auxp;
coff_last_function = symp;
if (S_GET_NUMBER_AUXILIARY (symp) < 1)
S_SET_NUMBER_AUXILIARY (symp, 1);
auxp = &coffsymbol (symp->bsym)->native[1].u.auxent;
memset (auxp->x_sym.x_fcnary.x_ary.x_dimen, 0,
sizeof (auxp->x_sym.x_fcnary.x_ary.x_dimen));
}
if (S_GET_STORAGE_CLASS (symp) == C_EFCN)
{
if (coff_last_function == 0)
as_fatal ("C_EFCN symbol out of scope");
SA_SET_SYM_FSIZE (coff_last_function,
(long) (S_GET_VALUE (symp)
- S_GET_VALUE (coff_last_function)));
set_end = coff_last_function;
coff_last_function = 0;
}
}
else if (SF_GET_TAG (symp))
last_tagP = symp;
else if (S_GET_STORAGE_CLASS (symp) == C_EOS)
set_end = last_tagP;
else if (S_GET_STORAGE_CLASS (symp) == C_FILE)
{
if (S_GET_VALUE (symp))
{
S_SET_VALUE ((symbolS *) S_GET_VALUE (symp), 0xdeadbeef);
S_SET_VALUE (symp, 0);
}
}
if (S_IS_EXTERNAL (symp))
S_SET_STORAGE_CLASS (symp, C_EXT);
else if (SF_GET_LOCAL (symp))
*punt = 1;
/* more ... */
}
if (set_end != (symbolS *) NULL
&& ! *punt)
{
SA_SET_SYM_ENDNDX (set_end, symp);
set_end = NULL;
}
if (coffsymbol (symp->bsym)->lineno)
{
int i, n;
struct line_no *lptr;
alent *l;
lptr = (struct line_no *) coffsymbol (symp->bsym)->lineno;
for (i = 0; lptr; lptr = lptr->next)
i++;
n = i + 1;
lptr = (struct line_no *) coffsymbol (symp->bsym)->lineno;
l = (alent *) bfd_alloc_by_size_t (stdoutput, n * sizeof (alent));
coffsymbol (symp->bsym)->lineno = l;
for (i = n - 1; i > 0; i--)
{
if (lptr->frag)
lptr->l.u.offset += lptr->frag->fr_address;
l[i] = lptr->l;
lptr = lptr->next;
}
}
}
/*
* implement the .section pseudo op:
* .section name {, "flags"}
* ^ ^
* | +--- optional flags: 'b' for bss
* | 'i' for info
* +-- section name 'l' for lib
* 'n' for noload
* 'o' for over
* 'w' for data
* 'd' (apparently m88k for data)
* 'x' for text
* But if the argument is not a quoted string, treat it as a
* subsegment number.
*/
void
obj_coff_section (ignore)
int ignore;
{
/* Strip out the section name */
char *section_name;
char c;
char *name;
unsigned int exp;
flagword flags;
asection *sec;
section_name = input_line_pointer;
c = get_symbol_end ();
name = xmalloc (input_line_pointer - section_name + 1);
strcpy (name, section_name);
*input_line_pointer = c;
SKIP_WHITESPACE ();
exp = 0;
flags = SEC_NO_FLAGS;
if (*input_line_pointer == ',')
{
++input_line_pointer;
SKIP_WHITESPACE ();
if (*input_line_pointer != '"')
exp = get_absolute_expression ();
else
{
++input_line_pointer;
while (*input_line_pointer != '"'
&& ! is_end_of_line[(unsigned char) *input_line_pointer])
{
switch (*input_line_pointer)
{
case 'b': flags |= SEC_ALLOC; flags &=~ SEC_LOAD; break;
case 'n': flags &=~ SEC_LOAD; break;
case 'd':
case 'w': flags &=~ SEC_READONLY; break;
case 'x': flags |= SEC_CODE; break;
case 'i': /* STYP_INFO */
case 'l': /* STYP_LIB */
case 'o': /* STYP_OVER */
as_warn ("unsupported section attribute '%c'",
*input_line_pointer);
break;
default:
as_warn("unknown section attribute '%c'",
*input_line_pointer);
break;
}
++input_line_pointer;
}
if (*input_line_pointer == '"')
++input_line_pointer;
}
}
sec = subseg_new (name, (subsegT) exp);
if (flags != SEC_NO_FLAGS)
{
if (! bfd_set_section_flags (stdoutput, sec, flags))
as_warn ("error setting flags for \"%s\": %s",
bfd_section_name (stdoutput, sec),
bfd_errmsg (bfd_get_error ()));
}
}
void
coff_frob_file ()
{
if (symbol_rootP == NULL
|| S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE)
{
assert (previous_file_symbol == 0);
c_dot_file_symbol ("fake");
}
}
void
coff_frob_section (strsec)
segT strsec;
{
segT sec;
char *strname, *p;
fragS *fragp;
bfd_vma size, n_entries;
/* @@ these should be in a "stabs.h" file, or maybe as.h */
#ifndef STAB_SECTION_NAME
#define STAB_SECTION_NAME ".stab"
#endif
#ifndef STAB_STRING_SECTION_NAME
#define STAB_STRING_SECTION_NAME ".stabstr"
#endif
if (strcmp (STAB_STRING_SECTION_NAME, strsec->name))
return;
sec = subseg_get (STAB_SECTION_NAME, 0);
/* size is already rounded up, since other section will be listed first */
size = bfd_get_section_size_before_reloc (strsec);
n_entries = bfd_get_section_size_before_reloc (sec) / 12 - 1;
/* Find first non-empty frag. It should be large enough. */
fragp = seg_info (sec)->frchainP->frch_root;
while (fragp && fragp->fr_fix == 0)
fragp = fragp->fr_next;
assert (fragp != 0 && fragp->fr_fix >= 12);
/* Store the values. */
p = fragp->fr_literal;
bfd_h_put_16 (stdoutput, n_entries, (bfd_byte *) p + 6);
bfd_h_put_32 (stdoutput, size, (bfd_byte *) p + 8);
}
void
obj_coff_init_stab_section (seg)
segT seg;
{
char *file;
char *p;
char *stabstr_name;
unsigned int stroff;
/* Make space for this first symbol. */
p = frag_more (12);
/* Zero it out. */
memset (p, 0, 12);
as_where (&file, (unsigned int *) NULL);
stabstr_name = (char *) alloca (strlen (seg->name) + 4);
strcpy (stabstr_name, seg->name);
strcat (stabstr_name, "str");
stroff = get_stab_string_offset (file, stabstr_name);
know (stroff == 1);
md_number_to_chars (p, stroff, 4);
}
#ifdef DEBUG
/* for debugging */
const char *
s_get_name (s)
symbolS *s;
{
return ((s == NULL) ? "(NULL)" : S_GET_NAME (s));
}
void
symbol_dump ()
{
symbolS *symbolP;
for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
{
printf("0x%lx: \"%s\" type = %ld, class = %d, segment = %d\n",
(unsigned long) symbolP,
S_GET_NAME(symbolP),
(long) S_GET_DATA_TYPE(symbolP),
S_GET_STORAGE_CLASS(symbolP),
(int) S_GET_SEGMENT(symbolP));
}
}
#endif /* DEBUG */
/* end of obj-coff.c */