gbdk-releases/sdcc/link/z80/lklibr.c
2015-01-10 16:25:09 +01:00

811 lines
18 KiB
C

/* lklibr.c */
/*
* (C) Copyright 1989-1995
* All Rights Reserved
*
* Alan R. Baldwin
* 721 Berkeley St.
* Kent, Ohio 44240
*
* With contributions for the
* object libraries from
* Ken Hornstein
* kenh@cmf.nrl.navy.mil
*
*/
/*
* Extensions: P. Felber
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "aslink.h"
/*)Module lklibr.c
*
* The module lklibr.c contains the functions which
* (1) specify the path(s) to library files [.LIB]
* (2) specify the library file(s) [.LIB] to search
* (3) search the library files for specific symbols
* and link the module containing this symbol
*
* lklibr.c contains the following functions:
* VOID addpath()
* VOID addlib()
* VOID addfile()
* VOID search()
* VOID fndsym()
* VOID library()
* VOID loadfile()
*
*/
#ifdef INDEXLIB
typedef struct slibrarysymbol mlibrarysymbol;
typedef struct slibrarysymbol *pmlibrarysymbol;
struct slibrarysymbol {
char name[40];
pmlibrarysymbol next;
};
typedef struct slibraryfile mlibraryfile;
typedef struct slibraryfile *pmlibraryfile;
struct slibraryfile {
int loaded;
char *libspc;
char *str;
char relfil[FILSPC];
char filename[FILSPC];
pmlibrarysymbol symbols;
pmlibraryfile next;
};
int buildlibraryindex();
#endif /* INDEXLIB */
/*)Function VOID addpath()
*
* The function addpath() creates a linked structure containing
* the paths to various object module library files.
*
* local variables:
* lbpath *lbph pointer to new path structure
* lbpath *lbp temporary pointer
*
* global variables:
* lbpath *lbphead The pointer to the first
* path structure
*
* functions called:
* char getnb() lklex.c
* VOID * new() lksym.c
* int strlen() c_library
* char * strcpy() c_library
* VOID unget() lklex.c
*
* side effects:
* An lbpath structure may be created.
*/
VOID
addpath()
{
struct lbpath *lbph, *lbp;
lbph = (struct lbpath *) new (sizeof(struct lbpath));
if (lbphead == NULL) {
lbphead = lbph;
} else {
lbp = lbphead;
while (lbp->next)
lbp = lbp->next;
lbp->next = lbph;
}
unget(getnb());
lbph->path = (char *) new (strlen(ip)+1);
strcpy(lbph->path, ip);
}
/*)Function VOID addlib()
*
* The function addlib() tests for the existance of a
* library path structure to determine the method of
* adding this library file to the library search structure.
*
* This function calls the function addfile() to actually
* add the library file to the search list.
*
* local variables:
* lbpath *lbph pointer to path structure
*
* global variables:
* lbpath *lbphead The pointer to the first
* path structure
*
* functions called:
* VOID addfile() lklibr.c
* char getnb() lklex.c
* VOID unget() lklex.c
*
* side effects:
* The function addfile() may add the file to
* the library search list.
*/
VOID
addlib()
{
struct lbpath *lbph;
unget(getnb());
if (lbphead == NULL) {
addfile(NULL,ip);
return;
}
for (lbph=lbphead; lbph; lbph=lbph->next) {
addfile(lbph->path,ip);
}
}
/*)Function VOID addfile(path,libfil)
*
* char *path library path specification
* char *libfil library file specification
*
* The function addfile() searches for the library file
* by concatenating the path and libfil specifications.
* if the library is found, an lbname structure is created
* and linked to any previously defined structures. This
* linked list is used by the function fndsym() to attempt
* to find any undefined symbols.
*
* The function does not give report an error on invalid
* path / file specifications or if the file is not found.
*
* local variables:
* lbname *lbnh pointer to new name structure
* lbname *lbn temporary pointer
*
* global variables:
* lbname *lbnhead The pointer to the first
* path structure
*
* functions called:
* char getnb() lklex.c
* VOID * new() lksym.c
* int strlen() c_library
* char * strcpy() c_library
* VOID unget() lklex.c
*
* side effects:
* An lbname structure may be created.
*/
VOID
addfile(path,libfil)
char *path;
char *libfil;
{
FILE *fp;
char *str;
struct lbname *lbnh, *lbn;
if ((path != NULL) && (strchr(libfil,':') == NULL)){
str = (char *) new (strlen(path) + strlen(libfil) + 6);
strcpy(str,path);
#ifdef OTHERSYSTEM
#ifdef SDK
#ifdef UNIX
if (str[strlen(str)-1] != '/') {
strcat(str,"/");
#else /* UNIX */
if (str[strlen(str)-1] != '\\') {
strcat(str,"\\");
#endif /* UNIX */
#else /* SDK */
if (str[strlen(str)-1] != '\\') {
strcat(str,"\\");
#endif /* SDK */
}
#endif
} else {
str = (char *) new (strlen(libfil) + 5);
}
#ifdef OTHERSYSTEM
#ifdef SDK
#ifdef UNIX
if (libfil[0] == '/') { libfil++; }
#else /* UNIX */
if (libfil[0] == '\\') { libfil++; }
#endif /* UNIX */
#else /* SDK */
if (libfil[0] == '\\') { libfil++; }
#endif /* SDK */
#endif
strcat(str,libfil);
if(strchr(str,FSEPX) == NULL) {
sprintf(&str[strlen(str)], "%clib", FSEPX);
}
if ((fp = fopen(str, "r")) != NULL) {
fclose(fp);
lbnh = (struct lbname *) new (sizeof(struct lbname));
if (lbnhead == NULL) {
lbnhead = lbnh;
} else {
lbn = lbnhead;
while (lbn->next)
lbn = lbn->next;
lbn->next = lbnh;
}
if ((path != NULL) && (strchr(libfil,':') == NULL)){
lbnh->path = path;
}
lbnh->libfil = (char *) new (strlen(libfil) + 1);
strcpy(lbnh->libfil,libfil);
lbnh->libspc = str;
} else {
free(str);
}
}
/*)Function VOID search()
*
* The function search() looks through all the symbol tables
* at the end of pass 1. If any undefined symbols are found
* then the function fndsym() is called. Function fndsym()
* searches any specified library files to automagically
* import the object modules containing the needed symbol.
*
* After a symbol is found and imported by the function
* fndsym() the symbol tables are again searched. The
* symbol tables are search until no more symbols can be
* resolved within the library files. This ensures that
* back references from one library module to another are
* also resolved.
*
* local variables:
* int i temporary counter
* sym *sp pointer to a symbol structure
* int symfnd found a symbol flag
*
* global variables:
* sym *symhash[] array of pointers to symbol tables
*
* functions called:
* int fndsym() lklibr.c
*
* side effects:
* If a symbol is found then the library object module
* containing the symbol will be imported and linked.
*/
VOID
search()
{
register struct sym *sp;
register int i, symfnd;
/*
* Look for undefined symbols. Keep
* searching until no more symbols are resolved.
*/
symfnd = 1;
while (symfnd) {
symfnd = 0;
/*
* Look through all the symbols
*/
for (i=0; i<NHASH; ++i) {
sp = symhash[i];
while (sp) {
/* If we find an undefined symbol
* (one where S_DEF is not set), then
* try looking for it. If we find it
* in any of the libraries then
* increment symfnd. This will force
* another pass of symbol searching and
* make sure that back references work.
*/
if ((sp->s_type & S_DEF) == 0) {
if (fndsym(sp->s_id)) {
symfnd++;
}
}
sp = sp->s_sp;
}
}
}
}
/*)Function VOID fndsym(name)
*
* char *name symbol name to find
*
* The function fndsym() searches through all combinations of the
* library path specifications (input by the -k option) and the
* library file specifications (input by the -l option) that
* lead to an existing file.
*
* The file specicifation may be formed in one of two ways:
*
* (1) If the library file contained an absolute
* path/file specification then this becomes filspc.
* (i.e. C:\...)
*
* (2) If the library file contains a relative path/file
* specification then the concatenation of the path
* and this file specification becomes filspc.
* (i.e. \...)
*
* The structure lbfile is created for the first library
* object file which contains the definition for the
* specified undefined symbol.
*
* If the library file [.LIB] contains file specifications for
* non existant files, no errors are returned.
*
* local variables:
* char buf[] [.REL] file input line
* char c [.REL] file input character
* FILE *fp file handle for object file
* lbfile *lbf temporary pointer
* lbfile *lbfh pointer to lbfile structure
* FILE *libfp file handle for library file
* lbname *lbnh pointer to lbname structure
* char *path file specification path
* char relfil[] [.REL] file specification
* char *str combined path and file specification
* char symname[] [.REL] file symbol string
*
* global variables:
* lbname *lbnhead The pointer to the first
* name structure
* lbfile *lbfhead The pointer to the first
* file structure
*
* functions called:
* int fclose() c_library
* int fgets() c_library
* FILE *fopen() c_library
* VOID free() c_library
* char getnb() lklex.c
* VOID lkexit() lkmain.c
* VOID loadfile() lklibr.c
* VOID * new() lksym.c
* char * sprintf() c_library
* int sscanf() c_library
* char * strcat() c_library
* char * strchr() c_library
* char * strcpy() c_library
* int strlen() c_library
* int strncmp() c_library
* VOID unget() lklex.c
*
* side effects:
* If the symbol is found then a new lbfile structure
* is created and added to the linked list of lbfile
* structures. The file containing the found symbol
* is linked.
*/
#ifdef INDEXLIB
/* First entry in the library object symbol cache */
mlibraryfile libr;
int fndsym( char *name )
{
struct lbfile *lbfh, *lbf;
pmlibraryfile ThisLibr;
pmlibrarysymbol ThisSym = NULL;
/* Build the index if this is the first call to fndsym */
if (libr.next==NULL)
buildlibraryindex();
/* Iterate through all library object files */
ThisLibr = libr.next;
while (ThisLibr) {
/* Iterate through all symbols in an object file */
ThisSym = ThisLibr->symbols->next;
while (ThisSym) {
if (!strcmp(ThisSym->name, name)) {
if (!ThisLibr->loaded) {
/* Object file is not loaded - add it to the list */
lbfh = (struct lbfile *) new (sizeof(struct lbfile));
if (lbfhead == NULL) {
lbfhead = lbfh;
} else {
lbf = lbfhead;
while (lbf->next)
lbf = lbf->next;
lbf->next = lbfh;
}
lbfh->libspc = ThisLibr->libspc;
lbfh->filspc = ThisLibr->str;
lbfh->relfil = (char *) new (strlen(ThisLibr->relfil) + 1);
strcpy(lbfh->relfil,ThisLibr->relfil);
loadfile(lbfh->filspc);
ThisLibr->loaded=1;
}
return (1); /* Found the symbol, return */
}
ThisSym=ThisSym->next; /* Next sym in library */
}
ThisLibr=ThisLibr->next; /* Next library in list */
}
return 0; /* Failure - symbol not found in any library */
};
/* buildlibraryindex - build an in-memory cache of the symbols contained in
* the libraries
*/
int buildlibraryindex()
{
FILE *libfp, *fp;
struct lbname *lbnh;
char relfil[NINPUT+2], *str, *path;
char buf[NINPUT+2], c;
char symname[NINPUT+2];
pmlibraryfile This;
pmlibrarysymbol ThisSym;
This=&libr;
/* Iterate through all library files */
/*1*/ for (lbnh=lbnhead; lbnh; lbnh=lbnh->next) {
libfp = fopen( lbnh->libspc, "r" );
if (libfp) {
path=lbnh->path;
/*
* Read in a line from the library file.
* This is the relative file specification
* for a .REL file in this library.
*/
/*2*/ while (fgets(relfil, NINPUT, libfp) != NULL) {
relfil[NINPUT+1] = '\0';
relfil[strlen(relfil) - 1] = '\0';
if (path != NULL) {
str = (char *)new(strlen(path)+strlen(relfil)+6);
strcpy(str,path);
#ifdef OTHERSYSTEM
#ifdef SDK
#ifdef UNIX
if (str[strlen(str)-1] != '/') {
strcat(str,"/");
#else /* UNIX */
if (str[strlen(str)-1] != '\\') {
strcat(str,"\\");
#endif /* UNIX */
#else /* SDK */
if (str[strlen(str)-1] != '\\') {
strcat(str,"\\");
#endif /* SDK */
}
#endif
} else {
str = (char *)new(strlen(relfil) + 5);
}
#ifdef SDK
#ifdef UNIX
if (relfil[0] == '/') {
#else /* UNIX */
if (relfil[0] == '\\') {
#endif /* UNIX */
#else /* SDK */
if (relfil[0] == '\\') {
#endif /* SDK */
strcat(str,relfil+1);
} else {
strcat(str,relfil);
}
if(strchr(str,FSEPX) == NULL) {
#ifdef SDK
sprintf(&str[strlen(str)], "%co", FSEPX);
#else /* SDK */
sprintf(&str[strlen(str)], "%crel", FSEPX);
#endif /* SDK */
}
/*3*/ if ((fp = fopen(str, "r")) != NULL) {
/* Opened OK - create a new libraryfile object for it */
This->next = (pmlibraryfile)new( sizeof( mlibraryfile ));
if (This->next == NULL) {
printf("panic: cant allocate memory.\n");
exit(-1);
}
This=This->next;
This->next = NULL;
This->loaded=-1;
strcpy( This->filename, str );
ThisSym = This->symbols = (pmlibrarysymbol)malloc( sizeof(mlibrarysymbol));
ThisSym->next = NULL;
/*
* Read in the object file. Look for lines that
* begin with "S" and end with "D". These are
* symbol table definitions. If we find one, see
* if it is our symbol. Make sure we only read in
* our object file and don't go into the next one.
*/
/*4*/ while (fgets(buf, NINPUT, fp) != NULL) {
buf[NINPUT+1] = '\0';
buf[strlen(buf) - 1] = '\0';
/*
* Skip everything that's not a symbol record.
*/
if (buf[0] != 'S')
continue;
/*
* When a 'T line' is found terminate file scan.
* All 'S line's preceed 'T line's in .REL files.
*/
if (buf[0] == 'T')
break;
sscanf(buf, "S %s %c", symname, &c);
/* If it's an actual symbol, record it */
/*5*/ if (c == 'D') {
ThisSym->next = (pmlibrarysymbol)malloc(sizeof(mlibrarysymbol));
ThisSym=ThisSym->next;
if (ThisSym == NULL) {
printf("panic: cant allocate memory.\n");
exit(-2);
}
This->loaded=0;
ThisSym->next=NULL;
This->str = str;
strcpy(This->relfil,relfil);
strcpy(ThisSym->name, symname);
This->libspc = lbnh->libspc;
}
} /* Closes while - read object file */
fclose(fp);
} /* Closes if object file opened OK */
} /* Ends while - processing all in libr */
fclose(libfp);
} /* Ends good open of libr file */
}
return 0;
}
#else /* INDEXLIB */
int
fndsym(name)
char *name;
{
FILE *libfp, *fp;
struct lbname *lbnh;
struct lbfile *lbfh, *lbf;
char relfil[NINPUT+2];
char buf[NINPUT+2];
char symname[NINPUT];
char *path,*str;
char c;
/*
* Search through every library in the linked list "lbnhead".
*/
/*1*/ for (lbnh=lbnhead; lbnh; lbnh=lbnh->next) {
if ((libfp = fopen(lbnh->libspc, "r")) == NULL) {
fprintf(stderr, "Cannot open library file %s\n",
lbnh->libspc);
lkexit(1);
}
path = lbnh->path;
/*
* Read in a line from the library file.
* This is the relative file specification
* for a .REL file in this library.
*/
/*2*/ while (fgets(relfil, NINPUT, libfp) != NULL) {
relfil[NINPUT+1] = '\0';
relfil[strlen(relfil) - 1] = '\0';
if (path != NULL) {
str = (char *) new (strlen(path)+strlen(relfil)+6);
strcpy(str,path);
#ifdef OTHERSYSTEM
#ifdef SDK
#ifdef UNIX
if (str[strlen(str)-1] != '/') {
strcat(str,"/");
#else /* UNIX */
if (str[strlen(str)-1] != '\\') {
strcat(str,"\\");
#endif /* UNIX */
#else /* SDK */
if (str[strlen(str)-1] != '\\') {
strcat(str,"\\");
#endif /* SDK */
}
#endif
} else {
str = (char *) new (strlen(relfil) + 5);
}
#ifdef SDK
#ifdef UNIX
if (relfil[0] == '/') {
#else /* UNIX */
if (relfil[0] == '\\') {
#endif /* UNIX */
#else /* SDK */
if (relfil[0] == '\\') {
#endif /* SDK */
strcat(str,relfil+1);
} else {
strcat(str,relfil);
}
if(strchr(str,FSEPX) == NULL) {
#ifdef SDK
sprintf(&str[strlen(str)], "%co", FSEPX);
#else /* SDK */
sprintf(&str[strlen(str)], "%crel", FSEPX);
#endif /* SDK */
}
/*3*/ if ((fp = fopen(str, "r")) != NULL) {
/*
* Read in the object file. Look for lines that
* begin with "S" and end with "D". These are
* symbol table definitions. If we find one, see
* if it is our symbol. Make sure we only read in
* our object file and don't go into the next one.
*/
/*4*/ while (fgets(buf, NINPUT, fp) != NULL) {
buf[NINPUT+1] = '\0';
buf[strlen(buf) - 1] = '\0';
/*
* Skip everything that's not a symbol record.
*/
if (buf[0] != 'S')
continue;
/*
* When a 'T line' is found terminate file scan.
* All 'S line's preceed 'T line's in .REL files.
*/
if (buf[0] == 'T')
break;
sscanf(buf, "S %s %c", symname, &c);
/*
* If we find a symbol definition for the
* symbol we're looking for, load in the
* file and add it to lbfhead so it gets
* loaded on pass number 2.
*/
/*5*/ if (strncmp(symname, name, NCPS) == 0 && c == 'D') {
lbfh = (struct lbfile *) new (sizeof(struct lbfile));
if (lbfhead == NULL) {
lbfhead = lbfh;
} else {
lbf = lbfhead;
while (lbf->next)
lbf = lbf->next;
lbf->next = lbfh;
}
lbfh->libspc = lbnh->libspc;
lbfh->filspc = str;
lbfh->relfil = (char *) new (strlen(relfil) + 1);
strcpy(lbfh->relfil,relfil);
fclose(fp);
fclose(libfp);
loadfile(str);
return (1);
/*5*/ }
/*4*/ }
fclose(fp);
/*3*/ }
free(str);
/*2*/ }
fclose(libfp);
/*1*/ }
return(0);
}
#endif /* INDEXLIB */
/*)Function VOID library()
*
* The function library() links all the library object files
* contained in the lbfile structures.
*
* local variables:
* lbfile *lbfh pointer to lbfile structure
*
* global variables:
* lbfile *lbfhead pointer to first lbfile structure
*
* functions called:
* VOID loadfile lklibr.c
*
* side effects:
* Links all files contained in the lbfile structures.
*/
VOID
library()
{
struct lbfile *lbfh;
for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
loadfile(lbfh->filspc);
}
}
/*)Function VOID loadfile(filspc)
*
* char *filspc library object file specification
*
* The function loadfile() links the library object module.
*
* local variables:
* FILE *fp file handle
* int i input line length
* char str[] file input line
*
* global variables:
* char *ip pointer to linker input string
*
* functions called:
* int fclose() c_library
* int fgets() c_library
* FILE * fopen() c_library
* VOID link() lkmain.c
* int strlen() c_library
*
* side effects:
* If file exists it is linked.
*/
VOID
loadfile(filspc)
char *filspc;
{
FILE *fp;
char str[NINPUT+2];
int i;
if ((fp = fopen(filspc,"r")) != NULL) {
while (fgets(str, NINPUT, fp) != NULL) {
str[NINPUT+1] = '\0';
i = strlen(str) - 1;
if (str[i] == '\n')
str[i] = '\0';
ip = str;
link();
}
fclose(fp);
}
}