* Copyright (c) 1982 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char sccsid
[] = "@(#)assyms.c 5.2 (Berkeley) 10/22/87";
* 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
Iptr
*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 */
* Managers of the symbol literal storage.
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 symtab
**hp
;
for (i
= 0; i
< NINST
; i
++)
itab
[i
] = (Iptr
*)BADPOINT
;
for (ip
= (Iptr
)instab
; FETCHNAME(ip
)[0]; ip
++) {
hp
= lookup(0); /* 0 => don't install this*/
*hp
= (struct symtab
*)ip
;
continue; /* was pseudo-op */
if (itab
[ip
->i_eopcode
] == (Iptr
*)BADPOINT
){
(Iptr
*)ClearCalloc(256, sizeof(Iptr
));
for (i
= 0; i
< 256; i
++)
itab
[ip
->i_eopcode
][ip
->i_popcode
] = ip
;
&& (sp->s_tag == LABELID) \
&& (STRPLACE(sp) & STR_CORE) \
&& (FETCHNAME(sp)[0] == 'L'))
* 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
;
* 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
)) {
* STABFLOATING indicates that the offset has been saved in s_desc, s_other
if(sp
->s_tag
== STABFLOATING
) {
sp
->s_value
= ( ( ((unsigned char) sp
->s_other
) << 16) | ( (unsigned short) sp
->s_desc
) );
sp
->s_value
= sp
->s_value
+ p
->s_value
;
else sp
->s_value
= p
->s_value
;
sp
->s_index
= p
->s_index
;
char *Calloc(number
, size
)
newstuff
= 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("\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: (void)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,
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 (from
= yytext
, len
= 0; *from
++; len
++)
(*hp
)->s_name
= (char *)savestr(yytext
, len
+ 1, STR_BOTH
);
* save a string str with len in the places indicated by place
struct strdesc
*savestr(str
, len
, place
)
* Compute the total length of the record to live in core
tlen
= sizeof(struct strdesc
) - sizeof(res
->sd_string
);
* See if there is enough space for the record,
* and allocate the record.
if (tlen
>= (STRPOOLDALLOP
- strplhead
->str_nalloc
))
res
= (struct strdesc
*)(strplhead
->str_names
+ strplhead
->str_nalloc
);
* Save the string information that is always present
res
->sd_stroff
= strfilepos
;
* Now, save the string itself. If str is null, then
* the characters have already been dumped to the file
if ((place
& STR_CORE
) && str
)
movestr(res
[0].sd_string
, str
, len
);
fwrite(str
, 1, len
, strfile
);
* Adjust the in core string pool size
strplhead
->str_nalloc
+= tlen
;
* 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..TYPH + (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 floating or large int number.");
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
;
bignumwrite(xp
->e_number
, reloc_how
);
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
);
* 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
;
reg
struct symtab
*sp
, *ub
;
char *name
; /* temp to save the name */
* We use sp->s_index to hold the length of the
* name; it isn't used for anything else
register struct allocbox
*allocwalk
;
totalstr
= sizeof(totalstr
);
DECLITERATE(allocwalk
, sp
, ub
) {
if (sp
->s_tag
>= IGNOREBOUND
)
name
= sp
->s_name
; /* save pointer */
* the length of the symbol table string
* always includes the trailing null;
* blast the pointer to its a.out value.
if (sp
->s_name
&& (sp
->s_index
= STRLEN(sp
))){
sp
->s_type
= sp
->s_ptype
;
sp
->s_type
= (sp
->s_type
& (~XFORW
));
if (readonlydata
&& (sp
->s_type
&~N_EXT
) == N_DATA
)
sp
->s_type
= N_TEXT
| (sp
->s_type
& N_EXT
);
bwrite((char *)&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",
* Construct the string pool from the symbols that were written,
* possibly fetching from the string file if the string
bwrite(&totalstr
, sizeof(totalstr
), symfile
);
DECLITERATE(allocwalk
, sp
, ub
) {
if (sp
->s_tag
>= IGNOREBOUND
)
if (STRPLACE(sp
) & STR_CORE
){
bwrite(FETCHNAME(sp
), STRLEN(sp
), symfile
);
} else if (STRPLACE(sp
) & STR_FILE
){
fseek(strfile
, STROFF(sp
), 0);
for (left
= STRLEN(sp
); left
> 0; left
-= nread
){
nread
= fread(rbuf
, sizeof(char),
min(sizeof(rbuf
), left
), strfile
);
bwrite(rbuf
, nread
, symfile
);
if (symsout
!= symsdesired
)
yyerror("INTERNAL ERROR: Wrote %d strings, wanted %d\n",