/* Copyright (c) 1980 Regents of the University of California */
static char sccsid
[] = "@(#)assyms.c 4.6 %G%";
* Managers for chunks of symbols allocated from calloc()
* We maintain a linked list of such chunks.
struct allocbox
*allochead
; /*head of chunk list*/
struct allocbox
*alloctail
; /*tail*/
struct allocbox
*newbox
; /*for creating a new chunk*/
struct symtab
*nextsym
; /*next symbol free*/
int symsleft
; /*slots left in current chunk*/
struct symtab
**symdelim
[NLOC
+ NLOC
+1];
struct symtab
**symptrub
;
* Managers for the dynamically extendable hash table
struct instab
*itab
[NINST
]; /*maps opcodes to instructions*/
* Counts what went into the symbol table, so that the
* size of the symbol table can be computed.
int nsyms
; /* total number in the symbol table */
int njxxx
; /* number of jxxx entrys */
int nforgotten
; /* number of symbols erroneously entered */
int nlabels
; /* number of label entries */
int hshused
; /* number of hash slots used */
* Managers of the symbol literal storage.
* If we have flexible names, then we allocate BUFSIZ long
* string, and pack strings into that. Otherwise, we allocate
* symbol storage in fixed hunks NCPS long when we allocate space
* for other symbol attributes.
struct strpool
*strplhead
= 0;
strpoolalloc(); /* get the first strpool storage area */
htaballoc(); /* get the first part of the hash table */
* Install all known instructions in the symbol table
register struct instab
*ip
;
register struct symtab
**hp
;
for (ip
= (struct instab
*)instab
; ip
->s_name
!= 0; ip
++) {
for (ip
= (struct instab
*)instab
; ip
->s_name
[0] != '\0'; ip
++){
hp
= lookup(0); /* 0 => don't install this*/
*hp
= (struct symtab
*)ip
;
continue; /* was pseudo-op */
itab
[ip
->i_opcode
& 0xFF] = ip
;
* Assign final values to symbols,
* and overwrite the index field with its relative position in
* the symbol table we give to the loader.
register struct symtab
*sp
;
register struct symtab
*ubsp
;
register struct allocbox
*allocwalk
;
DECLITERATE(allocwalk
, sp
, ubsp
)
if (sp
->s_tag
>= IGNOREBOUND
)
continue; /*totally ignore jxxx entries */
* Ignore stabs, but give them a symbol table index
if (sp
->s_type
& STABFLAG
)
if ((sp
->s_type
&XTYPE
)==XUNDEF
)
sp
->s_type
= XXTRN
+XUNDEF
;
else if ((sp
->s_type
&XTYPE
)==XDATA
)
sp
->s_value
+= usedot
[sp
->s_index
].e_xvalue
;
else if ((sp
->s_type
&XTYPE
)==XTEXT
)
sp
->s_value
+= usedot
[sp
->s_index
].e_xvalue
;
else if ((sp
->s_type
&XTYPE
)==XBSS
) {
sp
->s_value
= hdr
.a_bss
+ datbase
;
if ( (sp
->s_name
[0] != 'L')
|| (sp
->s_tag
!= LABELID
)
) /*then, we will write it later on*/
* For all of the stabs that had their final value undefined during pass 1
* and during pass 2 assign a final value.
* We have already given stab entrys a initial approximation
* when we constsructed the sorted symbol table.
* Iteration order doesn't matter.
register struct symtab
*sp
, **cosp
;
register struct symtab
*p
;
if(sp
->s_ptype
&& (sp
->s_type
& STABFLAG
)) {
sp
->s_value
= p
->s_value
;
sp
->s_index
= p
->s_index
;
char *Calloc(number
, size
)
newstuff
= (char *)sbrk(number
*size
);
if ((int)newstuff
== -1){
yyerror("Ran out of Memory");
char *ClearCalloc(number
, size
)
register char *newstuff
; /* r11 */
register int length
= number
* size
; /* r10 */
newstuff
= Calloc(number
, size
);
asm("movc5 $0, (r0), $0, r10, (r11)");
struct symtab
*symalloc()
newbox
= (struct allocbox
*)ClearCalloc(1,ALLOCQTY
);
nextsym
= &newbox
->symslots
[0];
allochead
= alloctail
= newbox
;
alloctail
->nextalloc
= newbox
;
register struct strpool
*new;
new = (struct strpool
*)Calloc(1, sizeof (struct strpool
));
new->str_next
= strplhead
;
struct symtab
**Pptr
, **Qptr
;
register struct symtab
*p
= *Pptr
;
register struct symtab
*q
= *Qptr
;
if (p
->s_index
< q
->s_index
)
if (p
->s_index
> q
->s_index
)
if (p
->s_value
< q
->s_value
)
if (p
->s_value
> q
->s_value
)
* Force jxxx entries to virtually preceed labels defined
* to follow the jxxxx instruction, so that bumping the
* jxxx instruction correctly fixes up the following labels
if (p
->s_tag
>= IGNOREBOUND
) /*p points to a jxxx*/
if (q
->s_tag
>= IGNOREBOUND
)
* both are now just plain labels; the relative order doesn't
* matter. Both can't be jxxxes, as they would have different
* We construct the auxiliary table of pointers, symptrs and
* We also assign preliminary values to stab entries that did not yet
* have an absolute value (because they initially referred to
* forward references). We don't worry about .stabds, as they
* already have an estimated final value
register struct symtab
*sp
;
register struct symtab
**cowalk
;
register struct allocbox
*allocwalk
;
int symsin
; /*number put into symptrs*/
symptrs
= (struct symtab
**)Calloc(nsyms
+ 2, sizeof *symptrs
);
* Allocate one word at the beginning of the symptr array
* so that backwards scans through the symptr array will
* work correctly while scanning through the zeroth segment
DECLITERATE(allocwalk
, sp
, ubsp
) {
if (sp
->s_ptype
&& (sp
->s_type
&STABFLAG
)){
sp
->s_value
= sp
->s_dest
->s_value
;
sp
->s_index
= sp
->s_dest
->s_index
;
yyerror("INTERNAL ERROR: overfilled symbol table indirection table");
yyerror("INTERNAL ERROR: installed %d syms, should have installed %d",
symptrub
= &symptrs
[nsyms
];
qsort(symptrs
, nsyms
, sizeof *symptrs
, symcmp
);
for (cowalk
= symptrs
, sp
= *cowalk
, segno
= 0, slotno
= 1;
for (; sp
&& sp
->s_index
== segno
; sp
= *++cowalk
);
symdelim
[slotno
] = cowalk
; /*forms the ub delimeter*/
register struct symtab
*sp
, **cosp
, *ub
;
printf("Symbol Table dump:\n");
for (segno
= 0; segno
< NLOC
+ NLOC
; segno
++){
printf("Segment number: %d\n", segno
);
SEGITERATE(segno
, 0, 0, cosp
, sp
, ub
, ++){
printf("\tSeg: %d \"%s\" value: %d index: %d tag %s\n",
sp
->s_value
, sp
->s_index
,
printf("\tSeg: %d \"%*.*s\" value: %d index: %d tag %s\n",
segno
, NCPS
, NCPS
, sp
->s_name
,
sp
->s_value
, sp
->s_index
,
printf("\t\ttype: %d jxbump %d jxfear: %d\n",
sp
->s_type
, sp
->s_jxbump
, sp
->s_jxfear
);
case JXACTIVE
: return("active");
case JXNOTYET
: return("notyet");
case JXALIGN
: return("align");
case JXQUESTIONABLE
: return("jxquestionable");
case JXINACTIVE
: return("inactive");
case JXTUNNEL
: return("tunnel");
case OBSOLETE
: return("obsolete");
case IGNOREBOUND
: return("ignorebound");
case STABFLOATING
: return("stabfloating");
case STABFIXED
: return("stabfixed");
case LABELID
: return("labelid");
case OKTOBUMP
: return("oktobump");
case ISET
: return("iset");
case ILSYM
: return("ilsym");
default: sprintf(tagbuff
,"%d", tag
);
register struct hashdallop
*new;
new = (struct hashdallop
*)ClearCalloc(1, sizeof (struct hashdallop
));
else { /* add AFTER the 1st slot */
new->h_next
= htab
->h_next
;
#define HASHCLOGGED (NHASH / 2)
* Lookup a symbol stored in extern yytext.
* All strings passed in via extern yytext had better have
* a trailing null. Strings are placed in yytext for hashing by
* syminstall() and by yylex();
* We take pains to avoid function calls; this functdion
* is called quite frequently, and the calls overhead
* in the vax contributes significantly to the overall
struct symtab
**lookup(instflg
)
int instflg
; /* 0: don't install */
register struct symtab
**hp
;
static struct hashdallop
*hdallop
;
static struct symtab
**emptyslot
;
static struct hashdallop
*emptyhd
;
static struct symtab
**hp_ub
;
for (nprobes
= 0, from
= yytext
;
nprobes
<<= 2, nprobes
+= *from
++)
nprobes
+= from
[-1] << 5;
for (hdallop
= htab
; hdallop
!= 0; hdallop
= hdallop
->h_next
){
for (hp
= &(hdallop
->h_htab
[initialprobe
]),
hp_ub
= &(hdallop
->h_htab
[NHASH
]);
(*hp
) && (nprobes
< NHASH
);
hp
-= (hp
>= hp_ub
) ? NHASH
:0,
for (len
= 0; (len
<NCPS
) && *from
; len
++)
if (len
>= NCPS
) /*both are maximal length*/
if (*to
== 0) /*assert *from == 0*/
if (*to
== *from
) /*assert both are == 0*/
if (*hp
== 0 && emptyslot
== 0 &&
hdallop
->h_nused
< HASHCLOGGED
) {
hdallop
= htab
->h_next
; /* aren't we smart! */
hp
= &hdallop
->h_htab
[initialprobe
];
for(len
= 0, from
= yytext
, to
= (*hp
)->s_name
; (len
<NCPS
); len
++)
if ((*to
++ = *from
++) == '\0')
for (from
= yytext
, len
= 1; *from
++; len
++)
if (len
>= (STRPOOLDALLOP
- strplhead
->str_nalloc
))
for ( (*hp
)->s_name
= to
= strplhead
->str_names
+ strplhead
->str_nalloc
, from
= yytext
;
( (*to
++ = *from
++) != '\0'); )
strplhead
->str_nalloc
+= len
;
register char *from
, *to
;
for (from
= str
, len
= 1; *from
++; len
++)
if (len
>= (STRPOOLDALLOP
- strplhead
->str_nalloc
))
for ( res
= to
= strplhead
->str_names
+ strplhead
->str_nalloc
, from
= str
;
( (*to
++ = *from
++) != '\0'); )
strplhead
->str_nalloc
+= len
;
* The relocation information is saved internally in an array of
* lists of relocation buffers. The relocation buffers are
* exactly the same size as a token buffer; if we use VM for the
* temporary file we reclaim this storage, otherwise we create
#define RELBUFLG TOKBUFLG
#define NRELOC ((TOKBUFLG - \
(sizeof (int) + sizeof (struct relbufdesc *)) \
) / (sizeof (struct relocation_info)))
struct relbufdesc
*rel_next
;
struct relocation_info rel_reloc
[NRELOC
];
extern struct relbufdesc
*tok_free
;
#define rel_free tok_free
static struct relbufdesc
*rel_temp
;
struct relocation_info r_can_1PC
;
struct relocation_info r_can_0PC
;
r_can_0PC
.r_symbolnum
= 0;
int reloc_how
; /* TYPB..TYPD + (possibly)RELOC_PCREL */
struct relocation_info reloc
;
register int x_type_mask
;
x_type_mask
= xp
->e_xtype
& ~XFORW
;
pcrel
= reloc_how
& RELOC_PCREL
;
reloc_how
&= ~RELOC_PCREL
;
yyerror("Padding error");
if (x_type_mask
== XUNDEF
)
yyerror("Undefined reference");
if ( (x_type_mask
!= XABS
) || pcrel
) {
if (ty_NORELOC
[reloc_how
])
yyerror("Illegal Relocation of float, double or quad.");
reloc
= pcrel
? r_can_1PC
: r_can_0PC
;
reloc
.r_address
= dotp
->e_xvalue
-
( (dotp
< &usedot
[NLOC
] || readonlydata
) ? 0 : datbase
);
reloc
.r_length
= ty_nlg
[reloc_how
];
reloc
.r_symbolnum
= xp
->e_xname
->s_index
;
if (readonlydata
&& (x_type_mask
&~XXTRN
) == XDATA
)
x_type_mask
= XTEXT
| (x_type_mask
&XXTRN
);
reloc
.r_symbolnum
= x_type_mask
;
if ( (relfil
== 0) || (relfil
->rel_count
>= NRELOC
) ){
rel_free
= rel_temp
->rel_next
;
rel_temp
= (struct relbufdesc
*)
Calloc(1,sizeof (struct relbufdesc
));
rel_temp
->rel_next
= relfil
;
relfil
= rusefile
[dotp
- &usedot
[0]] = rel_temp
;
relfil
->rel_reloc
[relfil
->rel_count
++] = reloc
;
* write the unrelocated value to the text file
dotp
->e_xvalue
+= ty_nbyte
[reloc_how
];
xp
->e_xvalue
-= dotp
->e_xvalue
;
bwrite((char *)&(xp
->e_xvalue
), ty_nbyte
[reloc_how
], txtfil
);
* Flush out all of the relocation information.
* Note that the individual lists of buffers are in
* reverse order, so we must reverse them
off_t
closeoutrel(relocfile
)
for (locindex
= 0; locindex
< NLOC
; locindex
++){
trsize
+= Closeoutrel(rusefile
[locindex
], relocfile
);
for (locindex
= 0; locindex
< NLOC
; locindex
++){
drsize
+= Closeoutrel(rusefile
[NLOC
+ locindex
], relocfile
);
u_long
Closeoutrel(relfil
, relocfile
)
struct relbufdesc
*relfil
;
tail
= Closeoutrel(relfil
->rel_next
, relocfile
);
bwrite((char *)&relfil
->rel_reloc
[0],
relfil
->rel_count
* sizeof (struct relocation_info
),
return(tail
+ relfil
->rel_count
* sizeof (struct relocation_info
));
#define NOUTSYMS (nsyms - njxxx - nforgotten - (savelabels ? 0 : nlabels))
return (sizeof (struct nlist
) * NOUTSYMS
);
* We write out the flexible length character strings for names
* 1) We have always! maintain a fixed sized name list entry;
* the string is indexed by a four byte quantity from the beginning
* of the string pool area. Index 0 is reserved, and indicates
* that there is no associated string. The first valid index is 4.
* 2) We concatenate together and write all of the strings
* in the string pool at the end of the name list. The first
* four bytes in the string pool are indexed only by 0 (see above);
* they contain the total number of bytes in the string pool.
* Write out n symbols to file f, beginning at p
* ignoring symbols that are obsolete, jxxx instructions, and
int symsout
; /*those actually written*/
int symsdesired
= NOUTSYMS
;
register struct symtab
*sp
, *ub
;
char *name
; /* temp to save the name */
long stroff
= sizeof (stroff
);
* We use sp->s_index to hold the length of the
* name; it isn't used for anything else
register struct allocbox
*allocwalk
;
DECLITERATE(allocwalk
, sp
, ub
)
if (sp
->s_tag
>= IGNOREBOUND
)
if ((sp
->s_name
[0] == 'L') && (sp
->s_tag
== LABELID
) && !savelabels
)
name
= sp
->s_name
; /* save pointer */
if ( (sp
->s_index
= strlen(sp
->s_name
)) != 0){
sp
->s_nmx
= stroff
; /* clobber pointer */
stroff
+= sp
->s_index
+ 1;
sp
->s_nmx
= 0; /* clobber pointer */
sp
->s_type
= (sp
->s_ptype
!= 0) ? sp
->s_ptype
: (sp
->s_type
& (~XFORW
));
if (readonlydata
&& (sp
->s_type
&~N_EXT
) == N_DATA
)
sp
->s_type
= N_TEXT
| (sp
->s_type
& N_EXT
);
bwrite(&sp
->s_nm
, sizeof (struct nlist
), symfile
);
sp
->s_name
= name
; /* restore pointer */
if (symsout
!= symsdesired
)
yyerror("INTERNAL ERROR: Wrote %d symbols, wanted to write %d symbols\n",
* Pass 2 through the string pool
bwrite(&stroff
, sizeof (stroff
), symfile
);
stroff
= sizeof (stroff
);
DECLITERATE(allocwalk
, sp
, ub
)
if (sp
->s_tag
>= IGNOREBOUND
)
if ((sp
->s_name
[0] == 'L') && (sp
->s_tag
== LABELID
) && !savelabels
)
sp
->s_index
= strlen(sp
->s_name
);
bwrite(sp
->s_name
, sp
->s_index
+ 1, symfile
);