struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / sdas / linksrc / lklibr.c
bloba4e1fbfd19c698a9354c7c1e7c47bcea574b1f20
1 /* lklibr.c */
3 /*
4 * Copyright (C) 1989-2009 Alan R. Baldwin
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * Alan R. Baldwin
21 * 721 Berkeley St.
22 * Kent, Ohio 44240
24 * With contributions for the
25 * object libraries from
26 * Ken Hornstein
27 * kenhat cmf dot nrl dot navy dot mil
32 * Extensions: P. Felber
35 #include <ctype.h>
36 #include <assert.h>
38 #include "aslink.h"
39 #include "lkrel.h"
40 #include "lklibr.h"
42 /*)Module lklibr.c
44 * The module lklibr.c contains the functions which
45 * (1) specify the path(s) to library files [.LIB]
46 * (2) specify the library file(s) [.LIB] to search
47 * (3) search the library files for specific symbols
48 * and link the module containing this symbol
50 * lklibr.c contains the following functions:
51 * VOID addpath()
52 * VOID addlib()
53 * VOID addfile()
54 * VOID search()
55 * VOID fndsym()
56 * VOID library()
57 * VOID loadfile()
61 #define EQ(A,B) !strcmp((A),(B))
62 #define NELEM(x) (sizeof (x) / sizeof (*x))
64 #ifdef INDEXLIB
65 /* First entry in the library object symbol cache */
66 pmlibraryfile libr = NULL;
68 int buildlibraryindex (void);
69 void freelibraryindex (void);
70 #endif /* INDEXLIB */
72 struct aslib_target *aslib_targets[] = {
73 &aslib_target_sdcclib,
74 &aslib_target_ar,
75 &aslib_target_lib,
78 /*)Function VOID addpath()
80 * The function addpath() creates a linked structure containing
81 * the paths to various object module library files.
83 * local variables:
84 * lbpath *lbph pointer to new path structure
85 * lbpath *lbp temporary pointer
87 * global variables:
88 * lbpath *lbphead The pointer to the first
89 * path structure
91 * functions called:
92 * int getnb() lklex.c
93 * VOID * new() lksym.c
94 * int strlen() c_library
95 * char * strcpy() c_library
96 * VOID unget() lklex.c
98 * side effects:
99 * An lbpath structure may be created.
102 VOID
103 addpath (void)
105 struct lbpath *lbph, *lbp;
107 lbph = (struct lbpath *) new (sizeof (struct lbpath));
108 if (lbphead == NULL)
110 lbphead = lbph;
112 else
114 lbp = lbphead;
115 while (lbp->next)
117 lbp = lbp->next;
119 lbp->next = lbph;
121 unget (getnb ());
122 lbph->path = strdup (ip);
125 /*)Function VOID addlib()
127 * The function addlib() tests for the existence of a
128 * library path structure to determine the method of
129 * adding this library file to the library search structure.
131 * This function calls the function addfile() to actually
132 * add the library file to the search list.
134 * local variables:
135 * lbpath *lbph pointer to path structure
137 * global variables:
138 * lbpath *lbphead The pointer to the first
139 * path structure
140 * ip a pointer to the library name
142 * functions called:
143 * VOID addfile() lklibr.c
144 * int getnb() lklex.c
145 * VOID unget() lklex.c
147 * side effects:
148 * The function addfile() may add the file to
149 * the library search list.
152 VOID
153 addlib (void)
155 struct lbpath *lbph;
156 int foundcount = 0;
158 unget (getnb ());
160 if (lbphead == NULL)
162 foundcount = addfile (NULL, ip);
164 else
166 for (lbph = lbphead; lbph; lbph = lbph->next)
168 foundcount += addfile (lbph->path, ip);
171 if (foundcount == 0)
173 fprintf (stderr, "?ASlink-Warning-Couldn't find library '%s'\n", ip);
177 /*)Function int addfile(path,libfil)
179 * char *path library path specification
180 * char *libfil library file specification
182 * The function addfile() searches for the library file
183 * by concatenating the path and libfil specifications.
184 * if the library is found, an lbname structure is created
185 * and linked to any previously defined structures. This
186 * linked list is used by the function fndsym() to attempt
187 * to find any undefined symbols.
189 * The function does not report an error on invalid
190 * path / file specifications or if the file is not found.
192 * local variables:
193 * lbname *lbnh pointer to new name structure
194 * lbname *lbn temporary pointer
195 * char * str path / file string
196 * char * strend end of path pointer
197 * char * str path / file string
198 * char * strend end of path pointer
200 * global variables:
201 * lbname *lbnhead The pointer to the first
202 * path structure
203 * int objflg linked file/library object output flag
205 * functions called:
206 * int getnb() lklex.c
207 * VOID * new() lksym.c
208 * int strlen() c_library
209 * char * strcpy() c_library
210 * VOID unget() lklex.c
212 * side effects:
213 * An lbname structure may be created.
215 * return:
216 * 1: the library was found
217 * 0: the library was not found
221 addfile (char *path, char *libfil)
223 FILE *fp;
224 char *str, *strend;
225 struct lbname *lbnh, *lbn;
226 #ifdef OTHERSYSTEM
227 int libfilinc = 0;
228 #endif
230 if (path != NULL)
232 str = (char *) new (strlen (path) + strlen (libfil) + 6);
233 strcpy (str, path);
234 strend = str + strlen(str) - 1;
235 #ifdef OTHERSYSTEM
236 if (strlen (str) && (*strend != '/') && (*strend != LKDIRSEP))
238 strcat (str, LKDIRSEPSTR);
240 #endif
242 else
244 str = (char *) new (strlen (libfil) + 5);
247 #ifdef OTHERSYSTEM
248 if ((libfil[0] == '/') || (libfil[0] == LKDIRSEP))
250 libfil++;
251 libfilinc = 1;
253 #endif
255 strcat (str, libfil);
256 if (strchr (libfil, FSEPX) == NULL)
258 sprintf (&str[strlen (str)], "%clib", FSEPX);
261 fp = fopen (str, "rb");
262 if (fp == NULL)
264 /*Ok, that didn't work. Try with the 'libfil' name only */
265 #ifdef OTHERSYSTEM
266 if (libfilinc)
267 libfil--;
268 #endif
269 fp = fopen (libfil, "rb");
270 if (fp != NULL)
272 /*Bingo! 'libfil' is the absolute path of the library */
273 strcpy (str, libfil);
274 path = NULL; /*This way 'libfil' and 'path' will be rebuilt from 'str' */
278 if (path == NULL)
280 /*'path' can not be null since it is needed to find the object files associated with
281 the library. So, get 'path' from 'str' and then chop it off and recreate 'libfil'.
282 That way putting 'path' and 'libfil' together will result into the original filepath
283 as contained in 'str'. */
284 int j;
285 path = strdup (str);
286 for (j = strlen (path) - 1; j >= 0; j--)
288 if ((path[j] == '/') || (path[j] == LKDIRSEP))
290 strcpy (libfil, &path[j + 1]);
291 path[j + 1] = 0;
292 break;
295 if (j <= 0)
296 path[0] = 0;
299 if (fp != NULL)
301 fclose (fp);
302 lbnh = (struct lbname *) new (sizeof (struct lbname));
303 if (lbnhead == NULL)
305 lbnhead = lbnh;
307 else
309 lbn = lbnhead;
310 while (lbn->next)
312 lbn = lbn->next;
314 lbn->next = lbnh;
317 lbnh->path = path;
318 lbnh->libfil = strdup (libfil);
319 lbnh->libspc = str;
320 lbnh->f_obj = objflg;
321 return 1;
323 else
325 free (str);
326 return 0;
330 /*)Function VOID search()
332 * The function search() looks through all the symbol tables
333 * at the end of pass 1. If any undefined symbols are found
334 * then the function fndsym() is called. Function fndsym()
335 * searches any specified library files to automagically
336 * import the object modules containing the needed symbol.
338 * After a symbol is found and imported by the function
339 * fndsym() the symbol tables are again searched. The
340 * symbol tables are searched until no more symbols can be
341 * resolved within the library files. This ensures that
342 * back references from one library module to another are
343 * also resolved.
345 * local variables:
346 * int i temporary counter
347 * sym *sp pointer to a symbol structure
348 * int symfnd found a symbol flag
350 * global variables:
351 * sym *symhash[] array of pointers to symbol tables
353 * functions called:
354 * int fndsym() lklibr.c
356 * side effects:
357 * If a symbol is found then the library object module
358 * containing the symbol will be imported and linked.
361 VOID
362 search (void)
364 struct sym *sp;
365 int i, symfnd;
368 * Look for undefined symbols. Keep
369 * searching until no more symbols are resolved.
371 symfnd = 1;
372 while (symfnd)
374 symfnd = 0;
376 * Look through all the symbols
378 for (i = 0; i < NHASH; ++i)
380 sp = symhash[i];
381 while (sp)
383 /* If we find an undefined symbol
384 * (one where S_DEF is not set), then
385 * try looking for it. If we find it
386 * in any of the libraries then
387 * increment symfnd. This will force
388 * another pass of symbol searching and
389 * make sure that back references work.
391 if ((sp->s_type & S_DEF) == 0)
393 if (fndsym (sp->s_id))
395 symfnd++;
398 sp = sp->s_sp;
404 /*)Function VOID fndsym(name)
406 * char *name symbol name to find
408 * The function fndsym() searches through all combinations of the
409 * library path specifications (input by the -k option) and the
410 * library file specifications (input by the -l option) that
411 * lead to an existing file.
413 * The file specification may be formed in one of two ways:
415 * (1) If the library file contained an absolute
416 * path/file specification then this becomes filspc.
417 * (i.e. C:\...)
419 * (2) If the library file contains a relative path/file
420 * specification then the concatenation of the path
421 * and this file specification becomes filspc.
422 * (i.e. \...)
424 * The structure lbfile is created for the first library
425 * object file which contains the definition for the
426 * specified undefined symbol.
428 * If the library file [.LIB] contains file specifications for
429 * non existant files, no errors are returned.
431 * local variables:
432 * char buf[] [.REL] file input line
433 * char c [.REL] file input character
434 * FILE *fp file handle for object file
435 * lbfile *lbf temporary pointer
436 * lbfile *lbfh pointer to lbfile structure
437 * FILE *libfp file handle for library file
438 * lbname *lbnh pointer to lbname structure
439 * char *path file specification path
440 * char relfil[] [.REL] file specification
441 * char *str combined path and file specification
442 * char symname[] [.REL] file symbol string
444 * global variables:
445 * lbname *lbnhead The pointer to the first
446 * name structure
447 * lbfile *lbfhead The pointer to the first
448 * file structure
449 * int obj_flag linked file/library object output flag
451 * functions called:
452 * int fclose() c_library
453 * FILE *fopen() c_library
454 * VOID free() c_library
455 * int getnb() lklex.c
456 * VOID lkexit() lkmain.c
457 * VOID loadfile() lklibr.c
458 * VOID * new() lksym.c
459 * char * sprintf() c_library
460 * int sscanf() c_library
461 * char * strcat() c_library
462 * char * strchr() c_library
463 * char * strcpy() c_library
464 * int strlen() c_library
465 * int strncmp() c_library
466 * VOID unget() lklex.c
468 * side effects:
469 * If the symbol is found then a new lbfile structure
470 * is created and added to the linked list of lbfile
471 * structures. The file containing the found symbol
472 * is linked.
475 #ifdef INDEXLIB
477 fndsym (char *name)
479 struct lbfile *lbfh, *lbf;
480 pmlibraryfile ThisLibr;
481 pmlibrarysymbol ThisSym = NULL;
483 pmlibraryfile FirstFound;
484 int numfound = 0;
486 D ("Searching symbol: %s\n", name);
488 /* Build the index if this is the first call to fndsym */
489 if (libr == NULL)
490 buildlibraryindex ();
492 /* Iterate through all library object files */
493 FirstFound = libr; /* So gcc stops whining */
494 for (ThisLibr = libr; ThisLibr != NULL; ThisLibr = ThisLibr->next)
496 /* Iterate through all symbols in an object file */
497 for (ThisSym = ThisLibr->symbols; ThisSym != NULL; ThisSym = ThisSym->next)
499 if (!strcmp (ThisSym->name, name))
501 if ((!ThisLibr->loaded) && (numfound == 0))
503 /* Object file is not loaded - add it to the list */
504 lbfh = (struct lbfile *) new (sizeof (struct lbfile));
505 if (lbfhead == NULL)
507 lbfhead = lbfh;
509 else
511 for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
514 lbf->next = lbfh;
516 lbfh->libspc = ThisLibr->libspc;
517 lbfh->filspc = ThisLibr->filspc;
518 lbfh->relfil = strdup (ThisLibr->relfil);
519 lbfh->offset = ThisLibr->offset;
520 lbfh->type = ThisLibr->type;
522 (*aslib_targets[lbfh->type]->loadfile) (lbfh);
524 ThisLibr->loaded = 1;
527 if (numfound == 0)
529 numfound++;
530 FirstFound = ThisLibr;
532 else
534 char absPath1[PATH_MAX];
535 char absPath2[PATH_MAX];
536 #if defined(_WIN32)
537 int j;
539 _fullpath (absPath1, FirstFound->libspc, PATH_MAX);
540 _fullpath (absPath2, ThisLibr->libspc, PATH_MAX);
541 for (j = 0; absPath1[j] != 0; j++)
542 absPath1[j] = tolower ((unsigned char) absPath1[j]);
543 for (j = 0; absPath2[j] != 0; j++)
544 absPath2[j] = tolower ((unsigned char) absPath2[j]);
545 #else
546 if (NULL == realpath (FirstFound->libspc, absPath1))
547 *absPath1 = '\0';
548 if (NULL == realpath (ThisLibr->libspc, absPath2))
549 *absPath2 = '\0';
550 #endif
551 if (!(EQ (absPath1, absPath2) && EQ (FirstFound->relfil, ThisLibr->relfil)))
553 if (numfound == 1)
555 fprintf (stderr, "?ASlink-Warning-Definition of public symbol '%s'" " found more than once:\n", name);
556 fprintf (stderr, " Library: '%s', Module: '%s'\n", FirstFound->libspc, FirstFound->relfil);
558 fprintf (stderr, " Library: '%s', Module: '%s'\n", ThisLibr->libspc, ThisLibr->relfil);
559 numfound++;
565 return numfound;
568 struct add_sym_s
570 pmlibraryfile plf;
571 pmlibrarysymbol pls;
574 static int
575 add_sybmol (const char *sym, void *param)
577 struct add_sym_s *as = (struct add_sym_s *) param;
578 pmlibrarysymbol ps = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
580 D (" Indexing symbol: %s\n", sym);
582 as->plf->loaded = 0;
583 ps->next = NULL;
584 ps->name = strdup (sym);
586 if (as->pls == NULL)
588 as->pls = as->plf->symbols = ps;
590 else
592 as->pls->next = ps;
593 as->pls = as->pls->next;
596 return 0;
599 pmlibrarysymbol
600 add_rel_index (FILE * fp, long size, pmlibraryfile This)
602 struct add_sym_s as;
603 as.plf = This;
604 as.pls = This->symbols;
606 assert (This->symbols == NULL);
608 enum_symbols (fp, size, &add_sybmol, &as);
610 return as.pls;
613 /* buildlibraryindex - build an in-memory cache of the symbols contained in
614 * the libraries
617 buildlibraryindex (void)
619 pmlibraryfile This = NULL;
620 struct lbname *lbnh;
623 * Search through every library in the linked list "lbnhead".
625 for (lbnh = lbnhead; lbnh; lbnh = lbnh->next)
627 FILE *libfp;
628 int i;
630 D ("Indexing library: %s\n", lbnh->libspc);
632 if ((libfp = fopen (lbnh->libspc, "rb")) == NULL)
634 fprintf (stderr, "?ASlink-Error-Cannot open library file %s\n", lbnh->libspc);
635 lkexit (1);
638 for (i = 0; i < NELEM (aslib_targets); ++i)
640 if ((*aslib_targets[i]->is_lib) (libfp))
642 This = (*aslib_targets[i]->buildlibraryindex) (lbnh, libfp, This, i);
643 break;
647 if (i >= NELEM (aslib_targets))
648 fprintf (stderr, "?ASlink-Error-Unknown library file format %s\n", lbnh->libspc);
650 fclose (libfp);
653 return 0;
656 /* Release all memory allocated for the in-memory library index */
657 void
658 freelibraryindex (void)
660 pmlibraryfile ThisLibr, ThisLibr2Free;
661 pmlibrarysymbol ThisSym, ThisSym2Free;
663 ThisLibr = libr;
665 while (ThisLibr)
667 ThisSym = ThisLibr->symbols;
669 while (ThisSym)
671 free (ThisSym->name);
672 ThisSym2Free = ThisSym;
673 ThisSym = ThisSym->next;
674 free (ThisSym2Free);
676 free (ThisLibr->filspc);
677 free (ThisLibr->relfil);
678 ThisLibr2Free = ThisLibr;
679 ThisLibr = ThisLibr->next;
680 free (ThisLibr2Free);
683 libr = NULL;
686 #else /* INDEXLIB */
688 struct load_sym_s
690 const char *name;
691 struct lbname *lbnh;
692 const char *relfil;
693 const char *filspc;
694 int offset;
695 int type;
698 static int
699 load_sybmol (const char *sym, void *params)
701 struct load_sym_s *ls = (struct load_sym_s *) params;
703 D (" Symbol: %s\n", sym);
705 if (strcmp (ls->name, sym) == 0)
707 struct lbfile *lbfh, *lbf;
709 D (" Symbol %s found in module %s!\n", sym, ls->relfil);
711 lbfh = (struct lbfile *) new (sizeof (struct lbfile));
712 lbfh->libspc = ls->lbnh->libspc;
713 lbfh->relfil = strdup (ls->relfil);
714 lbfh->filspc = strdup (ls->filspc);
715 lbfh->offset = ls->offset;
716 lbfh->type = ls->type;
718 if (lbfhead == NULL)
719 lbfhead = lbfh;
720 else
722 for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
724 lbf->next = lbfh;
726 (*aslib_targets[ls->type]->loadfile) (lbfh);
728 return 1;
730 else
731 return 0;
734 /*)Function int is_module_loaded(filspc)
736 * If this module has been already loaded
740 is_module_loaded (const char *filspc)
742 struct lbfile *lbf;
744 for (lbf = lbfhead; lbf != NULL; lbf = lbf->next)
746 if (EQ (filspc, lbf->filspc))
748 D (" Module %s already loaded!\n", filspc);
749 return 1; /* Module already loaded */
752 return 0;
756 add_rel_file (const char *name, struct lbname *lbnh, const char *relfil,
757 const char *filspc, int offset, FILE * fp, long size, int type)
759 struct load_sym_s ls;
761 /* If this module has been loaded already don't load it again. */
762 if (is_module_loaded (filspc))
763 return 0;
764 else
766 ls.name = name;
767 ls.lbnh = lbnh;
768 ls.relfil = relfil;
769 ls.filspc = filspc;
770 ls.offset = offset;
771 ls.type = type;
773 return enum_symbols (fp, size, &load_sybmol, &ls);
778 fndsym (const char *name)
780 FILE *libfp;
781 struct lbname *lbnh;
782 int i;
785 * Search through every library in the linked list "lbnhead".
788 D ("Searching symbol: %s\n", name);
790 for (lbnh = lbnhead; lbnh; lbnh = lbnh->next)
792 int ret = 0;
794 D ("Library: %s\n", lbnh->libspc);
796 if ((libfp = fopen (lbnh->libspc, "rb")) == NULL)
798 fprintf (stderr, "?ASlink-Error-Cannot open library file %s\n", lbnh->libspc);
799 lkexit (1);
802 for (i = 0; i < NELEM (aslib_targets); ++i)
804 if ((*aslib_targets[i]->is_lib) (libfp))
806 ret = (*aslib_targets[i]->fndsym) (name, lbnh, libfp, i);
807 break;
811 if (i >= NELEM (aslib_targets))
812 fprintf (stderr, "?ASlink-Error-Unknown library file format %s\n", lbnh->libspc);
814 fclose (libfp);
816 if (ret)
817 return 1;
819 } /* Ends good open of libr file */
820 return 0;
822 #endif /* INDEXLIB */
824 /*)Function VOID library()
826 * The function library() links all the library object files
827 * contained in the lbfile structures.
829 * local variables:
830 * lbfile *lbfh pointer to lbfile structure
832 * global variables:
833 * lbfile *lbfhead pointer to first lbfile structure
834 * int obj_flag linked file/library object output flag
836 * functions called:
837 * VOID loadfile lklibr.c
839 * side effects:
840 * Links all files contained in the lbfile structures.
843 VOID
844 library (void)
846 struct lbfile *lbfh;
848 for (lbfh = lbfhead; lbfh; lbfh = lbfh->next) {
849 obj_flag = lbfh->f_obj;
850 (*aslib_targets[lbfh->type]->loadfile) (lbfh);
853 #ifdef INDEXLIB
854 freelibraryindex ();
855 #endif