* as/asranlib/Makefile.in, as/asranlib/asranlib.dsp,
[fw/sdcc] / as / link / lkar.c
1 /* lkar.c - ar library format handling
2
3    Copyright (C) 1989-1995 Alan R. Baldwin
4    721 Berkeley St., Kent, Ohio 44240
5    Copyright (C) 2008-2009 Borut Razem, borut dot razem at siol dot net
6
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 /*
22  * With contributions for the
23  * object libraries from
24  * Ken Hornstein
25  * kenh@cmf.nrl.navy.mil
26  *
27  */
28
29 /*
30  * Extensions: P. Felber
31  */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <assert.h>
37
38 #include "aslink.h"
39 #include "lklibr.h"
40 #include "lkrel.h"
41 #include "lkar.h"
42
43
44 #ifndef max
45 # define max(a,b) ((a) > (b) ? (a) : (b))
46 #endif
47
48 #ifndef min
49 # define min(a,b) ((a) < (b) ? (a) : (b))
50 #endif
51
52
53 static int
54 is_ar (FILE * libfp)
55 {
56   char buf[SARMAG];
57   int ret;
58
59   if (!(ret = fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, ARMAG, SARMAG) == 0))
60     rewind (libfp);
61
62   return ret;
63 }
64
65 static struct ar_hdr *
66 ar_get_header (struct ar_hdr *hdr, FILE * libfp)
67 {
68   char header[ARHDR_LEN];
69   char buf[AR_DATE_LEN + 1];
70
71   if (fread (header, 1, sizeof (header), libfp) != sizeof (header)
72       || memcmp (header + AR_FMAG_OFFSET, ARFMAG, AR_FMAG_LEN) != 0)
73     {
74       /* not an ar archive */
75       return NULL;
76     }
77
78   memcpy (hdr->ar_name, &header[AR_NAME_OFFSET], AR_NAME_LEN);
79   hdr->ar_name[AR_NAME_LEN] = '\0';
80
81   memcpy (buf, &header[AR_DATE_OFFSET], AR_DATE_LEN);
82   buf[AR_DATE_LEN] = '\0';
83   hdr->ar_date = strtol (buf, NULL, 0);
84
85   memcpy (buf, &header[AR_UID_OFFSET], AR_GID_LEN);
86   buf[AR_GID_LEN] = '\0';
87   hdr->ar_uid = (uid_t) strtol (buf, NULL, 0);
88
89   memcpy (buf, &header[AR_GID_OFFSET], AR_DATE_LEN);
90   buf[AR_DATE_LEN] = '\0';
91   hdr->ar_gid = (gid_t) strtol (buf, NULL, 0);
92
93   memcpy (buf, &header[AR_MODE_OFFSET], AR_MODE_LEN);
94   buf[AR_MODE_LEN] = '\0';
95   hdr->ar_mode = (mode_t) strtoul (buf, NULL, 0);
96
97   memcpy (buf, &header[AR_SIZE_OFFSET], AR_SIZE_LEN);
98   buf[AR_SIZE_LEN] = '\0';
99   hdr->ar_size = strtol (buf, NULL, 0);
100
101   return hdr;
102 }
103
104 static char *sym_tab;
105 static int sym_tab_size;
106
107 static void
108 loadfile_ar (struct lbfile *lbfh)
109 {
110   FILE *fp;
111
112 #ifdef __CYGWIN__
113   char posix_path[PATH_MAX];
114   void cygwin_conv_to_full_posix_path (char *win_path, char *posix_path);
115   cygwin_conv_to_full_posix_path (lbfh->libspc, posix_path);
116   fp = fopen (posix_path, "rb");
117 #else
118   fp = fopen (lbfh->libspc, "rb");
119 #endif
120
121   if (fp != NULL)
122     {
123       struct ar_hdr hdr;
124
125       fseek (fp, lbfh->offset, SEEK_SET);
126       if (ar_get_header (&hdr, fp))
127         {
128           D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
129           load_rel (fp, hdr.ar_size);
130           fclose (fp);
131         }
132       else
133         {
134           fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh->libspc, lbfh->relfil);
135           fclose (fp);
136           lkexit (1);
137         }
138     }
139   else
140     {
141       fprintf (stderr, "?ASlink-Error-Opening library '%s'\n", lbfh->libspc);
142       lkexit (1);
143     }
144 }
145
146 #if INDEXLIB
147 char *
148 get_member_name (char *name)
149 {
150   if (name[0] == '/')
151     {
152       if (NULL != sym_tab)
153         {
154           char *p;
155
156           int name_offset = strtol (++name, &p, 0);
157           if (p != name && name_offset < sym_tab_size)
158             {
159               int len = p - name + 1;
160               while (len < AR_NAME_LEN && name[len++] == ' ')
161                 ;
162               if (len == AR_NAME_LEN)
163                 {
164                   char *n;
165
166                   /* long name: get it from the symbol table */
167                   name = &sym_tab[name_offset];
168                   for (p = name; *p != '/' && *p != '\n'; ++p)
169                     assert (p < &sym_tab[sym_tab_size]);
170
171                   if (p[0] != '/' || p[1] != '\n')
172                     while (*++p != '\n')
173                       assert (p < &sym_tab[sym_tab_size]);
174
175                   n = (char *) malloc (p - name + 1);
176                   memcpy (n, name, p - name);
177                   n[p - name] = '\0';
178                   return n;
179                 }
180             }
181         }
182     }
183   else
184     {
185       char *p = strrchr (name, '/');
186
187       if (NULL != p)
188         {
189           int len = p - name;
190           while (name[++len] == ' ')
191             ;
192           if (len == AR_NAME_LEN)
193             {
194               char *n = (char *) malloc (p - name + 1);
195               memcpy (n, name, p - name);
196               n[p - name] = '\0';
197               return n;
198             }
199         }
200     }
201
202   /* bad formed member name:
203      just return it */
204
205   return strdup (name);
206 }
207
208 static char *
209 get_member_name_by_offset (FILE * fp, long offset)
210 {
211   struct ar_hdr hdr;
212
213   fseek (fp, offset, SEEK_SET);
214
215   /* walk trough all archive members */
216   return (NULL != ar_get_header (&hdr, fp)) ? get_member_name (hdr.ar_name) : NULL;
217 }
218
219 static pmlibraryfile
220 find_member_by_offset (const char *libspc, long offset)
221 {
222   pmlibraryfile p;
223
224   for (p = libr; p; p = p->next)
225     {
226       if (0 == strcmp (libspc, p->libspc) && p->offset == offset)
227         return p;
228     }
229
230   return NULL;
231 }
232
233 static pmlibraryfile
234 buildlibraryindex_ar (struct lbname *lbnh, FILE * libfp, pmlibraryfile This, int type)
235 {
236   struct ar_hdr hdr;
237
238   /* walk trough all archive members */
239   while (ar_get_header (&hdr, libfp))
240     {
241       if (AR_IS_SYMBOL_TABLE (hdr))
242         {
243           char *buf, *po, *ps;
244           int i;
245           long nsym;
246
247           buf = (char *) new (hdr.ar_size);
248
249           if ((off_t) fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
250             {
251               free (buf);
252               return This;
253             }
254
255           nsym = sgetl (buf);
256
257           po = buf + 4;
258           ps = po + nsym * 4;
259
260           for (i = 0; i < nsym; ++i)
261             {
262               pmlibrarysymbol ThisSym;
263               char *sym;
264               long offset;
265               pmlibraryfile entry;
266
267               offset = sgetl (po);
268               po += 4;
269
270               sym = strdup (ps);
271               while (*ps++ != '\0')
272                 ;
273
274               if ((entry = find_member_by_offset (lbnh->libspc, offset)) != NULL)
275                 {
276                   for (ThisSym = entry->symbols; ThisSym->next != NULL; ThisSym = ThisSym->next)
277                     ;
278                 }
279               else
280                 {
281                   /* Opened OK - create a new libraryfile object for it */
282                   if (This == NULL)
283                     {
284                       assert (libr == NULL);
285                       libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
286                     }
287                   else
288                     {
289                       This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
290                       This = This->next;
291                     }
292                   This->next = NULL;
293                   This->loaded = -1;
294                   This->libspc = lbnh->libspc;
295                   This->offset = offset;
296                   This->relfil = get_member_name_by_offset (libfp, offset);     /* member name */
297                   This->filspc = strdup (This->relfil); /* member file name */
298                   This->type = type;
299
300                   /* start a new linked list of symbols for this module. */
301                   This->symbols = ThisSym = NULL;
302                 }
303
304               if (ThisSym == NULL)
305                 ThisSym = This->symbols = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
306               else
307                 {
308                   ThisSym->next = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
309                   ThisSym = ThisSym->next;
310                 }
311               This->loaded = 0;
312               ThisSym->next = NULL;
313               ThisSym->name = sym;
314             }
315           free (buf);
316
317           break;
318         }
319       else if (AR_IS_STRING_TABLE (hdr))
320         {
321           if (sym_tab)
322             free (sym_tab);
323
324           sym_tab = (char *) new (hdr.ar_size);
325
326           if ((off_t) fread (sym_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
327             {
328               free (sym_tab);
329               sym_tab_size = 0;
330               return This;
331             }
332           sym_tab_size = hdr.ar_size;
333         }
334       else
335         {
336           long moduleOffset = ftell (libfp);
337
338           /* Opened OK - create a new libraryfile object for it */
339           if (This == NULL)
340             {
341               assert (libr == NULL);
342               libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
343             }
344           else
345             {
346               This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
347               This = This->next;
348             }
349           This->next = NULL;
350           This->loaded = -1;
351           This->libspc = lbnh->libspc;
352           This->offset = moduleOffset - ARHDR_LEN;
353
354           This->relfil = get_member_name (hdr.ar_name); /* member name */
355           This->filspc = strdup (This->relfil); /* member file name */
356
357           D ("  Indexing module: %s\n", This->relfil);
358
359           This->type = type;
360
361           /* start a new linked list of symbols for this module. */
362           This->symbols = NULL;
363
364           add_rel_index (libfp, hdr.ar_size, This);
365
366           fseek (libfp, moduleOffset + hdr.ar_size, SEEK_SET);
367         }
368
369       if (hdr.ar_size & 1)
370         {
371           int c = getc (libfp);
372           assert (c == EOF || c == '\n');
373         }
374     }
375
376   if (NULL != sym_tab)
377     {
378       free (sym_tab);
379       sym_tab = NULL;
380       sym_tab_size = 0;
381     }
382
383   return This;
384 }
385
386 #else
387
388 #if 0
389 static int
390 load_adb (FILE * libfp, struct lbfile *lbfh)
391 {
392   struct ar_hdr hdr;
393   char *adb_name;
394
395   /* check if it is a .rel file */
396   if (0 != stricmp (&lbfh->relfil[strlen (lbfh->relfil) - 4], ".rel"))
397     return 0;
398
399
400   adb_name = (char *) new (strlen (lbfh->relfil) + 1);
401   memcpy (adb_name, lbfh->relfil, strlen (lbfh->relfil) - 4);
402   memcpy (&adb_name[strlen (lbfh->relfil) - 4], ".adb", 5);
403
404   if (!is_ar (libfp))
405     {
406       fprintf (stderr, "?ASlink-Error-%s is not an archive\n", lbfh->libspc);
407       fclose (libfp);
408       lkexit (1);
409     }
410
411
412   /* walk trough all archive members */
413   while (ar_get_header (&hdr, libfp))
414     {
415       if (AR_IS_STRING_TABLE (hdr))
416         {
417           if (sym_tab)
418             free (sym_tab);
419
420           sym_tab = (char *) new (hdr.ar_size);
421
422           if ((off_t) fread (sym_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
423             {
424               free (sym_tab);
425               sym_tab_size = 0;
426               return 0;
427             }
428           sym_tab_size = hdr.ar_size;
429         }
430       if (AR_IS_SYMBOL_TABLE (hdr) || 0 != stricmp (get_member_name (hdr.ar_name), adb_name))
431         {
432           /* skip the mamber */
433           fseek (libfp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
434         }
435       else
436         {
437           long left = hdr.ar_size;
438           char buf[4096];
439
440           while (left)
441             {
442               size_t n = min (left, sizeof buf);
443
444               if (fread (buf, 1, n, libfp) != n)
445                 {
446                   assert (0);
447                 }
448
449               fwrite (buf, 1, n, dfp);
450
451               left -= n;
452             }
453
454           if (hdr.ar_size & 1)
455             {
456               int c = getc (libfp);
457               assert (c == EOF || c == '\n');
458             }
459
460           free (adb_name);
461           return 1;
462         }
463     }
464
465   free (adb_name);
466   return 0;
467 }
468 #endif
469
470 static int
471 fndsym_ar (const char *name, struct lbname *lbnh, FILE * libfp, int type)
472 {
473   struct ar_hdr hdr;
474   int ret = 0;
475
476   /* walk trough all archive members */
477   while (ar_get_header (&hdr, libfp))
478     {
479       char filspc[PATH_MAX];
480
481       if (lbnh->path != NULL)
482         {
483           strcpy (filspc, lbnh->path);
484 #ifdef  OTHERSYSTEM
485           if (*filspc != '\0' && (filspc[strlen (filspc) - 1] != '/') && (filspc[strlen (filspc) - 1] != LKDIRSEP))
486             {
487               strcat (filspc, LKDIRSEPSTR);
488             }
489 #endif
490         }
491
492       if (AR_IS_SYMBOL_TABLE (hdr))
493         {
494           char *buf, *po, *ps;
495           int i;
496           long nsym;
497
498           buf = (char *) new (hdr.ar_size);
499
500           if ((off_t) fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
501             {
502               free (buf);
503               return 0;
504             }
505
506           nsym = sgetl (buf);
507
508           po = buf + 4;
509           ps = po + nsym * 4;
510
511           for (i = 0; i < nsym; ++i)
512             {
513               char *sym;
514               long offset;
515
516               offset = sgetl (po);
517               po += 4;
518
519               sym = ps;
520               while (*ps++ != '\0')
521                 ;
522
523               if (0 == strcmp (name, sym))
524                 {
525                   fseek (libfp, offset, SEEK_SET);
526                   if (ar_get_header (&hdr, libfp))
527                     {
528                       sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
529
530                       /* If this module has been loaded already don't load it again. */
531                       if (!is_module_loaded (filspc))
532                         {
533                           struct lbfile *lbfh, *lbf;
534
535                           lbfh = (struct lbfile *) new (sizeof (struct lbfile));
536                           lbfh->libspc = strdup (lbnh->libspc);
537                           lbfh->relfil = strdup (hdr.ar_name);
538                           lbfh->filspc = strdup (filspc);
539                           lbfh->offset = offset;
540                           lbfh->type = type;
541
542                           if (lbfhead == NULL)
543                             {
544                               lbfhead = lbfh;
545                             }
546                           else
547                             {
548                               for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
549                                 ;
550
551                               lbf->next = lbfh;
552                             }
553
554                           D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
555                           load_rel (libfp, hdr.ar_size);
556                           ///* if cdb information required & .adb file present */
557                           //if (dflag && dfp)
558                           //  {
559                           //    if (load_adb(FILE *libfp, struct lbfile *lbfh))
560                           //      SaveLinkedFilePath (filspc);
561                           //  }
562                           ret = 1;
563                           break;
564                         }
565                     }
566                   else
567                     {
568                       fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbnh->libspc, name);
569                       fclose (libfp);
570                       lkexit (1);
571                     }
572                 }
573             }
574           free (buf);
575
576           break;
577         }
578       else if (AR_IS_STRING_TABLE (hdr))
579         {
580           if (sym_tab)
581             free (sym_tab);
582
583           sym_tab = (char *) new (hdr.ar_size);
584
585           if ((off_t) fread (sym_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
586             {
587               free (sym_tab);
588               sym_tab = NULL;
589               sym_tab_size = 0;
590               return 0;
591             }
592           sym_tab_size = hdr.ar_size;
593         }
594       else
595         {
596           long moduleOffset = ftell (libfp);
597
598           D ("  Module: %s\n", hdr.ar_name);
599
600           sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
601
602           /* Opened OK - create a new libraryfile object for it */
603           ret = add_rel_file (name, lbnh, hdr.ar_name, filspc, moduleOffset - ARHDR_LEN, libfp, hdr.ar_size, type);
604           ///* if cdb information required & .adb file present */
605           //if (dflag && dfp)
606           //  {
607           //    if (load_adb(FILE *libfp, struct lbfile *lbfh))
608           //      SaveLinkedFilePath (filspc);
609           //  }
610           if (ret)
611             break;
612
613           fseek (libfp, moduleOffset + hdr.ar_size, SEEK_SET);
614         }
615
616       if (hdr.ar_size & 1)
617         {
618           int c = getc (libfp);
619           assert (c == EOF || c == '\n');
620         }
621     }
622
623   if (NULL != sym_tab)
624     {
625       free (sym_tab);
626       sym_tab = NULL;
627       sym_tab_size = 0;
628     }
629
630   return ret;
631 }
632 #endif
633
634 struct aslib_target aslib_target_ar = {
635   &is_ar,
636 #ifdef INDEXLIB
637   &buildlibraryindex_ar,
638 #else
639   &fndsym_ar,
640 #endif
641   &loadfile_ar,
642 };