use FSEPX to create filename
[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 <stdlib.h>
29 #include <string.h>
30 #include "aslink.h"
31
32 /*)Module       lklibr.c
33  *
34  *      The module lklibr.c contains the functions which
35  *      (1) specify the path(s) to library files [.LIB]
36  *      (2) specify the library file(s) [.LIB] to search
37  *      (3) search the library files for specific symbols
38  *          and link the module containing this symbol
39  *
40  *      lklibr.c contains the following functions:
41  *              VOID    addpath()
42  *              VOID    addlib()
43  *              VOID    addfile()
44  *              VOID    search()
45  *              VOID    fndsym()
46  *              VOID    library()
47  *              VOID    loadfile()
48  *
49  */
50
51 /*)Function     VOID    addpath()
52  *
53  *      The function addpath() creates a linked structure containing
54  *      the paths to various object module library files.
55  *
56  *      local variables:
57  *              lbpath  *lbph           pointer to new path structure
58  *              lbpath  *lbp            temporary pointer
59  *
60  *      global variables:
61  *              lbpath  *lbphead        The pointer to the first
62  *                                      path structure
63  *
64  *       functions called:
65  *              char    getnb()         lklex.c
66  *              VOID *  new()           lksym.c
67  *              int     strlen()        c_library
68  *              char *  strcpy()        c_library
69  *              VOID    unget()         lklex.c
70  *
71  *      side effects:
72  *              An lbpath structure may be created.
73  */
74
75 VOID
76 addpath()
77 {
78         struct lbpath *lbph, *lbp;
79
80         lbph = (struct lbpath *) new (sizeof(struct lbpath));
81         if (lbphead == NULL) {
82                 lbphead = lbph;
83         } else {
84                 lbp = lbphead;
85                 while (lbp->next)
86                         lbp = lbp->next;
87                 lbp->next = lbph;
88         }
89         unget(getnb());
90         lbph->path = (char *) new (strlen(ip)+1);
91         strcpy(lbph->path, ip);
92 }
93
94 /*)Function     VOID    addlib()
95  *
96  *      The function addlib() tests for the existance of a
97  *      library path structure to determine the method of
98  *      adding this library file to the library search structure.
99  *
100  *      This function calls the function addfile() to actually
101  *      add the library file to the search list.
102  *
103  *      local variables:
104  *              lbpath  *lbph           pointer to path structure
105  *
106  *      global variables:
107  *              lbpath  *lbphead        The pointer to the first
108  *                                      path structure
109  *
110  *       functions called:
111  *              VOID    addfile()       lklibr.c
112  *              char    getnb()         lklex.c
113  *              VOID    unget()         lklex.c
114  *
115  *      side effects:
116  *              The function addfile() may add the file to
117  *              the library search list.
118  */
119
120 VOID
121 addlib()
122 {
123         struct lbpath *lbph;
124
125         unget(getnb());
126
127         if (lbphead == NULL) {
128                 addfile(NULL,ip);
129                 return;
130         }       
131         for (lbph=lbphead; lbph; lbph=lbph->next) {
132                 addfile(lbph->path,ip);
133         }
134 }
135
136 /*)Function     VOID    addfile(path,libfil)
137  *
138  *              char    *path           library path specification
139  *              char    *libfil         library file specification
140  *
141  *      The function addfile() searches for the library file
142  *      by concatenating the path and libfil specifications.
143  *      if the library is found, an lbname structure is created
144  *      and linked to any previously defined structures.  This
145  *      linked list is used by the function fndsym() to attempt
146  *      to find any undefined symbols.
147  *
148  *      The function does not give report an error on invalid
149  *      path / file specifications or if the file is not found.
150  *
151  *      local variables:
152  *              lbname  *lbnh           pointer to new name structure
153  *              lbname  *lbn            temporary pointer
154  *
155  *      global variables:
156  *              lbname  *lbnhead        The pointer to the first
157  *                                      path structure
158  *
159  *       functions called:
160  *              char    getnb()         lklex.c
161  *              VOID *  new()           lksym.c
162  *              int     strlen()        c_library
163  *              char *  strcpy()        c_library
164  *              VOID    unget()         lklex.c
165  *
166  *      side effects:
167  *              An lbname structure may be created.
168  */
169
170 VOID
171 addfile(path,libfil)
172 char *path;
173 char *libfil;
174 {
175         FILE *fp;
176         char *str;
177         struct lbname *lbnh, *lbn;
178
179         if ((path != NULL) && (strchr(libfil,':') == NULL)){
180                 str = (char *) new (strlen(path) + strlen(libfil) + 6);
181                 strcpy(str,path);
182 #ifdef  OTHERSYSTEM
183                 if (str[strlen(str)-1] != '/') {
184                         strcat(str,"/");
185                 }
186 #endif
187         } else {
188                 str = (char *) new (strlen(libfil) + 5);
189         }
190 #ifdef  OTHERSYSTEM
191         if (libfil[0] == '/') { libfil++; }
192 #endif
193         strcat(str,libfil);
194         if(strchr(libfil,FSEPX) == NULL) {
195                 sprintf(&str[strlen(str)], "%clib", FSEPX);
196         }
197         if ((fp = fopen(str, "r")) != NULL) {
198                 fclose(fp);
199                 lbnh = (struct lbname *) new (sizeof(struct lbname));
200                 if (lbnhead == NULL) {
201                         lbnhead = lbnh;
202                 } else {
203                         lbn = lbnhead;
204                         while (lbn->next)
205                                 lbn = lbn->next;
206                         lbn->next = lbnh;
207                 }
208                 if ((path != NULL) && (strchr(libfil,':') == NULL)){
209                         lbnh->path = path;
210                 }
211                 lbnh->libfil = (char *) new (strlen(libfil) + 1);
212                 strcpy(lbnh->libfil,libfil);
213                 lbnh->libspc = str;
214         } else {
215                 free(str);
216         }
217 }
218
219 /*)Function     VOID    search()
220  *
221  *      The function search() looks through all the symbol tables
222  *      at the end of pass 1.  If any undefined symbols are found
223  *      then the function fndsym() is called. Function fndsym()
224  *      searches any specified library files to automagically
225  *      import the object modules containing the needed symbol.
226  *
227  *      After a symbol is found and imported by the function
228  *      fndsym() the symbol tables are again searched.  The
229  *      symbol tables are search until no more symbols can be
230  *      resolved within the library files.  This ensures that
231  *      back references from one library module to another are
232  *      also resolved.
233  *
234  *      local variables:
235  *              int     i               temporary counter
236  *              sym     *sp             pointer to a symbol structure
237  *              int     symfnd          found a symbol flag
238  *
239  *      global variables:
240  *              sym     *symhash[]      array of pointers to symbol tables
241  *
242  *       functions called:
243  *              int     fndsym()        lklibr.c
244  *
245  *      side effects:
246  *              If a symbol is found then the library object module
247  *              containing the symbol will be imported and linked.
248  */
249
250 VOID
251 search()
252 {
253         register struct sym *sp;
254         register int i,symfnd;
255
256         /*
257          * Look for undefined symbols.  Keep
258          * searching until no more symbols are resolved.
259          */
260         symfnd = 1;
261         while (symfnd) {
262                 symfnd = 0;
263                 /*
264                  * Look through all the symbols
265                  */
266                 for (i=0; i<NHASH; ++i) {
267                         sp = symhash[i];
268                         while (sp) {
269                                 /* If we find an undefined symbol
270                                  * (one where S_DEF is not set), then
271                                  * try looking for it.  If we find it
272                                  * in any of the libraries then
273                                  * increment symfnd.  This will force
274                                  * another pass of symbol searching and
275                                  * make sure that back references work.
276                                  */
277                                 if ((sp->s_type & S_DEF) == 0) {
278                                         if (fndsym(sp->s_id)) {
279                                                 symfnd++;
280                                         }
281                                 }
282                                 sp = sp->s_sp;
283                         }
284                 }
285         }
286 }
287
288 /*Load a .rel file embedded in a sdcclib file*/
289 void LoadRel(FILE * libfp, char * ModName)
290 {
291         char str[NINPUT+2];
292         int state=0;
293
294         while (fgets(str, NINPUT, libfp) != NULL)
295         {
296                 str[NINPUT+1] = '\0';
297                 chop_crlf(str);
298                 switch(state)
299                 {
300                         case 0:
301                                 if(EQ(str, "<FILE>"))
302                                 {
303                                         fgets(str, NINPUT, libfp);
304                                         str[NINPUT+1] = '\0';
305                                         chop_crlf(str);
306                                         if(EQ(str, ModName)) state=1;
307                                         else
308                                         {
309                                                 printf("Bad offset in library file str=%s, Modname=%s\n", str, ModName);
310                                                 lkexit(1);
311                                         }
312                                 }
313                         break;
314                         case 1:
315                                 if(EQ(str, "<REL>")) state=2;
316                         break;
317                         case 2:
318                                 if(EQ(str, "</REL>")) return;
319                                 ip = str;
320                                 link_main();
321                         break;
322                 }
323         }
324 }
325
326 /*Load an .adb file embedded in a sdcclib file.  If there is
327 something between <ADB> and </ADB> returns 1, otherwise returns 0.
328 This way the aomf51 will not have uselless empty modules. */
329
330 int LoadAdb(FILE * libfp)
331 {
332         char str[MAXLINE+1];
333         int state=0;
334         int ToReturn=0;
335
336         while (fgets(str, MAXLINE, libfp) != NULL)
337         {
338                 str[NINPUT+1] = '\0';
339                 chop_crlf(str);
340                 switch(state)
341                 {
342                         case 0:
343                                 if(EQ(str, "<ADB>")) state=1;
344                         break;
345                         case 1:
346                                 if(EQ(str, "</ADB>")) return ToReturn;
347                                 fprintf(dfp, "%s\n", str);
348                                 ToReturn=1;
349                         break;
350                 }
351         }
352         return ToReturn;
353 }
354
355 /*Check for a symbol in a SDCC library.  If found, add the embedded .rel and
356 .adb files from the library.  The library must be created with the SDCC
357 librarian 'sdcclib' since the linking process depends on the correct file offsets
358 embedded in the library file.*/
359
360 int SdccLib(char * PathLib, FILE * libfp, char * DirLib, char * SymName)
361 {
362         struct lbfile *lbfh, *lbf;
363         char ModName[NCPS]="";
364         char FLine[MAXLINE+1];
365         int state=0;
366         long IndexOffset=0, 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                                         sprintf(&DirLib[strlen(DirLib)], "%crel", 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 }