source: trunk/emx/src/emxexp/emxexp.c@ 3669

Last change on this file since 3669 was 1018, checked in by bird, 22 years ago

Don't start with ordinals unless told!

  • Property cvs2svn:cvs-rev set to 1.14
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 26.2 KB
Line 
1/* emxexp.c -- Create export definitions from .o and .obj files
2 Copyright (c) 1993-1998 Eberhard Mattes
3
4This file is part of emxexp.
5
6emxexp is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emxexp is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emxexp; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <stdarg.h>
25#include <string.h>
26#include <getopt.h>
27#include <errno.h>
28#include <ar.h>
29#include <sys/omflib.h>
30#include <a_out.h>
31#include "defs.h"
32#include "demangle.h"
33
34struct bss_list
35{
36 char *name;
37 struct bss_list *next;
38};
39
40/* if != 0 we're supposed to add ordinals to the symbols. */
41static int ordinal = 0;
42/* if set the ordinals is to be sequentially assigned with no
43 conveniency gaps or anything. */
44static int ordinal_seq = FALSE;
45static int noname_flag = FALSE;
46static int bss_flag = FALSE;
47static int weak_flag = FALSE;
48/* When clear we'll do sorting and handle make sure there no duplicate weak
49 names and such. If set we'll just dump the publics and comdefs as we
50 used to do. */
51static int legacy_mode = FALSE;
52
53static FILE *out_file;
54static const char *inp_fname;
55static const char *mod_name;
56static int new_mod = FALSE;
57static int last_dem = FALSE;
58static struct bss_list *bss_list = NULL;
59
60/* OMF globals */
61static struct segdef
62{
63 /* pointer to local name */
64 const char *name;
65} *segdefs;
66static unsigned num_segdefs;
67static char ** lnames;
68static unsigned num_lnames;
69
70/* Aout globals */
71static char *aout_segnames[] =
72{
73 NULL, NULL, /* 0 N_UNDF */
74 NULL, NULL, /* 2 N_ABS */
75 "TEXT32", "TEXT32", /* 4 N_TEXT */
76 "DATA32", "DATA32", /* 6 N_DATA */
77 "BSS32", "BSS32", /* 8 N_BSS */
78 NULL, NULL, /* a */
79 NULL, NULL, /* c, d N_WEAKU */
80 NULL, "TEXT32", /* d N_WEAKA, f N_WEAKT */
81 "DATA32", "BSS32", /* 10 N_WEAKD, 11 N_WEAKB */
82 NULL, NULL, NULL, NULL, NULL
83};
84
85/* Per segment name sorting
86 Symbols are orginized in two constructs. One is a global symbol name
87 string pool kind thing. The other is per segment.
88
89 Weak symbols and communial data may be overridden. In those cases we'll
90 unlink the symbol and reinstert it to ensure that we don't get it in the
91 wrong segment.
92 */
93
94/* module in which a symbol is defined. */
95struct new_module
96{
97 char * name; /* module name. */
98 struct new_module * next; /* next module in the chain. */
99};
100
101/* LIFO of modules. (only so we can free it)
102 The head module is the current one. */
103struct new_module *new_modules;
104
105
106/* one symbol */
107struct new_symbol
108{
109 char * name; /* Symbol name from heap. */
110 struct new_symbol *nexthash; /* Next hash table entry. */
111 struct new_symbol *next, *prev; /* Per segment chain. */
112 struct new_module *mod; /* Module in which the symbol is defined. */
113 unsigned fweak:1; /* Weak symbol. */
114 unsigned fcomm:1; /* Communial data. */
115 unsigned fdummy:1; /* Dummy node, the one which is first & last
116 in the lists to save use from any
117 unpleasant list head/tail thinking. */
118};
119
120/* List of segments. */
121static struct new_symgrp
122{
123 char * name; /* segment name */
124 struct new_symbol *head; /* head of list. Always starts with a dummy node. */
125 struct new_symbol *tail; /* tail of list. Always starts with a dummy node. */
126 struct new_symgrp *next; /* next segement. */
127} * new_symgrps;
128
129/* symbol string hash table */
130struct new_symbol * new_hashtable[211];
131
132
133
134static void error (const char *fmt, ...) NORETURN2;
135static void usage (void) NORETURN2;
136static void bad_omf (void) NORETURN2;
137
138
139static void error (const char *fmt, ...)
140{
141 va_list arg_ptr;
142
143 va_start (arg_ptr, fmt);
144 fprintf (stderr, "emxexp: ");
145 vfprintf (stderr, fmt, arg_ptr);
146 fputc ('\n', stderr);
147 exit (2);
148}
149
150
151/* Allocate N bytes of memory. Quit on failure. This function is
152 used like malloc(), but we don't have to check the return value. */
153
154static void *xmalloc (size_t n)
155{
156 void *p;
157
158 p = malloc (n);
159 if (p == NULL && n)
160 error ("Out of memory");
161 return p;
162}
163
164
165/* Change the allocation of PTR to N bytes. Quit on failure. This
166 function is used like realloc(), but we don't have to check the
167 return value. */
168
169static void *xrealloc (void *ptr, size_t n)
170{
171 void *p;
172
173 p = realloc (ptr, n);
174 if (p == NULL && n)
175 error ("Out of memory");
176 return p;
177}
178
179
180/* Create a duplicate of the string S on the heap. Quit on failure.
181 This function is used like strdup(), but we don't have to check the
182 return value. */
183
184static char *xstrdup (const char *s)
185{
186 char *p;
187
188 p = xmalloc (strlen (s) + 1);
189 strcpy (p, s);
190 return p;
191}
192
193
194
195/* How to call this program. */
196
197static void usage (void)
198{
199 fputs ("emxexp " VERSION INNOTEK_VERSION " -- Copyright (c) 1993-1995 by Eberhard Mattes\n\n"
200 "Usage: emxexp [-n] [-u] [-o[<ordinal>] <input_file>...\n\n"
201 "Options:\n"
202 " -n Output NONAME keyword for each exported symbol\n"
203 " -o Output ordinal numbers, starting at 1\n"
204 " -o<ordinal> Output ordinal numbers, starting at <ordinal>\n"
205 " -u Also export uninitialized variables - only legacy mode\n"
206 " -w Allow export of weak symbols - only legacy mode\n"
207 " -l Legacy mode - disables sorting and weak handling\n",
208 stderr);
209 exit (1);
210}
211
212
213/* New export function. This will filter out duplicated BSS32 and weak
214 symbols and insert the symbols into arrays according to segment
215 value. new_print() will be called when all the input files are
216 processed and do the actual printing and ordinal assignments. */
217
218static void new_export (const char *name, const char *segname, int fweak, int fcomm)
219{
220 struct new_symbol *psym;
221 unsigned uhash;
222 const char * psz;
223
224 /* compute hash */
225 for (uhash = 0, psz = name; *psz; *psz++)
226 uhash = uhash * 65599 + *psz;
227 uhash %= sizeof(new_hashtable) / sizeof(new_hashtable[0]);
228
229 /* look for it */
230 for (psym = new_hashtable[uhash]; psym; psym = psym->nexthash)
231 if (!strcmp(psym->name, name))
232 break;
233
234 /* new */
235 if (!psym)
236 {
237 /* create new symbol node */
238 psym = xmalloc(sizeof(*psym));
239 psym->name = xstrdup(name);
240
241 /* insert into hash */
242 psym->nexthash = new_hashtable[uhash];
243 new_hashtable[uhash] = psym;
244 }
245 else
246 {/* existing. look for overrided symbols (weak/comm) and ignore duplicates. */
247 if (fweak || fcomm)
248 psym = NULL; /* just skip it - did I forget something...? */
249 else
250 {
251 if (psym->fcomm || psym->fweak)
252 { /* unlink the symbol. */
253 psym->prev->next = psym->next;
254 psym->next->prev = psym->prev;
255 }
256 else
257 psym = NULL;
258 }
259 }
260
261 /* insert the correct list */
262 if (psym)
263 {
264 struct new_symgrp *psymgrp;
265
266 /* Set symbol data */
267 psym->fcomm = fcomm;
268 psym->fweak = fweak;
269 psym->fdummy = 0;
270 psym->mod = new_modules;
271
272
273 /* find the segment */
274 for (psymgrp = new_symgrps; psymgrp; psymgrp = psymgrp->next)
275 if ( psymgrp->name == segname
276 || (segname && psymgrp->name && !strcmp(psymgrp->name, segname))
277 )
278 break;
279
280 /* new or old ? */
281 if (!psymgrp)
282 {
283 psymgrp = xmalloc(sizeof(*psymgrp));
284 psymgrp->name = segname ? xstrdup(segname) : NULL;
285 psymgrp->head = xmalloc(sizeof(*psymgrp->head));
286 psymgrp->tail = xmalloc(sizeof(*psymgrp->tail));
287 memset(psymgrp->head, 0, sizeof(*psymgrp->head));
288 memset(psymgrp->tail, 0, sizeof(*psymgrp->tail));
289 psymgrp->head->fdummy = 1;
290 psymgrp->tail->fdummy = 1;
291 /* link dummies */
292 psymgrp->head->next = psymgrp->tail;
293 psymgrp->tail->prev = psymgrp->head;
294 psymgrp->head->name = psymgrp->tail->name = "#;$$$$$$dummy$$$$$$$$$$$;#";
295 /* link it in */
296 psymgrp->next = new_symgrps;
297 new_symgrps = psymgrp;
298 }
299
300 /* insert at tail. */
301 psym->prev = psymgrp->tail->prev;
302 psym->next = psymgrp->tail;
303 psymgrp->tail->prev->next = psym;
304 psymgrp->tail->prev = psym;
305 }
306}
307
308
309/* Print the publics. (new method)
310
311 When -o is not specified with number, to leave a round number of unused
312 ordinals between the segments out of convenience mostly. */
313
314static void new_print(FILE *phfile, struct new_symgrp *psymgrp)
315{
316 /* enumerate symbol groups (segments) */
317 for (; psymgrp; psymgrp = psymgrp->next)
318 {
319 struct new_symbol *psym;
320
321 /* print a decent header */
322 if (psymgrp->name)
323 fprintf (phfile, " ; segment %s\n", psymgrp->name);
324 else
325 fprintf (phfile, " ; segment noname\n");
326
327 /* enumerate symbols */
328 for (psym = psymgrp->head->next; psym != psymgrp->tail; psym = psym->next)
329 {
330 int cch;
331
332 cch = fprintf (phfile, " \"%s\"", psym->name);
333 /* fancy align */
334 if (cch < 69)
335 cch = 70 - cch;
336 else if (cch < 89)
337 cch = 90 - cch;
338 else if (cch < 119)
339 cch = 120 - cch;
340 else
341 cch = 40 - (cch % 39);
342 fprintf (phfile, "%*s", cch, "");
343
344 /* flags */
345 if (ordinal)
346 cch += fprintf (phfile, " @%-5d", ordinal++);
347 if (noname_flag)
348 cch += fprintf (phfile, " NONAME");
349
350 /* comments - the first one might be used by emximp later... */
351 fprintf (phfile, " ; magicseg='%s' len=%d",
352 psymgrp->name ? psymgrp->name : "", strlen(psym->name));
353 if (psym->fweak)
354 fprintf (phfile, " weak");
355 if (psym->fcomm)
356 fprintf (phfile, " comm");
357 if (psym->mod)
358 fprintf (phfile, " mod='%s'", psym->mod->name);
359
360 fputc ('\n', phfile);
361 }
362
363 /* skip a line and some ordinals if we're allowed */
364 fputc ('\n', phfile);
365 if (!ordinal_seq && ordinal)
366 ordinal = ((ordinal + 199) / 100) * 100;
367 }
368}
369
370
371static void export (const char *name)
372{
373 char *dem;
374
375 if (new_mod)
376 {
377 fprintf (out_file, "\n; From %s", inp_fname);
378 if (mod_name != NULL)
379 fprintf (out_file, "(%s)", mod_name);
380 fputc ('\n', out_file);
381 new_mod = FALSE;
382 }
383 dem = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS);
384 if (dem != NULL)
385 {
386 fprintf (out_file, "\n ; %s\n", dem);
387 free (dem);
388 last_dem = TRUE;
389 }
390 else if (last_dem)
391 {
392 fputc ('\n', out_file);
393 last_dem = FALSE;
394 }
395 fprintf (out_file, " \"%s\"", name);
396 if (ordinal != 0)
397 fprintf (out_file, " @%d", ordinal++);
398 if (noname_flag)
399 fprintf (out_file, " NONAME");
400 fputc ('\n', out_file);
401}
402
403
404static void export_bss (const char *name)
405{
406 struct bss_list *p;
407
408 if (bss_flag)
409 {
410 for (p = bss_list; p != NULL; p = p->next)
411 if (strcmp (p->name, name) == 0)
412 return;
413 p = xmalloc (sizeof (*p));
414 p->name = xmalloc (strlen (name) + 1);
415 strcpy (p->name, name);
416 p->next = bss_list;
417 bss_list = p;
418 export (name);
419 }
420}
421
422
423static void process_aout (FILE *inp_file, long size)
424{
425 byte *inp_buf;
426 const struct exec *a_out_h;
427 const byte *sym;
428 const struct nlist *sym_ptr;
429 const byte *str_ptr;
430 long str_size;
431 int sym_count, i;
432 const char *name;
433
434 new_mod = TRUE;
435
436 inp_buf = xmalloc (size);
437 size = fread (inp_buf, 1, size, inp_file);
438
439 a_out_h = (struct exec *)inp_buf;
440 if (size < sizeof (struct exec) || N_MAGIC (*a_out_h) != OMAGIC)
441 error ("Malformed input file `%s'", inp_fname);
442 sym = (inp_buf + sizeof (struct exec) + a_out_h->a_text
443 + a_out_h->a_data + a_out_h->a_trsize + a_out_h->a_drsize);
444 if (!a_out_h->a_syms)
445 return;
446 str_ptr = sym + a_out_h->a_syms;
447 if (str_ptr + 4 - inp_buf > size)
448 error ("Malformed input file `%s'", inp_fname);
449 str_size = *(long *)str_ptr;
450 sym_ptr = (const struct nlist *)sym;
451 sym_count = a_out_h->a_syms / sizeof (struct nlist);
452 if (str_ptr + str_size - inp_buf > size)
453 error ("Malformed input file `%s'", inp_fname);
454
455 for (i = 0; i < sym_count; ++i)
456 if (sym_ptr[i].n_type == (N_TEXT|N_EXT) ||
457 sym_ptr[i].n_type == (N_DATA|N_EXT) ||
458 ((!legacy_mode || weak_flag) &&
459 (sym_ptr[i].n_type == N_WEAKT ||
460 sym_ptr[i].n_type == N_WEAKD)))
461 {
462 name = str_ptr + sym_ptr[i].n_un.n_strx;
463 if (legacy_mode)
464 export (name);
465 else
466 new_export (name, aout_segnames[sym_ptr[i].n_type],
467 sym_ptr[i].n_type >= N_WEAKU && sym_ptr[i].n_type >= N_WEAKB,
468 FALSE);
469 }
470 else if ((sym_ptr[i].n_type == N_EXT && sym_ptr[i].n_value != 0) ||
471 sym_ptr[i].n_type == (N_BSS|N_EXT) ||
472 ((!legacy_mode || weak_flag) && sym_ptr[i].n_type == N_WEAKB))
473 {
474 name = str_ptr + sym_ptr[i].n_un.n_strx;
475 if (legacy_mode)
476 export_bss (name);
477 else
478 new_export (name, aout_segnames[sym_ptr[i].n_type],
479 sym_ptr[i].n_type >= N_WEAKU && sym_ptr[i].n_type >= N_WEAKB,
480 TRUE);
481 }
482
483 free (inp_buf);
484}
485
486
487static byte rec_buf[MAX_REC_SIZE+8];
488static int rec_type;
489static int rec_len;
490static int rec_idx;
491
492
493static void bad_omf (void)
494{
495 error ("Malformed OMF file `%s'", inp_fname);
496}
497
498
499static void get_mem (void *dst, int len)
500{
501 if (rec_idx + len > rec_len)
502 bad_omf ();
503 memcpy (dst, rec_buf + rec_idx, len);
504 rec_idx += len;
505}
506
507
508static int get_byte (void)
509{
510 if (rec_idx >= rec_len)
511 bad_omf ();
512 return rec_buf[rec_idx++];
513}
514
515
516static void get_string (byte *dst)
517{
518 int len;
519
520 len = get_byte ();
521 get_mem (dst, len);
522 dst[len] = 0;
523}
524
525
526static int get_index (void)
527{
528 int result;
529
530 result = get_byte ();
531 if (result & 0x80)
532 {
533 if (rec_idx >= rec_len)
534 bad_omf ();
535 result = ((result & 0x7f) << 8) | rec_buf[rec_idx++];
536 }
537 return result;
538}
539
540
541static word get_dword (void)
542{
543 dword result;
544
545 if (rec_idx + 4 > rec_len)
546 bad_omf ();
547 result = rec_buf[rec_idx++];
548 result |= rec_buf[rec_idx++] << 8;
549 result |= rec_buf[rec_idx++] << 16;
550 result |= rec_buf[rec_idx++] << 24;
551 return result;
552}
553
554
555static word get_word (void)
556{
557 word result;
558
559 if (rec_idx + 2 > rec_len)
560 bad_omf ();
561 result = rec_buf[rec_idx++];
562 result |= rec_buf[rec_idx++] << 8;
563 return result;
564}
565
566
567static dword get_word_or_dword (void)
568{
569 return rec_type & REC32 ? get_dword () : get_word ();
570}
571
572
573static dword get_commlen (void)
574{
575 dword result;
576
577 result = get_byte ();
578 if (result <= 0x80)
579 return result;
580 switch (result)
581 {
582 case 0x81:
583 return get_word ();
584 case 0x84:
585 result = get_byte ();
586 result |= get_byte () << 8;
587 result |= get_byte () << 16;
588 return result;
589 case 0x88:
590 return get_dword ();
591 default:
592 bad_omf ();
593 }
594}
595
596
597static void omf_pubdef (void)
598{
599 int type, group, seg;
600 word frame;
601 dword offset;
602 byte name[260];
603
604 group = get_index ();
605 seg = get_index ();
606 if (seg == 0)
607 frame = get_word ();
608
609 while (rec_idx < rec_len)
610 {
611 char *weak;
612 get_string (name);
613 offset = get_word_or_dword ();
614 type = get_index ();
615 weak = strstr(name, "$w$");
616 if (legacy_mode)
617 {
618 if (!weak || weak_flag)
619 export (name);
620 }
621 else
622 {
623 if (weak)
624 {
625 memmove(weak + 1, weak, strlen(weak) + 1);
626 *weak++ = '\0';
627 }
628 new_export (name, segdefs[seg].name, weak != NULL, FALSE);
629 }
630 }
631}
632
633
634static void omf_comdef (void)
635{
636 int type_index, data_type;
637 byte name[260];
638
639 while (rec_idx < rec_len)
640 {
641 char *weak;
642 get_string (name);
643 type_index = get_index ();
644 data_type = get_byte ();
645 switch (data_type)
646 {
647 case 0x61:
648 get_commlen ();
649 get_commlen ();
650 break;
651 case 0x62:
652 get_commlen ();
653 break;
654 default:
655 bad_omf ();
656 }
657
658 weak = strstr(name, "$w$");
659 if (legacy_mode)
660 {
661 if (!weak || weak_flag)
662 export_bss (name);
663 }
664 else
665 {
666 if (weak)
667 {
668 memmove(weak + 1, weak, strlen(weak) + 1);
669 *weak++ = '\0';
670 }
671 new_export (name, "BSS32", weak != NULL, TRUE);
672 }
673 }
674}
675
676
677static void omf_lnames (void)
678{
679 while (rec_idx < rec_len)
680 {
681 unsigned len = get_byte ();
682 if (!(num_lnames % 64))
683 lnames = xrealloc(lnames, sizeof(lnames[0]) * (num_lnames + 64));
684 lnames[num_lnames] = xmalloc(len + 1);
685 get_mem(lnames[num_lnames], len);
686 lnames[num_lnames][len] = '\0';
687 num_lnames++;
688 }
689}
690
691
692static void omf_segdef (void)
693{
694 byte flags;
695 unsigned nameidx;
696 unsigned classidx;
697 unsigned ovlidx;
698
699 /* all we want the the segment name */
700 flags = get_byte (); /* segment attributes */
701 if ((flags & 0xE0) == 0)
702 {
703 get_word (); /* frame number */
704 get_byte (); /* offset */
705 }
706 if (rec_type & REC32) /* segment length */
707 get_dword ();
708 else
709 get_word ();
710
711 nameidx = get_index ();
712 classidx = get_index ();
713 ovlidx = get_index ();
714 if (nameidx == 0)
715 nameidx = classidx; /* paranoia */
716
717 /* add it */
718 if (!(num_segdefs % 64))
719 segdefs = xrealloc (segdefs, sizeof(segdefs[0]) * (num_segdefs + 64));
720 if (nameidx != 0 && nameidx < num_lnames)
721 segdefs[num_segdefs].name = lnames[nameidx];
722 else
723 segdefs[num_segdefs].name = NULL;
724 num_segdefs++;
725}
726
727
728
729static void process_omf (FILE *inp_file)
730{
731 int i;
732 struct omf_rec rec;
733
734 /* init */
735 new_mod = TRUE;
736 lnames = xmalloc(sizeof(lnames[0])* 64);
737 lnames[0] = NULL;
738 num_lnames = 1; /* dummy entry */
739 segdefs = xmalloc(sizeof(segdefs[0])* 64);
740 memset(&segdefs[0], 0, sizeof(segdefs[0]));
741 num_segdefs = 1;
742
743 /* read */
744 do
745 {
746 if (fread (&rec, sizeof (rec), 1, inp_file) != 1)
747 error ("Unexpected end of file on input file `%s'", inp_fname);
748 rec_type = rec.rec_type;
749 rec_len = rec.rec_len;
750 rec_idx = 0;
751 if (rec_len > sizeof (rec_buf))
752 error ("OMF record too long in `%s'", inp_fname);
753 if (fread (rec_buf, rec_len, 1, inp_file) != 1)
754 error ("Unexpected end of file on input file `%s'", inp_fname);
755 --rec_len; /* Remove checksum */
756 switch (rec_type)
757 {
758 case PUBDEF:
759 case PUBDEF|REC32:
760 omf_pubdef ();
761 break;
762 case COMDEF:
763 if (!legacy_mode || bss_flag)
764 omf_comdef ();
765 break;
766 case LNAMES:
767 omf_lnames ();
768 break;
769 case SEGDEF:
770 case SEGDEF|REC32:
771 omf_segdef ();
772 break;
773 }
774 } while (rec.rec_type != MODEND && rec_type != (MODEND|REC32));
775
776 /* cleanup (entry 0 isn't used) */
777 for (i = 1; i < num_lnames; i++)
778 free(lnames[i]);
779 free(lnames);
780 free(segdefs);
781}
782
783
784/* Process one input file. */
785
786static void process (void)
787{
788 static char ar_magic[SARMAG+1] = ARMAG;
789 char ar_test[SARMAG], *p, *end;
790 struct ar_hdr ar;
791 long size, ar_pos, index;
792 int i, n;
793 FILE *inp_file;
794 char *long_names = NULL;
795 size_t long_names_size = 0;
796
797 mod_name = NULL;
798 inp_file = fopen (inp_fname, "rb");
799 if (inp_file == NULL)
800 error ("Cannot open input file `%s'", inp_fname);
801
802 /* Read some bytes from the start of the file to find out whether
803 this is an archive (.a) file or not. */
804
805 if (fread (ar_test, sizeof (ar_test), 1, inp_file) != 1)
806 error ("Cannot read input file `%s'", inp_fname);
807
808 if (memcmp (ar_test, ar_magic, SARMAG) == 0)
809 {
810
811 /* The input file is an archive. Loop over all the members of
812 the archive. */
813
814 ar_pos = SARMAG;
815 for (;;)
816 {
817
818 /* Read the header of the member. */
819
820 fseek (inp_file, ar_pos, SEEK_SET);
821 size = fread (&ar, 1, sizeof (ar), inp_file);
822 if (size == 0)
823 break;
824 else if (size != sizeof (ar))
825 error ("Malformed archive `%s'", inp_fname);
826
827 /* Decode the header. */
828
829 errno = 0;
830 size = strtol (ar.ar_size, &p, 10);
831 if (p == ar.ar_size || errno != 0 || size <= 0 || *p != ' ')
832 error ("Malformed archive header in `%s'", inp_fname);
833 ar_pos += (sizeof (ar) + size + 1) & -2;
834
835 /* Remove trailing blanks from the member name. */
836
837 i = sizeof (ar.ar_name) - 1;
838 while (i > 0 && ar.ar_name[i-1] == ' ')
839 --i;
840 ar.ar_name[i] = 0;
841
842 if (strcmp (ar.ar_name, "ARFILENAMES/") == 0)
843 {
844 size_t i;
845
846 /* The "ARFILENAMES/" member contains the long file
847 names, each one is terminated with a newline
848 character. Member names starting with a space are
849 also considered long file names because a leading
850 space is used for names pointing into the
851 "ARFILENAMES/" table. Read the "ARFILENAMES/" member
852 to LONG_NAMES. */
853
854 if (size != 0)
855 {
856 long_names_size = (size_t)size;
857 long_names = xmalloc (long_names_size);
858 size = fread (long_names, 1, long_names_size, inp_file);
859 if (ferror (inp_file))
860 error ("Cannot read `%s'", inp_fname);
861 if (size != long_names_size)
862 error ("%s: ARFILENAMES/ member is truncated", inp_fname);
863
864 /* Replace the newlines with nulls to make
865 processing a bit more convenient. */
866
867 for (i = 0; i < long_names_size; ++i)
868 if (long_names[i] == '\n')
869 long_names[i] = 0;
870 if (long_names[long_names_size-1] != 0)
871 error ("%s: ARFILENAMES/ member corrupt", inp_fname);
872 }
873 }
874
875 /* Ignore the __.SYMDEF and __.IMPORT members. */
876
877 else if (strcmp (ar.ar_name, "__.SYMDEF") != 0
878 && strcmp (ar.ar_name, "__.IMPORT") != 0)
879 {
880 /* Process the current member. First, fetch the name of
881 the member. If the ar_name starts with a space, the
882 decimal number following that space is an offset into
883 the "ARFILENAMES/" member. The number may be
884 followed by a space and a substring of the long file
885 name. */
886
887 mod_name = ar.ar_name;
888 if (mod_name[0] == ' ' && long_names != NULL
889 && (index = strtol (mod_name + 1, &end, 10)) >= 0
890 && index < long_names_size - 1
891 && (*end == 0 || *end == ' ')
892 && (index == 0 || long_names[index-1] == 0))
893 mod_name = long_names + index;
894
895 process_aout (inp_file, size);
896 }
897 }
898 }
899 else
900 {
901 if (*(word *)ar_test == 0407)
902 {
903 if (fseek (inp_file, 0L, SEEK_END) != 0)
904 error ("Input file `%s' is not seekable", inp_fname);
905 size = ftell (inp_file);
906 fseek (inp_file, 0L, SEEK_SET);
907 process_aout (inp_file, size);
908 }
909 else if (*(byte *)ar_test == LIBHDR)
910 {
911 struct omflib *lib;
912 char errmsg[512], name[257];
913 int page;
914
915 lib = omflib_open (inp_fname, errmsg);
916 if (lib == NULL)
917 error ("%s: %s", inp_fname, errmsg);
918
919 n = omflib_module_count (lib, errmsg);
920 if (n == -1)
921 error ("%s: %s", inp_fname, errmsg);
922 for (i = 0; i < n; ++i)
923 {
924 if (omflib_module_info (lib, i, name, &page, errmsg) != 0)
925 error ("%s: %s", inp_fname, errmsg);
926 else
927 {
928 fseek (inp_file, omflib_page_pos (lib, page), SEEK_SET);
929 mod_name = name;
930 process_omf (inp_file);
931 }
932 }
933 if (omflib_close (lib, errmsg) != 0)
934 error ("%s: %s", inp_fname, errmsg);
935 }
936 else
937 {
938 fseek (inp_file, 0L, SEEK_SET);
939 process_omf (inp_file);
940 }
941 }
942 fclose (inp_file);
943}
944
945
946/* Main line. */
947
948int main (int argc, char **argv)
949{
950 int c, i;
951 char *p;
952
953 _response (&argc, &argv);
954 _wildcard (&argc, &argv);
955 opterr = 0;
956 optind = 0;
957 while ((c = getopt (argc, argv, "no::uw")) != EOF)
958 {
959 switch (c)
960 {
961 case 'n':
962 noname_flag = TRUE;
963 break;
964 case 'o':
965 if (optarg == NULL)
966 ordinal = 1;
967 else
968 {
969 errno = 0;
970 ordinal = (int)strtol (optarg, &p, 0);
971 if (p == optarg || errno != 0 || *p != 0
972 || ordinal < 1 || ordinal > 65535)
973 usage ();
974 ordinal_seq = 1;
975 }
976 break;
977 case 'u':
978 bss_flag = TRUE;
979 break;
980 case 'w':
981 weak_flag = TRUE;
982 break;
983 case 'l':
984 legacy_mode = TRUE;
985 break;
986 default:
987 error ("Invalid option");
988 }
989 }
990
991 out_file = stdout;
992
993 if (optind >= argc)
994 usage ();
995
996 for (i = optind; i < argc; ++i)
997 {
998 inp_fname = argv[i];
999 process ();
1000 }
1001
1002 if (!legacy_mode)
1003 new_print(out_file, new_symgrps);
1004
1005 if (fflush (out_file) != 0 || (out_file != stdout && fclose (out_file) != 0))
1006 error ("Write error");
1007
1008 return 0;
1009}
Note: See TracBrowser for help on using the repository browser.