a6a549a78d201287d229ccb94a745a653c172972
[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 #include <stdio.h>
19 #include <string.h>
20 #include <alloc.h>
21 #include "aslink.h"
22
23 /*)Module       lklibr.c
24  *
25  *      The module lklibr.c contains the functions which
26  *      (1) specify the path(s) to library files [.LIB]
27  *      (2) specify the library file(s) [.LIB] to search
28  *      (3) search the library files for specific symbols
29  *          and link the module containing this symbol
30  *
31  *      lklibr.c contains the following functions:
32  *              VOID    addpath()
33  *              VOID    addlib()
34  *              VOID    addfile()
35  *              VOID    search()
36  *              VOID    fndsym()
37  *              VOID    library()
38  *              VOID    loadfile()
39  *
40  */
41
42 /*)Function     VOID    addpath()
43  *
44  *      The function addpath() creates a linked structure containing
45  *      the paths to various object module library files.
46  *
47  *      local variables:
48  *              lbpath  *lbph           pointer to new path structure
49  *              lbpath  *lbp            temporary pointer
50  *
51  *      global variables:
52  *              lbpath  *lbphead        The pointer to the first
53  *                                      path structure
54  *
55  *       functions called:
56  *              char    getnb()         lklex.c
57  *              VOID *  new()           lksym.c
58  *              int     strlen()        c_library
59  *              char *  strcpy()        c_library
60  *              VOID    unget()         lklex.c
61  *
62  *      side effects:
63  *              An lbpath structure may be created.
64  */
65
66 VOID
67 addpath()
68 {
69         struct lbpath *lbph, *lbp;
70
71         lbph = (struct lbpath *) new (sizeof(struct lbpath));
72         if (lbphead == NULL) {
73                 lbphead = lbph;
74         } else {
75                 lbp = lbphead;
76                 while (lbp->next)
77                         lbp = lbp->next;
78                 lbp->next = lbph;
79         }
80         unget(getnb());
81         lbph->path = (char *) new (strlen(ip)+1);
82         strcpy(lbph->path, ip);
83 }
84
85 /*)Function     VOID    addlib()
86  *
87  *      The function addlib() tests for the existance of a
88  *      library path structure to determine the method of
89  *      adding this library file to the library search structure.
90  *
91  *      This function calls the function addfile() to actually
92  *      add the library file to the search list.
93  *
94  *      local variables:
95  *              lbpath  *lbph           pointer to path structure
96  *
97  *      global variables:
98  *              lbpath  *lbphead        The pointer to the first
99  *                                      path structure
100  *
101  *       functions called:
102  *              VOID    addfile()       lklibr.c
103  *              char    getnb()         lklex.c
104  *              VOID    unget()         lklex.c
105  *
106  *      side effects:
107  *              The function addfile() may add the file to
108  *              the library search list.
109  */
110
111 VOID
112 addlib()
113 {
114         struct lbpath *lbph;
115
116         unget(getnb());
117
118         if (lbphead == NULL) {
119                 addfile(NULL,ip);
120                 return;
121         }       
122         for (lbph=lbphead; lbph; lbph=lbph->next) {
123                 addfile(lbph->path,ip);
124         }
125 }
126
127 /*)Function     VOID    addfile(path,libfil)
128  *
129  *              char    *path           library path specification
130  *              char    *libfil         library file specification
131  *
132  *      The function addfile() searches for the library file
133  *      by concatenating the path and libfil specifications.
134  *      if the library is found, an lbname structure is created
135  *      and linked to any previously defined structures.  This
136  *      linked list is used by the function fndsym() to attempt
137  *      to find any undefined symbols.
138  *
139  *      The function does not give report an error on invalid
140  *      path / file specifications or if the file is not found.
141  *
142  *      local variables:
143  *              lbname  *lbnh           pointer to new name structure
144  *              lbname  *lbn            temporary pointer
145  *
146  *      global variables:
147  *              lbname  *lbnhead        The pointer to the first
148  *                                      path structure
149  *
150  *       functions called:
151  *              char    getnb()         lklex.c
152  *              VOID *  new()           lksym.c
153  *              int     strlen()        c_library
154  *              char *  strcpy()        c_library
155  *              VOID    unget()         lklex.c
156  *
157  *      side effects:
158  *              An lbname structure may be created.
159  */
160
161 VOID
162 addfile(path,libfil)
163 char *path;
164 char *libfil;
165 {
166         FILE *fp;
167         char *str;
168         struct lbname *lbnh, *lbn;
169
170         if ((path != NULL) && (strchr(libfil,':') == NULL)){
171                 str = (char *) new (strlen(path) + strlen(libfil) + 6);
172                 strcpy(str,path);
173 #ifdef  OTHERSYSTEM
174                 if (str[strlen(str)-1] != '/') {
175                         strcat(str,"/");
176                 }
177 #endif
178         } else {
179                 str = (char *) new (strlen(libfil) + 5);
180         }
181 #ifdef  OTHERSYSTEM
182         if (libfil[0] == '/') { libfil++; }
183 #endif
184         strcat(str,libfil);
185         if(strchr(str,FSEPX) == NULL) {
186                 sprintf(&str[strlen(str)], "%clib", FSEPX);
187         }
188         if ((fp = fopen(str, "r")) != NULL) {
189                 fclose(fp);
190                 lbnh = (struct lbname *) new (sizeof(struct lbname));
191                 if (lbnhead == NULL) {
192                         lbnhead = lbnh;
193                 } else {
194                         lbn = lbnhead;
195                         while (lbn->next)
196                                 lbn = lbn->next;
197                         lbn->next = lbnh;
198                 }
199                 if ((path != NULL) && (strchr(libfil,':') == NULL)){
200                         lbnh->path = path;
201                 }
202                 lbnh->libfil = (char *) new (strlen(libfil) + 1);
203                 strcpy(lbnh->libfil,libfil);
204                 lbnh->libspc = str;
205                 fprintf(stderr,"library file %s\n",str);
206         } else {
207                 free(str);
208         }
209 }
210
211 /*)Function     VOID    search()
212  *
213  *      The function search() looks through all the symbol tables
214  *      at the end of pass 1.  If any undefined symbols are found
215  *      then the function fndsym() is called. Function fndsym()
216  *      searches any specified library files to automagically
217  *      import the object modules containing the needed symbol.
218  *
219  *      After a symbol is found and imported by the function
220  *      fndsym() the symbol tables are again searched.  The
221  *      symbol tables are search until no more symbols can be
222  *      resolved within the library files.  This ensures that
223  *      back references from one library module to another are
224  *      also resolved.
225  *
226  *      local variables:
227  *              int     i               temporary counter
228  *              sym     *sp             pointer to a symbol structure
229  *              int     symfnd          found a symbol flag
230  *
231  *      global variables:
232  *              sym     *symhash[]      array of pointers to symbol tables
233  *
234  *       functions called:
235  *              int     fndsym()        lklibr.c
236  *
237  *      side effects:
238  *              If a symbol is found then the library object module
239  *              containing the symbol will be imported and linked.
240  */
241
242 VOID
243 search()
244 {
245         register struct sym *sp;
246         register int i,symfnd;
247
248         /*
249          * Look for undefined symbols.  Keep
250          * searching until no more symbols are resolved.
251          */
252         symfnd = 1;
253         while (symfnd) {
254                 symfnd = 0;
255                 /*
256                  * Look through all the symbols
257                  */
258                 for (i=0; i<NHASH; ++i) {
259                         sp = symhash[i];
260                         while (sp) {
261                                 /* If we find an undefined symbol
262                                  * (one where S_DEF is not set), then
263                                  * try looking for it.  If we find it
264                                  * in any of the libraries then
265                                  * increment symfnd.  This will force
266                                  * another pass of symbol searching and
267                                  * make sure that back references work.
268                                  */
269                                 if ((sp->s_type & S_DEF) == 0) {
270                                         if (fndsym(sp->s_id)) {
271                                                 symfnd++;
272                                         }
273                                 }
274                                 sp = sp->s_sp;
275                         }
276                 }
277         }
278 }
279
280 /*)Function     VOID    fndsym(name)
281  *
282  *              char    *name           symbol name to find
283  *
284  *      The function fndsym() searches through all combinations of the
285  *      library path specifications (input by the -k option) and the
286  *      library file specifications (input by the -l option) that
287  *      lead to an existing file.
288  *
289  *      The file specicifation may be formed in one of two ways:
290  *
291  *      (1)     If the library file contained an absolute
292  *              path/file specification then this becomes filspc.
293  *              (i.e. C:\...)
294  *
295  *      (2)     If the library file contains a relative path/file
296  *              specification then the concatenation of the path
297  *              and this file specification becomes filspc.
298  *              (i.e. \...)
299  *
300  *      The structure lbfile is created for the first library
301  *      object file which contains the definition for the
302  *      specified undefined symbol.
303  *
304  *      If the library file [.LIB] contains file specifications for
305  *      non existant files, no errors are returned.
306  *
307  *      local variables:
308  *              char    buf[]           [.REL] file input line
309  *              char    c               [.REL] file input character
310  *              FILE    *fp             file handle for object file
311  *              lbfile  *lbf            temporary pointer
312  *              lbfile  *lbfh           pointer to lbfile structure
313  *              FILE    *libfp          file handle for library file
314  *              lbname  *lbnh           pointer to lbname structure
315  *              char    *path           file specification path
316  *              char    relfil[]        [.REL] file specification
317  *              char    *str            combined path and file specification
318  *              char    symname[]       [.REL] file symbol string
319  *
320  *      global variables:
321  *              lbname  *lbnhead        The pointer to the first
322  *                                      name structure
323  *              lbfile  *lbfhead        The pointer to the first
324  *                                      file structure
325  *
326  *       functions called:
327  *              int     fclose()        c_library
328  *              int     fgets()         c_library
329  *              FILE    *fopen()        c_library
330  *              VOID    free()          c_library
331  *              char    getnb()         lklex.c
332  *              VOID    lkexit()        lkmain.c
333  *              VOID    loadfile()      lklibr.c
334  *              VOID *  new()           lksym.c
335  *              char *  sprintf()       c_library
336  *              int     sscanf()        c_library
337  *              char *  strcat()        c_library
338  *              char *  strchr()        c_library
339  *              char *  strcpy()        c_library
340  *              int     strlen()        c_library
341  *              int     strncmp()       c_library
342  *              VOID    unget()         lklex.c
343  *
344  *      side effects:
345  *              If the symbol is found then a new lbfile structure
346  *              is created and added to the linked list of lbfile
347  *              structures.  The file containing the found symbol
348  *              is linked.
349  */
350
351 int
352 fndsym(name)
353 char *name;
354 {
355         FILE *libfp, *fp;
356         struct lbname *lbnh;
357         struct lbfile *lbfh, *lbf;
358         char relfil[NINPUT+2];
359         char buf[NINPUT+2];
360         char symname[NINPUT];
361         char *path,*str;
362         char c;
363
364         /*
365          * Search through every library in the linked list "lbnhead".
366          */
367
368 /*1*/   for (lbnh=lbnhead; lbnh; lbnh=lbnh->next) {
369                 if ((libfp = fopen(lbnh->libspc, "r")) == NULL) {
370                         fprintf(stderr, "Cannot open library file %s\n",
371                                 lbnh->libspc);
372                         lkexit(1);
373                 }
374                 path = lbnh->path;
375
376                 /*
377                  * Read in a line from the library file.
378                  * This is the relative file specification
379                  * for a .REL file in this library.
380                  */
381
382 /*2*/           while (fgets(relfil, NINPUT, libfp) != NULL) {
383                     relfil[NINPUT+1] = '\0';
384                     relfil[strlen(relfil) - 1] = '\0';
385                     if (path != NULL) {
386                         str = (char *) new (strlen(path)+strlen(relfil)+6);
387                         strcpy(str,path);
388 #ifdef  OTHERSYSTEM
389                         if (str[strlen(str)-1] != '/') {
390                                 strcat(str,"/");
391                         }
392 #endif
393                     } else {
394                         str = (char *) new (strlen(relfil) + 5);
395                     }
396                     if (relfil[0] == '\\') {
397                         strcat(str,relfil+1);
398                     } else {
399                         strcat(str,relfil);
400                     }
401                     if(strchr(str,FSEPX) == NULL) {
402                         sprintf(&str[strlen(str)], "%crel", FSEPX);
403                     }
404 /*3*/               if ((fp = fopen(str, "r")) != NULL) {
405
406                         /*
407                          * Read in the object file.  Look for lines that
408                          * begin with "S" and end with "D".  These are
409                          * symbol table definitions.  If we find one, see
410                          * if it is our symbol.  Make sure we only read in
411                          * our object file and don't go into the next one.
412                          */
413                         
414 /*4*/                   while (fgets(buf, NINPUT, fp) != NULL) {
415
416                         buf[NINPUT+1] = '\0';
417                         buf[strlen(buf) - 1] = '\0';
418
419                         /*
420                          * Skip everything that's not a symbol record.
421                          */
422                         if (buf[0] != 'S')
423                                 continue;
424
425                         /*
426                          * When a 'T line' is found terminate file scan.
427                          * All 'S line's preceed 'T line's in .REL files.
428                          */
429                         if (buf[0] == 'T')
430                                 break;
431
432                         sscanf(buf, "S %s %c", symname, &c);
433
434                         /*
435                          * If we find a symbol definition for the
436                          * symbol we're looking for, load in the
437                          * file and add it to lbfhead so it gets
438                          * loaded on pass number 2.
439                          */
440 /*5*/                   if (strncmp(symname, name, NCPS) == 0 && c == 'D') {
441
442                         lbfh = (struct lbfile *) new (sizeof(struct lbfile));
443                         if (lbfhead == NULL) {
444                                 lbfhead = lbfh;
445                         } else {
446                                 lbf = lbfhead;
447                                 while (lbf->next)
448                                         lbf = lbf->next;
449                                 lbf->next = lbfh;
450                         }
451                         lbfh->libspc = lbnh->libspc;
452                         lbfh->filspc = str;
453                         lbfh->relfil = (char *) new (strlen(relfil) + 1);
454                         strcpy(lbfh->relfil,relfil);
455                         fclose(fp);
456                         fclose(libfp);                 
457                         /* if cdb information required & cdb file present */
458                         if (dflag && dfp) {
459                             FILE *xfp = afile(str,"cdb",0);
460                             if (xfp) {
461                                 copyfile(dfp,xfp);
462                                 fclose(xfp);
463                             }
464                         }
465                         loadfile(str);
466                         return (1);
467
468 /*5*/                   }
469
470 /*4*/                   }
471                     fclose(fp);
472 /*3*/               }
473
474                     free(str);
475 /*2*/           }
476                 fclose(libfp);
477 /*1*/   }
478         return(0);
479 }
480
481 /*)Function     VOID    library()
482  *
483  *      The function library() links all the library object files
484  *      contained in the lbfile structures.
485  *
486  *      local variables:
487  *              lbfile  *lbfh           pointer to lbfile structure
488  *
489  *      global variables:
490  *              lbfile  *lbfhead        pointer to first lbfile structure
491  *
492  *       functions called:
493  *              VOID    loadfile        lklibr.c
494  *
495  *      side effects:
496  *              Links all files contained in the lbfile structures.
497  */
498
499 VOID
500 library()
501 {
502         struct lbfile *lbfh;
503
504         for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
505                 loadfile(lbfh->filspc);
506         }
507 }
508
509 /*)Function     VOID    loadfile(filspc)
510  *
511  *              char    *filspc         library object file specification
512  *
513  *      The function loadfile() links the library object module.
514  *
515  *      local variables:
516  *              FILE    *fp             file handle
517  *              int     i               input line length
518  *              char    str[]           file input line
519  *
520  *      global variables:
521  *              char    *ip             pointer to linker input string
522  *
523  *       functions called:
524  *              int     fclose()        c_library
525  *              int     fgets()         c_library
526  *              FILE *  fopen()         c_library
527  *              VOID    link_main()     lkmain.c
528  *              int     strlen()        c_library
529  *
530  *      side effects:
531  *              If file exists it is linked.
532  */
533
534 VOID
535 loadfile(filspc)
536 char *filspc;
537 {
538         FILE *fp;
539         char str[NINPUT+2];
540         int i;
541
542         if ((fp = fopen(filspc,"r")) != NULL) {
543                 while (fgets(str, NINPUT, fp) != NULL) {
544                         str[NINPUT+1] = '\0';
545                         i = strlen(str) - 1;
546                         if (str[i] == '\n')
547                                 str[i] = '\0';
548                         ip = str;
549                         link_main();
550                 }
551                 fclose(fp);
552         }
553 }