struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / sdas / linksrc / lkar.c
blob4236fdcdc0f91d040e2eeb22354a4ddc4c31a473
1 /* lkar.c - ar library format handling
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 gmail dot com
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 3, or (at your option) any
10 later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 * With contributions for the
22 * object libraries from
23 * Ken Hornstein
24 * kenh@cmf.nrl.navy.mil
29 * Extensions: P. Felber
32 #include <assert.h>
34 #include "aslink.h"
35 #include "lklibr.h"
36 #include "lkrel.h"
37 #include "lkar.h"
40 #ifndef max
41 # define max(a,b) ((a) > (b) ? (a) : (b))
42 #endif
44 #ifndef min
45 # define min(a,b) ((a) < (b) ? (a) : (b))
46 #endif
49 #ifndef HAVE_STRNDUP
50 char *
51 strndup (const char *str, size_t len)
53 char *s = (char *) malloc (len + 1);
54 memcpy (s, str, len);
55 s[len] = '\0';
56 return s;
58 #endif
60 static int
61 is_ar (FILE * libfp)
63 char buf[SARMAG];
64 int ret;
66 if (!(ret = fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, ARMAG, SARMAG) == 0))
67 rewind (libfp);
69 return ret;
72 static char *str_tab; /* string table */
73 static int str_tab_size; /* string table size */
75 static char *
76 get_long_name (const char *name)
78 assert ('/' == name[0]);
80 if (NULL != str_tab)
82 char *p;
84 int name_offset = strtol (++name, &p, 0);
85 if (p != name && name_offset < str_tab_size)
87 int len = p - name + 1;
88 while (len < AR_NAME_LEN && name[len++] == ' ')
90 if (len == AR_NAME_LEN)
92 const char *n;
94 /* long name: get it from the symbol table */
95 name = &str_tab[name_offset];
96 for (n = name; *n != '/' && *n != '\n'; ++n)
97 assert (n < &str_tab[str_tab_size]);
99 if (n[0] != '/' || n[1] != '\n')
100 while (*++n != '\n')
101 assert (n < &str_tab[str_tab_size]);
103 return strndup (name, n - name);
107 return NULL;
110 static char *
111 get_member_name (char *name, size_t *p_size, int allocate, FILE * libfp)
113 if (p_size != NULL)
114 *p_size = 0;
116 if (0 == memcmp (name, "#1/", 3))
118 char *p;
119 size_t len = strtoul (&name [3], &p, 10);
120 if (p > &name [3])
122 /* BSD appends real file name to the file header */
123 if (p_size != NULL)
124 *p_size = len;
126 if (allocate)
128 char *n = (char *) malloc (len);
129 if (fread (n, 1, len, libfp) != len)
131 /* not an ar archive or broken ar archive */
132 free (n);
133 return NULL;
135 else
136 return n;
138 else
140 /* just advance the file pointer */
141 fseek (libfp, len, SEEK_CUR);
142 return NULL;
145 else
147 /* not an ar archive or broken ar archive */
148 return NULL;
151 else if (allocate)
153 if (name[0] == '/')
155 char *n = get_long_name (name);
156 if (NULL != n)
157 return n;
159 else
161 const char *p = strrchr (name + 1, '/');
163 if (NULL != p)
165 int len = p - name;
166 while (name[++len] == ' ')
168 if (len == AR_NAME_LEN)
169 return strndup (name, p - name);
171 else
173 /* BSD formed member name:
174 trim trailing spaces */
175 p = name + AR_NAME_LEN;
176 while (*--p == ' ' && p >= name)
178 return strndup (name, p - name + 1);
182 /* bad formed member name or long name not found:
183 just return it */
185 return strdup (name);
187 else
188 return NULL;
191 static size_t
192 ar_get_header (struct ar_hdr *hdr, FILE * libfp, char **p_obj_name)
194 char header[ARHDR_LEN];
195 char buf[AR_DATE_LEN + 1];
196 char *obj_name;
197 size_t size;
199 if (fread (header, 1, sizeof (header), libfp) != sizeof (header)
200 || memcmp (header + AR_FMAG_OFFSET, ARFMAG, AR_FMAG_LEN) != 0)
202 /* not an ar archive */
203 return 0;
206 memcpy (hdr->ar_name, &header[AR_NAME_OFFSET], AR_NAME_LEN);
207 hdr->ar_name[AR_NAME_LEN] = '\0';
209 memcpy (buf, &header[AR_DATE_OFFSET], AR_DATE_LEN);
210 buf[AR_DATE_LEN] = '\0';
211 hdr->ar_date = strtol (buf, NULL, 0);
213 memcpy (buf, &header[AR_UID_OFFSET], AR_GID_LEN);
214 buf[AR_GID_LEN] = '\0';
215 hdr->ar_uid = (uid_t) strtol (buf, NULL, 0);
217 memcpy (buf, &header[AR_GID_OFFSET], AR_DATE_LEN);
218 buf[AR_DATE_LEN] = '\0';
219 hdr->ar_gid = (gid_t) strtol (buf, NULL, 0);
221 memcpy (buf, &header[AR_MODE_OFFSET], AR_MODE_LEN);
222 buf[AR_MODE_LEN] = '\0';
223 hdr->ar_mode = (mode_t) strtoul (buf, NULL, 0);
225 memcpy (buf, &header[AR_SIZE_OFFSET], AR_SIZE_LEN);
226 buf[AR_SIZE_LEN] = '\0';
227 hdr->ar_size = strtol (buf, NULL, 0);
229 obj_name = get_member_name (hdr->ar_name, &size, p_obj_name != NULL, libfp);
231 if (p_obj_name != NULL)
232 *p_obj_name = obj_name;
234 /* treat BSD appended real file name as a part of the header */
235 hdr->ar_size -= size;
237 return size + ARHDR_LEN;
240 #ifdef INDEXLIB
241 static char *
242 get_member_name_by_offset (FILE * fp, long offset)
244 struct ar_hdr hdr;
245 char *name;
247 fseek (fp, offset, SEEK_SET);
248 return (ar_get_header (&hdr, fp, &name) != 0) ? name : NULL;
251 static pmlibraryfile
252 find_member_by_offset (const char *libspc, long offset)
254 pmlibraryfile p;
256 /* walk trough all archive members */
257 for (p = libr; p; p = p->next)
259 if (0 == strcmp (libspc, p->libspc) && p->offset == offset)
260 return p;
263 return NULL;
266 static pmlibraryfile
267 buildlibraryindex_ar (struct lbname *lbnh, FILE * libfp, pmlibraryfile This, int type)
269 struct ar_hdr hdr;
270 char *obj_name;
271 size_t hdr_size;
272 int sym_found = 0;
274 /* walk trough all archive members */
275 while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
277 long pos = ftell (libfp);
279 if (AR_IS_SYMBOL_TABLE (obj_name))
281 char *buf, *po, *ps;
282 int i;
283 long nsym;
285 /* duplicated symbol table */
286 assert (!sym_found);
288 free (obj_name);
290 buf = (char *) new (hdr.ar_size);
292 if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
294 free (buf);
295 return This;
298 nsym = sgetl (buf);
300 po = buf + 4;
301 ps = po + nsym * 4;
303 for (i = 0; i < nsym; ++i)
305 pmlibrarysymbol ThisSym;
306 char *sym;
307 long offset;
308 pmlibraryfile entry;
310 offset = sgetl (po);
311 po += 4;
313 sym = strdup (ps);
314 ps += strlen (ps) + 1;
316 if ((entry = find_member_by_offset (lbnh->libspc, offset)) != NULL)
318 for (ThisSym = entry->symbols; ThisSym->next != NULL; ThisSym = ThisSym->next)
321 else
323 /* Opened OK - create a new libraryfile object for it */
324 if (This == NULL)
326 assert (libr == NULL);
327 libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
329 else
331 This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
332 This = This->next;
334 This->next = NULL;
335 This->loaded = 0;
336 This->libspc = lbnh->libspc;
337 This->offset = offset;
338 This->relfil = get_member_name_by_offset (libfp, offset); /* member name */
339 This->filspc = strdup (This->relfil); /* member file name */
340 This->type = type;
342 /* start a new linked list of symbols for this module. */
343 This->symbols = ThisSym = NULL;
346 if (ThisSym == NULL)
347 ThisSym = This->symbols = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
348 else
350 ThisSym->next = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
351 ThisSym = ThisSym->next;
353 ThisSym->next = NULL;
354 ThisSym->name = sym;
356 free (buf);
358 sym_found = 1;
360 /* string table already found: finish */
361 if (str_tab)
362 break;
364 else if (AR_IS_BSD_SYMBOL_TABLE (obj_name))
366 char *buf, *po, *ps;
367 int i;
368 long nsym, tablesize;
370 /* duplicated symbol table */
371 assert (!sym_found);
373 free (obj_name);
375 buf = (char *) new (hdr.ar_size);
377 if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
379 free (buf);
380 return This;
383 tablesize = sgetl (buf);
384 nsym = tablesize / 8;
386 po = buf + 4;
388 ps = po + tablesize + 4;
390 for (i = 0; i < nsym; ++i)
392 pmlibrarysymbol ThisSym;
393 char *sym;
394 long offset;
395 pmlibraryfile entry;
397 sym = ps + sgetl (po);
398 po += 4;
399 offset = sgetl (po);
400 po += 4;
402 sym = strdup (ps);
404 if ((entry = find_member_by_offset (lbnh->libspc, offset)) != NULL)
406 for (ThisSym = entry->symbols; ThisSym->next != NULL; ThisSym = ThisSym->next)
409 else
411 /* Opened OK - create a new libraryfile object for it */
412 if (This == NULL)
414 assert (libr == NULL);
415 libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
417 else
419 This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
420 This = This->next;
422 This->next = NULL;
423 This->loaded = 0;
424 This->libspc = lbnh->libspc;
425 This->offset = offset;
426 This->relfil = get_member_name_by_offset (libfp, offset); /* member name */
427 This->filspc = strdup (This->relfil); /* member file name */
428 This->type = type;
430 /* start a new linked list of symbols for this module. */
431 This->symbols = ThisSym = NULL;
434 if (ThisSym == NULL)
435 ThisSym = This->symbols = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
436 else
438 ThisSym->next = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
439 ThisSym = ThisSym->next;
441 ThisSym->next = NULL;
442 ThisSym->name = sym;
444 free (buf);
446 sym_found = 1;
448 /* string table already found: finish */
449 if (str_tab)
450 break;
452 else if (AR_IS_STRING_TABLE (obj_name))
454 free (obj_name);
456 /* duplicated string table */
457 assert (NULL == str_tab);
459 str_tab = (char *) new (hdr.ar_size);
461 if (fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
463 free (str_tab);
464 str_tab_size = 0;
465 return This;
467 str_tab_size = hdr.ar_size;
469 /* sybol table already found: finish */
470 if (sym_found)
471 break;
473 else
475 if (NULL == libr)
477 /* Opened OK - create a new libraryfile object for it */
478 if (This == NULL)
480 assert (libr == NULL);
481 libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
483 else
485 This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
486 This = This->next;
488 This->next = NULL;
489 This->loaded = -1;
490 This->libspc = lbnh->libspc;
491 This->offset = pos - hdr_size;
493 This->relfil = obj_name; /* member name */
494 This->filspc = strdup (This->relfil); /* member file name */
496 D (" Indexing module: %s\n", This->relfil);
498 This->type = type;
500 /* start a new linked list of symbols for this module. */
501 This->symbols = NULL;
503 add_rel_index (libfp, hdr.ar_size, This);
506 fseek (libfp, pos + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
509 if (NULL != str_tab)
511 /* has a symbol table: walk through modules and replace offsets with names */
512 pmlibraryfile lfp;
514 for (lfp = libr; lfp; lfp = lfp->next)
516 char *name = lfp->relfil;
517 if (name[0] == '/')
519 char *p = get_long_name (name);
520 if (NULL != p)
522 free (lfp->relfil);
523 lfp->relfil = p;
524 free (lfp->filspc);
525 lfp->filspc = strdup (p);
531 free (str_tab);
532 str_tab = NULL;
533 str_tab_size = 0;
536 return This;
539 #else
541 #if 0
542 static int
543 load_adb (FILE * libfp, struct lbfile *lbfh)
545 struct ar_hdr hdr;
546 char *adb_name;
547 char *obj_name;
548 size_t hdr_size;
550 /* check if it is a .rel file */
551 if (0 != stricmp (&lbfh->relfil[strlen (lbfh->relfil) - 4], ".rel"))
552 return 0;
555 adb_name = (char *) new (strlen (lbfh->relfil) + 1);
556 memcpy (adb_name, lbfh->relfil, strlen (lbfh->relfil) - 4);
557 memcpy (&adb_name[strlen (lbfh->relfil) - 4], ".adb", 5);
559 if (!is_ar (libfp))
561 fprintf (stderr, "?ASlink-Error-%s is not an archive\n", lbfh->libspc);
562 fclose (libfp);
563 lkexit (1);
566 /* walk trough all archive members */
567 while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
569 if (AR_IS_STRING_TABLE (obj_name))
571 free (obj_name);
573 if (str_tab)
574 free (str_tab);
576 str_tab = (char *) new (hdr.ar_size);
578 if ((off_t) fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
580 free (str_tab);
581 str_tab_size = 0;
582 return 0;
584 str_tab_size = hdr.ar_size;
586 if (AR_IS_SYMBOL_TABLE (obj_name) || 0 != stricmp (obj_name, adb_name))
588 free (obj_name);
590 /* skip the mamber */
591 fseek (libfp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
593 else
595 long left = hdr.ar_size;
596 char buf[4096];
598 free (obj_name);
600 while (left)
602 size_t n = min (left, sizeof buf);
604 if (fread (buf, 1, n, libfp) != n)
606 assert (0);
609 fwrite (buf, 1, n, yfp);
611 left -= n;
614 if (hdr.ar_size & 1)
615 getc (libfp);
617 free (adb_name);
618 return 1;
622 free (adb_name);
623 return 0;
625 #endif
627 static void
628 load_str_tab (FILE * libfp)
630 struct ar_hdr hdr;
631 char *obj_name;
632 size_t hdr_size;
634 /* walk trough all archive members */
635 while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
637 long pos = ftell (libfp);
639 if (AR_IS_STRING_TABLE (obj_name))
641 free (obj_name);
643 /* duplicated string table */
644 assert (NULL == str_tab);
646 str_tab = (char *) new (hdr.ar_size);
648 if (fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
650 free (str_tab);
651 str_tab_size = 0;
652 return;
654 str_tab_size = hdr.ar_size;
655 return;
658 fseek (libfp, pos + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
662 static int
663 fndsym_ar (const char *name, struct lbname *lbnh, FILE * libfp, int type)
665 struct ar_hdr hdr;
666 int ret = 0;
667 size_t hdr_size;
668 char *obj_name;
669 long pos;
671 pos = ftell (libfp);
672 load_str_tab (libfp);
673 fseek (libfp, pos, SEEK_SET);
675 /* walk trough all archive members */
676 while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
678 char filspc[PATH_MAX] = { 0 };
680 if (lbnh->path != NULL)
682 strcpy (filspc, lbnh->path);
683 if (*filspc != '\0' && (filspc[strlen (filspc) - 1] != '/') && (filspc[strlen (filspc) - 1] != LKDIRSEP))
685 strcat (filspc, LKDIRSEPSTR);
689 if (AR_IS_SYMBOL_TABLE (obj_name))
691 char *buf, *po, *ps;
692 int i;
693 long nsym;
695 free (obj_name);
697 buf = (char *) new (hdr.ar_size);
699 if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
701 free (buf);
702 return 0;
705 nsym = sgetl (buf);
707 po = buf + 4;
708 ps = po + nsym * 4;
710 for (i = 0; i < nsym; ++i)
712 char *sym;
713 long offset;
715 offset = sgetl (po);
716 po += 4;
718 sym = ps;
719 while (*ps++ != '\0')
722 if (0 == strcmp (name, sym))
724 fseek (libfp, offset, SEEK_SET);
725 if (ar_get_header (&hdr, libfp, &obj_name))
727 sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
729 /* If this module has been loaded already don't load it again. */
730 if (!is_module_loaded (filspc))
732 struct lbfile *lbfh, *lbf;
734 lbfh = (struct lbfile *) new (sizeof (struct lbfile));
735 lbfh->libspc = strdup (lbnh->libspc);
736 lbfh->relfil = obj_name;
737 lbfh->filspc = strdup (filspc);
738 lbfh->offset = offset;
739 lbfh->type = type;
741 if (lbfhead == NULL)
743 lbfhead = lbfh;
745 else
747 for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
750 lbf->next = lbfh;
753 D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
754 load_rel (libfp, hdr.ar_size);
755 ///* if cdb information required & .adb file present */
756 //if (yflag && yfp)
757 // {
758 // if (load_adb(FILE *libfp, struct lbfile *lbfh))
759 // SaveLinkedFilePath (filspc);
760 // }
761 ret = 1;
762 break;
765 else
767 fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbnh->libspc, name);
768 fclose (libfp);
769 lkexit (1);
773 free (buf);
775 break;
777 else if (AR_IS_BSD_SYMBOL_TABLE (obj_name))
779 char *buf, *po, *ps;
780 int i;
781 long nsym, tablesize;
783 free (obj_name);
785 buf = (char *) new (hdr.ar_size);
787 if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
789 free (buf);
790 return 0;
793 tablesize = sgetl (buf);
794 nsym = tablesize / 8;
796 po = buf + 4;
798 ps = po + tablesize + 4;
800 for (i = 0; i < nsym; ++i)
802 char *sym;
803 long offset;
805 sym = ps + sgetl (po);
806 po += 4;
807 offset = sgetl (po);
808 po += 4;
810 if (0 == strcmp (name, sym))
812 fseek (libfp, offset, SEEK_SET);
813 if (ar_get_header (&hdr, libfp, &obj_name))
815 sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
817 /* If this module has been loaded already don't load it again. */
818 if (!is_module_loaded (filspc))
820 struct lbfile *lbfh, *lbf;
822 lbfh = (struct lbfile *) new (sizeof (struct lbfile));
823 lbfh->libspc = strdup (lbnh->libspc);
824 lbfh->relfil = obj_name;
825 lbfh->filspc = strdup (filspc);
826 lbfh->offset = offset;
827 lbfh->type = type;
829 if (lbfhead == NULL)
831 lbfhead = lbfh;
833 else
835 for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
838 lbf->next = lbfh;
841 D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
842 load_rel (libfp, hdr.ar_size);
843 ///* if cdb information required & .adb file present */
844 //if (yflag && yfp)
845 // {
846 // if (load_adb(FILE *libfp, struct lbfile *lbfh))
847 // SaveLinkedFilePath (filspc);
848 // }
849 ret = 1;
850 break;
853 else
855 fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbnh->libspc, name);
856 fclose (libfp);
857 lkexit (1);
861 free (buf);
863 break;
865 else if (AR_IS_STRING_TABLE (obj_name))
867 free (obj_name);
869 if (str_tab)
870 free (str_tab);
872 str_tab = (char *) new (hdr.ar_size);
874 if (fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
876 free (str_tab);
877 str_tab = NULL;
878 str_tab_size = 0;
879 return 0;
881 str_tab_size = hdr.ar_size;
883 else
885 long pos = ftell (libfp);
887 free (obj_name);
889 D (" Module: %s\n", hdr.ar_name);
891 sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
893 /* Opened OK - create a new libraryfile object for it */
894 ret = add_rel_file (name, lbnh, hdr.ar_name, filspc, pos - hdr_size, libfp, hdr.ar_size, type);
895 ///* if cdb information required & .adb file present */
896 //if (yflag && yfp)
897 // {
898 // if (load_adb(FILE *libfp, struct lbfile *lbfh))
899 // SaveLinkedFilePath (filspc);
900 // }
901 if (ret)
902 break;
904 fseek (libfp, pos + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
908 if (NULL != str_tab)
910 free (str_tab);
911 str_tab = NULL;
912 str_tab_size = 0;
915 return ret;
917 #endif
919 static void
920 loadfile_ar (struct lbfile *lbfh)
922 FILE *fp;
923 fp = fopen (lbfh->libspc, "rb");
924 if (fp != NULL)
926 struct ar_hdr hdr;
928 fseek (fp, lbfh->offset, SEEK_SET);
929 if (ar_get_header (&hdr, fp, NULL) != 0)
931 D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
932 load_rel (fp, hdr.ar_size);
933 fclose (fp);
935 else
937 fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh->libspc, lbfh->relfil);
938 fclose (fp);
939 lkexit (1);
942 else
944 fprintf (stderr, "?ASlink-Error-Opening library '%s'\n", lbfh->libspc);
945 lkexit (1);
949 struct aslib_target aslib_target_ar = {
950 &is_ar,
951 #ifdef INDEXLIB
952 &buildlibraryindex_ar,
953 #else
954 &fndsym_ar,
955 #endif
956 &loadfile_ar,