4 * (C) Copyright 1989-1995
11 * With contributions for the
12 * object libraries from
14 * kenh@cmf.nrl.navy.mil
19 * Extensions: P. Felber
22 #define EQ(A,B) !strcmp((A),(B))
23 #define MAXLINE 254 /*when using fgets*/
32 * The module lklibr.c contains the functions which
33 * (1) specify the path(s) to library files [.LIB]
34 * (2) specify the library file(s) [.LIB] to search
35 * (3) search the library files for specific symbols
36 * and link the module containing this symbol
38 * lklibr.c contains the following functions:
50 typedef struct slibrarysymbol mlibrarysymbol;
51 typedef struct slibrarysymbol *pmlibrarysymbol;
53 struct slibrarysymbol {
58 typedef struct slibraryfile mlibraryfile;
59 typedef struct slibraryfile *pmlibraryfile;
66 char filename[FILSPC];
67 long offset; //if > 0, the embedded file offset in the library file libspc
68 pmlibrarysymbol symbols;
72 int buildlibraryindex();
75 /*)Function VOID addpath()
77 * The function addpath() creates a linked structure containing
78 * the paths to various object module library files.
81 * lbpath *lbph pointer to new path structure
82 * lbpath *lbp temporary pointer
85 * lbpath *lbphead The pointer to the first
89 * char getnb() lklex.c
90 * VOID * new() lksym.c
91 * int strlen() c_library
92 * char * strcpy() c_library
93 * VOID unget() lklex.c
96 * An lbpath structure may be created.
102 struct lbpath *lbph, *lbp;
104 lbph = (struct lbpath *) new (sizeof(struct lbpath));
105 if (lbphead == NULL) {
114 lbph->path = (char *) new (strlen(ip)+1);
115 strcpy(lbph->path, ip);
118 /*)Function VOID addlib()
120 * The function addlib() tests for the existance of a
121 * library path structure to determine the method of
122 * adding this library file to the library search structure.
124 * This function calls the function addfile() to actually
125 * add the library file to the search list.
128 * lbpath *lbph pointer to path structure
131 * lbpath *lbphead The pointer to the first
135 * VOID addfile() lklibr.c
136 * char getnb() lklex.c
137 * VOID unget() lklex.c
140 * The function addfile() may add the file to
141 * the library search list.
151 if (lbphead == NULL) {
155 for (lbph=lbphead; lbph; lbph=lbph->next) {
156 addfile(lbph->path,ip);
160 /*)Function VOID addfile(path,libfil)
162 * char *path library path specification
163 * char *libfil library file specification
165 * The function addfile() searches for the library file
166 * by concatenating the path and libfil specifications.
167 * if the library is found, an lbname structure is created
168 * and linked to any previously defined structures. This
169 * linked list is used by the function fndsym() to attempt
170 * to find any undefined symbols.
172 * The function does not give report an error on invalid
173 * path / file specifications or if the file is not found.
176 * lbname *lbnh pointer to new name structure
177 * lbname *lbn temporary pointer
180 * lbname *lbnhead The pointer to the first
184 * char getnb() lklex.c
185 * VOID * new() lksym.c
186 * int strlen() c_library
187 * char * strcpy() c_library
188 * VOID unget() lklex.c
191 * An lbname structure may be created.
201 struct lbname *lbnh, *lbn;
203 if ((path != NULL) && (strchr(libfil,':') == NULL)){
204 str = (char *) new (strlen(path) + strlen(libfil) + 6);
209 if (str[strlen(str)-1] != '/') {
212 if (str[strlen(str)-1] != '\\') {
216 if (str[strlen(str)-1] != '\\') {
222 str = (char *) new (strlen(libfil) + 5);
227 if (libfil[0] == '/') { libfil++; }
229 if (libfil[0] == '\\') { libfil++; }
232 if (libfil[0] == '\\') { libfil++; }
236 if(strchr(libfil,FSEPX) == NULL) {
237 sprintf(&str[strlen(str)], "%clib", FSEPX);
239 if ((fp = fopen(str, "r")) != NULL) {
241 lbnh = (struct lbname *) new (sizeof(struct lbname));
242 if (lbnhead == NULL) {
250 if ((path != NULL) && (strchr(libfil,':') == NULL)){
253 lbnh->libfil = (char *) new (strlen(libfil) + 1);
254 strcpy(lbnh->libfil,libfil);
261 /*)Function VOID search()
263 * The function search() looks through all the symbol tables
264 * at the end of pass 1. If any undefined symbols are found
265 * then the function fndsym() is called. Function fndsym()
266 * searches any specified library files to automagically
267 * import the object modules containing the needed symbol.
269 * After a symbol is found and imported by the function
270 * fndsym() the symbol tables are again searched. The
271 * symbol tables are search until no more symbols can be
272 * resolved within the library files. This ensures that
273 * back references from one library module to another are
277 * int i temporary counter
278 * sym *sp pointer to a symbol structure
279 * int symfnd found a symbol flag
282 * sym *symhash[] array of pointers to symbol tables
285 * int fndsym() lklibr.c
288 * If a symbol is found then the library object module
289 * containing the symbol will be imported and linked.
295 register struct sym *sp;
296 register int i, symfnd;
299 * Look for undefined symbols. Keep
300 * searching until no more symbols are resolved.
306 * Look through all the symbols
308 for (i=0; i<NHASH; ++i) {
311 /* If we find an undefined symbol
312 * (one where S_DEF is not set), then
313 * try looking for it. If we find it
314 * in any of the libraries then
315 * increment symfnd. This will force
316 * another pass of symbol searching and
317 * make sure that back references work.
319 if ((sp->s_type & S_DEF) == 0) {
320 if (fndsym(sp->s_id)) {
330 /*Load a .rel file embedded in a sdcclib file*/
331 void LoadRel(FILE * libfp, char * ModName)
336 while (fgets(str, NINPUT, libfp) != NULL)
338 str[NINPUT+1] = '\0';
343 if(EQ(str, "<FILE>"))
345 fgets(str, NINPUT, libfp);
346 str[NINPUT+1] = '\0';
348 if(EQ(str, ModName)) state=1;
351 printf("Bad offset in library file str=%s, Modname=%s\n", str, ModName);
357 if(EQ(str, "<REL>")) state=2;
360 if(EQ(str, "</REL>")) return;
368 /*)Function VOID fndsym(name)
370 * char *name symbol name to find
372 * The function fndsym() searches through all combinations of the
373 * library path specifications (input by the -k option) and the
374 * library file specifications (input by the -l option) that
375 * lead to an existing file.
377 * The file specicifation may be formed in one of two ways:
379 * (1) If the library file contained an absolute
380 * path/file specification then this becomes filspc.
383 * (2) If the library file contains a relative path/file
384 * specification then the concatenation of the path
385 * and this file specification becomes filspc.
388 * The structure lbfile is created for the first library
389 * object file which contains the definition for the
390 * specified undefined symbol.
392 * If the library file [.LIB] contains file specifications for
393 * non existant files, no errors are returned.
396 * char buf[] [.REL] file input line
397 * char c [.REL] file input character
398 * FILE *fp file handle for object file
399 * lbfile *lbf temporary pointer
400 * lbfile *lbfh pointer to lbfile structure
401 * FILE *libfp file handle for library file
402 * lbname *lbnh pointer to lbname structure
403 * char *path file specification path
404 * char relfil[] [.REL] file specification
405 * char *str combined path and file specification
406 * char symname[] [.REL] file symbol string
409 * lbname *lbnhead The pointer to the first
411 * lbfile *lbfhead The pointer to the first
415 * int fclose() c_library
416 * int fgets() c_library
417 * FILE *fopen() c_library
418 * VOID free() c_library
419 * char getnb() lklex.c
420 * VOID lkexit() lkmain.c
421 * VOID loadfile() lklibr.c
422 * VOID * new() lksym.c
423 * char * sprintf() c_library
424 * int sscanf() c_library
425 * char * strcat() c_library
426 * char * strchr() c_library
427 * char * strcpy() c_library
428 * int strlen() c_library
429 * int strncmp() c_library
430 * VOID unget() lklex.c
433 * If the symbol is found then a new lbfile structure
434 * is created and added to the linked list of lbfile
435 * structures. The file containing the found symbol
441 /* First entry in the library object symbol cache */
444 int fndsym( char *name )
446 struct lbfile *lbfh, *lbf;
447 pmlibraryfile ThisLibr;
448 pmlibrarysymbol ThisSym = NULL;
450 /* Build the index if this is the first call to fndsym */
454 /* Iterate through all library object files */
455 ThisLibr = libr.next;
458 /* Iterate through all symbols in an object file */
459 ThisSym = ThisLibr->symbols->next;
462 if (!strcmp(ThisSym->name, name)) {
463 if (!ThisLibr->loaded) {
464 /* Object file is not loaded - add it to the list */
465 lbfh = (struct lbfile *) new (sizeof(struct lbfile));
466 if (lbfhead == NULL) {
474 lbfh->libspc = ThisLibr->libspc;
475 lbfh->filspc = ThisLibr->str;
476 lbfh->relfil = (char *) new (strlen(ThisLibr->relfil) + 1);
477 strcpy(lbfh->relfil,ThisLibr->relfil);
478 lbfh->offset = ThisLibr->offset;
480 { /*For an embedded object file in a library*/
481 void loadfile_SdccLib(char * libspc, char * module, long offset);
482 loadfile_SdccLib(lbfh->libspc, lbfh->relfil, lbfh->offset);
485 { /*For a stand alone object file*/
486 loadfile(lbfh->filspc);
490 return (1); /* Found the symbol, return */
492 ThisSym=ThisSym->next; /* Next sym in library */
494 ThisLibr=ThisLibr->next; /* Next library in list */
496 return 0; /* Failure - symbol not found in any library */
499 pmlibraryfile buildlibraryindex_SdccLib(char * PathLib, FILE * libfp, char * DirLib, pmlibraryfile This)
501 char ModName[NCPS]="";
502 char FLine[MAXLINE+1];
504 long IndexOffset=0, FileOffset;
505 pmlibrarysymbol ThisSym;
510 fgets(FLine, MAXLINE, libfp);
516 if(EQ(FLine, "<INDEX>"))
518 /*The next line has the size of the index*/
520 fgets(FLine, MAXLINE, libfp);
522 IndexOffset=atol(FLine);
527 if(EQ(FLine, "<MODULE>"))
529 /*The next line has the name of the module and the offset
530 of the corresponding embedded file in the library*/
532 fgets(FLine, MAXLINE, libfp);
534 sscanf(FLine, "%s %ld", ModName, &FileOffset);
537 /*create a new libraryfile object for this module*/
538 This->next = (pmlibraryfile)new( sizeof( mlibraryfile ));
539 if (This->next == NULL)
541 printf("panic: can't allocate memory.\n");
547 This->loaded=-1; /*Kind of useless, but...*/
548 This->offset=FileOffset+IndexOffset;
549 This->libspc=PathLib;
550 strcpy(This->relfil, ModName);
553 sprintf(This->filename, "%s%s%co", DirLib, ModName, FSEPX);
555 sprintf(This->filename, "%s%s%crel", DirLib, ModName, FSEPX);
558 This->str=This->filename;
560 ThisSym = This->symbols = (pmlibrarysymbol)malloc( sizeof(mlibrarysymbol));
561 ThisSym->next = NULL;
563 else if(EQ(FLine, "</INDEX>"))
565 return This; /*Finish, get out of here*/
569 if(EQ(FLine, "</MODULE>"))
572 /*Create the index for the next module*/
578 ThisSym->next = (pmlibrarysymbol)malloc(sizeof(mlibrarysymbol));
579 ThisSym=ThisSym->next;
582 printf("panic: can't allocate memory.\n");
586 strcpy(ThisSym->name, FLine);
591 return This; /*State machine should never reach this point, but just in case...*/
596 return This; /*State machine should never reach this point, but just in case...*/
600 /* buildlibraryindex - build an in-memory cache of the symbols contained in
603 int buildlibraryindex(void)
607 char relfil[NINPUT+2], *str, *path;
608 char buf[NINPUT+2], c;
609 char symname[NINPUT+2];
611 pmlibrarysymbol ThisSym;
615 /* Iterate through all library files */
616 /*1*/ for (lbnh=lbnhead; lbnh; lbnh=lbnh->next) {
617 libfp = fopen( lbnh->libspc, "r" );
622 * Read in a line from the library file.
623 * This is the relative file specification
624 * for a .REL file in this library.
627 /*2*/ while (fgets(relfil, NINPUT, libfp) != NULL) {
628 relfil[NINPUT+1] = '\0';
631 str = (char *)new(strlen(path)+strlen(relfil)+6);
636 if (str[strlen(str)-1] != '/') {
639 if (str[strlen(str)-1] != '\\') {
643 if (str[strlen(str)-1] != '\\') {
649 str = (char *)new(strlen(relfil) + 5);
652 if(strcmp(relfil, "<SDCCLIB>")==0)
654 /*Get the built in index of a library*/
655 This=buildlibraryindex_SdccLib(lbnh->libspc, libfp, str, This);
658 break; /*get the index for next library*/
661 /*From here down, build the index for the original library
665 if (relfil[0] == '/') {
667 if (relfil[0] == '\\') {
670 if (relfil[0] == '\\') {
672 strcat(str,relfil+1);
676 if(strchr(str,FSEPX) == NULL) {
678 sprintf(&str[strlen(str)], "%co", FSEPX);
680 sprintf(&str[strlen(str)], "%crel", FSEPX);
683 /*3*/ if ((fp = fopen(str, "r")) != NULL) {
685 /* Opened OK - create a new libraryfile object for it */
686 This->next = (pmlibraryfile)new( sizeof( mlibraryfile ));
687 if (This->next == NULL) {
688 printf("panic: can't allocate memory.\n");
695 This->offset=-1; /*There should be a rel file*/
697 strcpy( This->filename, str );
699 ThisSym = This->symbols = (pmlibrarysymbol)malloc( sizeof(mlibrarysymbol));
700 ThisSym->next = NULL;
703 * Read in the object file. Look for lines that
704 * begin with "S" and end with "D". These are
705 * symbol table definitions. If we find one, see
706 * if it is our symbol. Make sure we only read in
707 * our object file and don't go into the next one.
710 /*4*/ while (fgets(buf, NINPUT, fp) != NULL) {
712 buf[NINPUT+1] = '\0';
713 buf[strlen(buf) - 1] = '\0';
716 * Skip everything that's not a symbol record.
722 * When a 'T line' is found terminate file scan.
723 * All 'S line's preceed 'T line's in .REL files.
728 sscanf(buf, "S %s %c", symname, &c);
730 /* If it's an actual symbol, record it */
731 /*5*/ if (c == 'D') {
732 ThisSym->next = (pmlibrarysymbol)malloc(sizeof(mlibrarysymbol));
733 ThisSym=ThisSym->next;
734 if (ThisSym == NULL) {
735 printf("panic: can't allocate memory.\n");
741 strcpy(This->relfil,relfil);
742 strcpy(ThisSym->name, symname);
743 This->libspc = lbnh->libspc;
745 } /* Closes while - read object file */
747 } /* Closes if object file opened OK */
748 } /* Ends while - processing all in libr */
750 } /* Ends good open of libr file */
757 /*Check for a symbol in a SDCC library. If found, add the embedded .rel.
758 The library must be created with the SDCC librarian 'sdcclib' since the
759 linking process depends on the correct file offsets embedded in the library
762 int SdccLib(char * PathLib, FILE * libfp, char * DirLib, char * SymName)
764 struct lbfile *lbfh, *lbf;
765 char ModName[NCPS]="";
766 char FLine[MAXLINE+1];
768 long IndexOffset=0, FileOffset;
773 fgets(FLine, MAXLINE, libfp);
779 if(EQ(FLine, "<INDEX>"))
781 /*The next line has the size of the index*/
783 fgets(FLine, MAXLINE, libfp);
785 IndexOffset=atol(FLine);
790 if(EQ(FLine, "<MODULE>"))
792 /*The next line has the name of the module and the offset
793 of the corresponding embedded file in the library*/
795 fgets(FLine, MAXLINE, libfp);
797 sscanf(FLine, "%s %ld", ModName, &FileOffset);
800 else if(EQ(FLine, "</INDEX>"))
802 /*Reached the end of the index. The symbol is not in this library.*/
807 if(EQ(FLine, "</MODULE>"))
809 /*The symbol is not in this module, try the next one*/
814 /*Check if this is the symbol we are looking for.*/
815 if (strncmp(SymName, FLine, NCPS)==0)
817 /*The symbol is in this module.*/
819 /*As in the original library format, it is assumed that the .rel
820 files reside in the same directory as the lib files.*/
821 strcat(DirLib, ModName);
823 sprintf(&DirLib[strlen(DirLib)], "%co", FSEPX);
825 sprintf(&DirLib[strlen(DirLib)], "%crel", FSEPX);
828 /*If this module has been loaded already don't load it again.*/
832 if(EQ(DirLib, lbf->filspc)) return 1;/*Already loaded*/
836 /*Add the embedded file to the list of files to be loaded in
837 the second pass. That is performed latter by the function
839 lbfh = (struct lbfile *) new (sizeof(struct lbfile));
852 lbfh->libspc = PathLib;
853 lbfh->filspc = DirLib;
854 lbfh->relfil = (char *) new (strlen(ModName) + 1);
855 strcpy(lbfh->relfil, ModName);
856 /*Library embedded file, so lbfh->offset must be >=0*/
857 lbfh->offset = IndexOffset+FileOffset;
859 /*Jump to where the .rel begins and load it.*/
860 fseek(libfp, lbfh->offset, SEEK_SET);
861 LoadRel(libfp, ModName);
863 return 1; /*Found the symbol, so success!*/
869 return 0; /*It should never reach this point, but just in case...*/
874 return 0; /*The symbol is not in this library*/
883 struct lbfile *lbfh, *lbf;
884 char relfil[NINPUT+2];
886 char symname[NINPUT];
892 * Search through every library in the linked list "lbnhead".
895 /*1*/ for (lbnh=lbnhead; lbnh; lbnh=lbnh->next) {
896 if ((libfp = fopen(lbnh->libspc, "r")) == NULL) {
897 fprintf(stderr, "Cannot open library file %s\n",
904 * Read in a line from the library file.
905 * This is the relative file specification
906 * for a .REL file in this library.
909 /*2*/ while (fgets(relfil, NINPUT, libfp) != NULL) {
910 relfil[NINPUT+1] = '\0';
913 str = (char *) new (strlen(path)+strlen(relfil)+6);
918 if (str[strlen(str)-1] != '/') {
921 if (str[strlen(str)-1] != '\\') {
925 if (str[strlen(str)-1] != '\\') {
931 str = (char *) new (strlen(relfil) + 5);
934 /*See if this is a library with embedded files*/
935 if(strcmp(relfil, "<SDCCLIB>")==0)
937 result=SdccLib(lbnh->libspc, libfp, str, name);
939 if(result) return(1); /*Found the symbol*/
941 /*The symbol is not in the current library,
942 check the next library in the list*/
946 /*From here down is the support for libraries in the original format*/
949 if (relfil[0] == '/') {
951 if (relfil[0] == '\\') {
954 if (relfil[0] == '\\') {
956 strcat(str,relfil+1);
960 if(strchr(relfil,FSEPX) == NULL) {
962 sprintf(&str[strlen(str)], "%co", FSEPX);
964 sprintf(&str[strlen(str)], "%crel", FSEPX);
967 /*3*/ if ((fp = fopen(str, "r")) != NULL) {
970 * Read in the object file. Look for lines that
971 * begin with "S" and end with "D". These are
972 * symbol table definitions. If we find one, see
973 * if it is our symbol. Make sure we only read in
974 * our object file and don't go into the next one.
977 /*4*/ while (fgets(buf, NINPUT, fp) != NULL) {
979 buf[NINPUT+1] = '\0';
980 buf[strlen(buf) - 1] = '\0';
983 * Skip everything that's not a symbol record.
989 * When a 'T line' is found terminate file scan.
990 * All 'S line's preceed 'T line's in .REL files.
995 sscanf(buf, "S %s %c", symname, &c);
998 * If we find a symbol definition for the
999 * symbol we're looking for, load in the
1000 * file and add it to lbfhead so it gets
1001 * loaded on pass number 2.
1003 /*5*/ if (strncmp(symname, name, NCPS) == 0 && c == 'D') {
1005 lbfh = (struct lbfile *) new (sizeof(struct lbfile));
1006 if (lbfhead == NULL) {
1014 lbfh->libspc = lbnh->libspc;
1016 lbfh->relfil = (char *) new (strlen(relfil) + 1);
1017 lbfh->offset = -1; /*Stand alone rel file*/
1018 strcpy(lbfh->relfil,relfil);
1036 #endif /* INDEXLIB */
1038 void loadfile_SdccLib(char * libspc, char * module, long offset)
1042 if ((fp = fopen(libspc,"r")) != NULL)
1044 fseek(fp, offset, SEEK_SET);
1045 LoadRel(fp, module);
1050 /*)Function VOID library()
1052 * The function library() links all the library object files
1053 * contained in the lbfile structures.
1056 * lbfile *lbfh pointer to lbfile structure
1059 * lbfile *lbfhead pointer to first lbfile structure
1062 * VOID loadfile lklibr.c
1065 * Links all files contained in the lbfile structures.
1071 struct lbfile *lbfh;
1073 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next)
1077 /*Stand alone rel file (original lib format)*/
1078 loadfile(lbfh->filspc);
1082 /*rel file embedded in lib (new lib format)*/
1083 loadfile_SdccLib(lbfh->libspc, lbfh->relfil, lbfh->offset);
1088 /*)Function VOID loadfile(filspc)
1090 * char *filspc library object file specification
1092 * The function loadfile() links the library object module.
1095 * FILE *fp file handle
1096 * int i input line length
1097 * char str[] file input line
1100 * char *ip pointer to linker input string
1103 * int fclose() c_library
1104 * int fgets() c_library
1105 * FILE * fopen() c_library
1106 * VOID link() lkmain.c
1107 * int strlen() c_library
1110 * If file exists it is linked.
1121 if ((fp = fopen(filspc,"r")) != NULL) {
1122 while (fgets(str, NINPUT, fp) != NULL) {
1123 str[NINPUT+1] = '\0';
1124 i = strlen(str) - 1;