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/>.
24 * With contributions for the
25 * object libraries from
27 * kenhat cmf dot nrl dot navy dot mil
32 * Extensions: P. Felber
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:
61 #define EQ(A,B) !strcmp((A),(B))
62 #define NELEM(x) (sizeof (x) / sizeof (*x))
65 /* First entry in the library object symbol cache */
66 pmlibraryfile libr
= NULL
;
68 int buildlibraryindex (void);
69 void freelibraryindex (void);
72 struct aslib_target
*aslib_targets
[] = {
73 &aslib_target_sdcclib
,
78 /*)Function VOID addpath()
80 * The function addpath() creates a linked structure containing
81 * the paths to various object module library files.
84 * lbpath *lbph pointer to new path structure
85 * lbpath *lbp temporary pointer
88 * lbpath *lbphead The pointer to the first
93 * VOID * new() lksym.c
94 * int strlen() c_library
95 * char * strcpy() c_library
96 * VOID unget() lklex.c
99 * An lbpath structure may be created.
105 struct lbpath
*lbph
, *lbp
;
107 lbph
= (struct lbpath
*) new (sizeof (struct lbpath
));
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.
135 * lbpath *lbph pointer to path structure
138 * lbpath *lbphead The pointer to the first
140 * ip a pointer to the library name
143 * VOID addfile() lklibr.c
144 * int getnb() lklex.c
145 * VOID unget() lklex.c
148 * The function addfile() may add the file to
149 * the library search list.
162 foundcount
= addfile (NULL
, ip
);
166 for (lbph
= lbphead
; lbph
; lbph
= lbph
->next
)
168 foundcount
+= addfile (lbph
->path
, ip
);
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.
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
201 * lbname *lbnhead The pointer to the first
203 * int objflg linked file/library object output flag
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
213 * An lbname structure may be created.
216 * 1: the library was found
217 * 0: the library was not found
221 addfile (char *path
, char *libfil
)
225 struct lbname
*lbnh
, *lbn
;
232 str
= (char *) new (strlen (path
) + strlen (libfil
) + 6);
234 strend
= str
+ strlen(str
) - 1;
236 if (strlen (str
) && (*strend
!= '/') && (*strend
!= LKDIRSEP
))
238 strcat (str
, LKDIRSEPSTR
);
244 str
= (char *) new (strlen (libfil
) + 5);
248 if ((libfil
[0] == '/') || (libfil
[0] == LKDIRSEP
))
255 strcat (str
, libfil
);
256 if (strchr (libfil
, FSEPX
) == NULL
)
258 sprintf (&str
[strlen (str
)], "%clib", FSEPX
);
261 fp
= fopen (str
, "rb");
264 /*Ok, that didn't work. Try with the 'libfil' name only */
269 fp
= fopen (libfil
, "rb");
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' */
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'. */
286 for (j
= strlen (path
) - 1; j
>= 0; j
--)
288 if ((path
[j
] == '/') || (path
[j
] == LKDIRSEP
))
290 strcpy (libfil
, &path
[j
+ 1]);
302 lbnh
= (struct lbname
*) new (sizeof (struct lbname
));
318 lbnh
->libfil
= strdup (libfil
);
320 lbnh
->f_obj
= objflg
;
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
346 * int i temporary counter
347 * sym *sp pointer to a symbol structure
348 * int symfnd found a symbol flag
351 * sym *symhash[] array of pointers to symbol tables
354 * int fndsym() lklibr.c
357 * If a symbol is found then the library object module
358 * containing the symbol will be imported and linked.
368 * Look for undefined symbols. Keep
369 * searching until no more symbols are resolved.
376 * Look through all the symbols
378 for (i
= 0; i
< NHASH
; ++i
)
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
))
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.
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.
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.
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
445 * lbname *lbnhead The pointer to the first
447 * lbfile *lbfhead The pointer to the first
449 * int obj_flag linked file/library object output flag
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
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
479 struct lbfile
*lbfh
, *lbf
;
480 pmlibraryfile ThisLibr
;
481 pmlibrarysymbol ThisSym
= NULL
;
483 pmlibraryfile FirstFound
;
486 D ("Searching symbol: %s\n", name
);
488 /* Build the index if this is the first call to fndsym */
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
));
511 for (lbf
= lbfhead
; lbf
->next
!= NULL
; lbf
= lbf
->next
)
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;
530 FirstFound
= ThisLibr
;
534 char absPath1
[PATH_MAX
];
535 char absPath2
[PATH_MAX
];
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
]);
546 if (NULL
== realpath (FirstFound
->libspc
, absPath1
))
548 if (NULL
== realpath (ThisLibr
->libspc
, absPath2
))
551 if (!(EQ (absPath1
, absPath2
) && EQ (FirstFound
->relfil
, ThisLibr
->relfil
)))
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
);
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
);
584 ps
->name
= strdup (sym
);
588 as
->pls
= as
->plf
->symbols
= ps
;
593 as
->pls
= as
->pls
->next
;
600 add_rel_index (FILE * fp
, long size
, pmlibraryfile This
)
604 as
.pls
= This
->symbols
;
606 assert (This
->symbols
== NULL
);
608 enum_symbols (fp
, size
, &add_sybmol
, &as
);
613 /* buildlibraryindex - build an in-memory cache of the symbols contained in
617 buildlibraryindex (void)
619 pmlibraryfile This
= NULL
;
623 * Search through every library in the linked list "lbnhead".
625 for (lbnh
= lbnhead
; lbnh
; lbnh
= lbnh
->next
)
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
);
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
);
647 if (i
>= NELEM (aslib_targets
))
648 fprintf (stderr
, "?ASlink-Error-Unknown library file format %s\n", lbnh
->libspc
);
656 /* Release all memory allocated for the in-memory library index */
658 freelibraryindex (void)
660 pmlibraryfile ThisLibr
, ThisLibr2Free
;
661 pmlibrarysymbol ThisSym
, ThisSym2Free
;
667 ThisSym
= ThisLibr
->symbols
;
671 free (ThisSym
->name
);
672 ThisSym2Free
= ThisSym
;
673 ThisSym
= ThisSym
->next
;
676 free (ThisLibr
->filspc
);
677 free (ThisLibr
->relfil
);
678 ThisLibr2Free
= ThisLibr
;
679 ThisLibr
= ThisLibr
->next
;
680 free (ThisLibr2Free
);
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
;
722 for (lbf
= lbfhead
; lbf
->next
!= NULL
; lbf
= lbf
->next
)
726 (*aslib_targets
[ls
->type
]->loadfile
) (lbfh
);
734 /*)Function int is_module_loaded(filspc)
736 * If this module has been already loaded
740 is_module_loaded (const char *filspc
)
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 */
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
))
773 return enum_symbols (fp
, size
, &load_sybmol
, &ls
);
778 fndsym (const char *name
)
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
)
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
);
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
);
811 if (i
>= NELEM (aslib_targets
))
812 fprintf (stderr
, "?ASlink-Error-Unknown library file format %s\n", lbnh
->libspc
);
819 } /* Ends good open of libr file */
822 #endif /* INDEXLIB */
824 /*)Function VOID library()
826 * The function library() links all the library object files
827 * contained in the lbfile structures.
830 * lbfile *lbfh pointer to lbfile structure
833 * lbfile *lbfhead pointer to first lbfile structure
834 * int obj_flag linked file/library object output flag
837 * VOID loadfile lklibr.c
840 * Links all files contained in the lbfile structures.
848 for (lbfh
= lbfhead
; lbfh
; lbfh
= lbfh
->next
) {
849 obj_flag
= lbfh
->f_obj
;
850 (*aslib_targets
[lbfh
->type
]->loadfile
) (lbfh
);