1 /* lklibr.c */
2
3 /*
4 * Copyright (C) 1989-2009 Alan R. Baldwin
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 *
20 * Alan R. Baldwin
21 * 721 Berkeley St.
22 * Kent, Ohio 44240
23 *
24 * With contributions for the
25 * object libraries from
26 * Ken Hornstein
27 * kenhat cmf dot nrl dot navy dot mil
28 *
29 */
30
31 /*
32 * Extensions: P. Felber
33 */
34
35 #include <ctype.h>
36 #include <assert.h>
37
38 #include "aslink.h"
39 #include "lkrel.h"
40 #include "lklibr.h"
41
42 /*)Module lklibr.c
43 *
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
49 *
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()
58 *
59 */
60
61 #define EQ(A,B) !strcmp((A),(B))
62 #define NELEM(x) (sizeof (x) / sizeof (*x))
63
64 #ifdef INDEXLIB
65 /* First entry in the library object symbol cache */
66 pmlibraryfile libr = NULL;
67
68 int buildlibraryindex (void);
69 void freelibraryindex (void);
70 #endif /* INDEXLIB */
71
72 struct aslib_target *aslib_targets[] = {
73 &aslib_target_sdcclib,
74 &aslib_target_ar,
75 &aslib_target_lib,
76 };
77
78 /*)Function VOID addpath()
79 *
80 * The function addpath() creates a linked structure containing
81 * the paths to various object module library files.
82 *
83 * local variables:
84 * lbpath *lbph pointer to new path structure
85 * lbpath *lbp temporary pointer
86 *
87 * global variables:
88 * lbpath *lbphead The pointer to the first
89 * path structure
90 *
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
97 *
98 * side effects:
99 * An lbpath structure may be created.
100 */
101
102 VOID
addpath(void)103 addpath (void)
104 {
105 struct lbpath *lbph, *lbp;
106
107 lbph = (struct lbpath *) new (sizeof (struct lbpath));
108 if (lbphead == NULL)
109 {
110 lbphead = lbph;
111 }
112 else
113 {
114 lbp = lbphead;
115 while (lbp->next)
116 {
117 lbp = lbp->next;
118 }
119 lbp->next = lbph;
120 }
121 unget (getnb ());
122 lbph->path = strdup (ip);
123 }
124
125 /*)Function VOID addlib()
126 *
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.
130 *
131 * This function calls the function addfile() to actually
132 * add the library file to the search list.
133 *
134 * local variables:
135 * lbpath *lbph pointer to path structure
136 *
137 * global variables:
138 * lbpath *lbphead The pointer to the first
139 * path structure
140 * ip a pointer to the library name
141 *
142 * functions called:
143 * VOID addfile() lklibr.c
144 * int getnb() lklex.c
145 * VOID unget() lklex.c
146 *
147 * side effects:
148 * The function addfile() may add the file to
149 * the library search list.
150 */
151
152 VOID
addlib(void)153 addlib (void)
154 {
155 struct lbpath *lbph;
156 int foundcount = 0;
157
158 unget (getnb ());
159
160 if (lbphead == NULL)
161 {
162 foundcount = addfile (NULL, ip);
163 }
164 else
165 {
166 for (lbph = lbphead; lbph; lbph = lbph->next)
167 {
168 foundcount += addfile (lbph->path, ip);
169 }
170 }
171 if (foundcount == 0)
172 {
173 fprintf (stderr, "?ASlink-Warning-Couldn't find library '%s'\n", ip);
174 }
175 }
176
177 /*)Function int addfile(path,libfil)
178 *
179 * char *path library path specification
180 * char *libfil library file specification
181 *
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.
188 *
189 * The function does not report an error on invalid
190 * path / file specifications or if the file is not found.
191 *
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
199 *
200 * global variables:
201 * lbname *lbnhead The pointer to the first
202 * path structure
203 * int objflg linked file/library object output flag
204 *
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
211 *
212 * side effects:
213 * An lbname structure may be created.
214 *
215 * return:
216 * 1: the library was found
217 * 0: the library was not found
218 */
219
220 int
addfile(char * path,char * libfil)221 addfile (char *path, char *libfil)
222 {
223 FILE *fp;
224 char *str, *strend;
225 struct lbname *lbnh, *lbn;
226 #ifdef OTHERSYSTEM
227 int libfilinc = 0;
228 #endif
229
230 if (path != NULL)
231 {
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))
237 {
238 strcat (str, LKDIRSEPSTR);
239 }
240 #endif
241 }
242 else
243 {
244 str = (char *) new (strlen (libfil) + 5);
245 }
246
247 #ifdef OTHERSYSTEM
248 if ((libfil[0] == '/') || (libfil[0] == LKDIRSEP))
249 {
250 libfil++;
251 libfilinc = 1;
252 }
253 #endif
254
255 strcat (str, libfil);
256 if (strchr (libfil, FSEPX) == NULL)
257 {
258 sprintf (&str[strlen (str)], "%clib", FSEPX);
259 }
260
261 fp = fopen (str, "rb");
262 if (fp == NULL)
263 {
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)
271 {
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' */
275 }
276 }
277
278 if (path == NULL)
279 {
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--)
287 {
288 if ((path[j] == '/') || (path[j] == LKDIRSEP))
289 {
290 strcpy (libfil, &path[j + 1]);
291 path[j + 1] = 0;
292 break;
293 }
294 }
295 if (j <= 0)
296 path[0] = 0;
297 }
298
299 if (fp != NULL)
300 {
301 fclose (fp);
302 lbnh = (struct lbname *) new (sizeof (struct lbname));
303 if (lbnhead == NULL)
304 {
305 lbnhead = lbnh;
306 }
307 else
308 {
309 lbn = lbnhead;
310 while (lbn->next)
311 {
312 lbn = lbn->next;
313 }
314 lbn->next = lbnh;
315 }
316
317 lbnh->path = path;
318 lbnh->libfil = strdup (libfil);
319 lbnh->libspc = str;
320 lbnh->f_obj = objflg;
321 return 1;
322 }
323 else
324 {
325 free (str);
326 return 0;
327 }
328 }
329
330 /*)Function VOID search()
331 *
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.
337 *
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.
344 *
345 * local variables:
346 * int i temporary counter
347 * sym *sp pointer to a symbol structure
348 * int symfnd found a symbol flag
349 *
350 * global variables:
351 * sym *symhash[] array of pointers to symbol tables
352 *
353 * functions called:
354 * int fndsym() lklibr.c
355 *
356 * side effects:
357 * If a symbol is found then the library object module
358 * containing the symbol will be imported and linked.
359 */
360
361 VOID
search(void)362 search (void)
363 {
364 struct sym *sp;
365 int i, symfnd;
366
367 /*
368 * Look for undefined symbols. Keep
369 * searching until no more symbols are resolved.
370 */
371 symfnd = 1;
372 while (symfnd)
373 {
374 symfnd = 0;
375 /*
376 * Look through all the symbols
377 */
378 for (i = 0; i < NHASH; ++i)
379 {
380 sp = symhash[i];
381 while (sp)
382 {
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.
390 */
391 if ((sp->s_type & S_DEF) == 0)
392 {
393 if (fndsym (sp->s_id))
394 {
395 symfnd++;
396 }
397 }
398 sp = sp->s_sp;
399 }
400 }
401 }
402 }
403
404 /*)Function VOID fndsym(name)
405 *
406 * char *name symbol name to find
407 *
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.
412 *
413 * The file specification may be formed in one of two ways:
414 *
415 * (1) If the library file contained an absolute
416 * path/file specification then this becomes filspc.
417 * (i.e. C:\...)
418 *
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. \...)
423 *
424 * The structure lbfile is created for the first library
425 * object file which contains the definition for the
426 * specified undefined symbol.
427 *
428 * If the library file [.LIB] contains file specifications for
429 * non existant files, no errors are returned.
430 *
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
443 *
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
450 *
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
467 *
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.
473 */
474
475 #ifdef INDEXLIB
476 int
fndsym(char * name)477 fndsym (char *name)
478 {
479 struct lbfile *lbfh, *lbf;
480 pmlibraryfile ThisLibr;
481 pmlibrarysymbol ThisSym = NULL;
482
483 pmlibraryfile FirstFound;
484 int numfound = 0;
485
486 D ("Searching symbol: %s\n", name);
487
488 /* Build the index if this is the first call to fndsym */
489 if (libr == NULL)
490 buildlibraryindex ();
491
492 /* Iterate through all library object files */
493 FirstFound = libr; /* So gcc stops whining */
494 for (ThisLibr = libr; ThisLibr != NULL; ThisLibr = ThisLibr->next)
495 {
496 /* Iterate through all symbols in an object file */
497 for (ThisSym = ThisLibr->symbols; ThisSym != NULL; ThisSym = ThisSym->next)
498 {
499 if (!strcmp (ThisSym->name, name))
500 {
501 if ((!ThisLibr->loaded) && (numfound == 0))
502 {
503 /* Object file is not loaded - add it to the list */
504 lbfh = (struct lbfile *) new (sizeof (struct lbfile));
505 if (lbfhead == NULL)
506 {
507 lbfhead = lbfh;
508 }
509 else
510 {
511 for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
512 ;
513
514 lbf->next = lbfh;
515 }
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;
521
522 (*aslib_targets[lbfh->type]->loadfile) (lbfh);
523
524 ThisLibr->loaded = 1;
525 }
526
527 if (numfound == 0)
528 {
529 numfound++;
530 FirstFound = ThisLibr;
531 }
532 else
533 {
534 char absPath1[PATH_MAX];
535 char absPath2[PATH_MAX];
536 #if defined(_WIN32)
537 int j;
538
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)))
552 {
553 if (numfound == 1)
554 {
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);
557 }
558 fprintf (stderr, " Library: '%s', Module: '%s'\n", ThisLibr->libspc, ThisLibr->relfil);
559 numfound++;
560 }
561 }
562 }
563 }
564 }
565 return numfound;
566 }
567
568 struct add_sym_s
569 {
570 pmlibraryfile plf;
571 pmlibrarysymbol pls;
572 };
573
574 static int
add_sybmol(const char * sym,void * param)575 add_sybmol (const char *sym, void *param)
576 {
577 struct add_sym_s *as = (struct add_sym_s *) param;
578 pmlibrarysymbol ps = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
579
580 D (" Indexing symbol: %s\n", sym);
581
582 as->plf->loaded = 0;
583 ps->next = NULL;
584 ps->name = strdup (sym);
585
586 if (as->pls == NULL)
587 {
588 as->pls = as->plf->symbols = ps;
589 }
590 else
591 {
592 as->pls->next = ps;
593 as->pls = as->pls->next;
594 }
595
596 return 0;
597 }
598
599 pmlibrarysymbol
add_rel_index(FILE * fp,long size,pmlibraryfile This)600 add_rel_index (FILE * fp, long size, pmlibraryfile This)
601 {
602 struct add_sym_s as;
603 as.plf = This;
604 as.pls = This->symbols;
605
606 assert (This->symbols == NULL);
607
608 enum_symbols (fp, size, &add_sybmol, &as);
609
610 return as.pls;
611 }
612
613 /* buildlibraryindex - build an in-memory cache of the symbols contained in
614 * the libraries
615 */
616 int
buildlibraryindex(void)617 buildlibraryindex (void)
618 {
619 pmlibraryfile This = NULL;
620 struct lbname *lbnh;
621
622 /*
623 * Search through every library in the linked list "lbnhead".
624 */
625 for (lbnh = lbnhead; lbnh; lbnh = lbnh->next)
626 {
627 FILE *libfp;
628 int i;
629
630 D ("Indexing library: %s\n", lbnh->libspc);
631
632 if ((libfp = fopen (lbnh->libspc, "rb")) == NULL)
633 {
634 fprintf (stderr, "?ASlink-Error-Cannot open library file %s\n", lbnh->libspc);
635 lkexit (1);
636 }
637
638 for (i = 0; i < NELEM (aslib_targets); ++i)
639 {
640 if ((*aslib_targets[i]->is_lib) (libfp))
641 {
642 This = (*aslib_targets[i]->buildlibraryindex) (lbnh, libfp, This, i);
643 break;
644 }
645 }
646
647 if (i >= NELEM (aslib_targets))
648 fprintf (stderr, "?ASlink-Error-Unknown library file format %s\n", lbnh->libspc);
649
650 fclose (libfp);
651 }
652
653 return 0;
654 }
655
656 /* Release all memory allocated for the in-memory library index */
657 void
freelibraryindex(void)658 freelibraryindex (void)
659 {
660 pmlibraryfile ThisLibr, ThisLibr2Free;
661 pmlibrarysymbol ThisSym, ThisSym2Free;
662
663 ThisLibr = libr;
664
665 while (ThisLibr)
666 {
667 ThisSym = ThisLibr->symbols;
668
669 while (ThisSym)
670 {
671 free (ThisSym->name);
672 ThisSym2Free = ThisSym;
673 ThisSym = ThisSym->next;
674 free (ThisSym2Free);
675 }
676 free (ThisLibr->filspc);
677 free (ThisLibr->relfil);
678 ThisLibr2Free = ThisLibr;
679 ThisLibr = ThisLibr->next;
680 free (ThisLibr2Free);
681 }
682
683 libr = NULL;
684 }
685
686 #else /* INDEXLIB */
687
688 struct load_sym_s
689 {
690 const char *name;
691 struct lbname *lbnh;
692 const char *relfil;
693 const char *filspc;
694 int offset;
695 int type;
696 };
697
698 static int
load_sybmol(const char * sym,void * params)699 load_sybmol (const char *sym, void *params)
700 {
701 struct load_sym_s *ls = (struct load_sym_s *) params;
702
703 D (" Symbol: %s\n", sym);
704
705 if (strcmp (ls->name, sym) == 0)
706 {
707 struct lbfile *lbfh, *lbf;
708
709 D (" Symbol %s found in module %s!\n", sym, ls->relfil);
710
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;
717
718 if (lbfhead == NULL)
719 lbfhead = lbfh;
720 else
721 {
722 for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
723 ;
724 lbf->next = lbfh;
725 }
726 (*aslib_targets[ls->type]->loadfile) (lbfh);
727
728 return 1;
729 }
730 else
731 return 0;
732 }
733
734 /*)Function int is_module_loaded(filspc)
735 *
736 * If this module has been already loaded
737 */
738
739 int
is_module_loaded(const char * filspc)740 is_module_loaded (const char *filspc)
741 {
742 struct lbfile *lbf;
743
744 for (lbf = lbfhead; lbf != NULL; lbf = lbf->next)
745 {
746 if (EQ (filspc, lbf->filspc))
747 {
748 D (" Module %s already loaded!\n", filspc);
749 return 1; /* Module already loaded */
750 }
751 }
752 return 0;
753 }
754
755 int
add_rel_file(const char * name,struct lbname * lbnh,const char * relfil,const char * filspc,int offset,FILE * fp,long size,int type)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)
758 {
759 struct load_sym_s ls;
760
761 /* If this module has been loaded already don't load it again. */
762 if (is_module_loaded (filspc))
763 return 0;
764 else
765 {
766 ls.name = name;
767 ls.lbnh = lbnh;
768 ls.relfil = relfil;
769 ls.filspc = filspc;
770 ls.offset = offset;
771 ls.type = type;
772
773 return enum_symbols (fp, size, &load_sybmol, &ls);
774 }
775 }
776
777 int
fndsym(const char * name)778 fndsym (const char *name)
779 {
780 FILE *libfp;
781 struct lbname *lbnh;
782 int i;
783
784 /*
785 * Search through every library in the linked list "lbnhead".
786 */
787
788 D ("Searching symbol: %s\n", name);
789
790 for (lbnh = lbnhead; lbnh; lbnh = lbnh->next)
791 {
792 int ret = 0;
793
794 D ("Library: %s\n", lbnh->libspc);
795
796 if ((libfp = fopen (lbnh->libspc, "rb")) == NULL)
797 {
798 fprintf (stderr, "?ASlink-Error-Cannot open library file %s\n", lbnh->libspc);
799 lkexit (1);
800 }
801
802 for (i = 0; i < NELEM (aslib_targets); ++i)
803 {
804 if ((*aslib_targets[i]->is_lib) (libfp))
805 {
806 ret = (*aslib_targets[i]->fndsym) (name, lbnh, libfp, i);
807 break;
808 }
809 }
810
811 if (i >= NELEM (aslib_targets))
812 fprintf (stderr, "?ASlink-Error-Unknown library file format %s\n", lbnh->libspc);
813
814 fclose (libfp);
815
816 if (ret)
817 return 1;
818
819 } /* Ends good open of libr file */
820 return 0;
821 }
822 #endif /* INDEXLIB */
823
824 /*)Function VOID library()
825 *
826 * The function library() links all the library object files
827 * contained in the lbfile structures.
828 *
829 * local variables:
830 * lbfile *lbfh pointer to lbfile structure
831 *
832 * global variables:
833 * lbfile *lbfhead pointer to first lbfile structure
834 * int obj_flag linked file/library object output flag
835 *
836 * functions called:
837 * VOID loadfile lklibr.c
838 *
839 * side effects:
840 * Links all files contained in the lbfile structures.
841 */
842
843 VOID
library(void)844 library (void)
845 {
846 struct lbfile *lbfh;
847
848 for (lbfh = lbfhead; lbfh; lbfh = lbfh->next) {
849 obj_flag = lbfh->f_obj;
850 (*aslib_targets[lbfh->type]->loadfile) (lbfh);
851 }
852
853 #ifdef INDEXLIB
854 freelibraryindex ();
855 #endif
856 }
857