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
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
24 * kenh@cmf.nrl.navy.mil
29 * Extensions: P. Felber
41 # define max(a,b) ((a) > (b) ? (a) : (b))
45 # define min(a,b) ((a) < (b) ? (a) : (b))
51 strndup (const char *str
, size_t len
)
53 char *s
= (char *) malloc (len
+ 1);
66 if (!(ret
= fread (buf
, 1, sizeof (buf
), libfp
) == sizeof (buf
) && memcmp (buf
, ARMAG
, SARMAG
) == 0))
72 static char *str_tab
; /* string table */
73 static int str_tab_size
; /* string table size */
76 get_long_name (const char *name
)
78 assert ('/' == name
[0]);
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
)
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')
101 assert (n
< &str_tab
[str_tab_size
]);
103 return strndup (name
, n
- name
);
111 get_member_name (char *name
, size_t *p_size
, int allocate
, FILE * libfp
)
116 if (0 == memcmp (name
, "#1/", 3))
119 size_t len
= strtoul (&name
[3], &p
, 10);
122 /* BSD appends real file name to the file header */
128 char *n
= (char *) malloc (len
);
129 if (fread (n
, 1, len
, libfp
) != len
)
131 /* not an ar archive or broken ar archive */
140 /* just advance the file pointer */
141 fseek (libfp
, len
, SEEK_CUR
);
147 /* not an ar archive or broken ar archive */
155 char *n
= get_long_name (name
);
161 const char *p
= strrchr (name
+ 1, '/');
166 while (name
[++len
] == ' ')
168 if (len
== AR_NAME_LEN
)
169 return strndup (name
, p
- name
);
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:
185 return strdup (name
);
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];
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 */
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
;
242 get_member_name_by_offset (FILE * fp
, long offset
)
247 fseek (fp
, offset
, SEEK_SET
);
248 return (ar_get_header (&hdr
, fp
, &name
) != 0) ? name
: NULL
;
252 find_member_by_offset (const char *libspc
, long offset
)
256 /* walk trough all archive members */
257 for (p
= libr
; p
; p
= p
->next
)
259 if (0 == strcmp (libspc
, p
->libspc
) && p
->offset
== offset
)
267 buildlibraryindex_ar (struct lbname
*lbnh
, FILE * libfp
, pmlibraryfile This
, int type
)
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
))
285 /* duplicated symbol table */
290 buf
= (char *) new (hdr
.ar_size
);
292 if (fread (buf
, 1, hdr
.ar_size
, libfp
) != hdr
.ar_size
)
303 for (i
= 0; i
< nsym
; ++i
)
305 pmlibrarysymbol ThisSym
;
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
)
323 /* Opened OK - create a new libraryfile object for it */
326 assert (libr
== NULL
);
327 libr
= This
= (pmlibraryfile
) new (sizeof (mlibraryfile
));
331 This
->next
= (pmlibraryfile
) new (sizeof (mlibraryfile
));
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 */
342 /* start a new linked list of symbols for this module. */
343 This
->symbols
= ThisSym
= NULL
;
347 ThisSym
= This
->symbols
= (pmlibrarysymbol
) new (sizeof (mlibrarysymbol
));
350 ThisSym
->next
= (pmlibrarysymbol
) new (sizeof (mlibrarysymbol
));
351 ThisSym
= ThisSym
->next
;
353 ThisSym
->next
= NULL
;
360 /* string table already found: finish */
364 else if (AR_IS_BSD_SYMBOL_TABLE (obj_name
))
368 long nsym
, tablesize
;
370 /* duplicated symbol table */
375 buf
= (char *) new (hdr
.ar_size
);
377 if (fread (buf
, 1, hdr
.ar_size
, libfp
) != hdr
.ar_size
)
383 tablesize
= sgetl (buf
);
384 nsym
= tablesize
/ 8;
388 ps
= po
+ tablesize
+ 4;
390 for (i
= 0; i
< nsym
; ++i
)
392 pmlibrarysymbol ThisSym
;
397 sym
= ps
+ sgetl (po
);
404 if ((entry
= find_member_by_offset (lbnh
->libspc
, offset
)) != NULL
)
406 for (ThisSym
= entry
->symbols
; ThisSym
->next
!= NULL
; ThisSym
= ThisSym
->next
)
411 /* Opened OK - create a new libraryfile object for it */
414 assert (libr
== NULL
);
415 libr
= This
= (pmlibraryfile
) new (sizeof (mlibraryfile
));
419 This
->next
= (pmlibraryfile
) new (sizeof (mlibraryfile
));
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 */
430 /* start a new linked list of symbols for this module. */
431 This
->symbols
= ThisSym
= NULL
;
435 ThisSym
= This
->symbols
= (pmlibrarysymbol
) new (sizeof (mlibrarysymbol
));
438 ThisSym
->next
= (pmlibrarysymbol
) new (sizeof (mlibrarysymbol
));
439 ThisSym
= ThisSym
->next
;
441 ThisSym
->next
= NULL
;
448 /* string table already found: finish */
452 else if (AR_IS_STRING_TABLE (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
)
467 str_tab_size
= hdr
.ar_size
;
469 /* sybol table already found: finish */
477 /* Opened OK - create a new libraryfile object for it */
480 assert (libr
== NULL
);
481 libr
= This
= (pmlibraryfile
) new (sizeof (mlibraryfile
));
485 This
->next
= (pmlibraryfile
) new (sizeof (mlibraryfile
));
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
);
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
);
511 /* has a symbol table: walk through modules and replace offsets with names */
514 for (lfp
= libr
; lfp
; lfp
= lfp
->next
)
516 char *name
= lfp
->relfil
;
519 char *p
= get_long_name (name
);
525 lfp
->filspc
= strdup (p
);
543 load_adb (FILE * libfp
, struct lbfile
*lbfh
)
550 /* check if it is a .rel file */
551 if (0 != stricmp (&lbfh
->relfil
[strlen (lbfh
->relfil
) - 4], ".rel"))
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);
561 fprintf (stderr
, "?ASlink-Error-%s is not an archive\n", lbfh
->libspc
);
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
))
576 str_tab
= (char *) new (hdr
.ar_size
);
578 if ((off_t
) fread (str_tab
, 1, hdr
.ar_size
, libfp
) != hdr
.ar_size
)
584 str_tab_size
= hdr
.ar_size
;
586 if (AR_IS_SYMBOL_TABLE (obj_name
) || 0 != stricmp (obj_name
, adb_name
))
590 /* skip the mamber */
591 fseek (libfp
, hdr
.ar_size
+ (hdr
.ar_size
& 1), SEEK_CUR
);
595 long left
= hdr
.ar_size
;
602 size_t n
= min (left
, sizeof buf
);
604 if (fread (buf
, 1, n
, libfp
) != n
)
609 fwrite (buf
, 1, n
, yfp
);
628 load_str_tab (FILE * libfp
)
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
))
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
)
654 str_tab_size
= hdr
.ar_size
;
658 fseek (libfp
, pos
+ hdr
.ar_size
+ (hdr
.ar_size
& 1), SEEK_SET
);
663 fndsym_ar (const char *name
, struct lbname
*lbnh
, FILE * libfp
, int type
)
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
))
697 buf
= (char *) new (hdr
.ar_size
);
699 if (fread (buf
, 1, hdr
.ar_size
, libfp
) != hdr
.ar_size
)
710 for (i
= 0; i
< nsym
; ++i
)
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
;
747 for (lbf
= lbfhead
; lbf
->next
!= NULL
; lbf
= lbf
->next
)
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 */
758 // if (load_adb(FILE *libfp, struct lbfile *lbfh))
759 // SaveLinkedFilePath (filspc);
767 fprintf (stderr
, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbnh
->libspc
, name
);
777 else if (AR_IS_BSD_SYMBOL_TABLE (obj_name
))
781 long nsym
, tablesize
;
785 buf
= (char *) new (hdr
.ar_size
);
787 if (fread (buf
, 1, hdr
.ar_size
, libfp
) != hdr
.ar_size
)
793 tablesize
= sgetl (buf
);
794 nsym
= tablesize
/ 8;
798 ps
= po
+ tablesize
+ 4;
800 for (i
= 0; i
< nsym
; ++i
)
805 sym
= ps
+ sgetl (po
);
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
;
835 for (lbf
= lbfhead
; lbf
->next
!= NULL
; lbf
= lbf
->next
)
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 */
846 // if (load_adb(FILE *libfp, struct lbfile *lbfh))
847 // SaveLinkedFilePath (filspc);
855 fprintf (stderr
, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbnh
->libspc
, name
);
865 else if (AR_IS_STRING_TABLE (obj_name
))
872 str_tab
= (char *) new (hdr
.ar_size
);
874 if (fread (str_tab
, 1, hdr
.ar_size
, libfp
) != hdr
.ar_size
)
881 str_tab_size
= hdr
.ar_size
;
885 long pos
= ftell (libfp
);
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 */
898 // if (load_adb(FILE *libfp, struct lbfile *lbfh))
899 // SaveLinkedFilePath (filspc);
904 fseek (libfp
, pos
+ hdr
.ar_size
+ (hdr
.ar_size
& 1), SEEK_SET
);
920 loadfile_ar (struct lbfile
*lbfh
)
923 fp
= fopen (lbfh
->libspc
, "rb");
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
);
937 fprintf (stderr
, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh
->libspc
, lbfh
->relfil
);
944 fprintf (stderr
, "?ASlink-Error-Opening library '%s'\n", lbfh
->libspc
);
949 struct aslib_target aslib_target_ar
= {
952 &buildlibraryindex_ar
,