#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "as.h"
#include "hash.h"
#include "obstack.h"
#include "struc-symbol.h"
#include "symbols.h"
#include "frags.h"
#include "expr.h"
#include "sections.h"
#include "read.h"
#include "xmalloc.h"
#include "messages.h"
#include "fixes.h"
#include "input-scrub.h"
#include "dwarf2dbg.h"
struct hash_control *sy_hash = NULL;
struct obstack notes = { 0 };
symbolS *symbol_rootP = NULL;
symbolS *symbol_lastP = NULL;
symbolS *symbol_lastIndexedP = NULL;
symbolS abs_symbol = { {{0}} };
typedef short unsigned int local_label_countT;
static void make_stab_for_symbol(
symbolS *symbolP);
static void make_subprogram_for_symbol(
symbolS *symbolP);
static void fb_label_init(void);
void
symbol_begin(
void)
{
symbol_lastP = NULL;
symbol_rootP = NULL;
sy_hash = hash_new();
memset((char *)(&abs_symbol), '\0', sizeof(abs_symbol));
abs_symbol.sy_type = N_ABS;
fb_label_init ();
}
#define LOCAL_LABEL_CHAR '\002'
#define FB_LABEL_SPECIAL (10)
static int32_t fb_low_counter[FB_LABEL_SPECIAL];
static int32_t *fb_labels;
static int32_t *fb_label_instances;
static int32_t fb_label_count;
static int32_t fb_label_max;
#define FB_LABEL_BUMP_BY (FB_LABEL_SPECIAL + 6)
static void
fb_label_init (void)
{
memset ((void *) fb_low_counter, '\0', sizeof (fb_low_counter));
}
void
fb_label_instance_inc (int32_t label)
{
int32_t *i;
if (label < FB_LABEL_SPECIAL)
{
++fb_low_counter[label];
return;
}
if (fb_labels != NULL)
{
for (i = fb_labels + FB_LABEL_SPECIAL;
i < fb_labels + fb_label_count; ++i)
{
if (*i == label)
{
++fb_label_instances[i - fb_labels];
return;
}
}
}
if (fb_labels == NULL)
{
fb_labels = (int32_t *) xmalloc (FB_LABEL_BUMP_BY * sizeof (int32_t));
fb_label_instances = (int32_t *) xmalloc (FB_LABEL_BUMP_BY * sizeof (int32_t));
fb_label_max = FB_LABEL_BUMP_BY;
fb_label_count = FB_LABEL_SPECIAL;
}
else if (fb_label_count == fb_label_max)
{
fb_label_max += FB_LABEL_BUMP_BY;
fb_labels = (int32_t *) xrealloc ((char *) fb_labels,
fb_label_max * sizeof (int32_t));
fb_label_instances = (int32_t *) xrealloc ((char *) fb_label_instances,
fb_label_max * sizeof (int32_t));
}
fb_labels[fb_label_count] = label;
fb_label_instances[fb_label_count] = 1;
++fb_label_count;
}
static int32_t
fb_label_instance (int32_t label)
{
int32_t *i;
if (label < FB_LABEL_SPECIAL)
{
return (fb_low_counter[label]);
}
if (fb_labels != NULL)
{
for (i = fb_labels + FB_LABEL_SPECIAL;
i < fb_labels + fb_label_count; ++i)
{
if (*i == label)
{
return (fb_label_instances[i - fb_labels]);
}
}
}
return 0;
}
char *
fb_label_name (int32_t n,
int32_t augend )
{
int32_t i;
static char symbol_name_build[24];
register char *p;
register char *q;
char symbol_name_temporary[20];
know (n >= 0);
#ifdef TC_MMIX
know ((uint32_t) augend <= 2 );
#else
know ((uint32_t) augend <= 1);
#endif
p = symbol_name_build;
#ifdef LOCAL_LABEL_PREFIX
*p++ = LOCAL_LABEL_PREFIX;
#endif
*p++ = 'L';
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;
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');
return (symbol_name_build);
}
char *
decode_local_label_name (char *s)
{
char *p;
char *symbol_decode;
int label_number;
int instance_number;
char *type;
int index = 0;
#ifdef LOCAL_LABEL_PREFIX
if (s[index] == LOCAL_LABEL_PREFIX)
++index;
#endif
if (s[index] != 'L')
return s;
for (label_number = 0, p = s + index + 1; isdigit (*p); ++p)
label_number = (10 * label_number) + *p - '0';
if (*p == LOCAL_LABEL_CHAR)
type = "fb";
else
return s;
for (instance_number = 0, p++; isdigit (*p); ++p)
instance_number = (10 * instance_number) + *p - '0';
#define MESSAGE_FORMAT "\"%d\" (instance number %d of a %s label)"
symbol_decode = obstack_alloc (¬es, strlen (MESSAGE_FORMAT) + 30);
sprintf (symbol_decode, MESSAGE_FORMAT, label_number, instance_number, type);
return symbol_decode;
}
void
local_colon(
int n)
{
fb_label_instance_inc (n);
colon (fb_label_name (n, 0), 1);
}
symbolS *
symbol_new(
char *name,
unsigned char type,
char other,
short desc,
valueT value,
struct frag *frag)
{
register symbolS * symbolP;
register char * preserved_copy_of_name;
register unsigned int name_length;
char * p;
name_length = strlen(name) + 1;
obstack_grow(¬es,name,name_length);
p=obstack_finish(¬es);
preserved_copy_of_name = p;
p=obstack_alloc(¬es,sizeof(struct symbol));
symbolP = (symbolS *) p;
symbolP -> sy_name = preserved_copy_of_name;
symbolP -> sy_type = type;
symbolP -> sy_other = other;
symbolP -> sy_desc = desc;
symbolP -> sy_value = value;
symbolP -> sy_frag = frag;
symbolP -> sy_prev_by_index = NULL;
symbolP -> sy_has_been_resolved = 0;
symbolP -> sy_next = NULL;
symbolP -> sy_forward = NULL;
symbolP -> expression = NULL;
#ifdef SUSPECT
symbolP -> sy_name_offset = ~ 0;
symbolP -> sy_number = ~ 0;
#endif
if (symbol_lastP)
{
symbol_lastP -> sy_next = symbolP;
}
else
{
symbol_rootP = symbolP;
}
symbol_lastP = symbolP;
return (symbolP);
}
symbolS *
symbol_create (const char *name,
segT segment,
valueT valu,
fragS *frag )
{
return symbol_new ((char *)name, 0, segment, 0, valu, frag);
}
void
symbol_assign_index(
struct symbol *symbolP)
{
if (symbolP->sy_prev_by_index != NULL)
{
as_fatal("symbol %s already has an index", symbolP->sy_name);
}
symbolP->sy_prev_by_index = symbol_lastIndexedP;
symbol_lastIndexedP = symbolP;
}
static volatile unsigned int temp;
void
colon(
char *sym_name,
int local_colon)
{
register struct symbol * symbolP;
if (frchain_now == NULL)
{
know(flagseen['n']);
as_fatal("with -n a section directive must be seen before assembly "
"can begin");
}
if (inlineasm_checks && local_colon == 0)
{
if (inlineasm_file_name)
as_warn_where_with_column(inlineasm_file_name, inlineasm_line_number,
inlineasm_column_number, "label definition in inlineasm");
else
as_bad("label definition in inlineasm");
}
if ((symbolP = symbol_table_lookup( sym_name )))
{
if ((symbolP -> sy_type & N_TYPE) == N_UNDF)
{
temp = symbolP->sy_desc;
if( symbolP -> sy_other == 0
&& (temp & (~(REFERENCE_TYPE | N_WEAK_REF | N_WEAK_DEF |
N_ARM_THUMB_DEF | N_SYMBOL_RESOLVER |
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;
symbolP -> sy_other = frchain_now->frch_nsect;
symbolP -> sy_desc &= ~REFERENCE_TYPE;
symbolP -> sy_desc &= ~(N_WEAK_REF & N_WEAK_DEF);
symbol_assign_index(symbolP);
#ifdef NeXT_MOD
if(flagseen['g'])
make_stab_for_symbol(symbolP);
#endif
if(debug_type == DEBUG_DWARF2)
make_subprogram_for_symbol(symbolP);
}
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,
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
if(flagseen['g'])
make_stab_for_symbol(symbolP);
#endif
if(debug_type == DEBUG_DWARF2)
make_subprogram_for_symbol(symbolP);
}
#ifdef tc_frob_label
tc_frob_label(symbolP);
#endif
}
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);
}
}
symbolS *
symbol_find_or_make(
char *name)
{
register symbolS * symbolP;
symbolP = symbol_table_lookup (name);
if (symbolP == NULL)
{
symbolP = symbol_new (name, N_UNDF, 0, 0, 0, & zero_address_frag);
symbol_table_insert (symbolP);
}
return (symbolP);
}
symbolS *
symbol_find(
char *name)
{
return ( (symbolS *) hash_find( sy_hash, name ));
}
symbolS *
symbol_table_lookup(
char *name)
{
register symbolS * symbolP;
symbolP = (symbolS *) hash_find( sy_hash, name );
if(symbolP != NULL)
symbolP->sy_desc &= ~REFERENCE_FLAG_UNDEFINED_LAZY;
return(symbolP);
}
#ifdef NeXT_MOD
static
void
make_stab_for_symbol(
symbolS *symbolP)
{
symbolS *stab;
int stabnamelen;
char *stabname;
if(symbolP->sy_name[0] == 'L')
return;
if((symbolP->sy_type & N_TYPE) != N_SECT)
return;
if(symbolP->sy_other != text_nsect)
return;
stabnamelen = strlen(symbolP->sy_name) + sizeof(":f3");
stabname = xmalloc(stabnamelen);
strcpy(stabname, symbolP->sy_name);
if(symbolP->sy_type & N_EXT)
strcat(stabname, ":F3");
else
strcat(stabname, ":f3");
stab = symbol_new(
stabname,
36,
text_nsect,
logical_input_line,
symbolP->sy_value,
symbolP->sy_frag);
free(stabname);
}
#endif
static
void
make_subprogram_for_symbol(
symbolS *symbolP)
{
struct dwarf2_subprogram_info *i;
static struct dwarf2_subprogram_info *last_dwarf2_subprogram_info = NULL;
if(symbolP->sy_name[0] == 'L')
return;
if((symbolP->sy_type & N_TYPE) != N_SECT)
return;
if(symbolP->sy_other != text_nsect)
return;
i = xmalloc(sizeof(struct dwarf2_subprogram_info));
i->name = symbolP->sy_name;
if(i->name[0] == '_')
i->name++;
i->file_number = dwarf2_file_number;
i->line_number = logical_input_line;
i->symbol = symbol_temp_new(symbolP->sy_other, symbolP->sy_value,
symbolP->sy_frag);
i->next = NULL;
if(dwarf2_subprograms_info == NULL){
dwarf2_subprograms_info = i;
last_dwarf2_subprogram_info = i;
}
else{
last_dwarf2_subprogram_info->next = i;
last_dwarf2_subprogram_info = i;
}
}
isymbolS *
indirect_symbol_new(
char *name,
struct frag *frag,
uint32_t offset)
{
isymbolS *isymbolP;
char *preserved_copy_of_name;
uint32_t name_length;
char *p;
struct frag *fr_next;
symbolS *symbolP;
#ifdef CHECK_INDIRECTS
uint32_t stride, fr_fix;
#endif
if(frchain_now->frch_isym_last != NULL &&
frchain_now->frch_isym_last->isy_frag->fr_fix == 0){
if(frchain_now->frch_isym_last->isy_frag->fr_next != NULL){
fr_next = frchain_now->frch_isym_last->isy_frag->fr_next;
while(fr_next->fr_fix == 0 &&
fr_next->fr_type == rs_fill &&
fr_next->fr_next != NULL)
fr_next = fr_next->fr_next;
frchain_now->frch_isym_last->isy_frag = fr_next;
}
}
name_length = strlen(name) + 1;
obstack_grow(¬es, name, name_length);
p = obstack_finish(¬es);
preserved_copy_of_name = p;
p = obstack_alloc(¬es, sizeof(struct indirect_symbol));
isymbolP = (isymbolS *)p;
isymbolP->isy_name = preserved_copy_of_name;
isymbolP->isy_offset = offset;
isymbolP->isy_frag = frag;
isymbolP->isy_next = NULL;
isymbolP->isy_symbol = NULL;
if(frchain_now->frch_isym_root == NULL){
#ifdef CHECK_INDIRECTS
if(offset != 0)
as_bad("missing or bad indirect symbol for section (%s,%s)",
frchain_now->frch_section.segname,
frchain_now->frch_section.sectname);
#endif
frchain_now->frch_isym_root = isymbolP;
frchain_now->frch_isym_last = isymbolP;
}
else{
#ifdef CHECK_INDIRECTS
if((frchain_now->frch_section.flags & SECTION_TYPE) ==
S_SYMBOL_STUBS)
stride = frchain_now->frch_section.reserved2;
else
stride = sizeof(uint32_t);
if(frag == frchain_now->frch_isym_last->isy_frag){
if(offset - frchain_now->frch_isym_last->isy_offset != stride)
as_bad("missing or bad indirect symbol for section "
"(%s,%s)", frchain_now->frch_section.segname,
frchain_now->frch_section.sectname);
}
else{
if(frchain_now->frch_isym_last->isy_frag->fr_fix < stride){
fr_fix = 0;
fr_next = frchain_now->frch_isym_last->isy_frag;
while(fr_fix + fr_next->fr_fix < stride &&
fr_next->fr_type == rs_fill &&
fr_next->fr_next != NULL){
fr_fix += fr_next->fr_fix;
fr_next = fr_next->fr_next;
}
if(frag != fr_next->fr_next ||
fr_fix + fr_next->fr_fix != stride ||
offset != 0)
as_bad("missing or bad indirect symbol for section "
"(%s,%s)", frchain_now->frch_section.segname,
frchain_now->frch_section.sectname);
}
else{
fr_next = frchain_now->frch_isym_last->isy_frag->fr_next;
while(fr_next->fr_fix == 0 &&
fr_next->fr_type == rs_fill &&
fr_next->fr_next != NULL)
fr_next = fr_next->fr_next;
if(frag != fr_next || offset != 0)
as_bad("missing or bad indirect symbol for section "
"(%s,%s)", frchain_now->frch_section.segname,
frchain_now->frch_section.sectname);
}
}
#endif
frchain_now->frch_isym_last->isy_next = isymbolP;
frchain_now->frch_isym_last = isymbolP;
}
if((frchain_now->frch_section.flags & SECTION_TYPE) ==
S_NON_LAZY_SYMBOL_POINTERS){
symbolP = (symbolS *)hash_find(sy_hash, name);
if(symbolP != NULL)
symbolP->sy_desc &= ~REFERENCE_FLAG_UNDEFINED_LAZY;
}
return(isymbolP);
}
const char *
S_GET_NAME (symbolS *s)
{
return s->sy_name;
}
int
S_IS_DEFINED (symbolS *s)
{
return (s->sy_type & N_TYPE) != N_UNDF;
}
#ifdef TC_SYMFIELD_TYPE
TC_SYMFIELD_TYPE *
symbol_get_tc (symbolS *s)
{
return &s->sy_tc;
}
void
symbol_set_tc (symbolS *s, TC_SYMFIELD_TYPE *o)
{
s->sy_tc = *o;
}
#endif
int
S_IS_LOCAL (symbolS *s)
{
const char *name;
name = S_GET_NAME (s);
if(name == NULL)
return(1);
if(name[0] == 'L' && flagseen['L'] == FALSE)
return(1);
else
return(0);
}
fragS *
symbol_get_frag (symbolS *s)
{
return(s->sy_frag);
}
symbolS *
symbol_temp_new(
segT nsect,
valueT value,
struct frag *frag)
{
return(symbol_new(FAKE_LABEL_NAME, N_SECT, nsect, 0, value, frag));
}
symbolS *
symbol_temp_new_now(void)
{
return(symbol_temp_new(now_seg, frag_now_fix(), frag_now));
}
symbolS *
symbol_temp_make(void)
{
return(symbol_new(FAKE_LABEL_NAME, N_UNDF, 0, 0, 0, & zero_address_frag));
}
void
symbol_set_value_now(
symbolS *sym)
{
sym->sy_type = N_SECT;
sym->sy_other = now_seg;
sym->sy_value = frag_now_fix();
sym->sy_frag = frag_now;
}