489 lines
10 KiB
C
489 lines
10 KiB
C
/* lksym.c */
|
|
|
|
/*
|
|
* (C) Copyright 1989-1995
|
|
* All Rights Reserved
|
|
*
|
|
* Alan R. Baldwin
|
|
* 721 Berkeley St.
|
|
* Kent, Ohio 44240
|
|
*
|
|
* 28-Oct-97 JLH:
|
|
* - lkpsym: Use StoreString for sym construction
|
|
* - change symeq() to do length-independent string compare
|
|
* - change hash() to do length-independent hash calculation
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#if defined(_MSC_VER)
|
|
#include <malloc.h>
|
|
#else
|
|
#include <alloc.h>
|
|
#endif
|
|
#include "aslink.h"
|
|
|
|
/*)Module lksym.c
|
|
*
|
|
* The module lksym.c contains the functions that operate
|
|
* on the symbol structures.
|
|
*
|
|
* lksym.c contains the following functions:
|
|
* int hash()
|
|
* sym * lkpsym()
|
|
* VOID * new()
|
|
* sym * newsym()
|
|
* VOID symdef()
|
|
* int symeq()
|
|
* VOID syminit()
|
|
* VOID symmod()
|
|
* Addr_T symval()
|
|
*
|
|
* lksym.c contains no local/static variables.
|
|
*/
|
|
|
|
/*)Function VOID syminit()
|
|
*
|
|
* The function syminit() is called to clear the hashtable.
|
|
*
|
|
* local variables:
|
|
* int h computed hash value
|
|
* sym ** spp pointer to an array of
|
|
* sym structure pointers
|
|
*
|
|
* global variables:
|
|
* sym * symhash[] array of pointers to NHASH
|
|
* linked symbol lists
|
|
*
|
|
* functions called:
|
|
* none
|
|
*
|
|
* side effects:
|
|
* (1) The symbol hash tables are cleared
|
|
*/
|
|
|
|
VOID
|
|
syminit()
|
|
{
|
|
// register int h;
|
|
struct sym **spp;
|
|
|
|
spp = &symhash[0];
|
|
while (spp < &symhash[NHASH])
|
|
*spp++ = NULL;
|
|
}
|
|
|
|
/*)Function sym * newsym()
|
|
*
|
|
* The function newsym() is called to evaluate the symbol
|
|
* definition/reference directive from the .rel file(s).
|
|
* If the symbol is not found in the symbol table a new
|
|
* symbol structure is created. Evaluation of the
|
|
* directive determines if this is a reference or a definition.
|
|
* Multiple definitions of the same variable will be flagged
|
|
* as an error if the values are not identical. A symbol
|
|
* definition places the symbol value and area extension
|
|
* into the symbols data structure. And finally, a pointer
|
|
* to the symbol structure is placed into the head structure
|
|
* symbol list. Refer to the description of the header, symbol,
|
|
* area, and areax structures in lkdata.c for structure and
|
|
* linkage details.
|
|
*
|
|
* local variables:
|
|
* int c character from input text
|
|
* int i evaluation value
|
|
* char id[] symbol name
|
|
* int nglob number of symbols in this header
|
|
* sym * tsp pointer to symbol structure
|
|
* sym ** s list of pointers to symbol structures
|
|
*
|
|
* global variables:
|
|
* areax *axp Pointer to the current
|
|
* areax structure
|
|
* head *headp The pointer to the first
|
|
* head structure of a linked list
|
|
* int lkerr error flag
|
|
*
|
|
* functions called:
|
|
* Addr_T eval() lkeval.c
|
|
* VOID exit() c_library
|
|
* int fprintf() c_library
|
|
* char getSid() lklex.c
|
|
* char get() lklex.c
|
|
* char getnb() lklex.c
|
|
* sym * lkpsym() lksym.c
|
|
*
|
|
* side effects:
|
|
* A symbol structure is created and/or modified.
|
|
* If structure space allocation fails linker will abort.
|
|
* Several severe errors (these are internal errors
|
|
* indicating a corrupted .rel file or corrupted
|
|
* assembler or linker) will terminated the linker.
|
|
*/
|
|
|
|
/*
|
|
* Find/Create a global symbol entry.
|
|
*
|
|
* S xxxxxx Defnnnn
|
|
* | | |
|
|
* | | `-- sp->s_addr
|
|
* | `----- sp->s_type
|
|
* `------------ sp->s_id
|
|
*
|
|
*/
|
|
struct sym *
|
|
newsym()
|
|
{
|
|
register unsigned i ;
|
|
register unsigned nglob ;
|
|
register int c ;
|
|
struct sym *tsp;
|
|
struct sym **s;
|
|
char id[NCPS];
|
|
|
|
getSid(id); // old: getid(id, -1);
|
|
tsp = lkpsym(id, 1);
|
|
c = getnb();get();get();
|
|
if (c == 'R') {
|
|
tsp->s_type |= S_REF;
|
|
if (eval()) {
|
|
fprintf(stderr, "Non zero S_REF\n");
|
|
lkerr++;
|
|
}
|
|
} else
|
|
if (c == 'D') {
|
|
i = eval();
|
|
if (tsp->s_type & S_DEF && tsp->s_addr != i) {
|
|
fprintf(stderr, "Multiple definition of %8s\n", id);
|
|
lkerr++;
|
|
}
|
|
tsp->s_type |= S_DEF;
|
|
/*
|
|
* Set value and area extension link.
|
|
*/
|
|
tsp->s_addr = i;
|
|
tsp->s_axp = axp;
|
|
} else {
|
|
fprintf(stderr, "Invalid symbol type %c for %8s\n", c, id);
|
|
lkexit(1);
|
|
}
|
|
/*
|
|
* Place pointer in header symbol list
|
|
*/
|
|
if (headp == NULL) {
|
|
fprintf(stderr, "No header defined\n");
|
|
lkexit(1);
|
|
}
|
|
nglob = hp->h_nglob;
|
|
s = hp->s_list;
|
|
for (i=0; i < nglob ;++i) {
|
|
if (s[i] == NULL) {
|
|
s[i] = tsp;
|
|
return(tsp);
|
|
}
|
|
}
|
|
fprintf(stderr, "Header symbol list overflow\n");
|
|
lkexit(1);
|
|
return(0);
|
|
}
|
|
|
|
/*)Function sym * lkpsym(id,f)
|
|
*
|
|
* char * id symbol name string
|
|
* int f f == 0, lookup only
|
|
* f != 0, create if not found
|
|
*
|
|
* The function lookup() searches the symbol hash tables for
|
|
* a symbol name match returning a pointer to the sym structure.
|
|
* If the symbol is not found then a sym structure is created,
|
|
* initialized, and linked to the appropriate hash table if f != 0.
|
|
* A pointer to this new sym structure is returned or a NULL
|
|
* pointer is returned if f == 0.
|
|
*
|
|
* local variables:
|
|
* int h computed hash value
|
|
* sym * sp pointer to a sym structure
|
|
*
|
|
* global varaibles:
|
|
* sym * symhash[] array of pointers to NHASH
|
|
* linked symbol lists
|
|
*
|
|
* functions called:
|
|
* int hash() lksym.c
|
|
* VOID * new() lksym.c
|
|
* int symeq() lksym.c
|
|
*
|
|
* side effects:
|
|
* If the function new() fails to allocate space
|
|
* for the new sym structure the linker terminates.
|
|
*/
|
|
|
|
struct sym *
|
|
lkpsym(id, f)
|
|
char *id;
|
|
{
|
|
register struct sym *sp;
|
|
register int h;
|
|
|
|
h = hash(id);
|
|
sp = symhash[h];
|
|
while (sp != NULL) {
|
|
if (symeq(id, sp->s_id))
|
|
return (sp);
|
|
sp = sp->s_sp;
|
|
}
|
|
if (f == 0)
|
|
return (NULL);
|
|
sp = (struct sym *) new (sizeof(struct sym));
|
|
sp->s_sp = symhash[h];
|
|
symhash[h] = sp;
|
|
sp->s_id = StoreString( id ); /* JLH */
|
|
return (sp);
|
|
}
|
|
|
|
/*)Function Addr_T symval(tsp)
|
|
*
|
|
* sym * tsp pointer to a symbol structure
|
|
*
|
|
* The function symval() returns the value of the
|
|
* relocated symbol by adding the variable definition
|
|
* value to the areax base address.
|
|
*
|
|
* local variables:
|
|
* Addr_T val relocated address value
|
|
*
|
|
* global variables:
|
|
* none
|
|
*
|
|
* functions called:
|
|
* none
|
|
*
|
|
* side effects:
|
|
* none
|
|
*/
|
|
|
|
Addr_T
|
|
symval(tsp)
|
|
register struct sym *tsp;
|
|
{
|
|
register Addr_T val;
|
|
|
|
val = tsp->s_addr;
|
|
if (tsp->s_axp) {
|
|
val += tsp->s_axp->a_addr;
|
|
}
|
|
return(val);
|
|
}
|
|
|
|
/*)Function VOID symdef(fp)
|
|
*
|
|
* FILE * fp file handle for output
|
|
*
|
|
* The function symdef() scans the hashed symbol table
|
|
* searching for variables referenced but not defined.
|
|
* Undefined variables are linked to the default
|
|
* area "_CODE" and reported as referenced by the
|
|
* appropriate module.
|
|
*
|
|
* local variables:
|
|
* int i hash table index loop variable
|
|
* sym * sp pointer to linked symbol structure
|
|
*
|
|
* global variables:
|
|
* area *areap The pointer to the first
|
|
* area structure of a linked list
|
|
* sym *symhash[NHASH] array of pointers to NHASH
|
|
* linked symbol lists
|
|
*
|
|
* functions called:
|
|
* symmod() lksym.c
|
|
*
|
|
* side effects:
|
|
* Undefined variables have their areas set to "_CODE".
|
|
*/
|
|
|
|
VOID
|
|
symdef(fp)
|
|
FILE *fp;
|
|
{
|
|
register struct sym *sp;
|
|
register int i;
|
|
|
|
for (i=0; i<NHASH; ++i) {
|
|
sp = symhash[i];
|
|
while (sp) {
|
|
if (sp->s_axp == NULL)
|
|
sp->s_axp = areap->a_axp;
|
|
if ((sp->s_type & S_DEF) == 0)
|
|
symmod(fp, sp);
|
|
sp = sp->s_sp;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*)Function VOID symmod(fp,tsp)
|
|
*
|
|
* FILE * fp output file handle
|
|
* sym * tsp pointer to a symbol structure
|
|
*
|
|
* The function symmod() scans the header structures
|
|
* searching for a reference to the symbol structure
|
|
* pointer to by tsp. The function then generates an error
|
|
* message whichs names the module having referenced the
|
|
* undefined variable.
|
|
*
|
|
* local variables:
|
|
* int i loop counter
|
|
* sym ** p pointer to a list of pointers
|
|
* to symbol structures
|
|
*
|
|
* global variables:
|
|
* head *headp The pointer to the first
|
|
* head structure of a linked list
|
|
* head *hp Pointer to the current
|
|
* head structure
|
|
* int lkerr error flag
|
|
*
|
|
* functions called:
|
|
* int fprintf() c_library
|
|
*
|
|
* side effects:
|
|
* Error output generated.
|
|
*/
|
|
|
|
VOID
|
|
symmod(fp, tsp)
|
|
FILE *fp;
|
|
struct sym *tsp;
|
|
{
|
|
register int i;
|
|
struct sym **p;
|
|
|
|
if ((hp = headp) != NULL) {
|
|
while(hp) {
|
|
p = hp->s_list;
|
|
for (i=0; i<hp->h_nglob; ++i) {
|
|
if (p[i] == tsp) {
|
|
fprintf(fp, "\n?ASlink-Warning-Undefined Global '%s' ", tsp->s_id);
|
|
fprintf(fp, "referenced by module '%s'\n", hp->m_id);
|
|
lkerr++;
|
|
}
|
|
}
|
|
hp = hp->h_hp;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*)Function int symeq(p1, p2)
|
|
*
|
|
* char * p1 name string
|
|
* char * p2 name string
|
|
*
|
|
* The function symeq() compares the two name strings for a match.
|
|
* The return value is 1 for a match and 0 for no match.
|
|
*
|
|
* local variables:
|
|
* int h loop counter
|
|
*
|
|
* global variables:
|
|
* char ccase[] an array of characters which
|
|
* perform the case translation function
|
|
*
|
|
* functions called:
|
|
* none
|
|
*
|
|
* side effects:
|
|
* none
|
|
*
|
|
*/
|
|
|
|
int
|
|
symeq(p1, p2)
|
|
register char *p1, *p2;
|
|
{
|
|
#if CASE_SENSITIVE
|
|
return (strcmp( p1, p2 ) == 0);
|
|
#else
|
|
return (strcmpi( p1, p2 ) == 0);
|
|
#endif
|
|
}
|
|
|
|
/*)Function int hash(p)
|
|
*
|
|
* char * p pointer to string to hash
|
|
*
|
|
* The function hash() computes a hash code using the sum
|
|
* of all characters mod table size algorithm.
|
|
*
|
|
* local variables:
|
|
* int h accumulated character sum
|
|
* int n loop counter
|
|
*
|
|
* global variables:
|
|
* char ccase[] an array of characters which
|
|
* perform the case translation function
|
|
*
|
|
* functions called:
|
|
* none
|
|
*
|
|
* side effects:
|
|
* none
|
|
*
|
|
*/
|
|
|
|
int
|
|
hash(p)
|
|
register char *p;
|
|
{
|
|
register int h;
|
|
|
|
h = 0;
|
|
while (*p) {
|
|
|
|
#if CASE_SENSITIVE
|
|
h += *p++;
|
|
#else
|
|
h += ccase[*p++];
|
|
#endif
|
|
|
|
};
|
|
return (h&HMASK);
|
|
}
|
|
|
|
/*)Function VOID * new(n)
|
|
*
|
|
* unsigned int n allocation size in bytes
|
|
*
|
|
* The function new() allocates n bytes of space and returns
|
|
* a pointer to this memory. If no space is available the
|
|
* linker is terminated.
|
|
*
|
|
* local variables:
|
|
* char * p a general pointer
|
|
* char * q a general pointer
|
|
*
|
|
* global variables:
|
|
* none
|
|
*
|
|
* functions called:
|
|
* int fprintf() c_library
|
|
* VOID * malloc() c_library
|
|
*
|
|
* side effects:
|
|
* Memory is allocated, if allocation fails
|
|
* the linker is terminated.
|
|
*/
|
|
|
|
VOID *
|
|
new(n)
|
|
unsigned int n;
|
|
{
|
|
register char *p;
|
|
|
|
if ((p = (char *) calloc(n, 1)) == NULL) {
|
|
fprintf(stderr, "Out of space!\n");
|
|
lkexit(1);
|
|
}
|
|
return (p);
|
|
}
|