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