Support for files created with the sdcc librarian
[fw/sdcc] / as / mcs51 / lklibr.c
1 /* lklibr.c */
2
3 /*
4  * (C) Copyright 1989-1995
5  * All Rights Reserved
6  *
7  * Alan R. Baldwin
8  * 721 Berkeley St.
9  * Kent, Ohio  44240
10  *
11  * With contributions for the
12  * object libraries from
13  * Ken Hornstein
14  * kenh@cmf.nrl.navy.mil
15  *
16  */
17
18 #define EQ(A,B) !strcmp((A),(B))
19 #define MAXLINE 254 /*when using fgets*/
20
21 #if defined(__APPLE__) && defined(__MACH__)
22 #include <sys/types.h>
23 #include <sys/malloc.h>
24 #else
25 #include <malloc.h>
26 #endif
27 #include <stdio.h>
28 #include <string.h>
29 #include "aslink.h"
30
31 /*)Module       lklibr.c
32  *
33  *      The module lklibr.c contains the functions which
34  *      (1) specify the path(s) to library files [.LIB]
35  *      (2) specify the library file(s) [.LIB] to search
36  *      (3) search the library files for specific symbols
37  *          and link the module containing this symbol
38  *
39  *      lklibr.c contains the following functions:
40  *              VOID    addpath()
41  *              VOID    addlib()
42  *              VOID    addfile()
43  *              VOID    search()
44  *              VOID    fndsym()
45  *              VOID    library()
46  *              VOID    loadfile()
47  *
48  */
49
50 /*)Function     VOID    addpath()
51  *
52  *      The function addpath() creates a linked structure containing
53  *      the paths to various object module library files.
54  *
55  *      local variables:
56  *              lbpath  *lbph           pointer to new path structure
57  *              lbpath  *lbp            temporary pointer
58  *
59  *      global variables:
60  *              lbpath  *lbphead        The pointer to the first
61  *                                      path structure
62  *
63  *       functions called:
64  *              char    getnb()         lklex.c
65  *              VOID *  new()           lksym.c
66  *              int     strlen()        c_library
67  *              char *  strcpy()        c_library
68  *              VOID    unget()         lklex.c
69  *
70  *      side effects:
71  *              An lbpath structure may be created.
72  */
73
74 VOID
75 addpath()
76 {
77         struct lbpath *lbph, *lbp;
78
79         lbph = (struct lbpath *) new (sizeof(struct lbpath));
80         if (lbphead == NULL) {
81                 lbphead = lbph;
82         } else {
83                 lbp = lbphead;
84                 while (lbp->next)
85                         lbp = lbp->next;
86                 lbp->next = lbph;
87         }
88         unget(getnb());
89         lbph->path = (char *) new (strlen(ip)+1);
90         strcpy(lbph->path, ip);
91 }
92
93 /*)Function     VOID    addlib()
94  *
95  *      The function addlib() tests for the existance of a
96  *      library path structure to determine the method of
97  *      adding this library file to the library search structure.
98  *
99  *      This function calls the function addfile() to actually
100  *      add the library file to the search list.
101  *
102  *      local variables:
103  *              lbpath  *lbph           pointer to path structure
104  *
105  *      global variables:
106  *              lbpath  *lbphead        The pointer to the first
107  *                                      path structure
108  *
109  *       functions called:
110  *              VOID    addfile()       lklibr.c
111  *              char    getnb()         lklex.c
112  *              VOID    unget()         lklex.c
113  *
114  *      side effects:
115  *              The function addfile() may add the file to
116  *              the library search list.
117  */
118
119 VOID
120 addlib()
121 {
122         struct lbpath *lbph;
123
124         unget(getnb());
125
126         if (lbphead == NULL) {
127                 addfile(NULL,ip);
128                 return;
129         }       
130         for (lbph=lbphead; lbph; lbph=lbph->next) {
131                 addfile(lbph->path,ip);
132         }
133 }
134
135 /*)Function     VOID    addfile(path,libfil)
136  *
137  *              char    *path           library path specification
138  *              char    *libfil         library file specification
139  *
140  *      The function addfile() searches for the library file
141  *      by concatenating the path and libfil specifications.
142  *      if the library is found, an lbname structure is created
143  *      and linked to any previously defined structures.  This
144  *      linked list is used by the function fndsym() to attempt
145  *      to find any undefined symbols.
146  *
147  *      The function does not give report an error on invalid
148  *      path / file specifications or if the file is not found.
149  *
150  *      local variables:
151  *              lbname  *lbnh           pointer to new name structure
152  *              lbname  *lbn            temporary pointer
153  *
154  *      global variables:
155  *              lbname  *lbnhead        The pointer to the first
156  *                                      path structure
157  *
158  *       functions called:
159  *              char    getnb()         lklex.c
160  *              VOID *  new()           lksym.c
161  *              int     strlen()        c_library
162  *              char *  strcpy()        c_library
163  *              VOID    unget()         lklex.c
164  *
165  *      side effects:
166  *              An lbname structure may be created.
167  */
168
169 VOID
170 addfile(path,libfil)
171 char *path;
172 char *libfil;
173 {
174         FILE *fp;
175         char *str;
176         struct lbname *lbnh, *lbn;
177
178         if ((path != NULL) && (strchr(libfil,':') == NULL)){
179                 str = (char *) new (strlen(path) + strlen(libfil) + 6);
180                 strcpy(str,path);
181 #ifdef  OTHERSYSTEM
182                 if (str[strlen(str)-1] != '/') {
183                         strcat(str,"/");
184                 }
185 #endif
186         } else {
187                 str = (char *) new (strlen(libfil) + 5);
188         }
189 #ifdef  OTHERSYSTEM
190         if (libfil[0] == '/') { libfil++; }
191 #endif
192         strcat(str,libfil);
193         if(strchr(libfil,FSEPX) == NULL) {
194                 sprintf(&str[strlen(str)], "%clib", FSEPX);
195         }
196         if ((fp = fopen(str, "r")) != NULL) {
197                 fclose(fp);
198                 lbnh = (struct lbname *) new (sizeof(struct lbname));
199                 if (lbnhead == NULL) {
200                         lbnhead = lbnh;
201                 } else {
202                         lbn = lbnhead;
203                         while (lbn->next)
204                                 lbn = lbn->next;
205                         lbn->next = lbnh;
206                 }
207                 if ((path != NULL) && (strchr(libfil,':') == NULL)){
208                         lbnh->path = path;
209                 }
210                 lbnh->libfil = (char *) new (strlen(libfil) + 1);
211                 strcpy(lbnh->libfil,libfil);
212                 lbnh->libspc = str;
213         } else {
214                 free(str);
215         }
216 }
217
218 /*)Function     VOID    search()
219  *
220  *      The function search() looks through all the symbol tables
221  *      at the end of pass 1.  If any undefined symbols are found
222  *      then the function fndsym() is called. Function fndsym()
223  *      searches any specified library files to automagically
224  *      import the object modules containing the needed symbol.
225  *
226  *      After a symbol is found and imported by the function
227  *      fndsym() the symbol tables are again searched.  The
228  *      symbol tables are search until no more symbols can be
229  *      resolved within the library files.  This ensures that
230  *      back references from one library module to another are
231  *      also resolved.
232  *
233  *      local variables:
234  *              int     i               temporary counter
235  *              sym     *sp             pointer to a symbol structure
236  *              int     symfnd          found a symbol flag
237  *
238  *      global variables:
239  *              sym     *symhash[]      array of pointers to symbol tables
240  *
241  *       functions called:
242  *              int     fndsym()        lklibr.c
243  *
244  *      side effects:
245  *              If a symbol is found then the library object module
246  *              containing the symbol will be imported and linked.
247  */
248
249 VOID
250 search()
251 {
252         register struct sym *sp;
253         register int i,symfnd;
254
255         /*
256          * Look for undefined symbols.  Keep
257          * searching until no more symbols are resolved.
258          */
259         symfnd = 1;
260         while (symfnd) {
261                 symfnd = 0;
262                 /*
263                  * Look through all the symbols
264                  */
265                 for (i=0; i<NHASH; ++i) {
266                         sp = symhash[i];
267                         while (sp) {
268                                 /* If we find an undefined symbol
269                                  * (one where S_DEF is not set), then
270                                  * try looking for it.  If we find it
271                                  * in any of the libraries then
272                                  * increment symfnd.  This will force
273                                  * another pass of symbol searching and
274                                  * make sure that back references work.
275                                  */
276                                 if ((sp->s_type & S_DEF) == 0) {
277                                         if (fndsym(sp->s_id)) {
278                                                 symfnd++;
279                                         }
280                                 }
281                                 sp = sp->s_sp;
282                         }
283                 }
284         }
285 }
286
287 /*Load a .rel file embedded in a sdcclib file*/
288 void LoadRel(FILE * libfp, char * ModName)
289 {
290         char str[NINPUT+2];
291         int state=0;
292
293         while (fgets(str, NINPUT, libfp) != NULL)
294         {
295                 str[NINPUT+1] = '\0';
296                 chop_crlf(str);
297                 switch(state)
298                 {
299                         case 0:
300                                 if(EQ(str, "<FILE>"))
301                                 {
302                                         fgets(str, NINPUT, libfp);
303                                         str[NINPUT+1] = '\0';
304                                         chop_crlf(str);
305                                         if(EQ(str, ModName)) state=1;
306                                         else
307                                         {
308                                                 printf("Bad offset in library file str=%s, Modname=%s\n", str, ModName);
309                                                 lkexit(1);
310                                         }
311                                 }
312                         break;
313                         case 1:
314                                 if(EQ(str, "<REL>")) state=2;
315                         break;
316                         case 2:
317                                 if(EQ(str, "</REL>")) return;
318                                 ip = str;
319                                 link_main();
320                         break;
321                 }
322         }
323 }
324
325 /*Load an .adb file embedded in a sdcclib file.  If there is
326 something between <ADB> and </ADB> returns 1, otherwise returns 0.
327 This way the aomf51 will not have uselless empty modules. */
328
329 int LoadAdb(FILE * libfp)
330 {
331         char str[MAXLINE+1];
332         int state=0;
333         int ToReturn=0;
334
335         while (fgets(str, MAXLINE, libfp) != NULL)
336         {
337                 str[NINPUT+1] = '\0';
338                 chop_crlf(str);
339                 switch(state)
340                 {
341                         case 0:
342                                 if(EQ(str, "<ADB>")) state=1;
343                         break;
344                         case 1:
345                                 if(EQ(str, "</ADB>")) return ToReturn;
346                                 fprintf(dfp, "%s\n", str);
347                                 ToReturn=1;
348                         break;
349                 }
350         }
351         return ToReturn;
352 }
353
354 /*Check for a symbol in a SDCC library.  If found, add the embedded .rel and
355 .adb files from the library.  The library must be created with the SDCC
356 librarian 'sdcclib' since the linking process depends on the correct file offsets
357 embedded in the library file.*/
358
359 int SdccLib(char * PathLib, FILE * libfp, char * DirLib, char * SymName)
360 {
361         struct lbfile *lbfh, *lbf;
362         char name[NCPS]="";
363         char ModName[NCPS]="";
364         char FLine[MAXLINE+1];
365         int state=0;
366         long IndexOffset, FileOffset;
367
368         while(!feof(libfp))
369     {
370         FLine[0]=0;
371         fgets(FLine, MAXLINE, libfp);
372         chop_crlf(FLine);
373
374         switch(state)
375         {
376             case 0:
377                 if(EQ(FLine, "<INDEX>"))
378                 {
379                                         /*The next line has the size of the index*/
380                     FLine[0]=0;
381                     fgets(FLine, MAXLINE, libfp);
382                     chop_crlf(FLine);
383                                         IndexOffset=atol(FLine);
384                                         state=1;
385                 }
386             break;
387             case 1:
388                 if(EQ(FLine, "<MODULE>"))
389                                 {
390                                         /*The next line has the name of the module and the offset
391                                         of the corresponding embedded file in the library*/
392                     FLine[0]=0;
393                     fgets(FLine, MAXLINE, libfp);
394                     chop_crlf(FLine);
395                                         sscanf(FLine, "%s %ld", ModName, &FileOffset);
396                                         state=2;
397                                 }
398                 else if(EQ(FLine, "</INDEX>"))
399                                 {
400                                         /*Reached the end of the index.  The symbol is not in this library.*/
401                                         return 0;
402                                 }
403             break;
404             case 2:
405                 if(EQ(FLine, "</MODULE>"))
406                                 {
407                                         /*The symbol is not in this module, try the next one*/
408                     state=1;
409                                 }
410                 else
411                                 {
412                                         /*Check if this is the symbol we are looking for.*/
413                                         if (strncmp(SymName, FLine, NCPS)==0)
414                                         {
415                                                 /*The symbol is in this module.*/
416
417                                                 /*As in the original library format, it is assumed that the .rel
418                                                 files reside in the same directory as the lib files.*/
419                                                 strcat(DirLib, ModName);
420                                                 strcat(DirLib, ".rel"); /*FSEPX???*/
421
422                                                 /*If this module has been loaded already don't load it again.*/
423                                                 lbf = lbfhead;
424                                                 while (lbf)
425                                                 {
426                                                         if(EQ(DirLib, lbf->filspc)) return 1;/*Already loaded*/
427                                                         lbf=lbf->next;
428                                                 }
429                                                 
430                                                 /*Add the embedded file to the list of files to be loaded in
431                                                 the second pass.  That is performed latter by the function
432                                                 library() below.*/
433                                                 lbfh = (struct lbfile *) new (sizeof(struct lbfile));
434                                                 if (lbfhead == NULL)
435                                                 {
436                                                         lbfhead = lbfh;
437                                                 }
438                                                 else
439                                                 {
440                                                         lbf = lbfhead;
441                                                         while (lbf->next)
442                                                         lbf = lbf->next;
443                                                         lbf->next = lbfh;
444                                                 }
445
446                                                 lbfh->libspc = PathLib;
447                                                 lbfh->filspc = DirLib;
448                                                 lbfh->relfil = (char *) new (strlen(ModName) + 1);
449                                                 strcpy(lbfh->relfil, ModName);
450                                                 /*Library embedded file, so lbfh->offset must be >=0*/
451                                                 lbfh->offset = IndexOffset+FileOffset;
452                                                 
453                                                 /*Jump to where the .rel begins and load it.*/
454                                                 fseek(libfp, lbfh->offset, SEEK_SET);
455                                                 LoadRel(libfp, ModName);
456
457                                                 /* if cdb information required & .adb file present */
458                                                 if (dflag && dfp)
459                                                 {
460                                                         if(LoadAdb(libfp))
461                                                                 SaveLinkedFilePath(DirLib);
462                                                 }
463                                                 return 1; /*Found the symbol, so success!*/
464                                         }
465                                 }
466             break;
467                         
468                         default:
469                                 return 0; /*It should never reach this point, but just in case...*/
470                         break;
471         }
472     }
473
474         return 0; /*The symbol is not in this library*/
475 }
476
477 /*)Function     VOID    fndsym(name)
478  *
479  *              char    *name           symbol name to find
480  *
481  *      The function fndsym() searches through all combinations of the
482  *      library path specifications (input by the -k option) and the
483  *      library file specifications (input by the -l option) that
484  *      lead to an existing file.
485  *
486  *      The file specicifation may be formed in one of two ways:
487  *
488  *      (1)     If the library file contained an absolute
489  *              path/file specification then this becomes filspc.
490  *              (i.e. C:\...)
491  *
492  *      (2)     If the library file contains a relative path/file
493  *              specification then the concatenation of the path
494  *              and this file specification becomes filspc.
495  *              (i.e. \...)
496  *
497  *      The structure lbfile is created for the first library
498  *      object file which contains the definition for the
499  *      specified undefined symbol.
500  *
501  *      If the library file [.LIB] contains file specifications for
502  *      non existant files, no errors are returned.
503  *
504  *      local variables:
505  *              char    buf[]           [.REL] file input line
506  *              char    c               [.REL] file input character
507  *              FILE    *fp             file handle for object file
508  *              lbfile  *lbf            temporary pointer
509  *              lbfile  *lbfh           pointer to lbfile structure
510  *              FILE    *libfp          file handle for library file
511  *              lbname  *lbnh           pointer to lbname structure
512  *              char    *path           file specification path
513  *              char    relfil[]        [.REL] file specification
514  *              char    *str            combined path and file specification
515  *              char    symname[]       [.REL] file symbol string
516  *
517  *      global variables:
518  *              lbname  *lbnhead        The pointer to the first
519  *                                      name structure
520  *              lbfile  *lbfhead        The pointer to the first
521  *                                      file structure
522  *
523  *       functions called:
524  *              int     fclose()        c_library
525  *              int     fgets()         c_library
526  *              FILE    *fopen()        c_library
527  *              VOID    free()          c_library
528  *              char    getnb()         lklex.c
529  *              VOID    lkexit()        lkmain.c
530  *              VOID    loadfile()      lklibr.c
531  *              VOID *  new()           lksym.c
532  *              char *  sprintf()       c_library
533  *              int     sscanf()        c_library
534  *              char *  strcat()        c_library
535  *              char *  strchr()        c_library
536  *              char *  strcpy()        c_library
537  *              int     strlen()        c_library
538  *              int     strncmp()       c_library
539  *              VOID    unget()         lklex.c
540  *
541  *      side effects:
542  *              If the symbol is found then a new lbfile structure
543  *              is created and added to the linked list of lbfile
544  *              structures.  The file containing the found symbol
545  *              is linked.
546  */
547
548 int
549 fndsym(name)
550 char *name;
551 {
552         FILE *libfp, *fp;
553         struct lbname *lbnh;
554         struct lbfile *lbfh, *lbf;
555         char relfil[NINPUT+2];
556         char buf[NINPUT+2];
557         char symname[NINPUT];
558         char *path,*str;
559         char c;
560         int result;
561
562         /*
563          * Search through every library in the linked list "lbnhead".
564          */
565
566         for (lbnh=lbnhead; lbnh; lbnh=lbnh->next)
567         {
568                 if ((libfp = fopen(lbnh->libspc, "r")) == NULL)
569                 {
570                         fprintf(stderr, "Cannot open library file %s\n",
571                                 lbnh->libspc);
572                         lkexit(1);
573                 }
574                 path = lbnh->path;
575
576                 /*
577                  * Read in a line from the library file.
578                  * This is the relative file specification
579                  * for a .REL file in this library.
580                  */
581
582                 while (fgets(relfil, NINPUT, libfp) != NULL)
583                 {
584                     relfil[NINPUT+1] = '\0';
585                     chop_crlf(relfil);
586                     if (path != NULL)
587                         {
588                                 str = (char *) new (strlen(path)+strlen(relfil)+6);
589                                 strcpy(str,path);
590 #ifdef  OTHERSYSTEM
591                                 if (str[strlen(str)-1] != '/')
592                                 {
593                                         strcat(str,"/");
594                                 }
595 #endif
596                     }
597                         else
598                         {
599                                 str = (char *) new (strlen(relfil) + 5);
600                     }
601
602                         if(strcmp(relfil, "<SDCCLIB>")==0)
603                         {
604                                 result=SdccLib(lbnh->libspc, libfp, str, name);
605                                 fclose(libfp);
606                                 if(result) return(1); /*Found the symbol*/
607                                 free(str);
608                                 /*The symbol is not in the current library,
609                                 check the next library in the list*/
610                                 break; 
611                         }
612
613                         /*From here down is the support for libraries in the original format*/
614                         if (relfil[0] == '\\')
615                         {
616                                 strcat(str,relfil+1);
617                     }
618                         else
619                         {
620                                 strcat(str,relfil);
621                     }
622                     
623                         if(strchr(relfil, FSEPX) == NULL)
624                         {
625                                 sprintf(&str[strlen(str)], "%crel", FSEPX);
626                     }
627
628                         if ((fp = fopen(str, "r")) != NULL)
629                         {
630
631                                 /*
632                                  * Read in the object file.  Look for lines that
633                                  * begin with "S" and end with "D".  These are
634                                  * symbol table definitions.  If we find one, see
635                                  * if it is our symbol.  Make sure we only read in
636                                  * our object file and don't go into the next one.
637                                  */
638                         
639                                 while (fgets(buf, NINPUT, fp) != NULL)
640                                 {
641                                         buf[NINPUT+1] = '\0';
642                                         chop_crlf(buf);
643                                         /*
644                                          * Skip everything that's not a symbol record.
645                                          */
646                                         if (buf[0] != 'S') continue;
647
648                                         /*
649                                         * When a 'T line' is found terminate file scan.
650                                         * All 'S line's preceed 'T line's in .REL files.
651                                         */
652                                         if (buf[0] == 'T') break;
653
654                                         sscanf(buf, "S %s %c", symname, &c);
655
656                                         /*
657                                         * If we find a symbol definition for the
658                                         * symbol we're looking for, load in the
659                                         * file and add it to lbfhead so it gets
660                                         * loaded on pass number 2.
661                                         */
662                                         if (strncmp(symname, name, NCPS) == 0 && c == 'D')
663                                         {
664                                                 lbfh = (struct lbfile *) new (sizeof(struct lbfile));
665                                                 if (lbfhead == NULL)
666                                                 {
667                                                         lbfhead = lbfh;
668                                                 }
669                                                 else
670                                                 {
671                                                         lbf = lbfhead;
672                                                         while (lbf->next)
673                                                         lbf = lbf->next;
674                                                         lbf->next = lbfh;
675                                                 }
676
677                                                 lbfh->libspc = lbnh->libspc;
678                                                 lbfh->filspc = str;
679                                                 lbfh->relfil = (char *) new (strlen(relfil) + 1);
680                                                 lbfh->offset = -1; /*Stand alone rel file*/
681                                                 strcpy(lbfh->relfil,relfil);
682                                                 fclose(fp);
683                                                 fclose(libfp);                 
684                         
685                                                 /* if cdb information required & adb file present */
686                                                 if (dflag && dfp)
687                                                 {
688                                                         FILE *xfp = afile(str,"adb",0); //JCF: Nov 30, 2002
689                                                         if (xfp)
690                                                         {
691                                                                 SaveLinkedFilePath(str);
692                                                                 copyfile(dfp,xfp);
693                                                                 fclose(xfp);
694                                                         }
695                                                 }
696                                                 loadfile(str);
697                                                 return (1);
698                                         }
699                                 }
700                                 fclose(fp);
701                         }
702                         free(str);
703                 }
704                 fclose(libfp);
705         }
706         return(0);
707 }
708
709 void loadfile_SdccLib(char * libspc, char * module, long offset)
710 {
711         FILE *fp;
712
713         if ((fp = fopen(libspc,"r")) != NULL)
714         {
715                 fseek(fp, offset, SEEK_SET);
716                 LoadRel(fp, module);
717                 fclose(fp);
718         }
719 }
720
721 /*)Function     VOID    library()
722  *
723  *      The function library() links all the library object files
724  *      contained in the lbfile structures.
725  *
726  *      local variables:
727  *              lbfile  *lbfh           pointer to lbfile structure
728  *
729  *      global variables:
730  *              lbfile  *lbfhead        pointer to first lbfile structure
731  *
732  *       functions called:
733  *              VOID    loadfile        lklibr.c
734  *
735  *      side effects:
736  *              Links all files contained in the lbfile structures.
737  */
738
739 VOID
740 library()
741 {
742         struct lbfile *lbfh;
743
744         for (lbfh=lbfhead; lbfh; lbfh=lbfh->next)
745         {
746                 if(lbfh->offset<0)
747                 {
748                         /*Stand alone rel file (original lib format)*/
749                         loadfile(lbfh->filspc);
750                 }
751                 else
752                 {
753                         /*rel file embedded in lib (new lib format)*/
754                         loadfile_SdccLib(lbfh->libspc, lbfh->relfil, lbfh->offset);
755                 }
756         }
757 }
758
759 /*)Function     VOID    loadfile(filspc)
760  *
761  *              char    *filspc         library object file specification
762  *
763  *      The function loadfile() links the library object module.
764  *
765  *      local variables:
766  *              FILE    *fp             file handle
767  *              int     i               input line length
768  *              char    str[]           file input line
769  *
770  *      global variables:
771  *              char    *ip             pointer to linker input string
772  *
773  *       functions called:
774  *              int     fclose()        c_library
775  *              int     fgets()         c_library
776  *              FILE *  fopen()         c_library
777  *              VOID    link_main()     lkmain.c
778  *              int     strlen()        c_library
779  *
780  *      side effects:
781  *              If file exists it is linked.
782  */
783
784 VOID
785 loadfile(filspc)
786 char *filspc;
787 {
788         FILE *fp;
789         char str[NINPUT+2];
790
791         if ((fp = fopen(filspc,"r")) != NULL) {
792                 while (fgets(str, NINPUT, fp) != NULL) {
793                         str[NINPUT+1] = '\0';
794                         chop_crlf(str);
795                         ip = str;
796                         link_main();
797                 }
798                 fclose(fp);
799         }
800 }