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